Git installer: Use a nicer small image file in the setup wizard
[msysgit.git] / share / WinGit / install.iss
blob253bbdabb3986bb14b14febffee4698ed5590cd7
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 InfoBeforeFile=gpl-2.0.rtf
24 PrivilegesRequired=none
25 UninstallDisplayIcon=etc\git.ico
27 ; Cosmetic
28 SetupIconFile=etc\git.ico
29 WizardImageBackColor=clWhite
30 WizardImageStretch=no
31 WizardImageFile=git.bmp
32 WizardSmallImageFile=gitsmall.bmp
34 [Tasks]
35 Name: quicklaunchicon; Description: Create a &Quick Launch icon; GroupDescription: Additional icons:; Flags: checkedonce
36 Name: desktopicon; Description: Create a &Desktop icon; GroupDescription: Additional icons:; Flags: checkedonce
37 Name: shellextension; Description: "Add ""Git Ba&sh Here"""; GroupDescription: Windows Explorer integration:; Flags: checkedonce
38 Name: guiextension; Description: "Add ""Git &GUI Here"""; GroupDescription: Windows Explorer integration:; Flags: checkedonce
40 [Files]
41 Source: *; DestDir: {app}; Excludes: \*.bmp, gpl-2.0.rtf, \install.*, \tmp.*, \bin\*install*; Flags: recursesubdirs replacesameversion
42 Source: ReleaseNotes.rtf; DestDir: {app}; Flags: isreadme replacesameversion
44 [Icons]
45 Name: {group}\Git GUI; Filename: {app}\bin\wish.exe; Parameters: """{app}\libexec\git-core\git-gui"""; WorkingDir: %HOMEDRIVE%%HOMEPATH%; IconFilename: {app}\etc\git.ico
46 Name: {group}\Git Bash; Filename: {syswow64}\cmd.exe; Parameters: "/c """"{app}\bin\sh.exe"" --login -i"""; WorkingDir: %HOMEDRIVE%%HOMEPATH%; IconFilename: {app}\etc\git.ico
47 Name: {group}\Uninstall Git; Filename: {uninstallexe}
48 Name: {userappdata}\Microsoft\Internet Explorer\Quick Launch\Git Bash; Filename: {syswow64}\cmd.exe; Parameters: "/c """"{app}\bin\sh.exe"" --login -i"""; WorkingDir: %HOMEDRIVE%%HOMEPATH%; IconFilename: {app}\etc\git.ico; Tasks: quicklaunchicon
49 Name: {code:GetShellFolder|desktop}\Git Bash; Filename: {syswow64}\cmd.exe; Parameters: "/c """"{app}\bin\sh.exe"" --login -i"""; WorkingDir: %HOMEDRIVE%%HOMEPATH%; 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\git-*.exe
58 Type: files; Name: {app}\libexec\git-core\git-*.exe
59 Type: dirifempty; Name: {app}\home\{username}
60 Type: dirifempty; Name: {app}\home
62 [Code]
64 Helper methods
67 function GetShellFolder(Param:string):string;
68 begin
69 if IsAdminLoggedOn then begin
70 Param:='{common'+Param+'}';
71 end else begin
72 Param:='{user'+Param+'}';
73 end;
74 Result:=ExpandConstant(Param);
75 end;
77 function CreateHardLink(lpFileName,lpExistingFileName:string;lpSecurityAttributes:Integer):Boolean;
78 external 'CreateHardLinkA@Kernel32.dll';
80 function GetEnvStrings(VarName:string;AllUsers:Boolean):TArrayOfString;
81 var
82 Path:string;
83 i:Longint;
84 p:Integer;
85 begin
86 Path:='';
88 // See http://www.jrsoftware.org/isfaq.php#env
89 if AllUsers then begin
90 // We ignore errors here. The resulting array of strings will be empty.
91 RegQueryStringValue(HKEY_LOCAL_MACHINE,'SYSTEM\CurrentControlSet\Control\Session Manager\Environment',VarName,Path);
92 end else begin
93 // We ignore errors here. The resulting array of strings will be empty.
94 RegQueryStringValue(HKEY_CURRENT_USER,'Environment',VarName,Path);
95 end;
97 // Make sure we have at least one semicolon.
98 Path:=Path+';';
100 // Split the directories in PATH into an array of strings.
101 i:=0;
102 SetArrayLength(Result,0);
104 p:=Pos(';',Path);
105 while p>0 do begin
106 SetArrayLength(Result,i+1);
107 if p>1 then begin
108 Result[i]:=Copy(Path,1,p-1);
109 i:=i+1;
110 end;
111 Path:=Copy(Path,p+1,Length(Path));
112 p:=Pos(';',Path);
113 end;
114 end;
116 function SetEnvStrings(VarName:string;AllUsers,DeleteIfEmpty:Boolean;DirStrings:TArrayOfString):Boolean;
118 Path,KeyName:string;
119 i:Longint;
120 begin
121 // Merge all non-empty directory strings into a PATH variable.
122 Path:='';
123 for i:=0 to GetArrayLength(DirStrings)-1 do begin
124 if Length(DirStrings[i])>0 then begin
125 if Length(Path)>0 then begin
126 Path:=Path+';'+DirStrings[i];
127 end else begin
128 Path:=DirStrings[i];
129 end;
130 end;
131 end;
133 // See http://www.jrsoftware.org/isfaq.php#env
134 if AllUsers then begin
135 KeyName:='SYSTEM\CurrentControlSet\Control\Session Manager\Environment';
136 if DeleteIfEmpty and (Length(Path)=0) then begin
137 Result:=(not RegValueExists(HKEY_LOCAL_MACHINE,KeyName,VarName)) or
138 RegDeleteValue(HKEY_LOCAL_MACHINE,KeyName,VarName);
139 end else begin
140 Result:=RegWriteStringValue(HKEY_LOCAL_MACHINE,KeyName,VarName,Path);
141 end;
142 end else begin
143 KeyName:='Environment';
144 if DeleteIfEmpty and (Length(Path)=0) then begin
145 Result:=(not RegValueExists(HKEY_CURRENT_USER,KeyName,VarName)) or
146 RegDeleteValue(HKEY_CURRENT_USER,KeyName,VarName);
147 end else begin
148 Result:=RegWriteStringValue(HKEY_CURRENT_USER,KeyName,VarName,Path);
149 end;
150 end;
151 end;
153 const
154 TortoiseSVNInstallKey='SOFTWARE\TortoiseSVN';
155 TortoiseCVSUninstallKey='SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\TortoiseCVS_is1';
156 PuTTYUninstallKey='SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\PuTTY_is1';
157 PuTTYPrivateKeyAssoc='PuTTYPrivateKey\shell\open\command';
159 function GetPuTTYLocation:string;
160 begin
161 // Prefer TortoisePlink over vanilla Plink for its GUI dialog to accept host keys.
162 if (IsWin64 and RegQueryStringValue(HKEY_LOCAL_MACHINE_64,TortoiseSVNInstallKey,'Directory',Result)) or
163 RegQueryStringValue(HKEY_LOCAL_MACHINE_32,TortoiseSVNInstallKey,'Directory',Result) then begin
164 // C:\Program Files\TortoiseSVN\
165 Result:=Result+'bin\';
166 // C:\Program Files\TortoiseSVN\bin\
167 end else begin
168 if not (IsWin64 and RegQueryStringValue(HKEY_LOCAL_MACHINE_64,TortoiseCVSUninstallKey,'InstallLocation',Result)) then begin
169 RegQueryStringValue(HKEY_LOCAL_MACHINE_32,TortoiseCVSUninstallKey,'InstallLocation',Result);
170 end;
171 // C:\Program Files\TortoiseCVS\
172 end;
174 if DirExists(Result) then begin
175 Result:=Result+'TortoisePlink.exe'
176 Exit;
177 end;
179 if not RegQueryStringValue(HKEY_LOCAL_MACHINE,PuTTYUninstallKey,'InstallLocation',Result) then begin
180 if RegQueryStringValue(HKEY_CLASSES_ROOT,PuTTYPrivateKeyAssoc,'',Result) then begin
181 // "C:\Program Files\PuTTY\pageant.exe" "%1"
182 Result:=RemoveQuotes(Result);
183 // C:\Program Files\PuTTY\pageant.exe" "%1
184 Result:=ExtractFilePath(Result);
185 end;
186 end;
187 // C:\Program Files\PuTTY\
189 if not DirExists(Result) then begin
190 // Guess something.
191 Result:='C:\Program Files\PuTTY\';
192 end;
194 Result:=Result+'plink.exe'
195 end;
197 const
198 // Git Path options.
199 GP_BashOnly = 1;
200 GP_Cmd = 2;
201 GP_CmdTools = 3;
203 // Git SSH options.
204 GS_OpenSSH = 1;
205 GS_Plink = 2;
207 // Git CRLF options.
208 GC_LFOnly = 1;
209 GC_CRLFAlways = 2;
210 GC_CRLFCommitAsIs = 3;
213 // Wizard page and variables for the Path options.
214 PathPage:TWizardPage;
215 RdbPath:array[GP_BashOnly..GP_CmdTools] of TRadioButton;
217 // Wizard page and variables for the SSH options.
218 PuTTYPage:TWizardPage;
219 RdbSSH:array[GS_OpenSSH..GS_Plink] of TRadioButton;
220 EdtPlink:TEdit;
222 // Wizard page and variables for the CR/LF options.
223 CRLFPage:TWizardPage;
224 RdbCRLF:array[GC_LFOnly..GC_CRLFCommitAsIs] of TRadioButton;
226 procedure BrowseForPuTTYFolder(Sender:TObject);
228 Path:string;
229 begin
230 Path:=ExtractFilePath(EdtPlink.Text);
231 BrowseForFolder('Please select the PuTTY folder:',Path,False);
232 if FileExists(Path+'\TortoisePlink.exe') then begin
233 EdtPlink.Text:=Path+'\TortoisePlink.exe';
234 RdbSSH[GS_Plink].Checked:=True;
235 end else if FileExists(Path+'\plink.exe') then begin
236 EdtPlink.Text:=Path+'\plink.exe';
237 RdbSSH[GS_Plink].Checked:=True;
238 end else begin
239 MsgBox('Please enter a valid path to "TortoisePlink.exe" or "plink.exe".',mbError,MB_OK);
240 end;
241 end;
244 Installer code
247 procedure InitializeWizard;
249 LblGitBash,LblGitCmd,LblGitCmdTools,LblGitCmdToolsWarn:TLabel;
250 LblOpenSSH,LblPlink:TLabel;
251 LblLFOnly,LblCRLFAlways,LblCRLFCommitAsIs:TLabel;
252 BtnPlink:TButton;
253 Data:String;
254 begin
255 // Create a custom page for modifying the environment.
256 PathPage:=CreateCustomPage(
257 wpSelectTasks,
258 'Adjusting your PATH environment',
259 'How would you like to use Git from the command line?'
262 // 1st choice
263 RdbPath[GP_BashOnly]:=TRadioButton.Create(PathPage);
264 with RdbPath[GP_BashOnly] do begin
265 Parent:=PathPage.Surface;
266 Caption:='Use Git Bash only';
267 Left:=ScaleX(4);
268 Top:=ScaleY(8);
269 Width:=ScaleX(129);
270 Height:=ScaleY(17);
271 Font.Style:=[fsBold];
272 TabOrder:=0;
273 Checked:=True;
274 end;
275 LblGitBash:=TLabel.Create(PathPage);
276 with LblGitBash do begin
277 Parent:=PathPage.Surface;
278 Caption:=
279 'This is the most conservative choice if you are concerned about the stability' + #13 +
280 'of your system. Your PATH will not be modified.';
281 Left:=ScaleX(28);
282 Top:=ScaleY(32);
283 Width:=ScaleX(405);
284 Height:=ScaleY(26);
285 end;
287 // 2nd choice
288 RdbPath[GP_Cmd]:=TRadioButton.Create(PathPage);
289 with RdbPath[GP_Cmd] do begin
290 Parent:=PathPage.Surface;
291 Caption:='Run Git from the Windows Command Prompt';
292 Left:=ScaleX(4);
293 Top:=ScaleY(76);
294 Width:=ScaleX(281);
295 Height:=ScaleY(17);
296 Font.Style:=[fsBold];
297 TabOrder:=1;
298 end;
299 LblGitCmd:=TLabel.Create(PathPage);
300 with LblGitCmd do begin
301 Parent:=PathPage.Surface;
302 Caption:=
303 'This option is considered safe and no conflicts with other tools are known.' + #13 +
304 'Only Git will be added to your PATH. Use this option if you want to use Git' + #13 +
305 'from a Cygwin Prompt (make sure to not have Cygwin''s Git installed).';
306 Left:=ScaleX(28);
307 Top:=ScaleY(100);
308 Width:=ScaleX(405);
309 Height:=ScaleY(39);
310 end;
312 // 3rd choice
313 RdbPath[GP_CmdTools]:=TRadioButton.Create(PathPage);
314 with RdbPath[GP_CmdTools] do begin
315 Parent:=PathPage.Surface;
316 Caption:='Run Git and included Unix tools from the Windows Command Prompt';
317 Left:=ScaleX(4);
318 Top:=ScaleY(152);
319 Width:=ScaleX(405);
320 Height:=ScaleY(17);
321 Font.Style:=[fsBold];
322 TabOrder:=2;
323 end;
324 LblGitCmdTools:=TLabel.Create(PathPage);
325 with LblGitCmdTools do begin
326 Parent:=PathPage.Surface;
327 Caption:='Both Git and its accompanying Unix tools will be added to your PATH.';
328 Left:=ScaleX(28);
329 Top:=ScaleY(176);
330 Width:=ScaleX(405);
331 Height:=ScaleY(13);
332 end;
333 LblGitCmdToolsWarn:=TLabel.Create(PathPage);
334 with LblGitCmdToolsWarn do begin
335 Parent:=PathPage.Surface;
336 Caption:=
337 'Warning: This will override Windows tools like find.exe and' + #13 +
338 'sort.exe. Select this option only if you understand the implications.';
339 Left:=ScaleX(28);
340 Top:=ScaleY(192);
341 Width:=ScaleX(376);
342 Height:=ScaleY(26);
343 Font.Color:=255;
344 Font.Style:=[fsBold];
345 end;
347 // Restore the setting chosen during a previous install.
348 Data:=GetPreviousData('Path Option','BashOnly');
349 if Data='BashOnly' then begin
350 RdbPath[GP_BashOnly].Checked:=True;
351 end else if Data='Cmd' then begin
352 RdbPath[GP_Cmd].Checked:=True;
353 end else if Data='CmdTools' then begin
354 RdbPath[GP_CmdTools].Checked:=True;
355 end;
357 // Create a custom page for using (Tortoise)Plink instead of OpenSSH.
358 PuTTYPage:=CreateCustomPage(
359 PathPage.ID,
360 'Choosing the SSH executable',
361 'Which Secure Shell client program would you like Git to use?'
364 // 1st choice
365 RdbSSH[GS_OpenSSH]:=TRadioButton.Create(PuTTYPage);
366 with RdbSSH[GS_OpenSSH] do begin
367 Parent:=PuTTYPage.Surface;
368 Caption:='Use OpenSSH';
369 Left:=ScaleX(4);
370 Top:=ScaleY(8);
371 Width:=ScaleX(129);
372 Height:=ScaleY(17);
373 Font.Style:=[fsBold];
374 TabOrder:=0;
375 Checked:=True;
376 end;
377 LblOpenSSH:=TLabel.Create(PuTTYPage);
378 with LblOpenSSH do begin
379 Parent:=PuTTYPage.Surface;
380 Caption:=
381 'This uses ssh.exe that comes with Git. The GIT_SSH and SVN_SSH' + #13 +
382 'environment variables will not be modified.';
383 Left:=ScaleX(28);
384 Top:=ScaleY(32);
385 Width:=ScaleX(324);
386 Height:=ScaleY(26);
387 end;
389 // 2nd choice
390 RdbSSH[GS_Plink]:=TRadioButton.Create(PuTTYPage);
391 with RdbSSH[GS_Plink] do begin
392 Parent:=PuTTYPage.Surface;
393 Caption:='Use (Tortoise)Plink';
394 Left:=ScaleX(4);
395 Top:=ScaleY(76);
396 Width:=ScaleX(281);
397 Height:=ScaleY(17);
398 Font.Style:=[fsBold];
399 TabOrder:=1;
400 end;
401 LblPlink:=TLabel.Create(PuTTYPage);
402 with LblPlink do begin
403 Parent:=PuTTYPage.Surface;
404 Caption:=
405 'This uses (Tortoise)Plink.exe from the TortoiseSVN/CVS or PuTTY' + #13 +
406 'applications which need to be provided by the user. The GIT_SSH and' + #13 +
407 'SVN_SSH environment variables will point to the below executable:';
408 Left:=ScaleX(28);
409 Top:=ScaleY(100);
410 Width:=ScaleX(340);
411 Height:=ScaleY(39);
412 end;
413 EdtPlink:=TEdit.Create(PuTTYPage);
414 with EdtPlink do begin
415 Parent:=PuTTYPage.Surface;
416 Text:=GetPuTTYLocation;
417 if not FileExists(Text) then begin
418 Text:='';
419 end;
420 Left:=ScaleX(28);
421 Top:=ScaleY(148);
422 Width:=ScaleX(316);
423 Height:=ScaleY(13);
424 end;
425 BtnPlink:=TButton.Create(PuTTYPage);
426 with BtnPlink do begin
427 Parent:=PuTTYPage.Surface;
428 Caption:='...';
429 OnClick:=@BrowseForPuTTYFolder;
430 Left:=ScaleX(348);
431 Top:=ScaleY(148);
432 Width:=ScaleX(21);
433 Height:=ScaleY(21);
434 end;
436 // Restore the setting chosen during a previous install.
437 Data:=GetPreviousData('SSH Option','OpenSSH');
438 if Data='OpenSSH' then begin
439 RdbSSH[GS_OpenSSH].Checked:=True;
440 end else if Data='Plink' then begin
441 RdbSSH[GS_Plink].Checked:=True;
442 end;
444 // Create a custom page for the autoCRLF setting.
445 CRLFPage:=CreateCustomPage(
446 PuTTYPage.ID,
447 'Choosing CR/LF behavior',
448 'Which CR/LF behavior would you like Git to have?'
451 // 1st choice
452 RdbCRLF[GC_LFOnly]:=TRadioButton.Create(CRLFPage);
453 with RdbCRLF[GC_LFOnly] do begin
454 Parent:=CRLFPage.Surface;
455 Caption:='Use Unix style line endings';
456 Left:=ScaleX(4);
457 Top:=ScaleY(8);
458 Width:=ScaleX(329);
459 Height:=ScaleY(17);
460 Font.Style:=[fsBold];
461 TabOrder:=0;
462 Checked:=False;
463 end;
464 LblLFOnly:=TLabel.Create(CRLFPage);
465 with LblLFOnly do begin
466 Parent:=CRLFPage.Surface;
467 Caption:=
468 'Choose this if a single Line Feed character ends your lines. Most Windows' + #13 +
469 'programs can cope with these line endings. However, some editors, like' + #13 +
470 'Notepad, will show everything in one line with this mode.';
471 Left:=ScaleX(28);
472 Top:=ScaleY(32);
473 Width:=ScaleX(364);
474 Height:=ScaleY(47);
475 end;
477 // 2nd choice
478 RdbCRLF[GC_CRLFAlways]:=TRadioButton.Create(CRLFPage);
479 with RdbCRLF[GC_CRLFAlways] do begin
480 Parent:=CRLFPage.Surface;
481 Caption:='Use Windows style line endings';
482 Left:=ScaleX(4);
483 Top:=ScaleY(76);
484 Width:=ScaleX(329);
485 Height:=ScaleY(17);
486 Font.Style:=[fsBold];
487 TabOrder:=1;
488 Checked:=True;
489 end;
490 LblCRLFAlways:=TLabel.Create(CRLFPage);
491 with LblCRLFAlways do begin
492 Parent:=CRLFPage.Surface;
493 Caption:=
494 'Choose this if your source code uses a Carriage Return and a Line Feed' + #13 +
495 'character to end lines. This is the DOS convention; your checked-out files' + #13 +
496 'might not be handled gracefully by MSYS / Cygwin command line utilities.';
497 Left:=ScaleX(28);
498 Top:=ScaleY(100);
499 Width:=ScaleX(364);
500 Height:=ScaleY(47);
501 end;
503 // 3rd choice
504 RdbCRLF[GC_CRLFCommitAsIs]:=TRadioButton.Create(CRLFPage);
505 with RdbCRLF[GC_CRLFCommitAsIs] do begin
506 Parent:=CRLFPage.Surface;
507 Caption:='Commit line endings as they are';
508 Left:=ScaleX(4);
509 Top:=ScaleY(152);
510 Width:=ScaleX(329);
511 Height:=ScaleY(17);
512 Font.Style:=[fsBold];
513 TabOrder:=2;
514 Checked:=False;
515 end;
516 LblCRLFCommitAsIs:=TLabel.Create(CRLFPage);
517 with LblCRLFCommitAsIs do begin
518 Parent:=CRLFPage.Surface;
519 Caption:=
520 'Choose this if you know what you are doing and want to track the files with' + #13 +
521 'the line endings exactly as they appear in the files. This option might' + #13 +
522 'cause your projects to be hard to use on other platforms.';
523 Left:=ScaleX(28);
524 Top:=ScaleY(176);
525 Width:=ScaleX(364);
526 Height:=ScaleY(47);
527 end;
529 // Restore the setting chosen during a previous install.
530 Data:=GetPreviousData('CRLF Option','CRLFAlways');
531 if Data='LFOnly' then begin
532 RdbCRLF[GC_LFOnly].Checked:=True;
533 end else if Data='CRLFAlways' then begin
534 RdbCRLF[GC_CRLFAlways].Checked:=True;
535 end else if Data='CRLFCommitAsIs' then begin
536 RdbCRLF[GC_CRLFCommitAsIs].Checked:=True;
537 end;
538 end;
540 function NextButtonClick(CurPageID:Integer):Boolean;
541 begin
542 if CurPageID<>PuTTYPage.ID then begin
543 Result:=True;
544 Exit;
545 end;
547 Result:=RdbSSH[GS_OpenSSH].Checked or
548 (RdbSSH[GS_Plink].Checked and FileExists(EdtPlink.Text));
550 if not Result then begin
551 MsgBox('Please enter a valid path to (Tortoise)Plink.exe.',mbError,MB_OK);
552 end;
553 end;
555 procedure CurStepChanged(CurStep:TSetupStep);
557 AppDir,FileName,Cmd,Msg:string;
558 BuiltIns,EnvPath,EnvHome,EnvSSH:TArrayOfString;
559 Count,i:Longint;
560 IsNTFS:Boolean;
561 FindRec:TFindRec;
562 RootKey:Integer;
563 begin
564 if CurStep<>ssPostInstall then begin
565 Exit;
566 end;
568 AppDir:=ExpandConstant('{app}');
571 Create the built-ins
574 // Load the built-ins from a text file.
575 FileName:=ExpandConstant('{app}\'+'{#emit APP_BUILTINS}');
576 if LoadStringsFromFile(FileName,BuiltIns) then begin
577 // Check if we are running on NTFS.
578 IsNTFS:=False;
579 if SetNTFSCompression(AppDir+'\bin\git.exe',true) then begin
580 IsNTFS:=SetNTFSCompression(AppDir+'\bin\git.exe',false);
581 end;
583 Count:=GetArrayLength(BuiltIns)-1;
585 // Delete those scripts from "bin" which have been replaced by built-ins in "libexec\git-core".
586 for i:=0 to Count do begin
587 FileName:=AppDir+'\bin\'+ChangeFileExt(ExtractFileName(BuiltIns[i]),'');
588 if FileExists(FileName) and (not DeleteFile(FileName)) then begin
589 Log('Line {#emit __LINE__}: Unable to delete script "'+FileName+'", ignoring.');
590 end;
591 end;
593 // Map the built-ins to git.exe.
594 if IsNTFS then begin
595 Log('Line {#emit __LINE__}: Partition seems to be NTFS, trying to create built-in aliases as hard links.');
597 for i:=0 to Count do begin
598 FileName:=AppDir+'\'+BuiltIns[i];
600 // On non-NTFS partitions, create hard links.
601 if (FileExists(FileName) and (not DeleteFile(FileName))) or
602 (not CreateHardLink(FileName,AppDir+'\bin\git.exe',0)) then begin
603 Log('Line {#emit __LINE__}: Unable to create hard link "'+FileName+'", will try to copy files.');
604 IsNTFS:=False;
605 Break;
606 end;
607 end;
609 Log('Line {#emit __LINE__}: Successfully created built-in aliases as hard links.');
610 end;
612 // The fallback is to copy the files.
613 if not IsNTFS then begin
614 Log('Line {#emit __LINE__}: Trying to create built-in aliases as file copies.');
616 for i:=0 to Count do begin
617 FileName:=AppDir+'\'+BuiltIns[i];
619 // On non-NTFS partitions, copy simply the files (overwriting existing ones).
620 if not FileCopy(AppDir+'\bin\git.exe',FileName,false) then begin
621 Msg:='Line {#emit __LINE__}: Unable to create file copy "'+FileName+'".';
622 MsgBox(Msg,mbError,MB_OK);
623 Log(Msg);
624 // This is not a critical error, Git could basically be used without the
625 // aliases for built-ins, so we continue.
626 end;
627 end;
629 Log('Line {#emit __LINE__}: Successfully created built-in aliases as file copies.');
630 end;
632 // Delete any duplicate files in case we are updating from a non-libexec to a libexec directory layout.
633 if FindFirst(AppDir+'\libexec\git-core\*',FindRec) then begin
634 repeat
635 if (FindRec.Attributes and FILE_ATTRIBUTE_DIRECTORY)=0 then begin
636 FileName:=AppDir+'\bin\'+FindRec.name;
637 if (Pos(FindRec.name,'git.exe')<>1) and FileExists(FileName) and (not DeleteFile(FileName)) then begin
638 Log('Line {#emit __LINE__}: Unable to delete dupe "'+FileName+'", ignoring.');
639 end;
640 end;
641 until not FindNext(FindRec);
642 FindClose(FindRec);
643 end;
644 end else begin
645 Msg:='Line {#emit __LINE__}: Unable to read file "{#emit APP_BUILTINS}".';
646 MsgBox(Msg,mbError,MB_OK);
647 Log(Msg);
648 // This is not a critical error, Git could basically be used without the
649 // aliases for built-ins, so we continue.
650 end;
653 Adapt core.autocrlf
656 if RdbCRLF[GC_LFOnly].checked then begin
657 Cmd:='core.autoCRLF input';
658 end else if RdbCRLF[GC_CRLFAlways].checked then begin
659 Cmd:='core.autoCRLF true';
660 end else begin
661 Cmd:='core.autoCRLF false';
662 end;
663 if not Exec(AppDir + '\bin\git.exe', 'config -f gitconfig ' + Cmd,
664 AppDir + '\etc', SW_HIDE, ewWaitUntilTerminated, i) then begin
665 Msg:='Could not set CR/LF behavior: ' + Cmd;
666 MsgBox(Msg,mbError,MB_OK);
667 Log(Msg);
668 end;
671 Modify the environment
673 This must happen no later than ssPostInstall to make
674 "ChangesEnvironment=yes" not happend before the change!
677 FileName:=AppDir+'\setup.ini';
679 // Delete GIT_SSH and SVN_SSH if a previous installation set them (this is required for the GS_OpenSSH case).
680 EnvSSH:=GetEnvStrings('GIT_SSH',IsAdminLoggedOn);
681 if (GetArrayLength(EnvSSH)=1) and
682 (CompareStr(EnvSSH[0],GetIniString('Environment','GIT_SSH','',FileName))=0) then begin
683 if not SetEnvStrings('GIT_SSH',IsAdminLoggedOn,True,[]) then begin
684 Msg:='Line {#emit __LINE__}: Unable to reset GIT_SSH prior to install.';
685 MsgBox(Msg,mbError,MB_OK);
686 Log(Msg);
687 // This is not a critical error, the user can probably fix it manually,
688 // so we continue.
689 end;
690 end;
692 EnvSSH:=GetEnvStrings('SVN_SSH',IsAdminLoggedOn);
693 if (GetArrayLength(EnvSSH)=1) and
694 (CompareStr(EnvSSH[0],GetIniString('Environment','SVN_SSH','',FileName))=0) then begin
695 if not SetEnvStrings('SVN_SSH',IsAdminLoggedOn,True,[]) then begin
696 Msg:='Line {#emit __LINE__}: Unable to reset SVN_SSH prior to install.';
697 MsgBox(Msg,mbError,MB_OK);
698 Log(Msg);
699 // This is not a critical error, the user can probably fix it manually,
700 // so we continue.
701 end;
702 end;
704 if RdbSSH[GS_Plink].Checked then begin
705 SetArrayLength(EnvSSH,1);
706 EnvSSH[0]:=EdtPlink.Text;
708 // Set GIT_SSH as specified by the user.
709 if not SetEnvStrings('GIT_SSH',IsAdminLoggedOn,True,EnvSSH) then begin
710 Msg:='Line {#emit __LINE__}: Unable to set the GIT_SSH environment variable.';
711 MsgBox(Msg,mbError,MB_OK);
712 Log(Msg);
713 // This is not a critical error, the user can probably fix it manually,
714 // so we continue.
715 end;
717 // Mark that we have changed GIT_SSH by writing its value to a file.
718 if not SetIniString('Environment','GIT_SSH',EnvSSH[0],FileName) then begin
719 Msg:='Line {#emit __LINE__}: Unable to write to file "'+FileName+'".';
720 MsgBox(Msg,mbError,MB_OK);
721 Log(Msg);
722 // This is not a critical error, though uninstall / reinstall will probably not run cleanly,
723 // so we continue.
724 end;
726 // Set SVN_SSH as specified by the user, but with escaped backslashes and quotes.
727 StringChangeEx(EnvSSH[0],'\','\\',True);
728 EnvSSH[0]:=AddQuotes(EnvSSH[0]);
730 if not SetEnvStrings('SVN_SSH',IsAdminLoggedOn,True,EnvSSH) then begin
731 Msg:='Line {#emit __LINE__}: Unable to set the SVN_SSH environment variable.';
732 MsgBox(Msg,mbError,MB_OK);
733 Log(Msg);
734 // This is not a critical error, the user can probably fix it manually,
735 // so we continue.
736 end;
738 // Mark that we have changed SVN_SSH by writing its value to a file.
739 if not SetIniString('Environment','SVN_SSH',EnvSSH[0],FileName) then begin
740 Msg:='Line {#emit __LINE__}: Unable to write to file "'+FileName+'".';
741 MsgBox(Msg,mbError,MB_OK);
742 Log(Msg);
743 // This is not a critical error, though uninstall / reinstall will probably not run cleanly,
744 // so we continue.
745 end;
746 end;
748 // Get the current user's directories in PATH.
749 EnvPath:=GetEnvStrings('PATH',IsAdminLoggedOn);
751 // First, remove the installation directory from PATH in any case.
752 for i:=0 to GetArrayLength(EnvPath)-1 do begin
753 if Pos(AppDir+'\',EnvPath[i]+'\')=1 then begin
754 EnvPath[i]:='';
755 end;
756 end;
758 // Delete HOME if a previous installation modified it.
759 EnvHome:=GetEnvStrings('HOME',IsAdminLoggedOn);
760 if (GetArrayLength(EnvHome)=1) and
761 (CompareStr(EnvHome[0],GetIniString('Environment','HOME','',FileName))=0) then begin
762 if not SetEnvStrings('HOME',IsAdminLoggedOn,True,[]) then begin
763 Msg:='Line {#emit __LINE__}: Unable to reset HOME prior to install.';
764 MsgBox(Msg,mbError,MB_OK);
765 Log(Msg);
766 // This is not a critical error, the user can probably fix it manually,
767 // so we continue.
768 end;
769 end;
771 // Modify the PATH variable as requested by the user.
772 if RdbPath[GP_Cmd].Checked or RdbPath[GP_CmdTools].Checked then begin
773 i:=GetArrayLength(EnvPath);
774 SetArrayLength(EnvPath,i+1);
776 // List \cmd before \bin so \cmd has higher priority and programs in
777 // there will be called in favor of those in \bin.
778 EnvPath[i]:=ExpandConstant('{app}\cmd');
780 if RdbPath[GP_CmdTools].Checked then begin
781 SetArrayLength(EnvPath,i+2);
782 EnvPath[i+1]:=ExpandConstant('{app}\bin');
784 // Set HOME for the Windows Command Prompt, but only if it has not been set manually before.
785 EnvHome:=GetEnvStrings('HOME',IsAdminLoggedOn);
786 i:=GetArrayLength(EnvHome);
787 if (i=0) or ((i=1) and (Length(EnvHome[0])=0)) then begin
788 SetArrayLength(EnvHome,1);
789 EnvHome[0]:=ExpandConstant('{%HOMEDRIVE}{%HOMEPATH}');
790 if not SetEnvStrings('HOME',IsAdminLoggedOn,True,EnvHome) then begin
791 Msg:='Line {#emit __LINE__}: Unable to set the HOME environment variable.';
792 MsgBox(Msg,mbError,MB_OK);
793 Log(Msg);
794 // This is not a critical error, the user can probably fix it manually,
795 // so we continue.
796 end;
798 // Mark that we have changed HOME.
799 if not SetIniString('Environment','HOME',EnvHome[0],FileName) then begin
800 Msg:='Line {#emit __LINE__}: Unable to write to file "'+FileName+'".';
801 MsgBox(Msg,mbError,MB_OK);
802 Log(Msg);
803 // This is not a critical error, though uninstall / reinstall will probably not run cleanly,
804 // so we continue.
805 end;
806 end;
807 end;
808 end;
810 // Set the current user's PATH directories.
811 if not SetEnvStrings('PATH',IsAdminLoggedOn,True,EnvPath) then begin
812 Msg:='Line {#emit __LINE__}: Unable to set the PATH environment variable.';
813 MsgBox(Msg,mbError,MB_OK);
814 Log(Msg);
815 // This is not a critical error, the user can probably fix it manually,
816 // so we continue.
817 end;
820 Create the Windows Explorer shell extensions
823 if IsAdminLoggedOn then begin
824 RootKey:=HKEY_LOCAL_MACHINE;
825 end else begin
826 RootKey:=HKEY_CURRENT_USER;
827 end;
829 if IsTaskSelected('shellextension') then begin
830 Cmd:=ExpandConstant('"{syswow64}\cmd.exe"');
831 if (not RegWriteStringValue(RootKey,'SOFTWARE\Classes\Directory\shell\git_shell','','Git Ba&sh Here')) or
832 (not RegWriteStringValue(RootKey,'SOFTWARE\Classes\Directory\shell\git_shell\command','',Cmd+' /c "pushd "%1" && "'+AppDir+'\bin\sh.exe" --login -i"')) then begin
833 Msg:='Line {#emit __LINE__}: Unable to create "Git Bash Here" shell extension.';
834 MsgBox(Msg,mbError,MB_OK);
835 Log(Msg);
836 // This is not a critical error, the user can probably fix it manually,
837 // so we continue.
838 end;
839 end;
841 if IsTaskSelected('guiextension') then begin
842 if (not RegWriteStringValue(RootKey,'SOFTWARE\Classes\Directory\shell\git_gui','','Git &GUI Here')) or
843 (not RegWriteStringValue(RootKey,'SOFTWARE\Classes\Directory\shell\git_gui\command','','"'+AppDir+'\bin\wish.exe" "'+AppDir+'\libexec\git-core\git-gui" "--working-dir" "%1"')) then begin
844 Msg:='Line {#emit __LINE__}: Unable to create "Git GUI Here" shell extension.';
845 MsgBox(Msg,mbError,MB_OK);
846 Log(Msg);
847 // This is not a critical error, the user can probably fix it manually,
848 // so we continue.
849 end;
850 end;
851 end;
853 procedure RegisterPreviousData(PreviousDataKey:Integer);
855 Data:string;
856 begin
857 // Git Path options.
858 Data:='';
859 if RdbPath[GP_BashOnly].Checked then begin
860 Data:='BashOnly';
861 end else if RdbPath[GP_Cmd].Checked then begin
862 Data:='Cmd';
863 end else if RdbPath[GP_CmdTools].Checked then begin
864 Data:='CmdTools';
865 end;
866 SetPreviousData(PreviousDataKey,'Path Option',Data);
868 // Git SSH options.
869 Data:='';
870 if RdbSSH[GS_OpenSSH].Checked then begin
871 Data:='OpenSSH';
872 end else if RdbSSH[GS_Plink].Checked then begin
873 Data:='Plink';
874 end;
875 SetPreviousData(PreviousDataKey,'SSH Option',Data);
877 // Git CR/LF options.
878 Data:='';
879 if RdbCRLF[GC_LFOnly].Checked then begin
880 Data:='LFOnly';
881 end else if RdbCRLF[GC_CRLFAlways].Checked then begin
882 Data:='CRLFAlways';
883 end else if RdbCRLF[GC_CRLFCommitAsIs].Checked then begin
884 Data:='CRLFCommitAsIs';
885 end;
886 SetPreviousData(PreviousDataKey,'CRLF Option',Data);
887 end;
890 Uninstaller code
893 function InitializeUninstall:Boolean;
895 FileName,NewName,Msg:string;
896 begin
897 FileName:=ExpandConstant('{app}')+'\bin\ssh-agent.exe';
898 if FileExists(FileName) then begin
899 // Create a temporary copy of the file we try to delete.
900 NewName:=FileName+'.'+IntToStr(1000+Random(9000));
901 Result:=FileCopy(FileName,NewName,True) and DeleteFile(FileName);
903 if not Result then begin
904 Msg:='Line {#emit __LINE__}: Please stop all ssh-agent processes and run uninstall again.';
905 MsgBox(Msg,mbError,MB_OK);
906 Log(Msg);
908 // Clean-up the temporary copy (ignoring any errors).
909 DeleteFile(NewName);
910 end else begin
911 // Clean-up the temporary copy (ignoring any errors).
912 RenameFile(NewName,FileName);
913 end;
914 end else begin
915 Result:=True;
916 end;
917 end;
919 procedure CurUninstallStepChanged(CurUninstallStep:TUninstallStep);
921 AppDir,Command,Msg:string;
922 EnvPath,EnvHome,EnvSSH:TArrayOfString;
923 i:Longint;
924 RootKey:Integer;
925 begin
926 if CurUninstallStep<>usUninstall then begin
927 Exit;
928 end;
931 Modify the environment
933 This must happen no later than usUninstall to make
934 "ChangesEnvironment=yes" not happend before the change!
937 AppDir:=ExpandConstant('{app}');
938 Command:=AppDir+'\setup.ini';
940 // Delete the current user's GIT_SSH and SVN_SSH if we set it.
941 EnvSSH:=GetEnvStrings('GIT_SSH',IsAdminLoggedOn);
942 if (GetArrayLength(EnvSSH)=1) and
943 (CompareStr(EnvSSH[0],GetIniString('Environment','GIT_SSH','',Command))=0) then begin
944 if not SetEnvStrings('GIT_SSH',IsAdminLoggedOn,True,[]) then begin
945 Msg:='Line {#emit __LINE__}: Unable to revert any possible changes to GIT_SSH.';
946 MsgBox(Msg,mbError,MB_OK);
947 Log(Msg);
948 // This is not a critical error, the user can probably fix it manually,
949 // so we continue.
950 end;
951 end;
953 EnvSSH:=GetEnvStrings('SVN_SSH',IsAdminLoggedOn);
954 if (GetArrayLength(EnvSSH)=1) and
955 (CompareStr(EnvSSH[0],GetIniString('Environment','SVN_SSH','',Command))=0) then begin
956 if not SetEnvStrings('SVN_SSH',IsAdminLoggedOn,True,[]) then begin
957 Msg:='Line {#emit __LINE__}: Unable to revert any possible changes to SVN_SSH.';
958 MsgBox(Msg,mbError,MB_OK);
959 Log(Msg);
960 // This is not a critical error, the user can probably fix it manually,
961 // so we continue.
962 end;
963 end;
965 // Get the current user's directories in PATH.
966 EnvPath:=GetEnvStrings('PATH',IsAdminLoggedOn);
968 // Remove the installation directory from PATH in any case, even if it
969 // was not added by the installer.
970 for i:=0 to GetArrayLength(EnvPath)-1 do begin
971 if Pos(AppDir+'\',EnvPath[i]+'\')=1 then begin
972 EnvPath[i]:='';
973 end;
974 end;
976 // Reset the current user's directories in PATH.
977 if not SetEnvStrings('PATH',IsAdminLoggedOn,True,EnvPath) then begin
978 Msg:='Line {#emit __LINE__}: Unable to revert any possible changes to PATH.';
979 MsgBox(Msg,mbError,MB_OK);
980 Log(Msg);
981 // This is not a critical error, the user can probably fix it manually,
982 // so we continue.
983 end;
985 // Reset the current user's HOME if we modified it.
986 EnvHome:=GetEnvStrings('HOME',IsAdminLoggedOn);
987 if (GetArrayLength(EnvHome)=1) and
988 (CompareStr(EnvHome[0],GetIniString('Environment','HOME','',Command))=0) then begin
989 if not SetEnvStrings('HOME',IsAdminLoggedOn,True,[]) then begin
990 Msg:='Line {#emit __LINE__}: Unable to revert any possible changes to HOME.';
991 MsgBox(Msg,mbError,MB_OK);
992 Log(Msg);
993 // This is not a critical error, the user can probably fix it manually,
994 // so we continue.
995 end;
996 end;
998 if FileExists(Command) and (not DeleteFile(Command)) then begin
999 Msg:='Line {#emit __LINE__}: Unable to delete file "'+Command+'".';
1000 MsgBox(Msg,mbError,MB_OK);
1001 Log(Msg);
1002 // This is not a critical error, the user can probably fix it manually,
1003 // so we continue.
1004 end;
1007 Delete the Windows Explorer shell extensions
1010 if IsAdminLoggedOn then begin
1011 RootKey:=HKEY_LOCAL_MACHINE;
1012 end else begin
1013 RootKey:=HKEY_CURRENT_USER;
1014 end;
1016 Command:='';
1017 RegQueryStringValue(RootKey,'SOFTWARE\Classes\Directory\shell\git_shell\command','',Command);
1018 if Pos(AppDir,Command)>0 then begin
1019 if not RegDeleteKeyIncludingSubkeys(RootKey,'SOFTWARE\Classes\Directory\shell\git_shell') then begin
1020 Msg:='Line {#emit __LINE__}: Unable to remove "Git Bash Here" shell extension.';
1021 MsgBox(Msg,mbError,MB_OK);
1022 Log(Msg);
1023 // This is not a critical error, the user can probably fix it manually,
1024 // so we continue.
1025 end;
1026 end;
1028 Command:='';
1029 RegQueryStringValue(RootKey,'SOFTWARE\Classes\Directory\shell\git_gui\command','',Command);
1030 if Pos(AppDir,Command)>0 then begin
1031 if not RegDeleteKeyIncludingSubkeys(RootKey,'SOFTWARE\Classes\Directory\shell\git_gui') then begin
1032 Msg:='Line {#emit __LINE__}: Unable to remove "Git GUI Here" shell extension.';
1033 MsgBox(Msg,mbError,MB_OK);
1034 Log(Msg);
1035 // This is not a critical error, the user can probably fix it manually,
1036 // so we continue.
1037 end;
1038 end;
1039 end;