Skip to content

Commit b4fc99e

Browse files
committed
dist: Add bin directory to system PATH in win32 installer
1 parent 92671d6 commit b4fc99e

File tree

1 file changed

+337
-0
lines changed

1 file changed

+337
-0
lines changed

src/etc/pkg/rust.nsi

Lines changed: 337 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,338 @@
44
# This is a NSIS win32 installer script the Rust toolchain.
55
#
66

7+
# FIXME: EnvVarUpdate belongs in its own file but I'm having a hard time figuring
8+
# out how to make !include look in the directory I want it to.
9+
10+
/**
11+
* EnvVarUpdate.nsh
12+
* : Environmental Variables: append, prepend, and remove entries
13+
*
14+
* WARNING: If you use StrFunc.nsh header then include it before this file
15+
* with all required definitions. This is to avoid conflicts
16+
*
17+
* Usage:
18+
* ${EnvVarUpdate} "ResultVar" "EnvVarName" "Action" "RegLoc" "PathString"
19+
*
20+
* Credits:
21+
* Version 1.0
22+
* * Cal Turney (turnec2)
23+
* * Amir Szekely (KiCHiK) and e-circ for developing the forerunners of this
24+
* function: AddToPath, un.RemoveFromPath, AddToEnvVar, un.RemoveFromEnvVar,
25+
* WriteEnvStr, and un.DeleteEnvStr
26+
* * Diego Pedroso (deguix) for StrTok
27+
* * Kevin English (kenglish_hi) for StrContains
28+
* * Hendri Adriaens (Smile2Me), Diego Pedroso (deguix), and Dan Fuhry
29+
* (dandaman32) for StrReplace
30+
*
31+
* Version 1.1 (compatibility with StrFunc.nsh)
32+
* * techtonik
33+
*
34+
* http://nsis.sourceforge.net/Environmental_Variables:_append%2C_prepend%2C_and_remove_entries
35+
*
36+
*/
37+
38+
39+
!ifndef ENVVARUPDATE_FUNCTION
40+
!define ENVVARUPDATE_FUNCTION
41+
!verbose push
42+
!verbose 3
43+
!include "LogicLib.nsh"
44+
!include "WinMessages.NSH"
45+
!include "StrFunc.nsh"
46+
47+
; ---- Fix for conflict if StrFunc.nsh is already includes in main file -----------------------
48+
!macro _IncludeStrFunction StrFuncName
49+
!ifndef ${StrFuncName}_INCLUDED
50+
${${StrFuncName}}
51+
!endif
52+
!ifndef Un${StrFuncName}_INCLUDED
53+
${Un${StrFuncName}}
54+
!endif
55+
!define un.${StrFuncName} "${Un${StrFuncName}}"
56+
!macroend
57+
58+
!insertmacro _IncludeStrFunction StrTok
59+
!insertmacro _IncludeStrFunction StrStr
60+
!insertmacro _IncludeStrFunction StrRep
61+
62+
; ---------------------------------- Macro Definitions ----------------------------------------
63+
!macro _EnvVarUpdateConstructor ResultVar EnvVarName Action Regloc PathString
64+
Push "${EnvVarName}"
65+
Push "${Action}"
66+
Push "${RegLoc}"
67+
Push "${PathString}"
68+
Call EnvVarUpdate
69+
Pop "${ResultVar}"
70+
!macroend
71+
!define EnvVarUpdate '!insertmacro "_EnvVarUpdateConstructor"'
72+
73+
!macro _unEnvVarUpdateConstructor ResultVar EnvVarName Action Regloc PathString
74+
Push "${EnvVarName}"
75+
Push "${Action}"
76+
Push "${RegLoc}"
77+
Push "${PathString}"
78+
Call un.EnvVarUpdate
79+
Pop "${ResultVar}"
80+
!macroend
81+
!define un.EnvVarUpdate '!insertmacro "_unEnvVarUpdateConstructor"'
82+
; ---------------------------------- Macro Definitions end-------------------------------------
83+
84+
;----------------------------------- EnvVarUpdate start----------------------------------------
85+
!define hklm_all_users 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"'
86+
!define hkcu_current_user 'HKCU "Environment"'
87+
88+
!macro EnvVarUpdate UN
89+
90+
Function ${UN}EnvVarUpdate
91+
92+
Push $0
93+
Exch 4
94+
Exch $1
95+
Exch 3
96+
Exch $2
97+
Exch 2
98+
Exch $3
99+
Exch
100+
Exch $4
101+
Push $5
102+
Push $6
103+
Push $7
104+
Push $8
105+
Push $9
106+
Push $R0
107+
108+
/* After this point:
109+
-------------------------
110+
$0 = ResultVar (returned)
111+
$1 = EnvVarName (input)
112+
$2 = Action (input)
113+
$3 = RegLoc (input)
114+
$4 = PathString (input)
115+
$5 = Orig EnvVar (read from registry)
116+
$6 = Len of $0 (temp)
117+
$7 = tempstr1 (temp)
118+
$8 = Entry counter (temp)
119+
$9 = tempstr2 (temp)
120+
$R0 = tempChar (temp) */
121+
122+
; Step 1: Read contents of EnvVarName from RegLoc
123+
;
124+
; Check for empty EnvVarName
125+
${If} $1 == ""
126+
SetErrors
127+
DetailPrint "ERROR: EnvVarName is blank"
128+
Goto EnvVarUpdate_Restore_Vars
129+
${EndIf}
130+
131+
; Check for valid Action
132+
${If} $2 != "A"
133+
${AndIf} $2 != "P"
134+
${AndIf} $2 != "R"
135+
SetErrors
136+
DetailPrint "ERROR: Invalid Action - must be A, P, or R"
137+
Goto EnvVarUpdate_Restore_Vars
138+
${EndIf}
139+
140+
${If} $3 == HKLM
141+
ReadRegStr $5 ${hklm_all_users} $1 ; Get EnvVarName from all users into $5
142+
${ElseIf} $3 == HKCU
143+
ReadRegStr $5 ${hkcu_current_user} $1 ; Read EnvVarName from current user into $5
144+
${Else}
145+
SetErrors
146+
DetailPrint 'ERROR: Action is [$3] but must be "HKLM" or HKCU"'
147+
Goto EnvVarUpdate_Restore_Vars
148+
${EndIf}
149+
150+
; Check for empty PathString
151+
${If} $4 == ""
152+
SetErrors
153+
DetailPrint "ERROR: PathString is blank"
154+
Goto EnvVarUpdate_Restore_Vars
155+
${EndIf}
156+
157+
; Make sure we've got some work to do
158+
${If} $5 == ""
159+
${AndIf} $2 == "R"
160+
SetErrors
161+
DetailPrint "$1 is empty - Nothing to remove"
162+
Goto EnvVarUpdate_Restore_Vars
163+
${EndIf}
164+
165+
; Step 2: Scrub EnvVar
166+
;
167+
StrCpy $0 $5 ; Copy the contents to $0
168+
; Remove spaces around semicolons (NOTE: spaces before the 1st entry or
169+
; after the last one are not removed here but instead in Step 3)
170+
${If} $0 != "" ; If EnvVar is not empty ...
171+
${Do}
172+
${${UN}StrStr} $7 $0 " ;"
173+
${If} $7 == ""
174+
${ExitDo}
175+
${EndIf}
176+
${${UN}StrRep} $0 $0 " ;" ";" ; Remove '<space>;'
177+
${Loop}
178+
${Do}
179+
${${UN}StrStr} $7 $0 "; "
180+
${If} $7 == ""
181+
${ExitDo}
182+
${EndIf}
183+
${${UN}StrRep} $0 $0 "; " ";" ; Remove ';<space>'
184+
${Loop}
185+
${Do}
186+
${${UN}StrStr} $7 $0 ";;"
187+
${If} $7 == ""
188+
${ExitDo}
189+
${EndIf}
190+
${${UN}StrRep} $0 $0 ";;" ";"
191+
${Loop}
192+
193+
; Remove a leading or trailing semicolon from EnvVar
194+
StrCpy $7 $0 1 0
195+
${If} $7 == ";"
196+
StrCpy $0 $0 "" 1 ; Change ';<EnvVar>' to '<EnvVar>'
197+
${EndIf}
198+
StrLen $6 $0
199+
IntOp $6 $6 - 1
200+
StrCpy $7 $0 1 $6
201+
${If} $7 == ";"
202+
StrCpy $0 $0 $6 ; Change ';<EnvVar>' to '<EnvVar>'
203+
${EndIf}
204+
; DetailPrint "Scrubbed $1: [$0]" ; Uncomment to debug
205+
${EndIf}
206+
207+
/* Step 3. Remove all instances of the target path/string (even if "A" or "P")
208+
$6 = bool flag (1 = found and removed PathString)
209+
$7 = a string (e.g. path) delimited by semicolon(s)
210+
$8 = entry counter starting at 0
211+
$9 = copy of $0
212+
$R0 = tempChar */
213+
214+
${If} $5 != "" ; If EnvVar is not empty ...
215+
StrCpy $9 $0
216+
StrCpy $0 ""
217+
StrCpy $8 0
218+
StrCpy $6 0
219+
220+
${Do}
221+
${${UN}StrTok} $7 $9 ";" $8 "0" ; $7 = next entry, $8 = entry counter
222+
223+
${If} $7 == "" ; If we've run out of entries,
224+
${ExitDo} ; were done
225+
${EndIf} ;
226+
227+
; Remove leading and trailing spaces from this entry (critical step for Action=Remove)
228+
${Do}
229+
StrCpy $R0 $7 1
230+
${If} $R0 != " "
231+
${ExitDo}
232+
${EndIf}
233+
StrCpy $7 $7 "" 1 ; Remove leading space
234+
${Loop}
235+
${Do}
236+
StrCpy $R0 $7 1 -1
237+
${If} $R0 != " "
238+
${ExitDo}
239+
${EndIf}
240+
StrCpy $7 $7 -1 ; Remove trailing space
241+
${Loop}
242+
${If} $7 == $4 ; If string matches, remove it by not appending it
243+
StrCpy $6 1 ; Set 'found' flag
244+
${ElseIf} $7 != $4 ; If string does NOT match
245+
${AndIf} $0 == "" ; and the 1st string being added to $0,
246+
StrCpy $0 $7 ; copy it to $0 without a prepended semicolon
247+
${ElseIf} $7 != $4 ; If string does NOT match
248+
${AndIf} $0 != "" ; and this is NOT the 1st string to be added to $0,
249+
StrCpy $0 $0;$7 ; append path to $0 with a prepended semicolon
250+
${EndIf} ;
251+
252+
IntOp $8 $8 + 1 ; Bump counter
253+
${Loop} ; Check for duplicates until we run out of paths
254+
${EndIf}
255+
256+
; Step 4: Perform the requested Action
257+
;
258+
${If} $2 != "R" ; If Append or Prepend
259+
${If} $6 == 1 ; And if we found the target
260+
DetailPrint "Target is already present in $1. It will be removed and"
261+
${EndIf}
262+
${If} $0 == "" ; If EnvVar is (now) empty
263+
StrCpy $0 $4 ; just copy PathString to EnvVar
264+
${If} $6 == 0 ; If found flag is either 0
265+
${OrIf} $6 == "" ; or blank (if EnvVarName is empty)
266+
DetailPrint "$1 was empty and has been updated with the target"
267+
${EndIf}
268+
${ElseIf} $2 == "A" ; If Append (and EnvVar is not empty),
269+
StrCpy $0 $0;$4 ; append PathString
270+
${If} $6 == 1
271+
DetailPrint "appended to $1"
272+
${Else}
273+
DetailPrint "Target was appended to $1"
274+
${EndIf}
275+
${Else} ; If Prepend (and EnvVar is not empty),
276+
StrCpy $0 $4;$0 ; prepend PathString
277+
${If} $6 == 1
278+
DetailPrint "prepended to $1"
279+
${Else}
280+
DetailPrint "Target was prepended to $1"
281+
${EndIf}
282+
${EndIf}
283+
${Else} ; If Action = Remove
284+
${If} $6 == 1 ; and we found the target
285+
DetailPrint "Target was found and removed from $1"
286+
${Else}
287+
DetailPrint "Target was NOT found in $1 (nothing to remove)"
288+
${EndIf}
289+
${If} $0 == ""
290+
DetailPrint "$1 is now empty"
291+
${EndIf}
292+
${EndIf}
293+
294+
; Step 5: Update the registry at RegLoc with the updated EnvVar and announce the change
295+
;
296+
ClearErrors
297+
${If} $3 == HKLM
298+
WriteRegExpandStr ${hklm_all_users} $1 $0 ; Write it in all users section
299+
${ElseIf} $3 == HKCU
300+
WriteRegExpandStr ${hkcu_current_user} $1 $0 ; Write it to current user section
301+
${EndIf}
302+
303+
IfErrors 0 +4
304+
MessageBox MB_OK|MB_ICONEXCLAMATION "Could not write updated $1 to $3"
305+
DetailPrint "Could not write updated $1 to $3"
306+
Goto EnvVarUpdate_Restore_Vars
307+
308+
; "Export" our change
309+
SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000
310+
311+
EnvVarUpdate_Restore_Vars:
312+
;
313+
; Restore the user's variables and return ResultVar
314+
Pop $R0
315+
Pop $9
316+
Pop $8
317+
Pop $7
318+
Pop $6
319+
Pop $5
320+
Pop $4
321+
Pop $3
322+
Pop $2
323+
Pop $1
324+
Push $0 ; Push my $0 (ResultVar)
325+
Exch
326+
Pop $0 ; Restore his $0
327+
328+
FunctionEnd
329+
330+
!macroend ; EnvVarUpdate UN
331+
!insertmacro EnvVarUpdate ""
332+
!insertmacro EnvVarUpdate "un."
333+
;----------------------------------- EnvVarUpdate end----------------------------------------
334+
335+
!verbose pop
336+
!endif
337+
338+
7339
Name "Rust"
8340
ShowInstDetails "show"
9341
ShowUninstDetails "show"
@@ -29,6 +361,10 @@ Section "Documentation"
29361
File /nonfatal /oname=rust.pdf doc\rust.pdf
30362
SectionEnd
31363
364+
Section "SystemPath"
365+
${EnvVarUpdate} $0 "PATH" "A" "HKLM" "$INSTDIR\bin"
366+
SectionEnd
367+
32368
Section "Uninstall"
33369
Delete $INSTDIR\uninstall.exe
34370
Delete $INSTDIR\bin\*.*
@@ -42,6 +378,7 @@ Section "Uninstall"
42378
RMDir $INSTDIR\doc
43379
RMDir $INSTDIR
44380
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Rust"
381+
${un.EnvVarUpdate} $0 "PATH" "R" "HKLM" "$INSTDIR\bin"
45382
SectionEnd
46383
47384
Section

0 commit comments

Comments
 (0)