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