WinGit: Customized setup window and task bar titles (cosmetics only)
[msysgit/mtrensch.git] / share / WinGit / install.iss
blob66237977dd1e203423dfc2dcd2fe8024aae98a96
1 #define APP_NAME 'Git'
2 #define APP_VERSION '%APPVERSION%'
3 #define APP_URL 'http://code.google.com/p/msysgit/'
4 #define APP_BUILTINS 'etc\fileList-builtins.txt'
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_NAME}
16 AppPublisherURL={#emit APP_URL}
17 AppVersion={#emit APP_VERSION}
18 AppVerName={#emit APP_NAME+' '+APP_VERSION}
19 ChangesEnvironment=yes
20 DefaultDirName={pf}\{#emit APP_NAME}
21 DefaultGroupName={#emit APP_NAME}
22 DisableReadyPage=yes
23 InfoAfterFile=ReleaseNotes.rtf
24 LicenseFile=gpl-2.0.rtf
25 PrivilegesRequired=none
26 UninstallDisplayIcon=etc\git.ico
28 ; Cosmetic
29 SetupIconFile=etc\git.ico
30 WizardSmallImageFile=git.bmp
32 [Tasks]
33 Name: quicklaunchicon; Description: "Create a &Quick Launch icon"; GroupDescription: "Additional icons:"; Flags: checkedonce
34 Name: desktopicon; Description: "Create a &Desktop icon"; GroupDescription: "Additional icons:"; Flags: checkedonce
35 Name: shellextension; Description: "Add ""Git Ba&sh Here"""; GroupDescription: "Windows Explorer integration:"; Flags: checkedonce
36 Name: guiextension; Description: "Add ""Git &GUI Here"""; GroupDescription: "Windows Explorer integration:"; Flags: checkedonce
38 [Files]
39 Source: "*"; DestDir: "{app}"; Excludes: "\*.bmp, gpl-2.0.rtf, \install.*, \tmp.*, \bin\*install*"; Flags: recursesubdirs
41 [Icons]
42 Name: "{group}\Git GUI"; Filename: "{app}\bin\wish.exe"; Parameters: """{app}\bin\git-gui"""; WorkingDir: "%USERPROFILE%"; IconFilename: "{app}\etc\git.ico"
43 Name: "{group}\Git Bash"; Filename: "{syswow64}\cmd.exe"; Parameters: "/c """"{app}\bin\sh.exe"" --login -i"""; WorkingDir: "%USERPROFILE%"; IconFilename: "{app}\etc\git.ico"
44 Name: "{group}\Uninstall Git"; Filename: "{uninstallexe}"
45 Name: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\Git Bash"; Filename: "{syswow64}\cmd.exe"; Parameters: "/c """"{app}\bin\sh.exe"" --login -i"""; WorkingDir: "%USERPROFILE%"; IconFilename: "{app}\etc\git.ico"; Tasks: quicklaunchicon
46 Name: "{code:GetShellFolder|desktop}\Git Bash"; Filename: "{syswow64}\cmd.exe"; Parameters: "/c """"{app}\bin\sh.exe"" --login -i"""; WorkingDir: "%USERPROFILE%"; IconFilename: "{app}\etc\git.ico"; Tasks: desktopicon
48 [Messages]
49 BeveledLabel={#emit APP_URL}
50 SetupAppTitle={#emit APP_NAME} Setup
51 SetupWindowTitle={#emit APP_NAME} Setup
53 [UninstallDelete]
54 Type: files; Name: "{app}\bin\git-*.exe"
55 Type: dirifempty; Name: "{app}\home\{username}"
56 Type: dirifempty; Name: "{app}\home"
58 [Code]
60 Helper methods
63 function GetShellFolder(Param:string):string;
64 begin
65 if IsAdminLoggedOn then begin
66 Param:='{common'+Param+'}';
67 end else begin
68 Param:='{user'+Param+'}';
69 end;
70 Result:=ExpandConstant(Param);
71 end;
73 function CreateHardLink(lpFileName,lpExistingFileName:string;lpSecurityAttributes:Integer):Boolean;
74 external 'CreateHardLinkA@Kernel32.dll';
76 function GetEnvStrings(VarName:string;AllUsers:Boolean):TArrayOfString;
77 var
78 Path:string;
79 i:Longint;
80 p:Integer;
81 begin
82 Path:='';
84 // See http://www.jrsoftware.org/isfaq.php#env
85 if AllUsers then begin
86 // We ignore errors here. The resulting array of strings will be empty.
87 RegQueryStringValue(HKEY_LOCAL_MACHINE,'SYSTEM\CurrentControlSet\Control\Session Manager\Environment',VarName,Path);
88 end else begin
89 // We ignore errors here. The resulting array of strings will be empty.
90 RegQueryStringValue(HKEY_CURRENT_USER,'Environment',VarName,Path);
91 end;
93 // Make sure we have at least one semicolon.
94 Path:=Path+';';
96 // Split the directories in PATH into an array of strings.
97 i:=0;
98 SetArrayLength(Result,0);
100 p:=Pos(';',Path);
101 while p>0 do begin
102 SetArrayLength(Result,i+1);
103 if p>1 then begin
104 Result[i]:=Copy(Path,1,p-1);
105 i:=i+1;
106 end;
107 Path:=Copy(Path,p+1,Length(Path));
108 p:=Pos(';',Path);
109 end;
110 end;
112 function SetEnvStrings(VarName:string;AllUsers,DeleteIfEmpty:Boolean;DirStrings:TArrayOfString):Boolean;
114 Path,KeyName:string;
115 i:Longint;
116 begin
117 // Merge all non-empty directory strings into a PATH variable.
118 Path:='';
119 for i:=0 to GetArrayLength(DirStrings)-1 do begin
120 if Length(DirStrings[i])>0 then begin
121 if Length(Path)>0 then begin
122 Path:=Path+';'+DirStrings[i];
123 end else begin
124 Path:=DirStrings[i];
125 end;
126 end;
127 end;
129 // See http://www.jrsoftware.org/isfaq.php#env
130 if AllUsers then begin
131 KeyName:='SYSTEM\CurrentControlSet\Control\Session Manager\Environment';
132 if DeleteIfEmpty and (Length(Path)=0) then begin
133 Result:=(not RegValueExists(HKEY_LOCAL_MACHINE,KeyName,VarName))
134 or RegDeleteValue(HKEY_LOCAL_MACHINE,KeyName,VarName);
135 end else begin
136 Result:=RegWriteStringValue(HKEY_LOCAL_MACHINE,KeyName,VarName,Path);
137 end;
138 end else begin
139 KeyName:='Environment';
140 if DeleteIfEmpty and (Length(Path)=0) then begin
141 Result:=(not RegValueExists(HKEY_CURRENT_USER,KeyName,VarName))
142 or RegDeleteValue(HKEY_CURRENT_USER,KeyName,VarName);
143 end else begin
144 Result:=RegWriteStringValue(HKEY_CURRENT_USER,KeyName,VarName,Path);
145 end;
146 end;
147 end;
150 Installer code
154 EnvPage:TWizardPage;
155 RdbGitBash,RdbGitCmd,RdbGitCmdTools:TRadioButton;
157 procedure InitializeWizard;
159 LblGitBash,LblGitCmd,LblGitCmdTools,LblGitCmdToolsWarn:TLabel;
160 begin
161 // Create a custom page for modifying the environment.
162 EnvPage:=CreateCustomPage(
163 wpSelectTasks,
164 'Adjusting your PATH environment',
165 'How would you like to use Git from the command line?'
168 // 1st choice
169 RdbGitBash:=TRadioButton.Create(EnvPage);
170 with RdbGitBash do begin
171 Parent:=EnvPage.Surface;
172 Caption:='Use Git Bash only';
173 Left:=ScaleX(4);
174 Top:=ScaleY(8);
175 Width:=ScaleX(129);
176 Height:=ScaleY(17);
177 Font.Style:=[fsBold];
178 TabOrder:=0;
179 Checked:=True;
180 end;
181 LblGitBash:=TLabel.Create(EnvPage);
182 with LblGitBash do begin
183 Parent:=EnvPage.Surface;
184 Caption:=
185 'This is the most conservative choice if you are concerned about the' + #13 +
186 'stability of your system. Your PATH will not be modified.';
187 Left:=ScaleX(28);
188 Top:=ScaleY(32);
189 Width:=ScaleX(324);
190 Height:=ScaleY(26);
191 end;
193 // 2nd choice
194 RdbGitCmd:=TRadioButton.Create(EnvPage);
195 with RdbGitCmd do begin
196 Parent:=EnvPage.Surface;
197 Caption:='Run Git from the Windows Command Prompt';
198 Left:=ScaleX(4);
199 Top:=ScaleY(76);
200 Width:=ScaleX(281);
201 Height:=ScaleY(17);
202 Font.Style:=[fsBold];
203 TabOrder:=1;
204 end;
205 LblGitCmd:=TLabel.Create(EnvPage);
206 with LblGitCmd do begin
207 Parent:=EnvPage.Surface;
208 Caption:=
209 'This option is considered safe and no conflicts with other tools are' + #13 +
210 'known. Only Git will be added to your PATH.';
211 Left:=ScaleX(28);
212 Top:=ScaleY(100);
213 Width:=ScaleX(316);
214 Height:=ScaleY(26);
215 end;
217 // 3rd choice
218 RdbGitCmdTools:=TRadioButton.Create(EnvPage);
219 with RdbGitCmdTools do begin
220 Parent:=EnvPage.Surface;
221 Caption:='Run Git and included Unix tools from the Windows Command Prompt';
222 Left:=ScaleX(4);
223 Top:=ScaleY(152);
224 Width:=ScaleX(405);
225 Height:=ScaleY(17);
226 Font.Style:=[fsBold];
227 TabOrder:=2;
228 end;
229 LblGitCmdTools:=TLabel.Create(EnvPage);
230 with LblGitCmdTools do begin
231 Parent:=EnvPage.Surface;
232 Caption:='Both Git and the Unix tools will be added to your PATH.';
233 Left:=ScaleX(28);
234 Top:=ScaleY(176);
235 Width:=ScaleX(280);
236 Height:=ScaleY(13);
237 end;
238 LblGitCmdToolsWarn:=TLabel.Create(EnvPage);
239 with LblGitCmdToolsWarn do begin
240 Parent:=EnvPage.Surface;
241 Caption:=
242 'Warning: This will override Windows tools like find.exe and' + #13 +
243 'sort.exe. Select this option only if you understand the implications.';
244 Left:=ScaleX(28);
245 Top:=ScaleY(192);
246 Width:=ScaleX(376);
247 Height:=ScaleY(26);
248 Font.Color:=255;
249 Font.Style:=[fsBold];
250 end;
251 end;
253 procedure CurStepChanged(CurStep:TSetupStep);
255 AppDir,FileName,Cmd,Msg:string;
256 BuiltIns,EnvPath,EnvHome:TArrayOfString;
257 Count,i:Longint;
258 IsNTFS:Boolean;
259 RootKey:Integer;
260 begin
261 if CurStep<>ssPostInstall then begin
262 Exit;
263 end;
265 AppDir:=ExpandConstant('{app}');
268 Create the built-ins
271 // Load the built-ins from a text file.
272 FileName:=ExpandConstant('{app}\'+'{#emit APP_BUILTINS}');
273 if LoadStringsFromFile(FileName,BuiltIns) then begin
274 // Check if we are running on NTFS.
275 IsNTFS:=False;
276 if SetNTFSCompression(AppDir+'\bin\git.exe',true) then begin
277 IsNTFS:=SetNTFSCompression(AppDir+'\bin\git.exe',false);
278 end;
280 Count:=GetArrayLength(BuiltIns)-1;
282 // Map the built-ins to git.exe.
283 if IsNTFS then begin
284 Log('Line {#emit __LINE__}: Partition seems to be NTFS, trying to create built-in aliases as hard links.');
286 for i:=0 to Count do begin
287 FileName:=AppDir+'\'+BuiltIns[i];
289 // On non-NTFS partitions, create hard links.
290 if (FileExists(FileName) and (not DeleteFile(FileName)))
291 or (not CreateHardLink(FileName,AppDir+'\bin\git.exe',0)) then begin
292 Log('Line {#emit __LINE__}: Unable to create hard link "'+FileName+'", will try to copy files.');
293 IsNTFS:=False;
294 Break;
295 end;
296 end;
298 Log('Line {#emit __LINE__}: Successfully created built-in aliases as hard links.');
299 end;
301 // The fallback is to copy the files.
302 if not IsNTFS then begin
303 Log('Line {#emit __LINE__}: Trying to create built-in aliases as file copies.');
305 for i:=0 to Count do begin
306 FileName:=AppDir+'\'+BuiltIns[i];
308 // On non-NTFS partitions, copy simply the files (overwriting existing ones).
309 if not FileCopy(AppDir+'\bin\git.exe',FileName,false) then begin
310 Msg:='Line {#emit __LINE__}: Unable to create file copy "'+FileName+'".';
311 MsgBox(Msg,mbError,MB_OK);
312 Log(Msg);
313 // This is not a critical error, Git could basically be used without the
314 // aliases for built-ins, so we continue.
315 end;
316 end;
318 Log('Line {#emit __LINE__}: Successfully created built-in aliases as file copies.');
319 end;
320 end else begin
321 Msg:='Line {#emit __LINE__}: Unable to read file "{#emit APP_BUILTINS}".';
322 MsgBox(Msg,mbError,MB_OK);
323 Log(Msg);
324 // This is not a critical error, Git could basically be used without the
325 // aliases for built-ins, so we continue.
326 end;
330 Modify the environment
332 This must happen no later than ssPostInstall to make
333 "ChangesEnvironment=yes" not happend before the change!
336 // Get the current user's directories in PATH.
337 EnvPath:=GetEnvStrings('PATH',IsAdminLoggedOn);
339 // First, remove the installation directory from PATH in any case.
340 for i:=0 to GetArrayLength(EnvPath)-1 do begin
341 if Pos(AppDir,EnvPath[i])=1 then begin
342 EnvPath[i]:='';
343 end;
344 end;
346 // Delete HOME if a previous installation modified it.
347 EnvHome:=GetEnvStrings('HOME',IsAdminLoggedOn);
348 if (GetArrayLength(EnvHome)=1) and
349 (CompareStr(EnvHome[0],GetIniString('Environment','HOME','',AppDir+'\setup.ini'))=0) then begin
350 if not SetEnvStrings('HOME',IsAdminLoggedOn,True,[]) then begin
351 Msg:='Line {#emit __LINE__}: Unable to reset HOME prior to install.';
352 MsgBox(Msg,mbError,MB_OK);
353 Log(Msg);
354 // This is not a critical error, the user can probably fix it manually,
355 // so we continue.
356 end;
357 end;
359 // Modify the PATH variable as requested by the user.
360 if RdbGitCmd.Checked or RdbGitCmdTools.Checked then begin
361 i:=GetArrayLength(EnvPath);
362 SetArrayLength(EnvPath,i+1);
364 // List \cmd before \bin so \cmd has higher priority and programs in
365 // there will be called in favor of those in \bin.
366 EnvPath[i]:=ExpandConstant('{app}\cmd');
368 if RdbGitCmdTools.Checked then begin
369 SetArrayLength(EnvPath,i+2);
370 EnvPath[i+1]:=ExpandConstant('{app}\bin');
372 // Set HOME for the Windows Command Prompt.
373 EnvHome:=GetEnvStrings('HOME',IsAdminLoggedOn);
374 i:=GetArrayLength(EnvHome);
375 if (i=0) or ((i=1) and (Length(EnvHome[0])=0)) then begin
376 SetArrayLength(EnvHome,1);
377 EnvHome[0]:=ExpandConstant('{%USERPROFILE}');
378 if not SetEnvStrings('HOME',IsAdminLoggedOn,True,EnvHome) then begin
379 Msg:='Line {#emit __LINE__}: Unable to set the HOME environment variable.';
380 MsgBox(Msg,mbError,MB_OK);
381 Log(Msg);
382 // This is not a critical error, the user can probably fix it manually,
383 // so we continue.
384 end;
386 // Mark that we have changed HOME.
387 FileName:=AppDir+'\setup.ini';
388 if not SetIniString('Environment','HOME',EnvHome[0],FileName) then begin
389 Msg:='Line {#emit __LINE__}: Unable to write to file "'+FileName+'".';
390 MsgBox(Msg,mbError,MB_OK);
391 Log(Msg);
392 // This is not a critical error, though uninstall / reinstall will probably not run cleanly,
393 // so we continue.
394 end;
395 end;
396 end;
397 end;
399 // Set the current user's PATH directories.
400 if not SetEnvStrings('PATH',IsAdminLoggedOn,True,EnvPath) then begin
401 Msg:='Line {#emit __LINE__}: Unable to set the PATH environment variable.';
402 MsgBox(Msg,mbError,MB_OK);
403 Log(Msg);
404 // This is not a critical error, the user can probably fix it manually,
405 // so we continue.
406 end;
409 Create the Windows Explorer shell extensions
412 if IsAdminLoggedOn then begin
413 RootKey:=HKEY_LOCAL_MACHINE;
414 end else begin
415 RootKey:=HKEY_CURRENT_USER;
416 end;
418 if IsTaskSelected('shellextension') then begin
419 Cmd:=ExpandConstant('"{syswow64}\cmd.exe"');
420 if (not RegWriteStringValue(RootKey,'SOFTWARE\Classes\Directory\shell\git_shell','','Git Ba&sh Here'))
421 or (not RegWriteStringValue(RootKey,'SOFTWARE\Classes\Directory\shell\git_shell\command','',Cmd+' /c "pushd "%1" && "'+AppDir+'\bin\sh.exe" --login -i"')) then begin
422 Msg:='Line {#emit __LINE__}: Unable to create "Git Bash Here" shell extension.';
423 MsgBox(Msg,mbError,MB_OK);
424 Log(Msg);
425 // This is not a critical error, the user can probably fix it manually,
426 // so we continue.
427 end;
428 end;
430 if IsTaskSelected('guiextension') then begin
431 if (not RegWriteStringValue(RootKey,'SOFTWARE\Classes\Directory\shell\git_gui','','Git &GUI Here'))
432 or (not RegWriteStringValue(RootKey,'SOFTWARE\Classes\Directory\shell\git_gui\command','','"'+AppDir+'\bin\wish.exe" "'+AppDir+'\bin\git-gui" "--working-dir" "%1"')) then begin
433 Msg:='Line {#emit __LINE__}: Unable to create "Git GUI Here" shell extension.';
434 MsgBox(Msg,mbError,MB_OK);
435 Log(Msg);
436 // This is not a critical error, the user can probably fix it manually,
437 // so we continue.
438 end;
439 end;
440 end;
443 Uninstaller code
446 function InitializeUninstall:Boolean;
448 FileName,NewName,Msg:string;
449 begin
450 FileName:=ExpandConstant('{app}')+'\bin\ssh-agent.exe';
451 if FileExists(FileName) then begin
452 // Create a temporary copy of the file we try to delete.
453 NewName:=FileName+'.'+IntToStr(1000+Random(9000));
454 Result:=FileCopy(FileName,NewName,True) and DeleteFile(FileName);
456 if not Result then begin
457 Msg:='Line {#emit __LINE__}: Please stop all ssh-agent processes and run uninstall again.';
458 MsgBox(Msg,mbError,MB_OK);
459 Log(Msg);
461 // Clean-up the temporary copy (ignoring any errors).
462 DeleteFile(NewName);
463 end else begin
464 // Clean-up the temporary copy (ignoring any errors).
465 RenameFile(NewName,FileName);
466 end;
467 end else begin
468 Result:=True;
469 end;
470 end;
472 procedure CurUninstallStepChanged(CurUninstallStep:TUninstallStep);
474 AppDir,Command,Msg:string;
475 EnvPath,EnvHome:TArrayOfString;
476 i:Longint;
477 RootKey:Integer;
478 begin
479 if CurUninstallStep<>usUninstall then begin
480 Exit;
481 end;
484 Modify the environment
486 This must happen no later than usUninstall to make
487 "ChangesEnvironment=yes" not happend before the change!
490 AppDir:=ExpandConstant('{app}');
492 // Get the current user's directories in PATH.
493 EnvPath:=GetEnvStrings('PATH',IsAdminLoggedOn);
495 // Remove the installation directory from PATH in any case, even if it
496 // was not added by the installer.
497 for i:=0 to GetArrayLength(EnvPath)-1 do begin
498 if Pos(AppDir,EnvPath[i])=1 then begin
499 EnvPath[i]:='';
500 end;
501 end;
503 // Reset the current user's directories in PATH.
504 if not SetEnvStrings('PATH',IsAdminLoggedOn,True,EnvPath) then begin
505 Msg:='Line {#emit __LINE__}: Unable to revert any possible changes to PATH.';
506 MsgBox(Msg,mbError,MB_OK);
507 Log(Msg);
508 // This is not a critical error, the user can probably fix it manually,
509 // so we continue.
510 end;
512 // Reset the current user's HOME if we modified it.
513 EnvHome:=GetEnvStrings('HOME',IsAdminLoggedOn);
514 if (GetArrayLength(EnvHome)=1) and
515 (CompareStr(EnvHome[0],GetIniString('Environment','HOME','',AppDir+'\setup.ini'))=0) then begin
516 if not SetEnvStrings('HOME',IsAdminLoggedOn,True,[]) then begin
517 Msg:='Line {#emit __LINE__}: Unable to revert any possible changes to HOME.';
518 MsgBox(Msg,mbError,MB_OK);
519 Log(Msg);
520 // This is not a critical error, the user can probably fix it manually,
521 // so we continue.
522 end;
523 end;
525 Command:=AppDir+'\setup.ini';
526 if not DeleteFile(Command) then begin
527 Msg:='Line {#emit __LINE__}: Unable to delete file "'+Command+'".';
528 MsgBox(Msg,mbError,MB_OK);
529 Log(Msg);
530 // This is not a critical error, the user can probably fix it manually,
531 // so we continue.
532 end;
535 Delete the Windows Explorer shell extensions
538 if IsAdminLoggedOn then begin
539 RootKey:=HKEY_LOCAL_MACHINE;
540 end else begin
541 RootKey:=HKEY_CURRENT_USER;
542 end;
544 Command:='';
545 RegQueryStringValue(RootKey,'SOFTWARE\Classes\Directory\shell\git_shell\command','',Command);
546 if Pos(AppDir,Command)>0 then begin
547 if not RegDeleteKeyIncludingSubkeys(RootKey,'SOFTWARE\Classes\Directory\shell\git_shell') then begin
548 Msg:='Line {#emit __LINE__}: Unable to remove "Git Bash Here" shell extension.';
549 MsgBox(Msg,mbError,MB_OK);
550 Log(Msg);
551 // This is not a critical error, the user can probably fix it manually,
552 // so we continue.
553 end;
554 end;
556 Command:='';
557 RegQueryStringValue(RootKey,'SOFTWARE\Classes\Directory\shell\git_gui\command','',Command);
558 if Pos(AppDir,Command)>0 then begin
559 if not RegDeleteKeyIncludingSubkeys(RootKey,'SOFTWARE\Classes\Directory\shell\git_gui') then begin
560 Msg:='Line {#emit __LINE__}: Unable to remove "Git GUI Here" shell extension.';
561 MsgBox(Msg,mbError,MB_OK);
562 Log(Msg);
563 // This is not a critical error, the user can probably fix it manually,
564 // so we continue.
565 end;
566 end;
567 end;