widgets.commitmsg: Factor out the 'hint' text behavior
[git-cola.git] / win32 / install.iss
blob927547fccbc28cceff4c5e939a812e0480964469
1 #define APP_NAME 'git-cola'
2 #define APP_LONGNAME 'git-cola - The highly caffeinated git GUI'
3 #define APP_VERSION '%APPVERSION%'
4 #define APP_URL 'http://git-cola.github.com/'
6 [Setup]
7 ; Compiler-related
8 InternalCompressLevel=max
9 OutputBaseFilename={#emit APP_NAME+'-'+APP_VERSION}
10 OutputDir=%OUTPUTDIR%
11 SolidCompression=yes
13 ; Installer-related
14 AllowNoIcons=yes
15 AppName={#emit APP_LONGNAME}
16 AppPublisherURL={#emit APP_URL}
17 AppVersion={#emit APP_VERSION}
18 AppVerName={#emit APP_LONGNAME+' '+APP_VERSION}
19 ChangesEnvironment=yes
20 DefaultDirName={pf}\{#emit APP_NAME}
21 DefaultGroupName={#emit APP_LONGNAME}
22 DisableReadyPage=yes
23 InfoBeforeFile=etc\gpl-2.0.rtf
24 PrivilegesRequired=none
25 UninstallDisplayIcon=etc\git.ico
27 ; Cosmetic
28 SetupIconFile=etc\git.ico
29 WizardSmallImageFile=etc\git.bmp
31 [Tasks]
32 Name: quicklaunchicon; Description: "Create a &Quick Launch icon"; GroupDescription: "Additional icons:"; Flags: checkedonce
33 Name: desktopicon; Description: "Create a &Desktop icon"; GroupDescription: "Additional icons:"; Flags: checkedonce
34 Name: guiextension; Description: "Add ""Git &Cola Here"""; GroupDescription: "Windows Explorer integration:"; Flags: checkedonce
36 [Files]
37 Source: "*"; DestDir: "{app}"; Excludes: "\*.bmp, \install.*, \tmp.*, \bin\*install*"; Flags: recursesubdirs
38 Source: "etc\ReleaseNotes.txt"; DestDir: "{app}\etc"; Flags: isreadme
40 [Icons]
41 Name: "{group}\git-cola"; Filename: "{code:GetPythonExe}"; Parameters: "{app}\bin\git-cola.pyw --prompt --git-path ""{code:GetGitExe}"""; WorkingDir: "%USERPROFILE%"; IconFilename: "{app}\etc\git.ico"
42 Name: "{group}\git-dag"; Filename: "{code:GetPythonExe}"; Parameters: "{app}\bin\git-dag.pyw --prompt --git-path ""{code:GetGitExe}"""; WorkingDir: "%USERPROFILE%"; IconFilename: "{app}\etc\git.ico"
43 Name: "{group}\git-cola Homepage"; Filename: "{#emit APP_URL}"; WorkingDir: "%USERPROFILE%";
44 Name: "{group}\Release Notes"; Filename: "{app}\etc\ReleaseNotes.txt"; WorkingDir: "%USERPROFILE%";
45 Name: "{group}\License"; Filename: "{app}\etc\gpl-2.0.rtf"; WorkingDir: "%USERPROFILE%";
46 Name: "{group}\Uninstall git-cola"; Filename: "{uninstallexe}"
47 Name: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\git-cola"; Filename: "{code:GetPythonExe}"; Parameters: "{app}\bin\git-cola.pyw --prompt --git-path ""{code:GetGitExe}"""; WorkingDir: "%USERPROFILE%"; IconFilename: "{app}\etc\git.ico"; Tasks: quicklaunchicon
48 Name: "{code:GetShellFolder|desktop}\git-cola"; Filename: "{code:GetPythonExe}"; Parameters: "{app}\bin\git-cola.pyw --prompt --git-path ""{code:GetGitExe}"""; WorkingDir: "%USERPROFILE%"; IconFilename: "{app}\etc\git.ico"; Tasks: desktopicon
49 Name: "{code:GetShellFolder|desktop}\git-dag"; Filename: "{code:GetPythonExe}"; Parameters: "{app}\bin\git-dag.pyw --prompt --git-path ""{code:GetGitExe}"""; WorkingDir: "%USERPROFILE%"; IconFilename: "{app}\etc\git.ico"; Tasks: desktopicon
51 [Messages]
52 BeveledLabel={#emit APP_URL}
53 SetupAppTitle={#emit APP_NAME} Setup
54 SetupWindowTitle={#emit APP_NAME} Setup
56 [UninstallDelete]
57 Type: files; Name: "{app}\bin\*"
58 Type: files; Name: "{app}\etc\*"
59 Type: files; Name: "{app}\share\git-cola\bin\*"
60 Type: files; Name: "{app}\share\git-cola\icons\*"
61 Type: files; Name: "{app}\share\git-cola\lib\cola\*"
62 Type: files; Name: "{app}\share\git-cola\lib\cola\classic\*"
63 Type: files; Name: "{app}\share\git-cola\lib\cola\dag\*"
64 Type: files; Name: "{app}\share\git-cola\lib\cola\main\*"
65 Type: files; Name: "{app}\share\git-cola\lib\cola\merge\*"
66 Type: files; Name: "{app}\share\git-cola\lib\cola\models\*"
67 Type: files; Name: "{app}\share\git-cola\lib\cola\prefs\*"
68 Type: files; Name: "{app}\share\git-cola\lib\cola\stash\*"
69 Type: files; Name: "{app}\share\git-cola\lib\cola\widgets\*"
70 Type: dirifempty; Name: "{app}\share\git-cola\lib\cola\classic"
71 Type: dirifempty; Name: "{app}\share\git-cola\lib\cola\dag"
72 Type: dirifempty; Name: "{app}\share\git-cola\lib\cola\main"
73 Type: dirifempty; Name: "{app}\share\git-cola\lib\cola\merge"
74 Type: dirifempty; Name: "{app}\share\git-cola\lib\cola\models"
75 Type: dirifempty; Name: "{app}\share\git-cola\lib\cola\prefs"
76 Type: dirifempty; Name: "{app}\share\git-cola\lib\cola\stash"
77 Type: dirifempty; Name: "{app}\share\git-cola\lib\cola\widgets"
78 Type: dirifempty; Name: "{app}\share\git-cola\lib\cola"
79 Type: dirifempty; Name: "{app}\share\git-cola\lib"
80 Type: dirifempty; Name: "{app}\share\git-cola\icons"
81 Type: dirifempty; Name: "{app}\share\git-cola\bin"
82 Type: dirifempty; Name: "{app}\etc"
83 Type: dirifempty; Name: "{app}\bin"
85 [Code]
87 Helper methods
90 var
91 PythonPage:TWizardPage;
92 GitPage:TWizardPage;
93 EdtPython:TEdit;
94 EdtGit:TEdit;
96 function GetEnvStrings(VarName:string;AllUsers:Boolean):TArrayOfString;
97 var
98 Path:string;
99 i:Longint;
100 p:Integer;
101 begin
102 Path:='';
104 // See http://www.jrsoftware.org/isfaq.php#env
105 if AllUsers then begin
106 // We ignore errors here. The resulting array of strings will be empty.
107 RegQueryStringValue(HKEY_LOCAL_MACHINE,'SYSTEM\CurrentControlSet\Control\Session Manager\Environment',VarName,Path);
108 end else begin
109 // We ignore errors here. The resulting array of strings will be empty.
110 RegQueryStringValue(HKEY_CURRENT_USER,'Environment',VarName,Path);
111 end;
113 // Make sure we have at least one semicolon.
114 Path:=Path+';';
116 // Split the directories in PATH into an array of strings.
117 i:=0;
118 SetArrayLength(Result,0);
120 p:=Pos(';',Path);
121 while p>0 do begin
122 SetArrayLength(Result,i+1);
123 if p>1 then begin
124 Result[i]:=Copy(Path,1,p-1);
125 i:=i+1;
126 end;
127 Path:=Copy(Path,p+1,Length(Path));
128 p:=Pos(';',Path);
129 end;
130 end;
132 function SetEnvStrings(VarName:string;AllUsers,DeleteIfEmpty:Boolean;DirStrings:TArrayOfString):Boolean;
134 Path,KeyName:string;
135 i:Longint;
136 begin
137 // Merge all non-empty directory strings into a PATH variable.
138 Path:='';
139 for i:=0 to GetArrayLength(DirStrings)-1 do begin
140 if Length(DirStrings[i])>0 then begin
141 if Length(Path)>0 then begin
142 Path:=Path+';'+DirStrings[i];
143 end else begin
144 Path:=DirStrings[i];
145 end;
146 end;
147 end;
149 // See http://www.jrsoftware.org/isfaq.php#env
150 if AllUsers then begin
151 KeyName:='SYSTEM\CurrentControlSet\Control\Session Manager\Environment';
152 if DeleteIfEmpty and (Length(Path)=0) then begin
153 Result:=(not RegValueExists(HKEY_LOCAL_MACHINE,KeyName,VarName))
154 or RegDeleteValue(HKEY_LOCAL_MACHINE,KeyName,VarName);
155 end else begin
156 Result:=RegWriteStringValue(HKEY_LOCAL_MACHINE,KeyName,VarName,Path);
157 end;
158 end else begin
159 KeyName:='Environment';
160 if DeleteIfEmpty and (Length(Path)=0) then begin
161 Result:=(not RegValueExists(HKEY_CURRENT_USER,KeyName,VarName))
162 or RegDeleteValue(HKEY_CURRENT_USER,KeyName,VarName);
163 end else begin
164 Result:=RegWriteStringValue(HKEY_CURRENT_USER,KeyName,VarName,Path);
165 end;
166 end;
167 end;
170 procedure BrowseForPythonFolder(Sender:TObject);
172 Path:string;
173 begin
174 Path:=GetPreviousData('PythonPath', 'C:\Python26');
175 EdtPython.Text:=Path;
176 Path:=ExtractFilePath(EdtPython.Text);
177 BrowseForFolder('Please select the Python folder:',Path,False);
178 Path:=Path+'\pythonw.exe';
179 if FileExists(Path) then begin
180 EdtPython.Text:=Path;
181 end else begin
182 MsgBox('Please enter a valid path to pythonw.exe.',mbError,MB_OK);
183 end;
184 end;
186 function GetPythonExe(Param: String): String;
187 begin
188 Result:=EdtPython.Text;
189 end;
191 procedure BrowseForGitFolder(Sender:TObject);
193 Path:string;
194 OldPath:string;
195 begin
196 Path:=GetPreviousData('GitPath', 'C:\Program Files\Git');
197 EdtGit.Text:=Path;
198 Path:=ExtractFilePath(EdtGit.Text);
199 BrowseForFolder('Please select the Git folder:',Path,False);
200 OldPath:=Path;
203 Check for both $DIR\git.exe and $DIR\bin\git.exe
206 Path:=OldPath+'\bin\git.exe';
207 if FileExists(Path) then begin
208 EdtGit.Text:=Path;
209 Exit;
210 end;
212 Path:=OldPath+'\git.exe';
213 if FileExists(Path) then begin
214 EdtGit.Text:=Path;
215 end else begin
216 MsgBox('Please enter a valid path to git.exe.',mbError,MB_OK);
217 end;
218 end;
221 function GetGitExe(Param: String): String;
222 begin
223 Result:=EdtGit.Text;
224 end;
226 procedure RegisterPreviousData(PreviousDataKey:Integer);
228 Path:string;
229 begin
230 Path:=ExtractFilePath(EdtPython.Text);
231 SetPreviousData(PreviousDataKey, 'PythonPath', Path);
233 Path:=ExtractFilePath(ExtractFilePath(EdtGit.Text));
234 SetPreviousData(PreviousDataKey, 'GitPath', Path);
235 end;
238 Installer code
242 procedure InitializeWizard;
244 BtnPython:TButton;
245 BtnGit:TButton;
246 LblPython:TLabel;
247 LblGit:TLabel;
248 begin
249 // Create a custom page for finding Python
250 PythonPage:=CreateCustomPage(
251 wpSelectTasks,
252 'Setup Python',
253 'Where is your Python folder?'
256 LblPython:=TLabel.Create(PythonPage);
257 with LblPython do begin
258 Parent:=PythonPage.Surface;
259 Caption:= 'Please provide the path to pythonw.exe.';
260 Left:=ScaleX(28);
261 Top:=ScaleY(100);
262 Width:=ScaleX(316);
263 Height:=ScaleY(39);
264 end;
266 EdtPython:=TEdit.Create(PythonPage);
267 with EdtPython do begin
268 Parent:=PythonPage.Surface;
269 Text:=GetPreviousData('PythonPath', 'C:\Python26');
270 Text:=Text+'pythonw.exe';
271 if not FileExists(Text) then begin
272 Text:='';
273 end;
274 Left:=ScaleX(28);
275 Top:=ScaleY(148);
276 Width:=ScaleX(316);
277 Height:=ScaleY(13);
278 end;
280 BtnPython:=TButton.Create(PythonPage);
281 with BtnPython do begin
282 Parent:=PythonPage.Surface;
283 Caption:='...';
284 OnClick:=@BrowseForPythonFolder;
285 Left:=ScaleX(348);
286 Top:=ScaleY(148);
287 Width:=ScaleX(21);
288 Height:=ScaleY(21);
289 end;
291 // Create a custom page for finding Git
292 GitPage:=CreateCustomPage(
293 wpSelectTasks,
294 'Setup Git',
295 'Where is your Git folder?'
298 LblGit:=TLabel.Create(GitPage);
299 with LblGit do begin
300 Parent:=GitPage.Surface;
301 Caption:= 'Please provide the path to git.exe.';
302 Left:=ScaleX(28);
303 Top:=ScaleY(100);
304 Width:=ScaleX(316);
305 Height:=ScaleY(39);
306 end;
308 EdtGit:=TEdit.Create(GitPage);
309 with EdtGit do begin
310 Parent:=GitPage.Surface;
311 Text:=GetPreviousData('GitPath', 'C:\Program Files\Git');
312 Text:=Text+'git.exe';
313 if not FileExists(Text) then begin
314 Text:='';
315 end;
316 Left:=ScaleX(28);
317 Top:=ScaleY(148);
318 Width:=ScaleX(316);
319 Height:=ScaleY(13);
320 end;
322 BtnGit:=TButton.Create(GitPage);
323 with BtnGit do begin
324 Parent:=GitPage.Surface;
325 Caption:='...';
326 OnClick:=@BrowseForGitFolder;
327 Left:=ScaleX(348);
328 Top:=ScaleY(148);
329 Width:=ScaleX(21);
330 Height:=ScaleY(21);
331 end;
332 end;
334 function NextButtonClick(CurPageID:Integer):Boolean;
335 begin
336 if CurPageID = PythonPage.ID then begin
337 Result:=FileExists(EdtPython.Text);
339 if not Result then begin
340 MsgBox('Please enter a valid path to pythonw.exe.',mbError,MB_OK);
341 end;
342 Exit;
343 end;
345 if CurPageID = GitPage.ID then begin
346 Result:=FileExists(EdtGit.Text);
348 if not Result then begin
349 MsgBox('Please enter a valid path to git.exe.',mbError,MB_OK);
350 end;
351 Exit;
352 end;
354 Result:=True;
355 end;
357 procedure CurStepChanged(CurStep:TSetupStep);
359 AppDir,BinDir,Msg:string;
360 EnvPath:TArrayOfString;
361 i:Longint;
362 RootKey:Integer;
363 begin
364 if CurStep<>ssPostInstall then begin
365 Exit;
366 end;
368 AppDir:=ExpandConstant('{app}');
369 BinDir:=ExpandConstant('{app}\bin');
372 Modify the environment
374 This must happen no later than ssPostInstall to make
375 "ChangesEnvironment=yes" not happend before the change!
378 // Get the current user's directories in PATH.
379 EnvPath:=GetEnvStrings('PATH',IsAdminLoggedOn);
381 // First, remove the installation directory from PATH in any case.
382 for i:=0 to GetArrayLength(EnvPath)-1 do begin
383 if Pos(AppDir,EnvPath[i])=1 then begin
384 EnvPath[i]:='';
385 end;
386 end;
388 // Modify the PATH variable as requested by the user.
389 i:=GetArrayLength(EnvPath);
390 SetArrayLength(EnvPath,i+1);
392 // Add \bin to the path
393 EnvPath[i]:=BinDir
395 // Set the current user's PATH directories.
396 if not SetEnvStrings('PATH',IsAdminLoggedOn,True,EnvPath) then begin
397 Msg:='Line {#emit __LINE__}: Unable to set the PATH environment variable.';
398 MsgBox(Msg,mbError,MB_OK);
399 Log(Msg);
400 // This is not a critical error, the user can probably fix it manually,
401 // so we continue.
402 end;
405 Create the Windows Explorer shell extensions
408 if IsAdminLoggedOn then begin
409 RootKey:=HKEY_LOCAL_MACHINE;
410 end else begin
411 RootKey:=HKEY_CURRENT_USER;
412 end;
414 if IsTaskSelected('guiextension') then begin
415 if (not RegWriteStringValue(RootKey,'SOFTWARE\Classes\Directory\shell\git_cola','','Git &Cola Here'))
416 or (not RegWriteStringValue(RootKey,'SOFTWARE\Classes\Directory\shell\git_cola\command','','"'+EdtPython.Text+'" "'+AppDir+'\bin\git-cola.pyw" "--repo" "%1" "--git-path" "'+EdtGit.Text+'"')) then begin
417 Msg:='Line {#emit __LINE__}: Unable to create "Git Cola Here" shell extension.';
418 MsgBox(Msg,mbError,MB_OK);
419 Log(Msg);
420 // This is not a critical error, the user can probably fix it manually,
421 // so we continue.
422 end;
423 end;
424 end;
427 Uninstaller code
430 function InitializeUninstall:Boolean;
431 begin
432 Result:=True;
433 end;
435 procedure CurUninstallStepChanged(CurUninstallStep:TUninstallStep);
437 AppDir,Command,Msg:string;
438 EnvPath:TArrayOfString;
439 i:Longint;
440 RootKey:Integer;
441 begin
442 if CurUninstallStep<>usUninstall then begin
443 Exit;
444 end;
447 Modify the environment
449 This must happen no later than usUninstall to make
450 "ChangesEnvironment=yes" not happend before the change!
453 AppDir:=ExpandConstant('{app}');
454 Command:=AppDir+'\setup.ini';
456 // Get the current user's directories in PATH.
457 EnvPath:=GetEnvStrings('PATH',IsAdminLoggedOn);
459 // Remove the installation directory from PATH in any case, even if it
460 // was not added by the installer.
461 for i:=0 to GetArrayLength(EnvPath)-1 do begin
462 if Pos(AppDir,EnvPath[i])=1 then begin
463 EnvPath[i]:='';
464 end;
465 end;
467 // Reset the current user's directories in PATH.
468 if not SetEnvStrings('PATH',IsAdminLoggedOn,True,EnvPath) then begin
469 Msg:='Line {#emit __LINE__}: Unable to revert any possible changes to PATH.';
470 MsgBox(Msg,mbError,MB_OK);
471 Log(Msg);
472 // This is not a critical error, the user can probably fix it manually,
473 // so we continue.
474 end;
476 if (FileExists(Command) and (not DeleteFile(Command))) then begin
477 Msg:='Line {#emit __LINE__}: Unable to delete file "'+Command+'".';
478 MsgBox(Msg,mbError,MB_OK);
479 Log(Msg);
480 // This is not a critical error, the user can probably fix it manually,
481 // so we continue.
482 end;
485 Delete the Windows Explorer shell extensions
488 if IsAdminLoggedOn then begin
489 RootKey:=HKEY_LOCAL_MACHINE;
490 end else begin
491 RootKey:=HKEY_CURRENT_USER;
492 end;
494 Command:='';
495 RegQueryStringValue(RootKey,'SOFTWARE\Classes\Directory\shell\git_cola\command','',Command);
496 if Pos(AppDir,Command)>0 then begin
497 if not RegDeleteKeyIncludingSubkeys(RootKey,'SOFTWARE\Classes\Directory\shell\git_cola') then begin
498 Msg:='Line {#emit __LINE__}: Unable to remove "Git Cola Here" shell extension.';
499 MsgBox(Msg,mbError,MB_OK);
500 Log(Msg);
501 // This is not a critical error, the user can probably fix it manually,
502 // so we continue.
503 end;
504 end;
505 end;
507 function GetShellFolder(Param:string):string;
508 begin
509 if IsAdminLoggedOn then begin
510 Param:='{common'+Param+'}';
511 end else begin
512 Param:='{user'+Param+'}';
513 end;
514 Result:=ExpandConstant(Param);
515 end;