4
4
# This is a NSIS win32 installer script the Rust toolchain.
5
5
#
6
6
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
+
7
339
Name "Rust"
8
340
ShowInstDetails "show"
9
341
ShowUninstDetails "show"
@@ -29,6 +361,10 @@ Section "Documentation"
29
361
File /nonfatal /oname=rust.pdf doc\rust.pdf
30
362
SectionEnd
31
363
364
+ Section "SystemPath"
365
+ ${EnvVarUpdate} $0 "PATH" "A" "HKLM" "$INSTDIR\bin"
366
+ SectionEnd
367
+
32
368
Section "Uninstall"
33
369
Delete $INSTDIR\uninstall.exe
34
370
Delete $INSTDIR\bin\*.*
@@ -42,6 +378,7 @@ Section "Uninstall"
42
378
RMDir $INSTDIR\doc
43
379
RMDir $INSTDIR
44
380
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Rust"
381
+ ${un.EnvVarUpdate} $0 "PATH" "R" "HKLM" "$INSTDIR\bin"
45
382
SectionEnd
46
383
47
384
Section
0 commit comments