comparison contrib/packaging/inno/modpath.iss @ 41847:0f49b56d5d74

inno: replace add_path.exe with a Pascal script While attempting to build the Inno installer, I was unable to find a copy of add_path.exe from the source site previously listed in the docs. Some quick Googling revealed that achieving this functionality in native Pascal scripts seems to be preferred these days. This commit vendors "Modify Path" (fetched from https://www.legroom.net/software/modpath) and plugs it into our Inno config file per its instructions. The existing Inno installer appears to only modify PATH for the current user (as opposed to at the system level). I've maintained this behavior with Modify Path. Although it would be trivial to change or add checkboxes to control the behavior. I'll leave this as a follow-up. Differential Revision: https://phab.mercurial-scm.org/D6060
author Gregory Szorc <gregory.szorc@gmail.com>
date Thu, 28 Feb 2019 12:54:48 -0800
parents
children 109315c41d5e
comparison
equal deleted inserted replaced
41846:765f836a9484 41847:0f49b56d5d74
1 // ----------------------------------------------------------------------------
2 //
3 // Inno Setup Ver: 5.4.2
4 // Script Version: 1.4.2
5 // Author: Jared Breland <jbreland@legroom.net>
6 // Homepage: http://www.legroom.net/software
7 // License: GNU Lesser General Public License (LGPL), version 3
8 // http://www.gnu.org/licenses/lgpl.html
9 //
10 // Script Function:
11 // Allow modification of environmental path directly from Inno Setup installers
12 //
13 // Instructions:
14 // Copy modpath.iss to the same directory as your setup script
15 //
16 // Add this statement to your [Setup] section
17 // ChangesEnvironment=true
18 //
19 // Add this statement to your [Tasks] section
20 // You can change the Description or Flags
21 // You can change the Name, but it must match the ModPathName setting below
22 // Name: modifypath; Description: &Add application directory to your environmental path; Flags: unchecked
23 //
24 // Add the following to the end of your [Code] section
25 // ModPathName defines the name of the task defined above
26 // ModPathType defines whether the 'user' or 'system' path will be modified;
27 // this will default to user if anything other than system is set
28 // setArrayLength must specify the total number of dirs to be added
29 // Result[0] contains first directory, Result[1] contains second, etc.
30 // const
31 // ModPathName = 'modifypath';
32 // ModPathType = 'user';
33 //
34 // function ModPathDir(): TArrayOfString;
35 // begin
36 // setArrayLength(Result, 1);
37 // Result[0] := ExpandConstant('{app}');
38 // end;
39 // #include "modpath.iss"
40 // ----------------------------------------------------------------------------
41
42 procedure ModPath();
43 var
44 oldpath: String;
45 newpath: String;
46 updatepath: Boolean;
47 pathArr: TArrayOfString;
48 aExecFile: String;
49 aExecArr: TArrayOfString;
50 i, d: Integer;
51 pathdir: TArrayOfString;
52 regroot: Integer;
53 regpath: String;
54
55 begin
56 // Get constants from main script and adjust behavior accordingly
57 // ModPathType MUST be 'system' or 'user'; force 'user' if invalid
58 if ModPathType = 'system' then begin
59 regroot := HKEY_LOCAL_MACHINE;
60 regpath := 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment';
61 end else begin
62 regroot := HKEY_CURRENT_USER;
63 regpath := 'Environment';
64 end;
65
66 // Get array of new directories and act on each individually
67 pathdir := ModPathDir();
68 for d := 0 to GetArrayLength(pathdir)-1 do begin
69 updatepath := true;
70
71 // Modify WinNT path
72 if UsingWinNT() = true then begin
73
74 // Get current path, split into an array
75 RegQueryStringValue(regroot, regpath, 'Path', oldpath);
76 oldpath := oldpath + ';';
77 i := 0;
78
79 while (Pos(';', oldpath) > 0) do begin
80 SetArrayLength(pathArr, i+1);
81 pathArr[i] := Copy(oldpath, 0, Pos(';', oldpath)-1);
82 oldpath := Copy(oldpath, Pos(';', oldpath)+1, Length(oldpath));
83 i := i + 1;
84
85 // Check if current directory matches app dir
86 if pathdir[d] = pathArr[i-1] then begin
87 // if uninstalling, remove dir from path
88 if IsUninstaller() = true then begin
89 continue;
90 // if installing, flag that dir already exists in path
91 end else begin
92 updatepath := false;
93 end;
94 end;
95
96 // Add current directory to new path
97 if i = 1 then begin
98 newpath := pathArr[i-1];
99 end else begin
100 newpath := newpath + ';' + pathArr[i-1];
101 end;
102 end;
103
104 // Append app dir to path if not already included
105 if (IsUninstaller() = false) AND (updatepath = true) then
106 newpath := newpath + ';' + pathdir[d];
107
108 // Write new path
109 RegWriteStringValue(regroot, regpath, 'Path', newpath);
110
111 // Modify Win9x path
112 end else begin
113
114 // Convert to shortened dirname
115 pathdir[d] := GetShortName(pathdir[d]);
116
117 // If autoexec.bat exists, check if app dir already exists in path
118 aExecFile := 'C:\AUTOEXEC.BAT';
119 if FileExists(aExecFile) then begin
120 LoadStringsFromFile(aExecFile, aExecArr);
121 for i := 0 to GetArrayLength(aExecArr)-1 do begin
122 if IsUninstaller() = false then begin
123 // If app dir already exists while installing, skip add
124 if (Pos(pathdir[d], aExecArr[i]) > 0) then
125 updatepath := false;
126 break;
127 end else begin
128 // If app dir exists and = what we originally set, then delete at uninstall
129 if aExecArr[i] = 'SET PATH=%PATH%;' + pathdir[d] then
130 aExecArr[i] := '';
131 end;
132 end;
133 end;
134
135 // If app dir not found, or autoexec.bat didn't exist, then (create and) append to current path
136 if (IsUninstaller() = false) AND (updatepath = true) then begin
137 SaveStringToFile(aExecFile, #13#10 + 'SET PATH=%PATH%;' + pathdir[d], True);
138
139 // If uninstalling, write the full autoexec out
140 end else begin
141 SaveStringsToFile(aExecFile, aExecArr, False);
142 end;
143 end;
144 end;
145 end;
146
147 // Split a string into an array using passed delimeter
148 procedure MPExplode(var Dest: TArrayOfString; Text: String; Separator: String);
149 var
150 i: Integer;
151 begin
152 i := 0;
153 repeat
154 SetArrayLength(Dest, i+1);
155 if Pos(Separator,Text) > 0 then begin
156 Dest[i] := Copy(Text, 1, Pos(Separator, Text)-1);
157 Text := Copy(Text, Pos(Separator,Text) + Length(Separator), Length(Text));
158 i := i + 1;
159 end else begin
160 Dest[i] := Text;
161 Text := '';
162 end;
163 until Length(Text)=0;
164 end;
165
166
167 procedure CurStepChanged(CurStep: TSetupStep);
168 var
169 taskname: String;
170 begin
171 taskname := ModPathName;
172 if CurStep = ssPostInstall then
173 if IsTaskSelected(taskname) then
174 ModPath();
175 end;
176
177 procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
178 var
179 aSelectedTasks: TArrayOfString;
180 i: Integer;
181 taskname: String;
182 regpath: String;
183 regstring: String;
184 appid: String;
185 begin
186 // only run during actual uninstall
187 if CurUninstallStep = usUninstall then begin
188 // get list of selected tasks saved in registry at install time
189 appid := '{#emit SetupSetting("AppId")}';
190 if appid = '' then appid := '{#emit SetupSetting("AppName")}';
191 regpath := ExpandConstant('Software\Microsoft\Windows\CurrentVersion\Uninstall\'+appid+'_is1');
192 RegQueryStringValue(HKLM, regpath, 'Inno Setup: Selected Tasks', regstring);
193 if regstring = '' then RegQueryStringValue(HKCU, regpath, 'Inno Setup: Selected Tasks', regstring);
194
195 // check each task; if matches modpath taskname, trigger patch removal
196 if regstring <> '' then begin
197 taskname := ModPathName;
198 MPExplode(aSelectedTasks, regstring, ',');
199 if GetArrayLength(aSelectedTasks) > 0 then begin
200 for i := 0 to GetArrayLength(aSelectedTasks)-1 do begin
201 if comparetext(aSelectedTasks[i], taskname) = 0 then
202 ModPath();
203 end;
204 end;
205 end;
206 end;
207 end;
208
209 function NeedRestart(): Boolean;
210 var
211 taskname: String;
212 begin
213 taskname := ModPathName;
214 if IsTaskSelected(taskname) and not UsingWinNT() then begin
215 Result := True;
216 end else begin
217 Result := False;
218 end;
219 end;