Skip to content

Commit 55c1025

Browse files
symballsymballleaanthony
authored
Add user install scope for Windows NSIS installer (#5094)
* * Add `InstallScope` to build options that will affect the NSIS output. * Modify the NSIS artefacts to handle install scope context * Include CLI flag handling `-installscope`. Defaults to current behaviour but, using `user` will target users AppData instead of program files * * fix typo and comment formatting --------- Co-authored-by: symball <contact@simonball.me> Co-authored-by: Lea Anthony <lea.anthony@gmail.com>
1 parent 324c2f3 commit 55c1025

7 files changed

Lines changed: 81 additions & 17 deletions

File tree

v2/cmd/wails/build.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@ package main
22

33
import (
44
"fmt"
5-
"github.com/wailsapp/wails/v2/pkg/commands/buildtags"
65
"os"
76
"runtime"
87
"strings"
98
"time"
109

10+
"github.com/wailsapp/wails/v2/pkg/commands/buildtags"
11+
1112
"github.com/leaanthony/slicer"
1213
"github.com/pterm/pterm"
1314
"github.com/wailsapp/wails/v2/cmd/wails/flags"
@@ -94,6 +95,7 @@ func buildApplication(f *flags.Build) error {
9495
SkipBindings: f.SkipBindings,
9596
ProjectData: projectOptions,
9697
SkipEmbedCreate: f.SkipEmbedCreate,
98+
InstallScope: f.InstallScope,
9799
}
98100

99101
tableData := pterm.TableData{
@@ -104,6 +106,7 @@ func buildApplication(f *flags.Build) error {
104106
{"Devtools", bool2Str(buildOptions.Devtools)},
105107
{"Frontend Directory", projectOptions.GetFrontendDir()},
106108
{"Obfuscated", bool2Str(f.Obfuscated)},
109+
{"Install Scope", f.InstallScope},
107110
}
108111
if f.Obfuscated {
109112
tableData = append(tableData, []string{"Garble Args", f.GarbleArgs})

v2/cmd/wails/flags/build.go

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ type Build struct {
3636
Debug bool `description:"Builds the application in debug mode"`
3737
Devtools bool `description:"Enable Devtools in productions, Already enabled in debug mode (-debug)"`
3838
NSIS bool `description:"Generate NSIS installer for Windows"`
39+
InstallScope string `description:"NSIS install scope: machine (default) or user"`
3940
TrimPath bool `description:"Remove all file system paths from the resulting executable"`
4041
WindowsConsole bool `description:"Keep the console when building for Windows"`
4142
Obfuscated bool `description:"Code obfuscation of bound Wails methods"`
@@ -66,11 +67,11 @@ func (b *Build) Default() *Build {
6667
}
6768

6869
result := &Build{
69-
Platform: defaultPlatform + "/" + defaultArch,
70-
WebView2: "download",
71-
GarbleArgs: "-literals -tiny -seed=random",
72-
73-
defaultArch: defaultArch,
70+
Platform: defaultPlatform + "/" + defaultArch,
71+
WebView2: "download",
72+
GarbleArgs: "-literals -tiny -seed=random",
73+
InstallScope: "machine",
74+
defaultArch: defaultArch,
7475
}
7576
result.BuildCommon = result.BuildCommon.Default()
7677
return result
@@ -126,6 +127,15 @@ func (b *Build) Process() error {
126127
b.wv2rtstrategy = "wv2runtime." + b.WebView2
127128
}
128129

130+
// Validate install scope
131+
b.InstallScope = strings.ToLower(b.InstallScope)
132+
if b.InstallScope != "" {
133+
validScopes := slicer.String([]string{"machine", "user"})
134+
if !validScopes.Contains(b.InstallScope) {
135+
return fmt.Errorf("invalid option for flag 'installscope': %s", b.InstallScope)
136+
}
137+
}
138+
129139
return nil
130140
}
131141

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
module panic-recovery-test
22

3-
go 1.21
3+
go 1.22.0
44

55
require github.com/wailsapp/wails/v2 v2.11.0

v2/pkg/buildassets/build/windows/installer/project.nsi

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,15 @@ ManifestDPIAware true
7272

7373
Name "${INFO_PRODUCTNAME}"
7474
OutFile "..\..\bin\${INFO_PROJECTNAME}-${ARCH}-installer.exe" # Name of the installer's file.
75-
InstallDir "$PROGRAMFILES64\${INFO_COMPANYNAME}\${INFO_PRODUCTNAME}" # Default installing folder ($PROGRAMFILES is Program Files folder).
75+
!ifdef WAILS_INSTALL_SCOPE
76+
!if "${WAILS_INSTALL_SCOPE}" == "user"
77+
InstallDir "$LOCALAPPDATA\Programs\${INFO_PRODUCTNAME}"
78+
!else
79+
InstallDir "$PROGRAMFILES64\${INFO_COMPANYNAME}\${INFO_PRODUCTNAME}"
80+
!endif
81+
!else
82+
InstallDir "$PROGRAMFILES64\${INFO_COMPANYNAME}\${INFO_PRODUCTNAME}"
83+
!endif # Default installing folder ($PROGRAMFILES is Program Files folder).
7684
ShowInstDetails show # This will always show the installation details.
7785

7886
Function .onInit

v2/pkg/buildassets/build/windows/installer/wails_tools.nsh

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -115,23 +115,59 @@ RequestExecutionLevel "${REQUEST_EXECUTION_LEVEL}"
115115
WriteUninstaller "$INSTDIR\uninstall.exe"
116116

117117
SetRegView 64
118-
WriteRegStr HKLM "${UNINST_KEY}" "Publisher" "${INFO_COMPANYNAME}"
119-
WriteRegStr HKLM "${UNINST_KEY}" "DisplayName" "${INFO_PRODUCTNAME}"
120-
WriteRegStr HKLM "${UNINST_KEY}" "DisplayVersion" "${INFO_PRODUCTVERSION}"
121-
WriteRegStr HKLM "${UNINST_KEY}" "DisplayIcon" "$INSTDIR\${PRODUCT_EXECUTABLE}"
122-
WriteRegStr HKLM "${UNINST_KEY}" "UninstallString" "$\"$INSTDIR\uninstall.exe$\""
123-
WriteRegStr HKLM "${UNINST_KEY}" "QuietUninstallString" "$\"$INSTDIR\uninstall.exe$\" /S"
118+
!ifdef WAILS_INSTALL_SCOPE
119+
!if "${WAILS_INSTALL_SCOPE}" == "user"
120+
WriteRegStr HKCU "${UNINST_KEY}" "Publisher" "${INFO_COMPANYNAME}"
121+
WriteRegStr HKCU "${UNINST_KEY}" "DisplayName" "${INFO_PRODUCTNAME}"
122+
WriteRegStr HKCU "${UNINST_KEY}" "DisplayVersion" "${INFO_PRODUCTVERSION}"
123+
WriteRegStr HKCU "${UNINST_KEY}" "DisplayIcon" "$INSTDIR\${PRODUCT_EXECUTABLE}"
124+
WriteRegStr HKCU "${UNINST_KEY}" "UninstallString" "$\"$INSTDIR\uninstall.exe$\""
125+
WriteRegStr HKCU "${UNINST_KEY}" "QuietUninstallString" "$\"$INSTDIR\uninstall.exe$\" /S"
126+
!else
127+
WriteRegStr HKLM "${UNINST_KEY}" "Publisher" "${INFO_COMPANYNAME}"
128+
WriteRegStr HKLM "${UNINST_KEY}" "DisplayName" "${INFO_PRODUCTNAME}"
129+
WriteRegStr HKLM "${UNINST_KEY}" "DisplayVersion" "${INFO_PRODUCTVERSION}"
130+
WriteRegStr HKLM "${UNINST_KEY}" "DisplayIcon" "$INSTDIR\${PRODUCT_EXECUTABLE}"
131+
WriteRegStr HKLM "${UNINST_KEY}" "UninstallString" "$\"$INSTDIR\uninstall.exe$\""
132+
WriteRegStr HKLM "${UNINST_KEY}" "QuietUninstallString" "$\"$INSTDIR\uninstall.exe$\" /S"
133+
!endif
134+
!else
135+
WriteRegStr HKLM "${UNINST_KEY}" "Publisher" "${INFO_COMPANYNAME}"
136+
WriteRegStr HKLM "${UNINST_KEY}" "DisplayName" "${INFO_PRODUCTNAME}"
137+
WriteRegStr HKLM "${UNINST_KEY}" "DisplayVersion" "${INFO_PRODUCTVERSION}"
138+
WriteRegStr HKLM "${UNINST_KEY}" "DisplayIcon" "$INSTDIR\${PRODUCT_EXECUTABLE}"
139+
WriteRegStr HKLM "${UNINST_KEY}" "UninstallString" "$\"$INSTDIR\uninstall.exe$\""
140+
WriteRegStr HKLM "${UNINST_KEY}" "QuietUninstallString" "$\"$INSTDIR\uninstall.exe$\" /S"
141+
!endif
124142

125143
${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2
126144
IntFmt $0 "0x%08X" $0
127-
WriteRegDWORD HKLM "${UNINST_KEY}" "EstimatedSize" "$0"
145+
146+
!ifdef WAILS_INSTALL_SCOPE
147+
!if "${WAILS_INSTALL_SCOPE}" == "user"
148+
WriteRegDWORD HKCU "${UNINST_KEY}" "EstimatedSize" "$0"
149+
!else
150+
WriteRegDWORD HKLM "${UNINST_KEY}" "EstimatedSize" "$0"
151+
!endif
152+
!else
153+
WriteRegDWORD HKLM "${UNINST_KEY}" "EstimatedSize" "$0"
154+
!endif
128155
!macroend
129156

130157
!macro wails.deleteUninstaller
131158
Delete "$INSTDIR\uninstall.exe"
132159

133160
SetRegView 64
134-
DeleteRegKey HKLM "${UNINST_KEY}"
161+
162+
!ifdef WAILS_INSTALL_SCOPE
163+
!if "${WAILS_INSTALL_SCOPE}" == "user"
164+
DeleteRegKey HKCU "${UNINST_KEY}"
165+
!else
166+
DeleteRegKey HKLM "${UNINST_KEY}"
167+
!endif
168+
!else
169+
DeleteRegKey HKLM "${UNINST_KEY}"
170+
!endif
135171
!macroend
136172

137173
!macro wails.setShellContext
@@ -183,7 +219,6 @@ RequestExecutionLevel "${REQUEST_EXECUTION_LEVEL}"
183219
; Backup the previously associated file class
184220
ReadRegStr $R0 SHELL_CONTEXT "Software\Classes\.${EXT}" ""
185221
WriteRegStr SHELL_CONTEXT "Software\Classes\.${EXT}" "${FILECLASS}_backup" "$R0"
186-
187222
WriteRegStr SHELL_CONTEXT "Software\Classes\.${EXT}" "" "${FILECLASS}"
188223

189224
WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}" "" `${DESCRIPTION}`

v2/pkg/commands/build/build.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ type Options struct {
5151
SkipModTidy bool // Skip mod tidy before compile
5252
IgnoreFrontend bool // Indicates if the frontend does not need building
5353
IgnoreApplication bool // Indicates if the application does not need building
54+
InstallScope string // "machine" (default) or "user"
5455
OutputFile string // Override the output filename
5556
BinDirectory string // Directory to use to write the built applications
5657
CleanBinDirectory bool // Indicates if the bin output directory should be cleaned before building

v2/pkg/commands/build/nsis_installer.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,13 @@ func makeNSIS(options *Options, installerKind string, amd64Binary string, arm64B
9999
if arm64Binary != "" {
100100
args = append(args, "-DARG_WAILS_ARM64_BINARY="+arm64Binary)
101101
}
102+
103+
// Install scope support
104+
if options.InstallScope == "user" {
105+
args = append(args, "-DWAILS_INSTALL_SCOPE=user")
106+
args = append(args, "-DREQUEST_EXECUTION_LEVEL=user")
107+
}
108+
102109
args = append(args, nsisProjectFile)
103110

104111
if verbose {

0 commit comments

Comments
 (0)