Updated msys-1.0.dll to MSYS-g02f8a49
[msysgit/kusma.git] / share / WinGit / install.iss
blob03326470ae2849991005df4573df6f89ecbaea0a
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 ; 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
39 Name: consolefont; Description: Use TrueType font (required for proper character encoding); GroupDescription: Console properties:; Flags: checkedonce
41 [Files]
42 Source: *; DestDir: {app}; Excludes: \*.bmp, gpl-2.0.rtf, \install.*, \tmp.*, \bin\*install*; Flags: recursesubdirs replacesameversion
43 Source: ReleaseNotes.rtf; DestDir: {app}; Flags: isreadme replacesameversion
45 [Icons]
46 Name: {group}\Git GUI; Filename: {app}\bin\wish.exe; Parameters: """{app}\libexec\git-core\git-gui"""; WorkingDir: %HOMEDRIVE%%HOMEPATH%; IconFilename: {app}\etc\git.ico
47 Name: {group}\Git Bash; Filename: {syswow64}\cmd.exe; Parameters: "/c """"{app}\bin\sh.exe"" --login -i"""; WorkingDir: %HOMEDRIVE%%HOMEPATH%; IconFilename: {app}\etc\git.ico
48 Name: {group}\Uninstall Git; Filename: {uninstallexe}
49 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
50 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
52 ; 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.
53 Name: {app}\Git Bash; Filename: {syswow64}\cmd.exe; Parameters: "/c """"{app}\bin\sh.exe"" --login -i"""; IconFilename: {app}\etc\git.ico; Tasks: shellextension
55 [Messages]
56 BeveledLabel={#emit APP_URL}
57 SetupAppTitle={#emit APP_NAME} Setup
58 SetupWindowTitle={#emit APP_NAME} Setup
60 [Registry]
61 Root: HKCU; Subkey: Console; ValueType: string; ValueName: FaceName; ValueData: Lucida Console; Tasks: consolefont
62 Root: HKCU; Subkey: Console; ValueType: dword; ValueName: FontFamily; ValueData: $00000036; Tasks: consolefont
63 Root: HKCU; Subkey: Console; ValueType: dword; ValueName: FontSize; ValueData: $000e0000; Tasks: consolefont
64 Root: HKCU; Subkey: Console; ValueType: dword; ValueName: FontWeight; ValueData: $00000190; Tasks: consolefont
66 Root: HKCU; Subkey: Console\Git Bash; ValueType: string; ValueName: FaceName; ValueData: Lucida Console; Flags: createvalueifdoesntexist
67 Root: HKCU; Subkey: Console\Git Bash; ValueType: dword; ValueName: FontFamily; ValueData: $00000036; Flags: createvalueifdoesntexist
68 Root: HKCU; Subkey: Console\Git Bash; ValueType: dword; ValueName: FontSize; ValueData: $000e0000; Flags: createvalueifdoesntexist
69 Root: HKCU; Subkey: Console\Git Bash; ValueType: dword; ValueName: FontWeight; ValueData: $00000190; Flags: createvalueifdoesntexist
71 [UninstallDelete]
72 Type: files; Name: {app}\bin\git-*.exe
73 Type: files; Name: {app}\libexec\git-core\git-*.exe
74 Type: dirifempty; Name: {app}\home\{username}
75 Type: dirifempty; Name: {app}\home
77 [Code]
79 Helper methods
82 function GetShellFolder(Param:string):string;
83 begin
84 if IsAdminLoggedOn then begin
85 Param:='{common'+Param+'}';
86 end else begin
87 Param:='{user'+Param+'}';
88 end;
89 Result:=ExpandConstant(Param);
90 end;
92 function CreateHardLink(lpFileName,lpExistingFileName:string;lpSecurityAttributes:Integer):Boolean;
93 external 'CreateHardLinkA@Kernel32.dll';
95 function GetEnvStrings(VarName:string;AllUsers:Boolean):TArrayOfString;
96 var
97 Path:string;
98 i:Longint;
99 p:Integer;
100 begin
101 Path:='';
103 // See http://www.jrsoftware.org/isfaq.php#env
104 if AllUsers then begin
105 // We ignore errors here. The resulting array of strings will be empty.
106 RegQueryStringValue(HKEY_LOCAL_MACHINE,'SYSTEM\CurrentControlSet\Control\Session Manager\Environment',VarName,Path);
107 end else begin
108 // We ignore errors here. The resulting array of strings will be empty.
109 RegQueryStringValue(HKEY_CURRENT_USER,'Environment',VarName,Path);
110 end;
112 // Make sure we have at least one semicolon.
113 Path:=Path+';';
115 // Split the directories in PATH into an array of strings.
116 i:=0;
117 SetArrayLength(Result,0);
119 p:=Pos(';',Path);
120 while p>0 do begin
121 SetArrayLength(Result,i+1);
122 if p>1 then begin
123 Result[i]:=Copy(Path,1,p-1);
124 i:=i+1;
125 end;
126 Path:=Copy(Path,p+1,Length(Path));
127 p:=Pos(';',Path);
128 end;
129 end;
131 function SetEnvStrings(VarName:string;AllUsers,DeleteIfEmpty:Boolean;DirStrings:TArrayOfString):Boolean;
133 Path,KeyName:string;
134 i:Longint;
135 begin
136 // Merge all non-empty directory strings into a PATH variable.
137 Path:='';
138 for i:=0 to GetArrayLength(DirStrings)-1 do begin
139 if Length(DirStrings[i])>0 then begin
140 if Length(Path)>0 then begin
141 Path:=Path+';'+DirStrings[i];
142 end else begin
143 Path:=DirStrings[i];
144 end;
145 end;
146 end;
148 // See http://www.jrsoftware.org/isfaq.php#env
149 if AllUsers then begin
150 KeyName:='SYSTEM\CurrentControlSet\Control\Session Manager\Environment';
151 if DeleteIfEmpty and (Length(Path)=0) then begin
152 Result:=(not RegValueExists(HKEY_LOCAL_MACHINE,KeyName,VarName)) or
153 RegDeleteValue(HKEY_LOCAL_MACHINE,KeyName,VarName);
154 end else begin
155 Result:=RegWriteStringValue(HKEY_LOCAL_MACHINE,KeyName,VarName,Path);
156 end;
157 end else begin
158 KeyName:='Environment';
159 if DeleteIfEmpty and (Length(Path)=0) then begin
160 Result:=(not RegValueExists(HKEY_CURRENT_USER,KeyName,VarName)) or
161 RegDeleteValue(HKEY_CURRENT_USER,KeyName,VarName);
162 end else begin
163 Result:=RegWriteStringValue(HKEY_CURRENT_USER,KeyName,VarName,Path);
164 end;
165 end;
166 end;
168 const
169 TortoiseSVNInstallKey='SOFTWARE\TortoiseSVN';
170 TortoiseCVSUninstallKey='SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\TortoiseCVS_is1';
171 PuTTYUninstallKey='SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\PuTTY_is1';
172 PuTTYPrivateKeyAssoc='PuTTYPrivateKey\shell\open\command';
174 function GetPuTTYLocation:string;
175 begin
176 // Prefer TortoisePlink over vanilla Plink for its GUI dialog to accept host keys.
177 if (IsWin64 and RegQueryStringValue(HKEY_LOCAL_MACHINE_64,TortoiseSVNInstallKey,'Directory',Result)) or
178 RegQueryStringValue(HKEY_LOCAL_MACHINE_32,TortoiseSVNInstallKey,'Directory',Result) then begin
179 // C:\Program Files\TortoiseSVN\
180 Result:=Result+'bin\';
181 // C:\Program Files\TortoiseSVN\bin\
182 end else begin
183 if not (IsWin64 and RegQueryStringValue(HKEY_LOCAL_MACHINE_64,TortoiseCVSUninstallKey,'InstallLocation',Result)) then begin
184 RegQueryStringValue(HKEY_LOCAL_MACHINE_32,TortoiseCVSUninstallKey,'InstallLocation',Result);
185 end;
186 // C:\Program Files\TortoiseCVS\
187 end;
189 if DirExists(Result) then begin
190 Result:=Result+'TortoisePlink.exe'
191 Exit;
192 end;
194 if not RegQueryStringValue(HKEY_LOCAL_MACHINE,PuTTYUninstallKey,'InstallLocation',Result) then begin
195 if RegQueryStringValue(HKEY_CLASSES_ROOT,PuTTYPrivateKeyAssoc,'',Result) then begin
196 // "C:\Program Files\PuTTY\pageant.exe" "%1"
197 Result:=RemoveQuotes(Result);
198 // C:\Program Files\PuTTY\pageant.exe" "%1
199 Result:=ExtractFilePath(Result);
200 end;
201 end;
202 // C:\Program Files\PuTTY\
204 if not DirExists(Result) then begin
205 // Guess something.
206 Result:=ExpandConstant('{pf}\PuTTY\');
207 end;
209 Result:=Result+'plink.exe'
210 end;
212 const
213 // Git Path options.
214 GP_BashOnly = 1;
215 GP_Cmd = 2;
216 GP_CmdTools = 3;
218 // Git SSH options.
219 GS_OpenSSH = 1;
220 GS_Plink = 2;
222 // Git line ending conversion options.
223 GC_LFOnly = 1;
224 GC_CRLFAlways = 2;
225 GC_CRLFCommitAsIs = 3;
228 // Wizard page and variables for the Path options.
229 PathPage:TWizardPage;
230 RdbPath:array[GP_BashOnly..GP_CmdTools] of TRadioButton;
232 // Wizard page and variables for the SSH options.
233 PuTTYPage:TWizardPage;
234 RdbSSH:array[GS_OpenSSH..GS_Plink] of TRadioButton;
235 EdtPlink:TEdit;
237 // Wizard page and variables for the line ending conversion options.
238 CRLFPage:TWizardPage;
239 RdbCRLF:array[GC_LFOnly..GC_CRLFCommitAsIs] of TRadioButton;
241 procedure BrowseForPuTTYFolder(Sender:TObject);
243 Path:string;
244 begin
245 Path:=ExtractFilePath(EdtPlink.Text);
246 BrowseForFolder('Please select the PuTTY folder:',Path,False);
247 if FileExists(Path+'\TortoisePlink.exe') then begin
248 EdtPlink.Text:=Path+'\TortoisePlink.exe';
249 RdbSSH[GS_Plink].Checked:=True;
250 end else if FileExists(Path+'\plink.exe') then begin
251 EdtPlink.Text:=Path+'\plink.exe';
252 RdbSSH[GS_Plink].Checked:=True;
253 end else begin
254 MsgBox('Please enter a valid path to "TortoisePlink.exe" or "plink.exe".',mbError,MB_OK);
255 end;
256 end;
259 Installer code
262 procedure InitializeWizard;
264 PrevPageID:Integer;
265 LblGitBash,LblGitCmd,LblGitCmdTools,LblGitCmdToolsWarn:TLabel;
266 LblOpenSSH,LblPlink:TLabel;
267 PuTTYSessions:TArrayOfString;
268 LblLFOnly,LblCRLFAlways,LblCRLFCommitAsIs:TLabel;
269 BtnPlink:TButton;
270 Data:String;
271 begin
272 PrevPageID:=wpSelectTasks;
275 * Create a custom page for modifying the environment.
278 PathPage:=CreateCustomPage(
279 PrevPageID,
280 'Adjusting your PATH environment',
281 'How would you like to use Git from the command line?'
283 PrevPageID:=PathPage.ID;
285 // 1st choice
286 RdbPath[GP_BashOnly]:=TRadioButton.Create(PathPage);
287 with RdbPath[GP_BashOnly] do begin
288 Parent:=PathPage.Surface;
289 Caption:='Use Git Bash only';
290 Left:=ScaleX(4);
291 Top:=ScaleY(8);
292 Width:=ScaleX(129);
293 Height:=ScaleY(17);
294 Font.Style:=[fsBold];
295 TabOrder:=0;
296 Checked:=True;
297 end;
298 LblGitBash:=TLabel.Create(PathPage);
299 with LblGitBash do begin
300 Parent:=PathPage.Surface;
301 Caption:=
302 'This is the most conservative choice if you are concerned about the stability' + #13 +
303 'of your system. Your PATH will not be modified.';
304 Left:=ScaleX(28);
305 Top:=ScaleY(32);
306 Width:=ScaleX(405);
307 Height:=ScaleY(26);
308 end;
310 // 2nd choice
311 RdbPath[GP_Cmd]:=TRadioButton.Create(PathPage);
312 with RdbPath[GP_Cmd] do begin
313 Parent:=PathPage.Surface;
314 Caption:='Run Git from the Windows Command Prompt';
315 Left:=ScaleX(4);
316 Top:=ScaleY(76);
317 Width:=ScaleX(281);
318 Height:=ScaleY(17);
319 Font.Style:=[fsBold];
320 TabOrder:=1;
321 end;
322 LblGitCmd:=TLabel.Create(PathPage);
323 with LblGitCmd do begin
324 Parent:=PathPage.Surface;
325 Caption:=
326 'This option is considered safe and no conflicts with other tools are known.' + #13 +
327 'Only Git will be added to your PATH. Use this option if you want to use Git' + #13 +
328 'from a Cygwin Prompt (make sure to not have Cygwin''s Git installed).';
329 Left:=ScaleX(28);
330 Top:=ScaleY(100);
331 Width:=ScaleX(405);
332 Height:=ScaleY(39);
333 end;
335 // 3rd choice
336 RdbPath[GP_CmdTools]:=TRadioButton.Create(PathPage);
337 with RdbPath[GP_CmdTools] do begin
338 Parent:=PathPage.Surface;
339 Caption:='Run Git and included Unix tools from the Windows Command Prompt';
340 Left:=ScaleX(4);
341 Top:=ScaleY(152);
342 Width:=ScaleX(405);
343 Height:=ScaleY(17);
344 Font.Style:=[fsBold];
345 TabOrder:=2;
346 end;
347 LblGitCmdTools:=TLabel.Create(PathPage);
348 with LblGitCmdTools do begin
349 Parent:=PathPage.Surface;
350 Caption:='Both Git and its accompanying Unix tools will be added to your PATH.';
351 Left:=ScaleX(28);
352 Top:=ScaleY(176);
353 Width:=ScaleX(405);
354 Height:=ScaleY(13);
355 end;
356 LblGitCmdToolsWarn:=TLabel.Create(PathPage);
357 with LblGitCmdToolsWarn do begin
358 Parent:=PathPage.Surface;
359 Caption:=
360 'Warning: This will override Windows tools like find.exe and' + #13 +
361 'sort.exe. Select this option only if you understand the implications.';
362 Left:=ScaleX(28);
363 Top:=ScaleY(192);
364 Width:=ScaleX(376);
365 Height:=ScaleY(26);
366 Font.Color:=255;
367 Font.Style:=[fsBold];
368 end;
370 // Restore the setting chosen during a previous install.
371 Data:=GetPreviousData('Path Option','BashOnly');
372 if Data='BashOnly' then begin
373 RdbPath[GP_BashOnly].Checked:=True;
374 end else if Data='Cmd' then begin
375 RdbPath[GP_Cmd].Checked:=True;
376 end else if Data='CmdTools' then begin
377 RdbPath[GP_CmdTools].Checked:=True;
378 end;
381 * Create a custom page for using (Tortoise)Plink instead of OpenSSH
382 * if at least one PuTTY session is found in the Registry.
385 if RegGetSubkeyNames(HKEY_CURRENT_USER,'Software\SimonTatham\PuTTY\Sessions',PuTTYSessions) and (GetArrayLength(PuTTYSessions)>0) then begin
386 PuTTYPage:=CreateCustomPage(
387 PrevPageID,
388 'Choosing the SSH executable',
389 'Which Secure Shell client program would you like Git to use?'
391 PrevPageID:=PuTTYPage.ID;
393 // 1st choice
394 RdbSSH[GS_OpenSSH]:=TRadioButton.Create(PuTTYPage);
395 with RdbSSH[GS_OpenSSH] do begin
396 Parent:=PuTTYPage.Surface;
397 Caption:='Use OpenSSH';
398 Left:=ScaleX(4);
399 Top:=ScaleY(8);
400 Width:=ScaleX(129);
401 Height:=ScaleY(17);
402 Font.Style:=[fsBold];
403 TabOrder:=0;
404 Checked:=True;
405 end;
406 LblOpenSSH:=TLabel.Create(PuTTYPage);
407 with LblOpenSSH do begin
408 Parent:=PuTTYPage.Surface;
409 Caption:=
410 'This uses ssh.exe that comes with Git. The GIT_SSH and SVN_SSH' + #13 +
411 'environment variables will not be modified.';
412 Left:=ScaleX(28);
413 Top:=ScaleY(32);
414 Width:=ScaleX(324);
415 Height:=ScaleY(26);
416 end;
418 // 2nd choice
419 RdbSSH[GS_Plink]:=TRadioButton.Create(PuTTYPage);
420 with RdbSSH[GS_Plink] do begin
421 Parent:=PuTTYPage.Surface;
422 Caption:='Use (Tortoise)Plink';
423 Left:=ScaleX(4);
424 Top:=ScaleY(76);
425 Width:=ScaleX(281);
426 Height:=ScaleY(17);
427 Font.Style:=[fsBold];
428 TabOrder:=1;
429 end;
430 LblPlink:=TLabel.Create(PuTTYPage);
431 with LblPlink do begin
432 Parent:=PuTTYPage.Surface;
433 Caption:=
434 'PuTTY sessions were found in your Registry. You may specify the path' + #13 +
435 'to an existing copy of (Tortoise)Plink.exe from the TortoiseSVN/CVS' + #13 +
436 'or PuTTY applications. The GIT_SSH and SVN_SSH environment' + #13 +
437 'variables will be adjusted to point to the following executable:';
438 Left:=ScaleX(28);
439 Top:=ScaleY(100);
440 Width:=ScaleX(340);
441 Height:=ScaleY(52);
442 end;
443 EdtPlink:=TEdit.Create(PuTTYPage);
444 with EdtPlink do begin
445 Parent:=PuTTYPage.Surface;
446 Text:=GetPuTTYLocation;
447 if not FileExists(Text) then begin
448 Text:='';
449 end;
450 Left:=ScaleX(28);
451 Top:=ScaleY(161);
452 Width:=ScaleX(316);
453 Height:=ScaleY(13);
454 end;
455 BtnPlink:=TButton.Create(PuTTYPage);
456 with BtnPlink do begin
457 Parent:=PuTTYPage.Surface;
458 Caption:='...';
459 OnClick:=@BrowseForPuTTYFolder;
460 Left:=ScaleX(348);
461 Top:=ScaleY(161);
462 Width:=ScaleX(21);
463 Height:=ScaleY(21);
464 end;
466 // Restore the setting chosen during a previous install.
467 Data:=GetPreviousData('SSH Option','OpenSSH');
468 if Data='OpenSSH' then begin
469 RdbSSH[GS_OpenSSH].Checked:=True;
470 end else if Data='Plink' then begin
471 RdbSSH[GS_Plink].Checked:=True;
472 end;
473 end else begin
474 PuTTYPage:=NIL;
475 end;
478 * Create a custom page for the core.autocrlf setting.
481 CRLFPage:=CreateCustomPage(
482 PrevPageID,
483 'Configuring the line ending conversions',
484 'How should Git treat line endings in text files?'
486 PrevPageID:=CRLFPage.ID;
488 // 1st choice
489 RdbCRLF[GC_CRLFAlways]:=TRadioButton.Create(CRLFPage);
490 with RdbCRLF[GC_CRLFAlways] do begin
491 Parent:=CRLFPage.Surface;
492 Caption:='Checkout Windows-style, commit Unix-style line endings';
493 Left:=ScaleX(4);
494 Top:=ScaleY(8);
495 Width:=ScaleX(340);
496 Height:=ScaleY(17);
497 Font.Style:=[fsBold];
498 TabOrder:=0;
499 Checked:=True;
500 end;
501 LblCRLFAlways:=TLabel.Create(CRLFPage);
502 with LblCRLFAlways do begin
503 Parent:=CRLFPage.Surface;
504 Caption:=
505 'Git will convert LF to CRLF when checking out text files. When committing' + #13 +
506 'text files, CRLF will be converted to LF. For cross-platform projects,' + #13 +
507 'this is the recommended setting on Windows ("core.autocrlf" is set to "true").';
508 Left:=ScaleX(28);
509 Top:=ScaleY(32);
510 Width:=ScaleX(372);
511 Height:=ScaleY(47);
512 end;
514 // 2nd choice
515 RdbCRLF[GC_LFOnly]:=TRadioButton.Create(CRLFPage);
516 with RdbCRLF[GC_LFOnly] do begin
517 Parent:=CRLFPage.Surface;
518 Caption:='Checkout as-is, commit Unix-style line endings';
519 Left:=ScaleX(4);
520 Top:=ScaleY(80);
521 Width:=ScaleX(340);
522 Height:=ScaleY(17);
523 Font.Style:=[fsBold];
524 TabOrder:=1;
525 Checked:=False;
526 end;
527 LblLFOnly:=TLabel.Create(CRLFPage);
528 with LblLFOnly do begin
529 Parent:=CRLFPage.Surface;
530 Caption:=
531 'Git will not perform any conversion when checking out text files. When' + #13 +
532 'committing text files, CRLF will be converted to LF. For cross-platform projects,' + #13 +
533 'this is the recommended setting on Unix ("core.autocrlf" is set to "input").';
534 Left:=ScaleX(28);
535 Top:=ScaleY(104);
536 Width:=ScaleX(372);
537 Height:=ScaleY(47);
538 end;
540 // 3rd choice
541 RdbCRLF[GC_CRLFCommitAsIs]:=TRadioButton.Create(CRLFPage);
542 with RdbCRLF[GC_CRLFCommitAsIs] do begin
543 Parent:=CRLFPage.Surface;
544 Caption:='Checkout as-is, commit as-is';
545 Left:=ScaleX(4);
546 Top:=ScaleY(152);
547 Width:=ScaleX(340);
548 Height:=ScaleY(17);
549 Font.Style:=[fsBold];
550 TabOrder:=2;
551 Checked:=False;
552 end;
553 LblCRLFCommitAsIs:=TLabel.Create(CRLFPage);
554 with LblCRLFCommitAsIs do begin
555 Parent:=CRLFPage.Surface;
556 Caption:=
557 'Git will not perform any conversions when checking out or committing' + #13 +
558 'text files. Choosing this option is not recommended for cross-platform' + #13 +
559 'projects ("core.autocrlf" is set to "false").';
560 Left:=ScaleX(28);
561 Top:=ScaleY(176);
562 Width:=ScaleX(372);
563 Height:=ScaleY(47);
564 end;
566 // Restore the setting chosen during a previous install.
567 Data:=GetPreviousData('CRLF Option','CRLFAlways');
568 if Data='LFOnly' then begin
569 RdbCRLF[GC_LFOnly].Checked:=True;
570 end else if Data='CRLFAlways' then begin
571 RdbCRLF[GC_CRLFAlways].Checked:=True;
572 end else if Data='CRLFCommitAsIs' then begin
573 RdbCRLF[GC_CRLFCommitAsIs].Checked:=True;
574 end;
575 end;
577 function NextButtonClick(CurPageID:Integer):Boolean;
578 begin
579 if (PuTTYPage=NIL) or (CurPageID<>PuTTYPage.ID) then begin
580 Result:=True;
581 Exit;
582 end;
584 Result:=RdbSSH[GS_OpenSSH].Checked or
585 (RdbSSH[GS_Plink].Checked and FileExists(EdtPlink.Text));
587 if not Result then begin
588 MsgBox('Please enter a valid path to (Tortoise)Plink.exe.',mbError,MB_OK);
589 end;
590 end;
592 procedure CurStepChanged(CurStep:TSetupStep);
594 AppDir,FileName,Cmd,Msg:string;
595 BuiltIns,EnvPath,EnvHome,EnvSSH:TArrayOfString;
596 Count,i:Longint;
597 IsNTFS:Boolean;
598 FindRec:TFindRec;
599 RootKey:Integer;
600 begin
601 if CurStep<>ssPostInstall then begin
602 Exit;
603 end;
605 AppDir:=ExpandConstant('{app}');
608 Create the built-ins
611 // Load the built-ins from a text file.
612 FileName:=ExpandConstant('{app}\{#emit APP_BUILTINS}');
613 if LoadStringsFromFile(FileName,BuiltIns) then begin
614 // Check if we are running on NTFS.
615 IsNTFS:=False;
616 if SetNTFSCompression(AppDir+'\bin\git.exe',true) then begin
617 IsNTFS:=SetNTFSCompression(AppDir+'\bin\git.exe',false);
618 end;
620 Count:=GetArrayLength(BuiltIns)-1;
622 // Delete those scripts from "bin" which have been replaced by built-ins in "libexec\git-core".
623 for i:=0 to Count do begin
624 FileName:=AppDir+'\bin\'+ChangeFileExt(ExtractFileName(BuiltIns[i]),'');
625 if FileExists(FileName) and (not DeleteFile(FileName)) then begin
626 Log('Line {#emit __LINE__}: Unable to delete script "'+FileName+'", ignoring.');
627 end;
628 end;
630 // Map the built-ins to git.exe.
631 if IsNTFS then begin
632 Log('Line {#emit __LINE__}: Partition seems to be NTFS, trying to create built-in aliases as hard links.');
634 for i:=0 to Count do begin
635 FileName:=AppDir+'\'+BuiltIns[i];
637 // On non-NTFS partitions, create hard links.
638 if (FileExists(FileName) and (not DeleteFile(FileName))) or
639 (not CreateHardLink(FileName,AppDir+'\bin\git.exe',0)) then begin
640 Log('Line {#emit __LINE__}: Unable to create hard link "'+FileName+'", will try to copy files.');
641 IsNTFS:=False;
642 Break;
643 end;
644 end;
646 Log('Line {#emit __LINE__}: Successfully created built-in aliases as hard links.');
647 end;
649 // The fallback is to copy the files.
650 if not IsNTFS then begin
651 Log('Line {#emit __LINE__}: Trying to create built-in aliases as file copies.');
653 for i:=0 to Count do begin
654 FileName:=AppDir+'\'+BuiltIns[i];
656 // On non-NTFS partitions, copy simply the files (overwriting existing ones).
657 if not FileCopy(AppDir+'\bin\git.exe',FileName,false) then begin
658 Msg:='Line {#emit __LINE__}: Unable to create file copy "'+FileName+'".';
659 MsgBox(Msg,mbError,MB_OK);
660 Log(Msg);
661 // This is not a critical error, Git could basically be used without the
662 // aliases for built-ins, so we continue.
663 end;
664 end;
666 Log('Line {#emit __LINE__}: Successfully created built-in aliases as file copies.');
667 end;
669 // Delete any duplicate files in case we are updating from a non-libexec to a libexec directory layout.
670 if FindFirst(AppDir+'\libexec\git-core\*',FindRec) then begin
671 repeat
672 if (FindRec.Attributes and FILE_ATTRIBUTE_DIRECTORY)=0 then begin
673 FileName:=AppDir+'\bin\'+FindRec.name;
674 if (Pos(FindRec.name,'git.exe')<>1) and FileExists(FileName) and (not DeleteFile(FileName)) then begin
675 Log('Line {#emit __LINE__}: Unable to delete dupe "'+FileName+'", ignoring.');
676 end;
677 end;
678 until not FindNext(FindRec);
679 FindClose(FindRec);
680 end;
681 end else begin
682 Msg:='Line {#emit __LINE__}: Unable to read file "{#emit APP_BUILTINS}".';
683 MsgBox(Msg,mbError,MB_OK);
684 Log(Msg);
685 // This is not a critical error, Git could basically be used without the
686 // aliases for built-ins, so we continue.
687 end;
690 Adapt core.autocrlf
693 if RdbCRLF[GC_LFOnly].checked then begin
694 Cmd:='core.autocrlf input';
695 end else if RdbCRLF[GC_CRLFAlways].checked then begin
696 Cmd:='core.autocrlf true';
697 end else begin
698 Cmd:='core.autocrlf false';
699 end;
700 if not Exec(AppDir + '\bin\git.exe', 'config -f gitconfig ' + Cmd,
701 AppDir + '\etc', SW_HIDE, ewWaitUntilTerminated, i) then begin
702 Msg:='Unable to configure the line ending conversion: ' + Cmd;
703 MsgBox(Msg,mbError,MB_OK);
704 Log(Msg);
705 end;
708 Modify the environment
710 This must happen no later than ssPostInstall to make
711 "ChangesEnvironment=yes" not happend before the change!
714 FileName:=AppDir+'\setup.ini';
716 // Delete GIT_SSH and SVN_SSH if a previous installation set them (this is required for the GS_OpenSSH case).
717 EnvSSH:=GetEnvStrings('GIT_SSH',IsAdminLoggedOn);
718 if (GetArrayLength(EnvSSH)=1) and
719 (CompareStr(EnvSSH[0],GetIniString('Environment','GIT_SSH','',FileName))=0) then begin
720 if not SetEnvStrings('GIT_SSH',IsAdminLoggedOn,True,[]) then begin
721 Msg:='Line {#emit __LINE__}: Unable to reset GIT_SSH prior to install.';
722 MsgBox(Msg,mbError,MB_OK);
723 Log(Msg);
724 // This is not a critical error, the user can probably fix it manually,
725 // so we continue.
726 end;
727 end;
729 EnvSSH:=GetEnvStrings('SVN_SSH',IsAdminLoggedOn);
730 if (GetArrayLength(EnvSSH)=1) and
731 (CompareStr(EnvSSH[0],GetIniString('Environment','SVN_SSH','',FileName))=0) then begin
732 if not SetEnvStrings('SVN_SSH',IsAdminLoggedOn,True,[]) then begin
733 Msg:='Line {#emit __LINE__}: Unable to reset SVN_SSH prior to install.';
734 MsgBox(Msg,mbError,MB_OK);
735 Log(Msg);
736 // This is not a critical error, the user can probably fix it manually,
737 // so we continue.
738 end;
739 end;
741 if (PuTTYPage<>NIL) and RdbSSH[GS_Plink].Checked then begin
742 SetArrayLength(EnvSSH,1);
743 EnvSSH[0]:=EdtPlink.Text;
745 // Set GIT_SSH as specified by the user.
746 if not SetEnvStrings('GIT_SSH',IsAdminLoggedOn,True,EnvSSH) then begin
747 Msg:='Line {#emit __LINE__}: Unable to set the GIT_SSH environment variable.';
748 MsgBox(Msg,mbError,MB_OK);
749 Log(Msg);
750 // This is not a critical error, the user can probably fix it manually,
751 // so we continue.
752 end;
754 // Mark that we have changed GIT_SSH by writing its value to a file.
755 if not SetIniString('Environment','GIT_SSH',EnvSSH[0],FileName) then begin
756 Msg:='Line {#emit __LINE__}: Unable to write to file "'+FileName+'".';
757 MsgBox(Msg,mbError,MB_OK);
758 Log(Msg);
759 // This is not a critical error, though uninstall / reinstall will probably not run cleanly,
760 // so we continue.
761 end;
763 // Set SVN_SSH as specified by the user, but with escaped backslashes and quotes.
764 StringChangeEx(EnvSSH[0],'\','\\',True);
765 EnvSSH[0]:=AddQuotes(EnvSSH[0]);
767 if not SetEnvStrings('SVN_SSH',IsAdminLoggedOn,True,EnvSSH) then begin
768 Msg:='Line {#emit __LINE__}: Unable to set the SVN_SSH environment variable.';
769 MsgBox(Msg,mbError,MB_OK);
770 Log(Msg);
771 // This is not a critical error, the user can probably fix it manually,
772 // so we continue.
773 end;
775 // Mark that we have changed SVN_SSH by writing its value to a file.
776 if not SetIniString('Environment','SVN_SSH',EnvSSH[0],FileName) then begin
777 Msg:='Line {#emit __LINE__}: Unable to write to file "'+FileName+'".';
778 MsgBox(Msg,mbError,MB_OK);
779 Log(Msg);
780 // This is not a critical error, though uninstall / reinstall will probably not run cleanly,
781 // so we continue.
782 end;
783 end;
785 // Get the current user's directories in PATH.
786 EnvPath:=GetEnvStrings('PATH',IsAdminLoggedOn);
788 // First, remove the installation directory from PATH in any case.
789 for i:=0 to GetArrayLength(EnvPath)-1 do begin
790 if Pos(AppDir+'\',EnvPath[i]+'\')=1 then begin
791 EnvPath[i]:='';
792 end;
793 end;
795 // Delete HOME if a previous installation modified it.
796 EnvHome:=GetEnvStrings('HOME',IsAdminLoggedOn);
797 if (GetArrayLength(EnvHome)=1) and
798 (CompareStr(EnvHome[0],GetIniString('Environment','HOME','',FileName))=0) then begin
799 if not SetEnvStrings('HOME',IsAdminLoggedOn,True,[]) then begin
800 Msg:='Line {#emit __LINE__}: Unable to reset HOME prior to install.';
801 MsgBox(Msg,mbError,MB_OK);
802 Log(Msg);
803 // This is not a critical error, the user can probably fix it manually,
804 // so we continue.
805 end;
806 end;
808 // Modify the PATH variable as requested by the user.
809 if RdbPath[GP_Cmd].Checked or RdbPath[GP_CmdTools].Checked then begin
810 i:=GetArrayLength(EnvPath);
811 SetArrayLength(EnvPath,i+1);
813 // List \cmd before \bin so \cmd has higher priority and programs in
814 // there will be called in favor of those in \bin.
815 EnvPath[i]:=ExpandConstant('{app}\cmd');
817 if RdbPath[GP_CmdTools].Checked then begin
818 SetArrayLength(EnvPath,i+2);
819 EnvPath[i+1]:=ExpandConstant('{app}\bin');
821 // Set HOME for the Windows Command Prompt, but only if it has not been set manually before.
822 EnvHome:=GetEnvStrings('HOME',IsAdminLoggedOn);
823 i:=GetArrayLength(EnvHome);
824 if (i=0) or ((i=1) and (Length(EnvHome[0])=0)) then begin
825 SetArrayLength(EnvHome,1);
826 EnvHome[0]:=ExpandConstant('{%HOMEDRIVE}{%HOMEPATH}');
827 if not SetEnvStrings('HOME',IsAdminLoggedOn,True,EnvHome) then begin
828 Msg:='Line {#emit __LINE__}: Unable to set the HOME environment variable.';
829 MsgBox(Msg,mbError,MB_OK);
830 Log(Msg);
831 // This is not a critical error, the user can probably fix it manually,
832 // so we continue.
833 end;
835 // Mark that we have changed HOME.
836 if not SetIniString('Environment','HOME',EnvHome[0],FileName) then begin
837 Msg:='Line {#emit __LINE__}: Unable to write to file "'+FileName+'".';
838 MsgBox(Msg,mbError,MB_OK);
839 Log(Msg);
840 // This is not a critical error, though uninstall / reinstall will probably not run cleanly,
841 // so we continue.
842 end;
843 end;
844 end;
845 end;
847 // Set the current user's PATH directories.
848 if not SetEnvStrings('PATH',IsAdminLoggedOn,True,EnvPath) then begin
849 Msg:='Line {#emit __LINE__}: Unable to set the PATH environment variable.';
850 MsgBox(Msg,mbError,MB_OK);
851 Log(Msg);
852 // This is not a critical error, the user can probably fix it manually,
853 // so we continue.
854 end;
857 Create the Windows Explorer shell extensions
860 if IsAdminLoggedOn then begin
861 RootKey:=HKEY_LOCAL_MACHINE;
862 end else begin
863 RootKey:=HKEY_CURRENT_USER;
864 end;
866 if IsTaskSelected('shellextension') then begin
867 if (not RegWriteStringValue(RootKey,'SOFTWARE\Classes\Directory\shell\git_shell','','Git Ba&sh Here')) or
868 (not RegWriteStringValue(RootKey,'SOFTWARE\Classes\Directory\shell\git_shell\command','','wscript "'+AppDir+'\Git Bash.vbs" "%1"')) then begin
869 Msg:='Line {#emit __LINE__}: Unable to create "Git Bash Here" shell extension.';
870 MsgBox(Msg,mbError,MB_OK);
871 Log(Msg);
872 // This is not a critical error, the user can probably fix it manually,
873 // so we continue.
874 end;
875 end;
877 if IsTaskSelected('guiextension') then begin
878 if (not RegWriteStringValue(RootKey,'SOFTWARE\Classes\Directory\shell\git_gui','','Git &GUI Here')) or
879 (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
880 Msg:='Line {#emit __LINE__}: Unable to create "Git GUI Here" shell extension.';
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;
887 end;
889 procedure RegisterPreviousData(PreviousDataKey:Integer);
891 Data:string;
892 begin
893 // Git Path options.
894 Data:='';
895 if RdbPath[GP_BashOnly].Checked then begin
896 Data:='BashOnly';
897 end else if RdbPath[GP_Cmd].Checked then begin
898 Data:='Cmd';
899 end else if RdbPath[GP_CmdTools].Checked then begin
900 Data:='CmdTools';
901 end;
902 SetPreviousData(PreviousDataKey,'Path Option',Data);
904 // Git SSH options.
905 Data:='';
906 if (PuTTYPage=NIL) or RdbSSH[GS_OpenSSH].Checked then begin
907 Data:='OpenSSH';
908 end else if RdbSSH[GS_Plink].Checked then begin
909 Data:='Plink';
910 end;
911 SetPreviousData(PreviousDataKey,'SSH Option',Data);
913 // Line ending conversion options.
914 Data:='';
915 if RdbCRLF[GC_LFOnly].Checked then begin
916 Data:='LFOnly';
917 end else if RdbCRLF[GC_CRLFAlways].Checked then begin
918 Data:='CRLFAlways';
919 end else if RdbCRLF[GC_CRLFCommitAsIs].Checked then begin
920 Data:='CRLFCommitAsIs';
921 end;
922 SetPreviousData(PreviousDataKey,'CRLF Option',Data);
923 end;
926 Uninstaller code
929 function InitializeUninstall:Boolean;
931 FileName,NewName,Msg:string;
932 begin
933 FileName:=ExpandConstant('{app}\bin\ssh-agent.exe');
934 if FileExists(FileName) then begin
935 // Create a temporary copy of the file we try to delete.
936 NewName:=FileName+'.'+IntToStr(1000+Random(9000));
937 Result:=FileCopy(FileName,NewName,True) and DeleteFile(FileName);
939 if not Result then begin
940 Msg:='Line {#emit __LINE__}: Please stop all ssh-agent processes and run uninstall again.';
941 MsgBox(Msg,mbError,MB_OK);
942 Log(Msg);
944 // Clean-up the temporary copy (ignoring any errors).
945 DeleteFile(NewName);
946 end else begin
947 // Clean-up the temporary copy (ignoring any errors).
948 RenameFile(NewName,FileName);
949 end;
950 end else begin
951 Result:=True;
952 end;
953 end;
955 procedure CurUninstallStepChanged(CurUninstallStep:TUninstallStep);
957 AppDir,Command,Msg:string;
958 EnvPath,EnvHome,EnvSSH:TArrayOfString;
959 i:Longint;
960 RootKey:Integer;
961 begin
962 if CurUninstallStep<>usUninstall then begin
963 Exit;
964 end;
967 Modify the environment
969 This must happen no later than usUninstall to make
970 "ChangesEnvironment=yes" not happend before the change!
973 AppDir:=ExpandConstant('{app}');
974 Command:=AppDir+'\setup.ini';
976 // Delete the current user's GIT_SSH and SVN_SSH if we set it.
977 EnvSSH:=GetEnvStrings('GIT_SSH',IsAdminLoggedOn);
978 if (GetArrayLength(EnvSSH)=1) and
979 (CompareStr(EnvSSH[0],GetIniString('Environment','GIT_SSH','',Command))=0) then begin
980 if not SetEnvStrings('GIT_SSH',IsAdminLoggedOn,True,[]) then begin
981 Msg:='Line {#emit __LINE__}: Unable to revert any possible changes to GIT_SSH.';
982 MsgBox(Msg,mbError,MB_OK);
983 Log(Msg);
984 // This is not a critical error, the user can probably fix it manually,
985 // so we continue.
986 end;
987 end;
989 EnvSSH:=GetEnvStrings('SVN_SSH',IsAdminLoggedOn);
990 if (GetArrayLength(EnvSSH)=1) and
991 (CompareStr(EnvSSH[0],GetIniString('Environment','SVN_SSH','',Command))=0) then begin
992 if not SetEnvStrings('SVN_SSH',IsAdminLoggedOn,True,[]) then begin
993 Msg:='Line {#emit __LINE__}: Unable to revert any possible changes to SVN_SSH.';
994 MsgBox(Msg,mbError,MB_OK);
995 Log(Msg);
996 // This is not a critical error, the user can probably fix it manually,
997 // so we continue.
998 end;
999 end;
1001 // Get the current user's directories in PATH.
1002 EnvPath:=GetEnvStrings('PATH',IsAdminLoggedOn);
1004 // Remove the installation directory from PATH in any case, even if it
1005 // was not added by the installer.
1006 for i:=0 to GetArrayLength(EnvPath)-1 do begin
1007 if Pos(AppDir+'\',EnvPath[i]+'\')=1 then begin
1008 EnvPath[i]:='';
1009 end;
1010 end;
1012 // Reset the current user's directories in PATH.
1013 if not SetEnvStrings('PATH',IsAdminLoggedOn,True,EnvPath) then begin
1014 Msg:='Line {#emit __LINE__}: Unable to revert any possible changes to PATH.';
1015 MsgBox(Msg,mbError,MB_OK);
1016 Log(Msg);
1017 // This is not a critical error, the user can probably fix it manually,
1018 // so we continue.
1019 end;
1021 // Reset the current user's HOME if we modified it.
1022 EnvHome:=GetEnvStrings('HOME',IsAdminLoggedOn);
1023 if (GetArrayLength(EnvHome)=1) and
1024 (CompareStr(EnvHome[0],GetIniString('Environment','HOME','',Command))=0) then begin
1025 if not SetEnvStrings('HOME',IsAdminLoggedOn,True,[]) then begin
1026 Msg:='Line {#emit __LINE__}: Unable to revert any possible changes to HOME.';
1027 MsgBox(Msg,mbError,MB_OK);
1028 Log(Msg);
1029 // This is not a critical error, the user can probably fix it manually,
1030 // so we continue.
1031 end;
1032 end;
1034 if FileExists(Command) and (not DeleteFile(Command)) then begin
1035 Msg:='Line {#emit __LINE__}: Unable to delete file "'+Command+'".';
1036 MsgBox(Msg,mbError,MB_OK);
1037 Log(Msg);
1038 // This is not a critical error, the user can probably fix it manually,
1039 // so we continue.
1040 end;
1043 Delete the Windows Explorer shell extensions
1046 if IsAdminLoggedOn then begin
1047 RootKey:=HKEY_LOCAL_MACHINE;
1048 end else begin
1049 RootKey:=HKEY_CURRENT_USER;
1050 end;
1052 Command:='';
1053 RegQueryStringValue(RootKey,'SOFTWARE\Classes\Directory\shell\git_shell\command','',Command);
1054 if Pos(AppDir,Command)>0 then begin
1055 if not RegDeleteKeyIncludingSubkeys(RootKey,'SOFTWARE\Classes\Directory\shell\git_shell') then begin
1056 Msg:='Line {#emit __LINE__}: Unable to remove "Git Bash Here" shell extension.';
1057 MsgBox(Msg,mbError,MB_OK);
1058 Log(Msg);
1059 // This is not a critical error, the user can probably fix it manually,
1060 // so we continue.
1061 end;
1062 end;
1064 Command:='';
1065 RegQueryStringValue(RootKey,'SOFTWARE\Classes\Directory\shell\git_gui\command','',Command);
1066 if Pos(AppDir,Command)>0 then begin
1067 if not RegDeleteKeyIncludingSubkeys(RootKey,'SOFTWARE\Classes\Directory\shell\git_gui') then begin
1068 Msg:='Line {#emit __LINE__}: Unable to remove "Git GUI Here" shell extension.';
1069 MsgBox(Msg,mbError,MB_OK);
1070 Log(Msg);
1071 // This is not a critical error, the user can probably fix it manually,
1072 // so we continue.
1073 end;
1074 end;
1075 end;