Installer: Use components instead of tasks for optional stuff
[msysgit/mtrensch.git] / share / WinGit / install.iss
blobc2178d1a5f2810f4f540cea494eabe4bb7b15f77
1 #define APP_NAME 'Git'
2 #define APP_VERSION '%APPVERSION%'
3 #define APP_URL 'http://msysgit.googlecode.com/'
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 ; Uncomment the line below to be able to compile the script from within the IDE.
14 ;SourceDir={#GetEnv('TEMP')}\WinGit
16 ; Installer-related
17 AllowNoIcons=yes
18 AppName={#emit APP_NAME}
19 AppPublisherURL={#emit APP_URL}
20 AppVersion={#emit APP_VERSION}
21 AppVerName={#emit APP_NAME+' '+APP_VERSION}
22 ChangesEnvironment=yes
23 DefaultDirName={pf}\{#emit APP_NAME}
24 DefaultGroupName={#emit APP_NAME}
25 DisableReadyPage=yes
26 InfoBeforeFile=gpl-2.0.rtf
27 PrivilegesRequired=none
28 UninstallDisplayIcon=etc\git.ico
30 ; Cosmetic
31 SetupIconFile=etc\git.ico
32 WizardImageBackColor=clWhite
33 WizardImageStretch=no
34 WizardImageFile=git.bmp
35 WizardSmallImageFile=gitsmall.bmp
37 [Types]
38 ; Define a dummy type to avoid getting the default ones.
39 Name: custom; Description: Custom installation; Flags: iscustom
41 [Components]
42 Name: icons; Description: Additional icons; Types: custom
43 Name: icons\quicklaunch; Description: In the Quick Launch; Types: custom
44 Name: icons\desktop; Description: On the Desktop; Types: custom
45 Name: ext; Description: Windows Explorer integration; Types: custom
46 Name: ext\shellhere; Description: """Git Bash Here"" context menu entry"; Types: custom
47 Name: ext\guihere; Description: """Git GUI Here"" context menu entry"; Types: custom
48 Name: consolefont; Description: Use a TrueType font in the console (required for proper character encoding); Types: custom
50 [Files]
51 Source: *; DestDir: {app}; Excludes: \*.bmp, gpl-2.0.rtf, \*.iss, \tmp.*, \bin\*install*; Flags: recursesubdirs replacesameversion
52 Source: ReleaseNotes.rtf; DestDir: {app}; Flags: isreadme replacesameversion
54 [Icons]
55 Name: {group}\Git GUI; Filename: {app}\bin\wish.exe; Parameters: """{app}\libexec\git-core\git-gui"""; WorkingDir: %HOMEDRIVE%%HOMEPATH%; IconFilename: {app}\etc\git.ico
56 Name: {group}\Git Bash; Filename: {syswow64}\cmd.exe; Parameters: "/c """"{app}\bin\sh.exe"" --login -i"""; WorkingDir: %HOMEDRIVE%%HOMEPATH%; IconFilename: {app}\etc\git.ico
57 Name: {group}\Uninstall Git; Filename: {uninstallexe}
58 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; Components: icons\quicklaunch
59 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; Components: icons\desktop
61 ; Create a special shortcut that does not set a working directory. This is used by "Git Bash.vbs", which in turn is run by the "Git Bash Here" shell extension.
62 Name: {app}\Git Bash; Filename: {syswow64}\cmd.exe; Parameters: "/c """"{app}\bin\sh.exe"" --login -i"""; IconFilename: {app}\etc\git.ico
64 [Messages]
65 BeveledLabel={#emit APP_URL}
66 SetupAppTitle={#emit APP_NAME} Setup
67 SetupWindowTitle={#emit APP_NAME} Setup
69 [Registry]
70 Root: HKCU; Subkey: Console; ValueType: string; ValueName: FaceName; ValueData: Lucida Console; Components: consolefont
71 Root: HKCU; Subkey: Console; ValueType: dword; ValueName: FontFamily; ValueData: $00000036; Components: consolefont
72 Root: HKCU; Subkey: Console; ValueType: dword; ValueName: FontSize; ValueData: $000e0000; Components: consolefont
73 Root: HKCU; Subkey: Console; ValueType: dword; ValueName: FontWeight; ValueData: $00000190; Components: consolefont
75 Root: HKCU; Subkey: Console\Git Bash; ValueType: string; ValueName: FaceName; ValueData: Lucida Console; Flags: createvalueifdoesntexist
76 Root: HKCU; Subkey: Console\Git Bash; ValueType: dword; ValueName: FontFamily; ValueData: $00000036; Flags: createvalueifdoesntexist
77 Root: HKCU; Subkey: Console\Git Bash; ValueType: dword; ValueName: FontSize; ValueData: $000e0000; Flags: createvalueifdoesntexist
78 Root: HKCU; Subkey: Console\Git Bash; ValueType: dword; ValueName: FontWeight; ValueData: $00000190; Flags: createvalueifdoesntexist
80 [UninstallDelete]
81 ; Delete the built-ins.
82 Type: files; Name: {app}\bin\git-*.exe
83 Type: files; Name: {app}\libexec\git-core\git-*.exe
84 Type: files; Name: {app}\libexec\git-core\git.exe
85 ; Delete a home directory inside the msysGit directory.
86 Type: dirifempty; Name: {app}\home\{username}
87 Type: dirifempty; Name: {app}\home
89 [Code]
90 #include "helpers.inc.iss"
91 #include "putty.inc.iss"
93 function CreateHardLink(lpFileName,lpExistingFileName:String;lpSecurityAttributes:Integer):Boolean;
94 #ifdef UNICODE
95 external 'CreateHardLinkW@Kernel32.dll stdcall delayload setuponly';
96 #else
97 external 'CreateHardLinkA@Kernel32.dll stdcall delayload setuponly';
98 #endif
100 function CreateSymbolicLink(lpSymlinkFileName,lpTargetFileName:String;dwFlags:DWORD):Boolean;
101 #ifdef UNICODE
102 external 'CreateSymbolicLinkW@Kernel32.dll stdcall delayload setuponly';
103 #else
104 external 'CreateSymbolicLinkA@Kernel32.dll stdcall delayload setuponly';
105 #endif
107 const
108 // Git Path options.
109 GP_BashOnly = 1;
110 GP_Cmd = 2;
111 GP_CmdTools = 3;
113 // Git SSH options.
114 GS_OpenSSH = 1;
115 GS_Plink = 2;
117 // Git line ending conversion options.
118 GC_LFOnly = 1;
119 GC_CRLFAlways = 2;
120 GC_CRLFCommitAsIs = 3;
123 // Wizard page and variables for the Path options.
124 PathPage:TWizardPage;
125 RdbPath:array[GP_BashOnly..GP_CmdTools] of TRadioButton;
127 // Wizard page and variables for the SSH options.
128 PuTTYPage:TWizardPage;
129 RdbSSH:array[GS_OpenSSH..GS_Plink] of TRadioButton;
130 EdtPlink:TEdit;
132 // Wizard page and variables for the line ending conversion options.
133 CRLFPage:TWizardPage;
134 RdbCRLF:array[GC_LFOnly..GC_CRLFCommitAsIs] of TRadioButton;
136 procedure BrowseForPuTTYFolder(Sender:TObject);
138 Path:String;
139 begin
140 Path:=ExtractFilePath(EdtPlink.Text);
141 BrowseForFolder('Please select the PuTTY folder:',Path,False);
142 if FileExists(Path+'\TortoisePlink.exe') then begin
143 EdtPlink.Text:=Path+'\TortoisePlink.exe';
144 RdbSSH[GS_Plink].Checked:=True;
145 end else if FileExists(Path+'\plink.exe') then begin
146 EdtPlink.Text:=Path+'\plink.exe';
147 RdbSSH[GS_Plink].Checked:=True;
148 end else begin
149 MsgBox('Please enter a valid path to "TortoisePlink.exe" or "plink.exe".',mbError,MB_OK);
150 end;
151 end;
154 Installer code
157 procedure InitializeWizard;
159 PrevPageID:Integer;
160 LblGitBash,LblGitCmd,LblGitCmdTools,LblGitCmdToolsWarn:TLabel;
161 LblOpenSSH,LblPlink:TLabel;
162 PuTTYSessions:TArrayOfString;
163 LblLFOnly,LblCRLFAlways,LblCRLFCommitAsIs:TLabel;
164 BtnPlink:TButton;
165 Data:String;
166 begin
167 PrevPageID:=wpSelectProgramGroup;
170 * Create a custom page for modifying the environment.
173 PathPage:=CreateCustomPage(
174 PrevPageID,
175 'Adjusting your PATH environment',
176 'How would you like to use Git from the command line?'
178 PrevPageID:=PathPage.ID;
180 // 1st choice
181 RdbPath[GP_BashOnly]:=TRadioButton.Create(PathPage);
182 with RdbPath[GP_BashOnly] do begin
183 Parent:=PathPage.Surface;
184 Caption:='Use Git Bash only';
185 Left:=ScaleX(4);
186 Top:=ScaleY(8);
187 Width:=ScaleX(129);
188 Height:=ScaleY(17);
189 Font.Style:=[fsBold];
190 TabOrder:=0;
191 Checked:=True;
192 end;
193 LblGitBash:=TLabel.Create(PathPage);
194 with LblGitBash do begin
195 Parent:=PathPage.Surface;
196 Caption:=
197 'This is the most conservative choice if you are concerned about the stability' + #13 +
198 'of your system. Your PATH will not be modified.';
199 Left:=ScaleX(28);
200 Top:=ScaleY(32);
201 Width:=ScaleX(405);
202 Height:=ScaleY(26);
203 end;
205 // 2nd choice
206 RdbPath[GP_Cmd]:=TRadioButton.Create(PathPage);
207 with RdbPath[GP_Cmd] do begin
208 Parent:=PathPage.Surface;
209 Caption:='Run Git from the Windows Command Prompt';
210 Left:=ScaleX(4);
211 Top:=ScaleY(76);
212 Width:=ScaleX(281);
213 Height:=ScaleY(17);
214 Font.Style:=[fsBold];
215 TabOrder:=1;
216 end;
217 LblGitCmd:=TLabel.Create(PathPage);
218 with LblGitCmd do begin
219 Parent:=PathPage.Surface;
220 Caption:=
221 'This option is considered safe and no conflicts with other tools are known.' + #13 +
222 'Only Git will be added to your PATH. Use this option if you want to use Git' + #13 +
223 'from a Cygwin Prompt (make sure to not have Cygwin''s Git installed).';
224 Left:=ScaleX(28);
225 Top:=ScaleY(100);
226 Width:=ScaleX(405);
227 Height:=ScaleY(39);
228 end;
230 // 3rd choice
231 RdbPath[GP_CmdTools]:=TRadioButton.Create(PathPage);
232 with RdbPath[GP_CmdTools] do begin
233 Parent:=PathPage.Surface;
234 Caption:='Run Git and included Unix tools from the Windows Command Prompt';
235 Left:=ScaleX(4);
236 Top:=ScaleY(152);
237 Width:=ScaleX(405);
238 Height:=ScaleY(17);
239 Font.Style:=[fsBold];
240 TabOrder:=2;
241 end;
242 LblGitCmdTools:=TLabel.Create(PathPage);
243 with LblGitCmdTools do begin
244 Parent:=PathPage.Surface;
245 Caption:='Both Git and its accompanying Unix tools will be added to your PATH.';
246 Left:=ScaleX(28);
247 Top:=ScaleY(176);
248 Width:=ScaleX(405);
249 Height:=ScaleY(13);
250 end;
251 LblGitCmdToolsWarn:=TLabel.Create(PathPage);
252 with LblGitCmdToolsWarn do begin
253 Parent:=PathPage.Surface;
254 Caption:=
255 'Warning: This will override Windows tools like find.exe and' + #13 +
256 'sort.exe. Select this option only if you understand the implications.';
257 Left:=ScaleX(28);
258 Top:=ScaleY(192);
259 Width:=ScaleX(376);
260 Height:=ScaleY(26);
261 Font.Color:=255;
262 Font.Style:=[fsBold];
263 end;
265 // Restore the setting chosen during a previous install.
266 Data:=GetPreviousData('Path Option','BashOnly');
267 if Data='BashOnly' then begin
268 RdbPath[GP_BashOnly].Checked:=True;
269 end else if Data='Cmd' then begin
270 RdbPath[GP_Cmd].Checked:=True;
271 end else if Data='CmdTools' then begin
272 RdbPath[GP_CmdTools].Checked:=True;
273 end;
276 * Create a custom page for using (Tortoise)Plink instead of OpenSSH
277 * if at least one PuTTY session is found in the Registry.
280 if RegGetSubkeyNames(HKEY_CURRENT_USER,'Software\SimonTatham\PuTTY\Sessions',PuTTYSessions) and (GetArrayLength(PuTTYSessions)>0) then begin
281 PuTTYPage:=CreateCustomPage(
282 PrevPageID,
283 'Choosing the SSH executable',
284 'Which Secure Shell client program would you like Git to use?'
286 PrevPageID:=PuTTYPage.ID;
288 // 1st choice
289 RdbSSH[GS_OpenSSH]:=TRadioButton.Create(PuTTYPage);
290 with RdbSSH[GS_OpenSSH] do begin
291 Parent:=PuTTYPage.Surface;
292 Caption:='Use OpenSSH';
293 Left:=ScaleX(4);
294 Top:=ScaleY(8);
295 Width:=ScaleX(129);
296 Height:=ScaleY(17);
297 Font.Style:=[fsBold];
298 TabOrder:=0;
299 Checked:=True;
300 end;
301 LblOpenSSH:=TLabel.Create(PuTTYPage);
302 with LblOpenSSH do begin
303 Parent:=PuTTYPage.Surface;
304 Caption:=
305 'This uses ssh.exe that comes with Git. The GIT_SSH and SVN_SSH' + #13 +
306 'environment variables will not be modified.';
307 Left:=ScaleX(28);
308 Top:=ScaleY(32);
309 Width:=ScaleX(324);
310 Height:=ScaleY(26);
311 end;
313 // 2nd choice
314 RdbSSH[GS_Plink]:=TRadioButton.Create(PuTTYPage);
315 with RdbSSH[GS_Plink] do begin
316 Parent:=PuTTYPage.Surface;
317 Caption:='Use (Tortoise)Plink';
318 Left:=ScaleX(4);
319 Top:=ScaleY(76);
320 Width:=ScaleX(281);
321 Height:=ScaleY(17);
322 Font.Style:=[fsBold];
323 TabOrder:=1;
324 end;
325 LblPlink:=TLabel.Create(PuTTYPage);
326 with LblPlink do begin
327 Parent:=PuTTYPage.Surface;
328 Caption:=
329 'PuTTY sessions were found in your Registry. You may specify the path' + #13 +
330 'to an existing copy of (Tortoise)Plink.exe from the TortoiseSVN/CVS' + #13 +
331 'or PuTTY applications. The GIT_SSH and SVN_SSH environment' + #13 +
332 'variables will be adjusted to point to the following executable:';
333 Left:=ScaleX(28);
334 Top:=ScaleY(100);
335 Width:=ScaleX(340);
336 Height:=ScaleY(52);
337 end;
338 EdtPlink:=TEdit.Create(PuTTYPage);
339 with EdtPlink do begin
340 Parent:=PuTTYPage.Surface;
341 Text:=GetPuTTYLocation;
342 if not FileExists(Text) then begin
343 Text:='';
344 end;
345 Left:=ScaleX(28);
346 Top:=ScaleY(161);
347 Width:=ScaleX(316);
348 Height:=ScaleY(13);
349 end;
350 BtnPlink:=TButton.Create(PuTTYPage);
351 with BtnPlink do begin
352 Parent:=PuTTYPage.Surface;
353 Caption:='...';
354 OnClick:=@BrowseForPuTTYFolder;
355 Left:=ScaleX(348);
356 Top:=ScaleY(161);
357 Width:=ScaleX(21);
358 Height:=ScaleY(21);
359 end;
361 // Restore the setting chosen during a previous install.
362 Data:=GetPreviousData('SSH Option','OpenSSH');
363 if Data='OpenSSH' then begin
364 RdbSSH[GS_OpenSSH].Checked:=True;
365 end else if Data='Plink' then begin
366 RdbSSH[GS_Plink].Checked:=True;
367 end;
368 end else begin
369 PuTTYPage:=NIL;
370 end;
373 * Create a custom page for the core.autocrlf setting.
376 CRLFPage:=CreateCustomPage(
377 PrevPageID,
378 'Configuring the line ending conversions',
379 'How should Git treat line endings in text files?'
381 PrevPageID:=CRLFPage.ID;
383 // 1st choice
384 RdbCRLF[GC_CRLFAlways]:=TRadioButton.Create(CRLFPage);
385 with RdbCRLF[GC_CRLFAlways] do begin
386 Parent:=CRLFPage.Surface;
387 Caption:='Checkout Windows-style, commit Unix-style line endings';
388 Left:=ScaleX(4);
389 Top:=ScaleY(8);
390 Width:=ScaleX(340);
391 Height:=ScaleY(17);
392 Font.Style:=[fsBold];
393 TabOrder:=0;
394 Checked:=True;
395 end;
396 LblCRLFAlways:=TLabel.Create(CRLFPage);
397 with LblCRLFAlways do begin
398 Parent:=CRLFPage.Surface;
399 Caption:=
400 'Git will convert LF to CRLF when checking out text files. When committing' + #13 +
401 'text files, CRLF will be converted to LF. For cross-platform projects,' + #13 +
402 'this is the recommended setting on Windows ("core.autocrlf" is set to "true").';
403 Left:=ScaleX(28);
404 Top:=ScaleY(32);
405 Width:=ScaleX(372);
406 Height:=ScaleY(47);
407 end;
409 // 2nd choice
410 RdbCRLF[GC_LFOnly]:=TRadioButton.Create(CRLFPage);
411 with RdbCRLF[GC_LFOnly] do begin
412 Parent:=CRLFPage.Surface;
413 Caption:='Checkout as-is, commit Unix-style line endings';
414 Left:=ScaleX(4);
415 Top:=ScaleY(80);
416 Width:=ScaleX(340);
417 Height:=ScaleY(17);
418 Font.Style:=[fsBold];
419 TabOrder:=1;
420 Checked:=False;
421 end;
422 LblLFOnly:=TLabel.Create(CRLFPage);
423 with LblLFOnly do begin
424 Parent:=CRLFPage.Surface;
425 Caption:=
426 'Git will not perform any conversion when checking out text files. When' + #13 +
427 'committing text files, CRLF will be converted to LF. For cross-platform projects,' + #13 +
428 'this is the recommended setting on Unix ("core.autocrlf" is set to "input").';
429 Left:=ScaleX(28);
430 Top:=ScaleY(104);
431 Width:=ScaleX(372);
432 Height:=ScaleY(47);
433 end;
435 // 3rd choice
436 RdbCRLF[GC_CRLFCommitAsIs]:=TRadioButton.Create(CRLFPage);
437 with RdbCRLF[GC_CRLFCommitAsIs] do begin
438 Parent:=CRLFPage.Surface;
439 Caption:='Checkout as-is, commit as-is';
440 Left:=ScaleX(4);
441 Top:=ScaleY(152);
442 Width:=ScaleX(340);
443 Height:=ScaleY(17);
444 Font.Style:=[fsBold];
445 TabOrder:=2;
446 Checked:=False;
447 end;
448 LblCRLFCommitAsIs:=TLabel.Create(CRLFPage);
449 with LblCRLFCommitAsIs do begin
450 Parent:=CRLFPage.Surface;
451 Caption:=
452 'Git will not perform any conversions when checking out or committing' + #13 +
453 'text files. Choosing this option is not recommended for cross-platform' + #13 +
454 'projects ("core.autocrlf" is set to "false").';
455 Left:=ScaleX(28);
456 Top:=ScaleY(176);
457 Width:=ScaleX(372);
458 Height:=ScaleY(47);
459 end;
461 // Restore the setting chosen during a previous install.
462 Data:=GetPreviousData('CRLF Option','CRLFAlways');
463 if Data='LFOnly' then begin
464 RdbCRLF[GC_LFOnly].Checked:=True;
465 end else if Data='CRLFAlways' then begin
466 RdbCRLF[GC_CRLFAlways].Checked:=True;
467 end else if Data='CRLFCommitAsIs' then begin
468 RdbCRLF[GC_CRLFCommitAsIs].Checked:=True;
469 end;
470 end;
472 function NextButtonClick(CurPageID:Integer):Boolean;
473 begin
474 if (PuTTYPage=NIL) or (CurPageID<>PuTTYPage.ID) then begin
475 Result:=True;
476 Exit;
477 end;
479 Result:=RdbSSH[GS_OpenSSH].Checked or
480 (RdbSSH[GS_Plink].Checked and FileExists(EdtPlink.Text));
482 if not Result then begin
483 MsgBox('Please enter a valid path to (Tortoise)Plink.exe.',mbError,MB_OK);
484 end;
485 end;
487 procedure CurStepChanged(CurStep:TSetupStep);
489 AppDir,FileName,Cmd,Msg:String;
490 BuiltIns,EnvPath,EnvHome,EnvSSH:TArrayOfString;
491 Count,i:Longint;
492 LinkCreated:Boolean;
493 FindRec:TFindRec;
494 RootKey:Integer;
495 begin
496 if CurStep<>ssPostInstall then begin
497 Exit;
498 end;
500 AppDir:=ExpandConstant('{app}');
503 Create the built-ins
506 // Load the built-ins from a text file.
507 FileName:=ExpandConstant('{app}\{#emit APP_BUILTINS}');
508 if LoadStringsFromFile(FileName,BuiltIns) then begin
509 Count:=GetArrayLength(BuiltIns)-1;
511 // Delete those scripts from "bin" which have been replaced by built-ins in "libexec\git-core".
512 for i:=0 to Count do begin
513 FileName:=AppDir+'\bin\'+ChangeFileExt(ExtractFileName(BuiltIns[i]),'');
514 if FileExists(FileName) and (not DeleteFile(FileName)) then begin
515 Log('Line {#emit __LINE__}: Unable to delete script "'+FileName+'", ignoring.');
516 end;
517 end;
519 // Create built-ins as aliases for git.exe.
520 for i:=0 to Count do begin
521 FileName:=AppDir+'\'+BuiltIns[i];
523 // Delete any existing built-in.
524 if FileExists(FileName) and (not DeleteFile(FileName)) then begin
525 Log('Line {#emit __LINE__}: Unable to delete existing built-in "'+FileName+'", skipping.');
526 continue;
527 end;
530 // This will throw an exception on pre-WinVista systems.
531 LinkCreated:=CreateSymbolicLink(FileName,AppDir+'\bin\git.exe',0);
532 except
533 LinkCreated:=False;
534 Log('Line {#emit __LINE__}: Creating symbolic link "'+FileName+'" failed, will try a hard link.');
535 end;
537 if not LinkCreated then begin
539 // This will throw an exception on pre-Win2k systems.
540 LinkCreated:=CreateHardLink(FileName,AppDir+'\bin\git.exe',0);
541 except
542 LinkCreated:=False;
543 Log('Line {#emit __LINE__}: Creating hardlink "'+FileName+'" failed, will try a copy.');
544 end;
545 end;
547 if not LinkCreated then begin
548 if not FileCopy(AppDir+'\bin\git.exe',FileName,False) then begin
549 Log('Line {#emit __LINE__}: Creating copy "'+FileName+'" failed, giving up.');
550 // This is not a critical error, Git could basically be used without the
551 // aliases for built-ins, so we continue.
552 end;
553 end;
554 end;
556 // Delete any duplicate files in case we are updating from a non-libexec to a libexec directory layout.
557 if FindFirst(AppDir+'\libexec\git-core\*',FindRec) then begin
558 repeat
559 if (FindRec.Attributes and FILE_ATTRIBUTE_DIRECTORY)=0 then begin
560 FileName:=AppDir+'\bin\'+FindRec.name;
561 if (Pos(FindRec.name,'git.exe')<>1) and FileExists(FileName) and (not DeleteFile(FileName)) then begin
562 Log('Line {#emit __LINE__}: Unable to delete dupe "'+FileName+'", ignoring.');
563 end;
564 end;
565 until not FindNext(FindRec);
566 FindClose(FindRec);
567 end;
568 end else begin
569 Msg:='Line {#emit __LINE__}: Unable to read file "{#emit APP_BUILTINS}".';
570 MsgBox(Msg,mbError,MB_OK);
571 Log(Msg);
572 // This is not a critical error, Git could basically be used without the
573 // aliases for built-ins, so we continue.
574 end;
577 Adapt core.autocrlf
580 if RdbCRLF[GC_LFOnly].checked then begin
581 Cmd:='core.autocrlf input';
582 end else if RdbCRLF[GC_CRLFAlways].checked then begin
583 Cmd:='core.autocrlf true';
584 end else begin
585 Cmd:='core.autocrlf false';
586 end;
587 if not Exec(AppDir + '\bin\git.exe', 'config -f gitconfig ' + Cmd,
588 AppDir + '\etc', SW_HIDE, ewWaitUntilTerminated, i) then begin
589 Msg:='Unable to configure the line ending conversion: ' + Cmd;
590 MsgBox(Msg,mbError,MB_OK);
591 Log(Msg);
592 end;
595 Modify the environment
597 This must happen no later than ssPostInstall to make
598 "ChangesEnvironment=yes" not happend before the change!
601 FileName:=AppDir+'\setup.ini';
603 // Delete GIT_SSH and SVN_SSH if a previous installation set them (this is required for the GS_OpenSSH case).
604 EnvSSH:=GetEnvStrings('GIT_SSH',IsAdminLoggedOn);
605 if (GetArrayLength(EnvSSH)=1) and
606 (CompareStr(RemoveQuotes(EnvSSH[0]),GetIniString('Environment','GIT_SSH','',FileName))=0) then begin
607 if not SetEnvStrings('GIT_SSH',IsAdminLoggedOn,True,[]) then begin
608 Msg:='Line {#emit __LINE__}: Unable to reset GIT_SSH prior to install.';
609 MsgBox(Msg,mbError,MB_OK);
610 Log(Msg);
611 // This is not a critical error, the user can probably fix it manually,
612 // so we continue.
613 end;
614 end;
616 EnvSSH:=GetEnvStrings('SVN_SSH',IsAdminLoggedOn);
617 if (GetArrayLength(EnvSSH)=1) and
618 (CompareStr(RemoveQuotes(EnvSSH[0]),GetIniString('Environment','SVN_SSH','',FileName))=0) then begin
619 if not SetEnvStrings('SVN_SSH',IsAdminLoggedOn,True,[]) then begin
620 Msg:='Line {#emit __LINE__}: Unable to reset SVN_SSH prior to install.';
621 MsgBox(Msg,mbError,MB_OK);
622 Log(Msg);
623 // This is not a critical error, the user can probably fix it manually,
624 // so we continue.
625 end;
626 end;
628 if (PuTTYPage<>NIL) and RdbSSH[GS_Plink].Checked then begin
629 SetArrayLength(EnvSSH,1);
630 EnvSSH[0]:=EdtPlink.Text;
632 // Set GIT_SSH as specified by the user.
633 if not SetEnvStrings('GIT_SSH',IsAdminLoggedOn,True,EnvSSH) then begin
634 Msg:='Line {#emit __LINE__}: Unable to set the GIT_SSH environment variable.';
635 MsgBox(Msg,mbError,MB_OK);
636 Log(Msg);
637 // This is not a critical error, the user can probably fix it manually,
638 // so we continue.
639 end;
641 // Mark that we have changed GIT_SSH by writing its value to a file.
642 if not SetIniString('Environment','GIT_SSH',EnvSSH[0],FileName) then begin
643 Msg:='Line {#emit __LINE__}: Unable to write to file "'+FileName+'".';
644 MsgBox(Msg,mbError,MB_OK);
645 Log(Msg);
646 // This is not a critical error, though uninstall / reinstall will probably not run cleanly,
647 // so we continue.
648 end;
650 // Set SVN_SSH as specified by the user, but with escaped backslashes and quotes.
651 StringChangeEx(EnvSSH[0],'\','\\',True);
652 EnvSSH[0]:=AddQuotes(EnvSSH[0]);
654 if not SetEnvStrings('SVN_SSH',IsAdminLoggedOn,True,EnvSSH) then begin
655 Msg:='Line {#emit __LINE__}: Unable to set the SVN_SSH environment variable.';
656 MsgBox(Msg,mbError,MB_OK);
657 Log(Msg);
658 // This is not a critical error, the user can probably fix it manually,
659 // so we continue.
660 end;
662 // Mark that we have changed SVN_SSH by writing its value to a file.
663 if not SetIniString('Environment','SVN_SSH',EnvSSH[0],FileName) then begin
664 Msg:='Line {#emit __LINE__}: Unable to write to file "'+FileName+'".';
665 MsgBox(Msg,mbError,MB_OK);
666 Log(Msg);
667 // This is not a critical error, though uninstall / reinstall will probably not run cleanly,
668 // so we continue.
669 end;
670 end;
672 // Get the current user's directories in PATH.
673 EnvPath:=GetEnvStrings('PATH',IsAdminLoggedOn);
675 // First, remove the installation directory from PATH in any case.
676 for i:=0 to GetArrayLength(EnvPath)-1 do begin
677 if Pos(AppDir+'\',EnvPath[i]+'\')=1 then begin
678 EnvPath[i]:='';
679 end;
680 end;
682 // Delete HOME if a previous installation modified it.
683 EnvHome:=GetEnvStrings('HOME',IsAdminLoggedOn);
684 if (GetArrayLength(EnvHome)=1) and
685 (CompareStr(RemoveQuotes(EnvHome[0]),GetIniString('Environment','HOME','',FileName))=0) then begin
686 if not SetEnvStrings('HOME',IsAdminLoggedOn,True,[]) then begin
687 Msg:='Line {#emit __LINE__}: Unable to reset HOME prior to install.';
688 MsgBox(Msg,mbError,MB_OK);
689 Log(Msg);
690 // This is not a critical error, the user can probably fix it manually,
691 // so we continue.
692 end;
693 end;
695 // Modify the PATH variable as requested by the user.
696 if RdbPath[GP_Cmd].Checked or RdbPath[GP_CmdTools].Checked then begin
697 i:=GetArrayLength(EnvPath);
698 SetArrayLength(EnvPath,i+1);
700 // List \cmd before \bin so \cmd has higher priority and programs in
701 // there will be called in favor of those in \bin.
702 EnvPath[i]:=ExpandConstant('{app}\cmd');
704 if RdbPath[GP_CmdTools].Checked then begin
705 SetArrayLength(EnvPath,i+2);
706 EnvPath[i+1]:=ExpandConstant('{app}\bin');
708 // Set HOME for the Windows Command Prompt, but only if it has not been set manually before.
709 EnvHome:=GetEnvStrings('HOME',IsAdminLoggedOn);
710 i:=GetArrayLength(EnvHome);
711 if (i=0) or ((i=1) and (Length(EnvHome[0])=0)) then begin
712 SetArrayLength(EnvHome,1);
713 EnvHome[0]:=ExpandConstant('{%HOMEDRIVE}{%HOMEPATH}');
714 if not SetEnvStrings('HOME',IsAdminLoggedOn,True,EnvHome) then begin
715 Msg:='Line {#emit __LINE__}: Unable to set the HOME environment variable.';
716 MsgBox(Msg,mbError,MB_OK);
717 Log(Msg);
718 // This is not a critical error, the user can probably fix it manually,
719 // so we continue.
720 end;
722 // Mark that we have changed HOME.
723 if not SetIniString('Environment','HOME',EnvHome[0],FileName) then begin
724 Msg:='Line {#emit __LINE__}: Unable to write to file "'+FileName+'".';
725 MsgBox(Msg,mbError,MB_OK);
726 Log(Msg);
727 // This is not a critical error, though uninstall / reinstall will probably not run cleanly,
728 // so we continue.
729 end;
730 end;
731 end;
732 end;
734 // Set the current user's PATH directories.
735 if not SetEnvStrings('PATH',IsAdminLoggedOn,True,EnvPath) then begin
736 Msg:='Line {#emit __LINE__}: Unable to set the PATH environment variable.';
737 MsgBox(Msg,mbError,MB_OK);
738 Log(Msg);
739 // This is not a critical error, the user can probably fix it manually,
740 // so we continue.
741 end;
744 Create the Windows Explorer shell extensions
747 if IsAdminLoggedOn then begin
748 RootKey:=HKEY_LOCAL_MACHINE;
749 end else begin
750 RootKey:=HKEY_CURRENT_USER;
751 end;
753 if IsComponentSelected('ext\shellhere') then begin
754 if (not RegWriteStringValue(RootKey,'SOFTWARE\Classes\Directory\shell\git_shell','','Git Ba&sh Here')) or
755 (not RegWriteStringValue(RootKey,'SOFTWARE\Classes\Directory\shell\git_shell\command','','wscript "'+AppDir+'\Git Bash.vbs" "%1"')) then begin
756 Msg:='Line {#emit __LINE__}: Unable to create "Git Bash Here" shell extension.';
757 MsgBox(Msg,mbError,MB_OK);
758 Log(Msg);
759 // This is not a critical error, the user can probably fix it manually,
760 // so we continue.
761 end;
762 end;
764 if IsComponentSelected('ext\guihere') then begin
765 if (not RegWriteStringValue(RootKey,'SOFTWARE\Classes\Directory\shell\git_gui','','Git &GUI Here')) or
766 (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
767 Msg:='Line {#emit __LINE__}: Unable to create "Git GUI Here" shell extension.';
768 MsgBox(Msg,mbError,MB_OK);
769 Log(Msg);
770 // This is not a critical error, the user can probably fix it manually,
771 // so we continue.
772 end;
773 end;
774 end;
776 procedure RegisterPreviousData(PreviousDataKey:Integer);
778 Data:String;
779 begin
780 // Git Path options.
781 Data:='';
782 if RdbPath[GP_BashOnly].Checked then begin
783 Data:='BashOnly';
784 end else if RdbPath[GP_Cmd].Checked then begin
785 Data:='Cmd';
786 end else if RdbPath[GP_CmdTools].Checked then begin
787 Data:='CmdTools';
788 end;
789 SetPreviousData(PreviousDataKey,'Path Option',Data);
791 // Git SSH options.
792 Data:='';
793 if (PuTTYPage=NIL) or RdbSSH[GS_OpenSSH].Checked then begin
794 Data:='OpenSSH';
795 end else if RdbSSH[GS_Plink].Checked then begin
796 Data:='Plink';
797 end;
798 SetPreviousData(PreviousDataKey,'SSH Option',Data);
800 // Line ending conversion options.
801 Data:='';
802 if RdbCRLF[GC_LFOnly].Checked then begin
803 Data:='LFOnly';
804 end else if RdbCRLF[GC_CRLFAlways].Checked then begin
805 Data:='CRLFAlways';
806 end else if RdbCRLF[GC_CRLFCommitAsIs].Checked then begin
807 Data:='CRLFCommitAsIs';
808 end;
809 SetPreviousData(PreviousDataKey,'CRLF Option',Data);
810 end;
813 Uninstaller code
816 function InitializeUninstall:Boolean;
818 FileName,NewName,Msg:String;
819 begin
820 FileName:=ExpandConstant('{app}\bin\ssh-agent.exe');
821 if FileExists(FileName) then begin
822 // Create a temporary copy of the file we try to delete.
823 NewName:=FileName+'.'+IntToStr(1000+Random(9000));
824 Result:=FileCopy(FileName,NewName,True) and DeleteFile(FileName);
826 if not Result then begin
827 Msg:='Line {#emit __LINE__}: Please stop all ssh-agent processes and run uninstall again.';
828 MsgBox(Msg,mbError,MB_OK);
829 Log(Msg);
831 // Clean-up the temporary copy (ignoring any errors).
832 DeleteFile(NewName);
833 end else begin
834 // Clean-up the temporary copy (ignoring any errors).
835 RenameFile(NewName,FileName);
836 end;
837 end else begin
838 Result:=True;
839 end;
840 end;
842 procedure CurUninstallStepChanged(CurUninstallStep:TUninstallStep);
844 AppDir,Command,Msg:String;
845 EnvPath,EnvHome,EnvSSH:TArrayOfString;
846 i:Longint;
847 RootKey:Integer;
848 begin
849 if CurUninstallStep<>usUninstall then begin
850 Exit;
851 end;
854 Modify the environment
856 This must happen no later than usUninstall to make
857 "ChangesEnvironment=yes" not happend before the change!
860 AppDir:=ExpandConstant('{app}');
861 Command:=AppDir+'\setup.ini';
863 // Delete the current user's GIT_SSH and SVN_SSH if we set it.
864 EnvSSH:=GetEnvStrings('GIT_SSH',IsAdminLoggedOn);
865 if (GetArrayLength(EnvSSH)=1) and
866 (CompareStr(RemoveQuotes(EnvSSH[0]),GetIniString('Environment','GIT_SSH','',Command))=0) then begin
867 if not SetEnvStrings('GIT_SSH',IsAdminLoggedOn,True,[]) then begin
868 Msg:='Line {#emit __LINE__}: Unable to revert any possible changes to GIT_SSH.';
869 MsgBox(Msg,mbError,MB_OK);
870 Log(Msg);
871 // This is not a critical error, the user can probably fix it manually,
872 // so we continue.
873 end;
874 end;
876 EnvSSH:=GetEnvStrings('SVN_SSH',IsAdminLoggedOn);
877 if (GetArrayLength(EnvSSH)=1) and
878 (CompareStr(RemoveQuotes(EnvSSH[0]),GetIniString('Environment','SVN_SSH','',Command))=0) then begin
879 if not SetEnvStrings('SVN_SSH',IsAdminLoggedOn,True,[]) then begin
880 Msg:='Line {#emit __LINE__}: Unable to revert any possible changes to SVN_SSH.';
881 MsgBox(Msg,mbError,MB_OK);
882 Log(Msg);
883 // This is not a critical error, the user can probably fix it manually,
884 // so we continue.
885 end;
886 end;
888 // Get the current user's directories in PATH.
889 EnvPath:=GetEnvStrings('PATH',IsAdminLoggedOn);
891 // Remove the installation directory from PATH in any case, even if it
892 // was not added by the installer.
893 for i:=0 to GetArrayLength(EnvPath)-1 do begin
894 if Pos(AppDir+'\',EnvPath[i]+'\')=1 then begin
895 EnvPath[i]:='';
896 end;
897 end;
899 // Reset the current user's directories in PATH.
900 if not SetEnvStrings('PATH',IsAdminLoggedOn,True,EnvPath) then begin
901 Msg:='Line {#emit __LINE__}: Unable to revert any possible changes to PATH.';
902 MsgBox(Msg,mbError,MB_OK);
903 Log(Msg);
904 // This is not a critical error, the user can probably fix it manually,
905 // so we continue.
906 end;
908 // Reset the current user's HOME if we modified it.
909 EnvHome:=GetEnvStrings('HOME',IsAdminLoggedOn);
910 if (GetArrayLength(EnvHome)=1) and
911 (CompareStr(RemoveQuotes(EnvHome[0]),GetIniString('Environment','HOME','',Command))=0) then begin
912 if not SetEnvStrings('HOME',IsAdminLoggedOn,True,[]) then begin
913 Msg:='Line {#emit __LINE__}: Unable to revert any possible changes to HOME.';
914 MsgBox(Msg,mbError,MB_OK);
915 Log(Msg);
916 // This is not a critical error, the user can probably fix it manually,
917 // so we continue.
918 end;
919 end;
921 if FileExists(Command) and (not DeleteFile(Command)) then begin
922 Msg:='Line {#emit __LINE__}: Unable to delete file "'+Command+'".';
923 MsgBox(Msg,mbError,MB_OK);
924 Log(Msg);
925 // This is not a critical error, the user can probably fix it manually,
926 // so we continue.
927 end;
930 Delete the Windows Explorer shell extensions
933 if IsAdminLoggedOn then begin
934 RootKey:=HKEY_LOCAL_MACHINE;
935 end else begin
936 RootKey:=HKEY_CURRENT_USER;
937 end;
939 Command:='';
940 RegQueryStringValue(RootKey,'SOFTWARE\Classes\Directory\shell\git_shell\command','',Command);
941 if Pos(AppDir,Command)>0 then begin
942 if not RegDeleteKeyIncludingSubkeys(RootKey,'SOFTWARE\Classes\Directory\shell\git_shell') then begin
943 Msg:='Line {#emit __LINE__}: Unable to remove "Git Bash Here" shell extension.';
944 MsgBox(Msg,mbError,MB_OK);
945 Log(Msg);
946 // This is not a critical error, the user can probably fix it manually,
947 // so we continue.
948 end;
949 end;
951 Command:='';
952 RegQueryStringValue(RootKey,'SOFTWARE\Classes\Directory\shell\git_gui\command','',Command);
953 if Pos(AppDir,Command)>0 then begin
954 if not RegDeleteKeyIncludingSubkeys(RootKey,'SOFTWARE\Classes\Directory\shell\git_gui') then begin
955 Msg:='Line {#emit __LINE__}: Unable to remove "Git GUI Here" shell extension.';
956 MsgBox(Msg,mbError,MB_OK);
957 Log(Msg);
958 // This is not a critical error, the user can probably fix it manually,
959 // so we continue.
960 end;
961 end;
962 end;