installer: add comments to explain AfterInstall and PreUninstall trick
[msysgit/kirr.git] / share / WinGit / install.iss
blob339ab9adde924ece5a22510c1f51360fd5d292ce
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: assoc; Description: Associate .git* configuration files with the default text editor; Types: custom
49 Name: consolefont; Description: Use a TrueType font in the console (required for proper character encoding); Types: custom
51 [Files]
52 Source: *; DestDir: {app}; Excludes: \*.bmp, gpl-2.0.rtf, \*.iss, \tmp.*, \bin\*install*; Flags: recursesubdirs replacesameversion
53 Source: ReleaseNotes.rtf; DestDir: {app}; Flags: isreadme replacesameversion
55 [Icons]
56 Name: {group}\Git GUI; Filename: {app}\bin\wish.exe; Parameters: """{app}\libexec\git-core\git-gui"""; WorkingDir: %HOMEDRIVE%%HOMEPATH%; IconFilename: {app}\etc\git.ico
57 Name: {group}\Git Bash; Filename: {syswow64}\cmd.exe; Parameters: "/c """"{app}\bin\sh.exe"" --login -i"""; WorkingDir: %HOMEDRIVE%%HOMEPATH%; IconFilename: {app}\etc\git.ico
58 Name: {group}\Uninstall Git; Filename: {uninstallexe}
59 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
60 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
62 ; 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.
63 Name: {app}\Git Bash; Filename: {syswow64}\cmd.exe; Parameters: "/c """"{app}\bin\sh.exe"" --login -i"""; IconFilename: {app}\etc\git.ico
65 [Messages]
66 BeveledLabel={#emit APP_URL}
67 SetupAppTitle={#emit APP_NAME} Setup
68 SetupWindowTitle={#emit APP_NAME} Setup
70 [Registry]
71 ; There is no "Console" key in HKLM.
72 Root: HKCU; Subkey: Console; ValueType: string; ValueName: FaceName; ValueData: Lucida Console; Components: consolefont
73 Root: HKCU; Subkey: Console; ValueType: dword; ValueName: FontFamily; ValueData: $00000036; Components: consolefont
74 Root: HKCU; Subkey: Console; ValueType: dword; ValueName: FontSize; ValueData: $000e0000; Components: consolefont
75 Root: HKCU; Subkey: Console; ValueType: dword; ValueName: FontWeight; ValueData: $00000190; Components: consolefont
77 Root: HKCU; Subkey: Console\Git Bash; ValueType: string; ValueName: FaceName; ValueData: Lucida Console; Flags: createvalueifdoesntexist
78 Root: HKCU; Subkey: Console\Git Bash; ValueType: dword; ValueName: FontFamily; ValueData: $00000036; Flags: createvalueifdoesntexist
79 Root: HKCU; Subkey: Console\Git Bash; ValueType: dword; ValueName: FontSize; ValueData: $000e0000; Flags: createvalueifdoesntexist
80 Root: HKCU; Subkey: Console\Git Bash; ValueType: dword; ValueName: FontWeight; ValueData: $00000190; Flags: createvalueifdoesntexist
82 ; File associations for configuration files that may be contained in a repository (so this does not include ".gitconfig").
83 Root: HKLM; Subkey: Software\Classes\.gitattributes; ValueType: string; ValueData: txtfile; Flags: createvalueifdoesntexist; Check: IsAdminLoggedOn; Components: assoc
84 Root: HKLM; Subkey: Software\Classes\.gitattributes; ValueType: string; ValueName: Content Type; ValueData: text/plain; Flags: createvalueifdoesntexist; Check: IsAdminLoggedOn; Components: assoc
85 Root: HKLM; Subkey: Software\Classes\.gitattributes; ValueType: string; ValueName: PerceivedType; ValueData: text; Flags: createvalueifdoesntexist; Check: IsAdminLoggedOn; Components: assoc
86 Root: HKCU; Subkey: Software\Classes\.gitattributes; ValueType: string; ValueData: txtfile; Flags: createvalueifdoesntexist; Check: not IsAdminLoggedOn; Components: assoc
87 Root: HKCU; Subkey: Software\Classes\.gitattributes; ValueType: string; ValueName: Content Type; ValueData: text/plain; Flags: createvalueifdoesntexist; Check: not IsAdminLoggedOn; Components: assoc
88 Root: HKCU; Subkey: Software\Classes\.gitattributes; ValueType: string; ValueName: PerceivedType; ValueData: text; Flags: createvalueifdoesntexist; Check: not IsAdminLoggedOn; Components: assoc
90 Root: HKLM; Subkey: Software\Classes\.gitignore; ValueType: string; ValueData: txtfile; Flags: createvalueifdoesntexist; Check: IsAdminLoggedOn; Components: assoc
91 Root: HKLM; Subkey: Software\Classes\.gitignore; ValueType: string; ValueName: Content Type; ValueData: text/plain; Flags: createvalueifdoesntexist; Check: IsAdminLoggedOn; Components: assoc
92 Root: HKLM; Subkey: Software\Classes\.gitignore; ValueType: string; ValueName: PerceivedType; ValueData: text; Flags: createvalueifdoesntexist; Check: IsAdminLoggedOn; Components: assoc
93 Root: HKCU; Subkey: Software\Classes\.gitignore; ValueType: string; ValueData: txtfile; Flags: createvalueifdoesntexist; Check: not IsAdminLoggedOn; Components: assoc
94 Root: HKCU; Subkey: Software\Classes\.gitignore; ValueType: string; ValueName: Content Type; ValueData: text/plain; Flags: createvalueifdoesntexist; Check: not IsAdminLoggedOn; Components: assoc
95 Root: HKCU; Subkey: Software\Classes\.gitignore; ValueType: string; ValueName: PerceivedType; ValueData: text; Flags: createvalueifdoesntexist; Check: not IsAdminLoggedOn; Components: assoc
97 Root: HKLM; Subkey: Software\Classes\.gitmodules; ValueType: string; ValueData: txtfile; Flags: createvalueifdoesntexist; Check: IsAdminLoggedOn; Components: assoc
98 Root: HKLM; Subkey: Software\Classes\.gitmodules; ValueType: string; ValueName: Content Type; ValueData: text/plain; Flags: createvalueifdoesntexist; Check: IsAdminLoggedOn; Components: assoc
99 Root: HKLM; Subkey: Software\Classes\.gitmodules; ValueType: string; ValueName: PerceivedType; ValueData: text; Flags: createvalueifdoesntexist; Check: IsAdminLoggedOn; Components: assoc
100 Root: HKCU; Subkey: Software\Classes\.gitmodules; ValueType: string; ValueData: txtfile; Flags: createvalueifdoesntexist; Check: not IsAdminLoggedOn; Components: assoc
101 Root: HKCU; Subkey: Software\Classes\.gitmodules; ValueType: string; ValueName: Content Type; ValueData: text/plain; Flags: createvalueifdoesntexist; Check: not IsAdminLoggedOn; Components: assoc
102 Root: HKCU; Subkey: Software\Classes\.gitmodules; ValueType: string; ValueName: PerceivedType; ValueData: text; Flags: createvalueifdoesntexist; Check: not IsAdminLoggedOn; Components: assoc
104 [UninstallDelete]
105 ; Delete the built-ins.
106 Type: files; Name: {app}\bin\git-*.exe
107 Type: files; Name: {app}\libexec\git-core\git-*.exe
108 Type: files; Name: {app}\libexec\git-core\git.exe
110 ; Delete a home directory inside the msysGit directory.
111 Type: dirifempty; Name: {app}\home\{username}
112 Type: dirifempty; Name: {app}\home
114 [Code]
115 #include "helpers.inc.iss"
116 #include "putty.inc.iss"
118 function CreateHardLink(lpFileName,lpExistingFileName:String;lpSecurityAttributes:Integer):Boolean;
119 #ifdef UNICODE
120 external 'CreateHardLinkW@Kernel32.dll stdcall delayload setuponly';
121 #else
122 external 'CreateHardLinkA@Kernel32.dll stdcall delayload setuponly';
123 #endif
125 function CreateSymbolicLink(lpSymlinkFileName,lpTargetFileName:String;dwFlags:DWORD):Boolean;
126 #ifdef UNICODE
127 external 'CreateSymbolicLinkW@Kernel32.dll stdcall delayload setuponly';
128 #else
129 external 'CreateSymbolicLinkA@Kernel32.dll stdcall delayload setuponly';
130 #endif
132 const
133 // Git Path options.
134 GP_BashOnly = 1;
135 GP_Cmd = 2;
136 GP_CmdTools = 3;
138 // Git SSH options.
139 GS_OpenSSH = 1;
140 GS_Plink = 2;
142 // Git line ending conversion options.
143 GC_LFOnly = 1;
144 GC_CRLFAlways = 2;
145 GC_CRLFCommitAsIs = 3;
148 // Wizard page and variables for the Path options.
149 PathPage:TWizardPage;
150 RdbPath:array[GP_BashOnly..GP_CmdTools] of TRadioButton;
152 // Wizard page and variables for the SSH options.
153 PuTTYPage:TWizardPage;
154 RdbSSH:array[GS_OpenSSH..GS_Plink] of TRadioButton;
155 EdtPlink:TEdit;
157 // Wizard page and variables for the line ending conversion options.
158 CRLFPage:TWizardPage;
159 RdbCRLF:array[GC_LFOnly..GC_CRLFCommitAsIs] of TRadioButton;
161 procedure BrowseForPuTTYFolder(Sender:TObject);
163 Path:String;
164 begin
165 Path:=ExtractFilePath(EdtPlink.Text);
166 BrowseForFolder('Please select the PuTTY folder:',Path,False);
167 if FileExists(Path+'\TortoisePlink.exe') then begin
168 EdtPlink.Text:=Path+'\TortoisePlink.exe';
169 RdbSSH[GS_Plink].Checked:=True;
170 end else if FileExists(Path+'\plink.exe') then begin
171 EdtPlink.Text:=Path+'\plink.exe';
172 RdbSSH[GS_Plink].Checked:=True;
173 end else begin
174 MsgBox('Please enter a valid path to "TortoisePlink.exe" or "plink.exe".',mbError,MB_OK);
175 end;
176 end;
179 Installer code
182 procedure InitializeWizard;
184 PrevPageID:Integer;
185 LblGitBash,LblGitCmd,LblGitCmdTools,LblGitCmdToolsWarn:TLabel;
186 LblOpenSSH,LblPlink:TLabel;
187 PuTTYSessions:TArrayOfString;
188 LblLFOnly,LblCRLFAlways,LblCRLFCommitAsIs:TLabel;
189 BtnPlink:TButton;
190 Data:String;
191 begin
192 PrevPageID:=wpSelectProgramGroup;
195 * Create a custom page for modifying the environment.
198 PathPage:=CreateCustomPage(
199 PrevPageID,
200 'Adjusting your PATH environment',
201 'How would you like to use Git from the command line?'
203 PrevPageID:=PathPage.ID;
205 // 1st choice
206 RdbPath[GP_BashOnly]:=TRadioButton.Create(PathPage);
207 with RdbPath[GP_BashOnly] do begin
208 Parent:=PathPage.Surface;
209 Caption:='Use Git Bash only';
210 Left:=ScaleX(4);
211 Top:=ScaleY(8);
212 Width:=ScaleX(129);
213 Height:=ScaleY(17);
214 Font.Style:=[fsBold];
215 TabOrder:=0;
216 Checked:=True;
217 end;
218 LblGitBash:=TLabel.Create(PathPage);
219 with LblGitBash do begin
220 Parent:=PathPage.Surface;
221 Caption:=
222 'This is the most conservative choice if you are concerned about the stability' + #13 +
223 'of your system. Your PATH will not be modified.';
224 Left:=ScaleX(28);
225 Top:=ScaleY(32);
226 Width:=ScaleX(405);
227 Height:=ScaleY(26);
228 end;
230 // 2nd choice
231 RdbPath[GP_Cmd]:=TRadioButton.Create(PathPage);
232 with RdbPath[GP_Cmd] do begin
233 Parent:=PathPage.Surface;
234 Caption:='Run Git from the Windows Command Prompt';
235 Left:=ScaleX(4);
236 Top:=ScaleY(76);
237 Width:=ScaleX(281);
238 Height:=ScaleY(17);
239 Font.Style:=[fsBold];
240 TabOrder:=1;
241 end;
242 LblGitCmd:=TLabel.Create(PathPage);
243 with LblGitCmd do begin
244 Parent:=PathPage.Surface;
245 Caption:=
246 'This option is considered safe and no conflicts with other tools are known.' + #13 +
247 'Only Git will be added to your PATH. Use this option if you want to use Git' + #13 +
248 'from a Cygwin Prompt (make sure to not have Cygwin''s Git installed).';
249 Left:=ScaleX(28);
250 Top:=ScaleY(100);
251 Width:=ScaleX(405);
252 Height:=ScaleY(39);
253 end;
255 // 3rd choice
256 RdbPath[GP_CmdTools]:=TRadioButton.Create(PathPage);
257 with RdbPath[GP_CmdTools] do begin
258 Parent:=PathPage.Surface;
259 Caption:='Run Git and included Unix tools from the Windows Command Prompt';
260 Left:=ScaleX(4);
261 Top:=ScaleY(152);
262 Width:=ScaleX(405);
263 Height:=ScaleY(17);
264 Font.Style:=[fsBold];
265 TabOrder:=2;
266 end;
267 LblGitCmdTools:=TLabel.Create(PathPage);
268 with LblGitCmdTools do begin
269 Parent:=PathPage.Surface;
270 Caption:='Both Git and its accompanying Unix tools will be added to your PATH.';
271 Left:=ScaleX(28);
272 Top:=ScaleY(176);
273 Width:=ScaleX(405);
274 Height:=ScaleY(13);
275 end;
276 LblGitCmdToolsWarn:=TLabel.Create(PathPage);
277 with LblGitCmdToolsWarn do begin
278 Parent:=PathPage.Surface;
279 Caption:=
280 'Warning: This will override Windows tools like find.exe and' + #13 +
281 'sort.exe. Select this option only if you understand the implications.';
282 Left:=ScaleX(28);
283 Top:=ScaleY(192);
284 Width:=ScaleX(376);
285 Height:=ScaleY(26);
286 Font.Color:=255;
287 Font.Style:=[fsBold];
288 end;
290 // Restore the setting chosen during a previous install.
291 Data:=GetPreviousData('Path Option','BashOnly');
292 if Data='BashOnly' then begin
293 RdbPath[GP_BashOnly].Checked:=True;
294 end else if Data='Cmd' then begin
295 RdbPath[GP_Cmd].Checked:=True;
296 end else if Data='CmdTools' then begin
297 RdbPath[GP_CmdTools].Checked:=True;
298 end;
301 * Create a custom page for using (Tortoise)Plink instead of OpenSSH
302 * if at least one PuTTY session is found in the Registry.
305 if RegGetSubkeyNames(HKEY_CURRENT_USER,'Software\SimonTatham\PuTTY\Sessions',PuTTYSessions) and (GetArrayLength(PuTTYSessions)>0) then begin
306 PuTTYPage:=CreateCustomPage(
307 PrevPageID,
308 'Choosing the SSH executable',
309 'Which Secure Shell client program would you like Git to use?'
311 PrevPageID:=PuTTYPage.ID;
313 // 1st choice
314 RdbSSH[GS_OpenSSH]:=TRadioButton.Create(PuTTYPage);
315 with RdbSSH[GS_OpenSSH] do begin
316 Parent:=PuTTYPage.Surface;
317 Caption:='Use OpenSSH';
318 Left:=ScaleX(4);
319 Top:=ScaleY(8);
320 Width:=ScaleX(129);
321 Height:=ScaleY(17);
322 Font.Style:=[fsBold];
323 TabOrder:=0;
324 Checked:=True;
325 end;
326 LblOpenSSH:=TLabel.Create(PuTTYPage);
327 with LblOpenSSH do begin
328 Parent:=PuTTYPage.Surface;
329 Caption:=
330 'This uses ssh.exe that comes with Git. The GIT_SSH and SVN_SSH' + #13 +
331 'environment variables will not be modified.';
332 Left:=ScaleX(28);
333 Top:=ScaleY(32);
334 Width:=ScaleX(324);
335 Height:=ScaleY(26);
336 end;
338 // 2nd choice
339 RdbSSH[GS_Plink]:=TRadioButton.Create(PuTTYPage);
340 with RdbSSH[GS_Plink] do begin
341 Parent:=PuTTYPage.Surface;
342 Caption:='Use (Tortoise)Plink';
343 Left:=ScaleX(4);
344 Top:=ScaleY(76);
345 Width:=ScaleX(281);
346 Height:=ScaleY(17);
347 Font.Style:=[fsBold];
348 TabOrder:=1;
349 end;
350 LblPlink:=TLabel.Create(PuTTYPage);
351 with LblPlink do begin
352 Parent:=PuTTYPage.Surface;
353 Caption:=
354 'PuTTY sessions were found in your Registry. You may specify the path' + #13 +
355 'to an existing copy of (Tortoise)Plink.exe from the TortoiseSVN/CVS' + #13 +
356 'or PuTTY applications. The GIT_SSH and SVN_SSH environment' + #13 +
357 'variables will be adjusted to point to the following executable:';
358 Left:=ScaleX(28);
359 Top:=ScaleY(100);
360 Width:=ScaleX(340);
361 Height:=ScaleY(52);
362 end;
363 EdtPlink:=TEdit.Create(PuTTYPage);
364 with EdtPlink do begin
365 Parent:=PuTTYPage.Surface;
366 Text:=GetPuTTYLocation;
367 if not FileExists(Text) then begin
368 Text:='';
369 end;
370 Left:=ScaleX(28);
371 Top:=ScaleY(161);
372 Width:=ScaleX(316);
373 Height:=ScaleY(13);
374 end;
375 BtnPlink:=TButton.Create(PuTTYPage);
376 with BtnPlink do begin
377 Parent:=PuTTYPage.Surface;
378 Caption:='...';
379 OnClick:=@BrowseForPuTTYFolder;
380 Left:=ScaleX(348);
381 Top:=ScaleY(161);
382 Width:=ScaleX(21);
383 Height:=ScaleY(21);
384 end;
386 // Restore the setting chosen during a previous install.
387 Data:=GetPreviousData('SSH Option','OpenSSH');
388 if Data='OpenSSH' then begin
389 RdbSSH[GS_OpenSSH].Checked:=True;
390 end else if Data='Plink' then begin
391 RdbSSH[GS_Plink].Checked:=True;
392 end;
393 end else begin
394 PuTTYPage:=NIL;
395 end;
398 * Create a custom page for the core.autocrlf setting.
401 CRLFPage:=CreateCustomPage(
402 PrevPageID,
403 'Configuring the line ending conversions',
404 'How should Git treat line endings in text files?'
406 PrevPageID:=CRLFPage.ID;
408 // 1st choice
409 RdbCRLF[GC_CRLFAlways]:=TRadioButton.Create(CRLFPage);
410 with RdbCRLF[GC_CRLFAlways] do begin
411 Parent:=CRLFPage.Surface;
412 Caption:='Checkout Windows-style, commit Unix-style line endings';
413 Left:=ScaleX(4);
414 Top:=ScaleY(8);
415 Width:=ScaleX(340);
416 Height:=ScaleY(17);
417 Font.Style:=[fsBold];
418 TabOrder:=0;
419 Checked:=True;
420 end;
421 LblCRLFAlways:=TLabel.Create(CRLFPage);
422 with LblCRLFAlways do begin
423 Parent:=CRLFPage.Surface;
424 Caption:=
425 'Git will convert LF to CRLF when checking out text files. When committing' + #13 +
426 'text files, CRLF will be converted to LF. For cross-platform projects,' + #13 +
427 'this is the recommended setting on Windows ("core.autocrlf" is set to "true").';
428 Left:=ScaleX(28);
429 Top:=ScaleY(32);
430 Width:=ScaleX(372);
431 Height:=ScaleY(47);
432 end;
434 // 2nd choice
435 RdbCRLF[GC_LFOnly]:=TRadioButton.Create(CRLFPage);
436 with RdbCRLF[GC_LFOnly] do begin
437 Parent:=CRLFPage.Surface;
438 Caption:='Checkout as-is, commit Unix-style line endings';
439 Left:=ScaleX(4);
440 Top:=ScaleY(80);
441 Width:=ScaleX(340);
442 Height:=ScaleY(17);
443 Font.Style:=[fsBold];
444 TabOrder:=1;
445 Checked:=False;
446 end;
447 LblLFOnly:=TLabel.Create(CRLFPage);
448 with LblLFOnly do begin
449 Parent:=CRLFPage.Surface;
450 Caption:=
451 'Git will not perform any conversion when checking out text files. When' + #13 +
452 'committing text files, CRLF will be converted to LF. For cross-platform projects,' + #13 +
453 'this is the recommended setting on Unix ("core.autocrlf" is set to "input").';
454 Left:=ScaleX(28);
455 Top:=ScaleY(104);
456 Width:=ScaleX(372);
457 Height:=ScaleY(47);
458 end;
460 // 3rd choice
461 RdbCRLF[GC_CRLFCommitAsIs]:=TRadioButton.Create(CRLFPage);
462 with RdbCRLF[GC_CRLFCommitAsIs] do begin
463 Parent:=CRLFPage.Surface;
464 Caption:='Checkout as-is, commit as-is';
465 Left:=ScaleX(4);
466 Top:=ScaleY(152);
467 Width:=ScaleX(340);
468 Height:=ScaleY(17);
469 Font.Style:=[fsBold];
470 TabOrder:=2;
471 Checked:=False;
472 end;
473 LblCRLFCommitAsIs:=TLabel.Create(CRLFPage);
474 with LblCRLFCommitAsIs do begin
475 Parent:=CRLFPage.Surface;
476 Caption:=
477 'Git will not perform any conversions when checking out or committing' + #13 +
478 'text files. Choosing this option is not recommended for cross-platform' + #13 +
479 'projects ("core.autocrlf" is set to "false").';
480 Left:=ScaleX(28);
481 Top:=ScaleY(176);
482 Width:=ScaleX(372);
483 Height:=ScaleY(47);
484 end;
486 // Restore the setting chosen during a previous install.
487 Data:=GetPreviousData('CRLF Option','CRLFAlways');
488 if Data='LFOnly' then begin
489 RdbCRLF[GC_LFOnly].Checked:=True;
490 end else if Data='CRLFAlways' then begin
491 RdbCRLF[GC_CRLFAlways].Checked:=True;
492 end else if Data='CRLFCommitAsIs' then begin
493 RdbCRLF[GC_CRLFCommitAsIs].Checked:=True;
494 end;
495 end;
497 function NextButtonClick(CurPageID:Integer):Boolean;
498 begin
499 if (PuTTYPage=NIL) or (CurPageID<>PuTTYPage.ID) then begin
500 Result:=True;
501 Exit;
502 end;
504 Result:=RdbSSH[GS_OpenSSH].Checked or
505 (RdbSSH[GS_Plink].Checked and FileExists(EdtPlink.Text));
507 if not Result then begin
508 MsgBox('Please enter a valid path to (Tortoise)Plink.exe.',mbError,MB_OK);
509 end;
510 end;
512 // AfterInstall
514 // Even though the name of this procedure suggests otherwise most of the
515 // code below is only executed once after the regular installation code
516 // is finished. This happens because of the if-guard right in the
517 // beginning of this procedure.
518 procedure CurStepChanged(CurStep:TSetupStep);
520 AppDir,FileName,Cmd,Msg:String;
521 BuiltIns,EnvPath,EnvHome,EnvSSH:TArrayOfString;
522 Count,i:Longint;
523 LinkCreated:Boolean;
524 FindRec:TFindRec;
525 RootKey:Integer;
526 begin
527 if CurStep<>ssPostInstall then begin
528 Exit;
529 end;
531 AppDir:=ExpandConstant('{app}');
534 Create the built-ins
537 // Load the built-ins from a text file.
538 FileName:=ExpandConstant('{app}\{#emit APP_BUILTINS}');
539 if LoadStringsFromFile(FileName,BuiltIns) then begin
540 Count:=GetArrayLength(BuiltIns)-1;
542 // Delete those scripts from "bin" which have been replaced by built-ins in "libexec\git-core".
543 for i:=0 to Count do begin
544 FileName:=AppDir+'\bin\'+ChangeFileExt(ExtractFileName(BuiltIns[i]),'');
545 if FileExists(FileName) and (not DeleteFile(FileName)) then begin
546 Log('Line {#emit __LINE__}: Unable to delete script "'+FileName+'", ignoring.');
547 end;
548 end;
550 // Create built-ins as aliases for git.exe.
551 for i:=0 to Count do begin
552 FileName:=AppDir+'\'+BuiltIns[i];
554 // Delete any existing built-in.
555 if FileExists(FileName) and (not DeleteFile(FileName)) then begin
556 Log('Line {#emit __LINE__}: Unable to delete existing built-in "'+FileName+'", skipping.');
557 continue;
558 end;
561 // This will throw an exception on pre-WinVista systems.
562 LinkCreated:=CreateSymbolicLink(FileName,AppDir+'\bin\git.exe',0);
563 except
564 LinkCreated:=False;
565 Log('Line {#emit __LINE__}: Creating symbolic link "'+FileName+'" failed, will try a hard link.');
566 end;
568 if not LinkCreated then begin
570 // This will throw an exception on pre-Win2k systems.
571 LinkCreated:=CreateHardLink(FileName,AppDir+'\bin\git.exe',0);
572 except
573 LinkCreated:=False;
574 Log('Line {#emit __LINE__}: Creating hardlink "'+FileName+'" failed, will try a copy.');
575 end;
576 end;
578 if not LinkCreated then begin
579 if not FileCopy(AppDir+'\bin\git.exe',FileName,False) then begin
580 Log('Line {#emit __LINE__}: Creating copy "'+FileName+'" failed, giving up.');
581 // This is not a critical error, Git could basically be used without the
582 // aliases for built-ins, so we continue.
583 end;
584 end;
585 end;
587 // Delete any duplicate files in case we are updating from a non-libexec to a libexec directory layout.
588 if FindFirst(AppDir+'\libexec\git-core\*',FindRec) then begin
589 repeat
590 if (FindRec.Attributes and FILE_ATTRIBUTE_DIRECTORY)=0 then begin
591 FileName:=AppDir+'\bin\'+FindRec.name;
592 if (Pos(FindRec.name,'git.exe')<>1) and FileExists(FileName) and (not DeleteFile(FileName)) then begin
593 Log('Line {#emit __LINE__}: Unable to delete dupe "'+FileName+'", ignoring.');
594 end;
595 end;
596 until not FindNext(FindRec);
597 FindClose(FindRec);
598 end;
599 end else begin
600 Msg:='Line {#emit __LINE__}: Unable to read file "{#emit APP_BUILTINS}".';
601 MsgBox(Msg,mbError,MB_OK);
602 Log(Msg);
603 // This is not a critical error, Git could basically be used without the
604 // aliases for built-ins, so we continue.
605 end;
608 Adapt core.autocrlf
611 if RdbCRLF[GC_LFOnly].checked then begin
612 Cmd:='core.autocrlf input';
613 end else if RdbCRLF[GC_CRLFAlways].checked then begin
614 Cmd:='core.autocrlf true';
615 end else begin
616 Cmd:='core.autocrlf false';
617 end;
618 if not Exec(AppDir + '\bin\git.exe', 'config -f gitconfig ' + Cmd,
619 AppDir + '\etc', SW_HIDE, ewWaitUntilTerminated, i) then begin
620 Msg:='Unable to configure the line ending conversion: ' + Cmd;
621 MsgBox(Msg,mbError,MB_OK);
622 Log(Msg);
623 end;
626 Modify the environment
628 This must happen no later than ssPostInstall to make
629 "ChangesEnvironment=yes" not happend before the change!
632 FileName:=AppDir+'\setup.ini';
634 // Delete GIT_SSH and SVN_SSH if a previous installation set them (this is required for the GS_OpenSSH case).
635 EnvSSH:=GetEnvStrings('GIT_SSH',IsAdminLoggedOn);
636 if (GetArrayLength(EnvSSH)=1) and
637 (CompareStr(RemoveQuotes(EnvSSH[0]),GetIniString('Environment','GIT_SSH','',FileName))=0) then begin
638 if not SetEnvStrings('GIT_SSH',IsAdminLoggedOn,True,[]) then begin
639 Msg:='Line {#emit __LINE__}: Unable to reset GIT_SSH prior to install.';
640 MsgBox(Msg,mbError,MB_OK);
641 Log(Msg);
642 // This is not a critical error, the user can probably fix it manually,
643 // so we continue.
644 end;
645 end;
647 EnvSSH:=GetEnvStrings('SVN_SSH',IsAdminLoggedOn);
648 if (GetArrayLength(EnvSSH)=1) and
649 (CompareStr(RemoveQuotes(EnvSSH[0]),GetIniString('Environment','SVN_SSH','',FileName))=0) then begin
650 if not SetEnvStrings('SVN_SSH',IsAdminLoggedOn,True,[]) then begin
651 Msg:='Line {#emit __LINE__}: Unable to reset SVN_SSH prior to install.';
652 MsgBox(Msg,mbError,MB_OK);
653 Log(Msg);
654 // This is not a critical error, the user can probably fix it manually,
655 // so we continue.
656 end;
657 end;
659 if (PuTTYPage<>NIL) and RdbSSH[GS_Plink].Checked then begin
660 SetArrayLength(EnvSSH,1);
661 EnvSSH[0]:=EdtPlink.Text;
663 // Set GIT_SSH as specified by the user.
664 if not SetEnvStrings('GIT_SSH',IsAdminLoggedOn,True,EnvSSH) then begin
665 Msg:='Line {#emit __LINE__}: Unable to set the GIT_SSH environment variable.';
666 MsgBox(Msg,mbError,MB_OK);
667 Log(Msg);
668 // This is not a critical error, the user can probably fix it manually,
669 // so we continue.
670 end;
672 // Mark that we have changed GIT_SSH by writing its value to a file.
673 if not SetIniString('Environment','GIT_SSH',EnvSSH[0],FileName) then begin
674 Msg:='Line {#emit __LINE__}: Unable to write to file "'+FileName+'".';
675 MsgBox(Msg,mbError,MB_OK);
676 Log(Msg);
677 // This is not a critical error, though uninstall / reinstall will probably not run cleanly,
678 // so we continue.
679 end;
681 // Set SVN_SSH as specified by the user, but with escaped backslashes and quotes.
682 StringChangeEx(EnvSSH[0],'\','\\',True);
683 EnvSSH[0]:=AddQuotes(EnvSSH[0]);
685 if not SetEnvStrings('SVN_SSH',IsAdminLoggedOn,True,EnvSSH) then begin
686 Msg:='Line {#emit __LINE__}: Unable to set the SVN_SSH environment variable.';
687 MsgBox(Msg,mbError,MB_OK);
688 Log(Msg);
689 // This is not a critical error, the user can probably fix it manually,
690 // so we continue.
691 end;
693 // Mark that we have changed SVN_SSH by writing its value to a file.
694 if not SetIniString('Environment','SVN_SSH',EnvSSH[0],FileName) then begin
695 Msg:='Line {#emit __LINE__}: Unable to write to file "'+FileName+'".';
696 MsgBox(Msg,mbError,MB_OK);
697 Log(Msg);
698 // This is not a critical error, though uninstall / reinstall will probably not run cleanly,
699 // so we continue.
700 end;
701 end;
703 // Get the current user's directories in PATH.
704 EnvPath:=GetEnvStrings('PATH',IsAdminLoggedOn);
706 // First, remove the installation directory from PATH in any case.
707 for i:=0 to GetArrayLength(EnvPath)-1 do begin
708 if Pos(AppDir+'\',EnvPath[i]+'\')=1 then begin
709 EnvPath[i]:='';
710 end;
711 end;
713 // Delete HOME if a previous installation modified it.
714 EnvHome:=GetEnvStrings('HOME',IsAdminLoggedOn);
715 if (GetArrayLength(EnvHome)=1) and
716 (CompareStr(RemoveQuotes(EnvHome[0]),GetIniString('Environment','HOME','',FileName))=0) then begin
717 if not SetEnvStrings('HOME',IsAdminLoggedOn,True,[]) then begin
718 Msg:='Line {#emit __LINE__}: Unable to reset HOME prior to install.';
719 MsgBox(Msg,mbError,MB_OK);
720 Log(Msg);
721 // This is not a critical error, the user can probably fix it manually,
722 // so we continue.
723 end;
724 end;
726 // Modify the PATH variable as requested by the user.
727 if RdbPath[GP_Cmd].Checked or RdbPath[GP_CmdTools].Checked then begin
728 i:=GetArrayLength(EnvPath);
729 SetArrayLength(EnvPath,i+1);
731 // List \cmd before \bin so \cmd has higher priority and programs in
732 // there will be called in favor of those in \bin.
733 EnvPath[i]:=ExpandConstant('{app}\cmd');
735 if RdbPath[GP_CmdTools].Checked then begin
736 SetArrayLength(EnvPath,i+2);
737 EnvPath[i+1]:=ExpandConstant('{app}\bin');
739 // Set HOME for the Windows Command Prompt, but only if it has not been set manually before.
740 EnvHome:=GetEnvStrings('HOME',IsAdminLoggedOn);
741 i:=GetArrayLength(EnvHome);
742 if (i=0) or ((i=1) and (Length(EnvHome[0])=0)) then begin
743 SetArrayLength(EnvHome,1);
744 EnvHome[0]:=ExpandConstant('{%HOMEDRIVE}{%HOMEPATH}');
745 if not SetEnvStrings('HOME',IsAdminLoggedOn,True,EnvHome) then begin
746 Msg:='Line {#emit __LINE__}: Unable to set the HOME environment variable.';
747 MsgBox(Msg,mbError,MB_OK);
748 Log(Msg);
749 // This is not a critical error, the user can probably fix it manually,
750 // so we continue.
751 end;
753 // Mark that we have changed HOME.
754 if not SetIniString('Environment','HOME',EnvHome[0],FileName) then begin
755 Msg:='Line {#emit __LINE__}: Unable to write to file "'+FileName+'".';
756 MsgBox(Msg,mbError,MB_OK);
757 Log(Msg);
758 // This is not a critical error, though uninstall / reinstall will probably not run cleanly,
759 // so we continue.
760 end;
761 end;
762 end;
763 end;
765 // Set the current user's PATH directories.
766 if not SetEnvStrings('PATH',IsAdminLoggedOn,True,EnvPath) then begin
767 Msg:='Line {#emit __LINE__}: Unable to set the PATH environment variable.';
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;
775 Create the Windows Explorer shell extensions
778 if IsAdminLoggedOn then begin
779 RootKey:=HKEY_LOCAL_MACHINE;
780 end else begin
781 RootKey:=HKEY_CURRENT_USER;
782 end;
784 if IsComponentSelected('ext\shellhere') then begin
785 if (not RegWriteStringValue(RootKey,'SOFTWARE\Classes\Directory\shell\git_shell','','Git Ba&sh Here')) or
786 (not RegWriteStringValue(RootKey,'SOFTWARE\Classes\Directory\shell\git_shell\command','','wscript "'+AppDir+'\Git Bash.vbs" "%1"')) then begin
787 Msg:='Line {#emit __LINE__}: Unable to create "Git Bash Here" shell extension.';
788 MsgBox(Msg,mbError,MB_OK);
789 Log(Msg);
790 // This is not a critical error, the user can probably fix it manually,
791 // so we continue.
792 end;
793 end;
795 if IsComponentSelected('ext\guihere') then begin
796 if (not RegWriteStringValue(RootKey,'SOFTWARE\Classes\Directory\shell\git_gui','','Git &GUI Here')) or
797 (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
798 Msg:='Line {#emit __LINE__}: Unable to create "Git GUI Here" shell extension.';
799 MsgBox(Msg,mbError,MB_OK);
800 Log(Msg);
801 // This is not a critical error, the user can probably fix it manually,
802 // so we continue.
803 end;
804 end;
805 end;
807 procedure RegisterPreviousData(PreviousDataKey:Integer);
809 Data:String;
810 begin
811 // Git Path options.
812 Data:='';
813 if RdbPath[GP_BashOnly].Checked then begin
814 Data:='BashOnly';
815 end else if RdbPath[GP_Cmd].Checked then begin
816 Data:='Cmd';
817 end else if RdbPath[GP_CmdTools].Checked then begin
818 Data:='CmdTools';
819 end;
820 SetPreviousData(PreviousDataKey,'Path Option',Data);
822 // Git SSH options.
823 Data:='';
824 if (PuTTYPage=NIL) or RdbSSH[GS_OpenSSH].Checked then begin
825 Data:='OpenSSH';
826 end else if RdbSSH[GS_Plink].Checked then begin
827 Data:='Plink';
828 end;
829 SetPreviousData(PreviousDataKey,'SSH Option',Data);
831 // Line ending conversion options.
832 Data:='';
833 if RdbCRLF[GC_LFOnly].Checked then begin
834 Data:='LFOnly';
835 end else if RdbCRLF[GC_CRLFAlways].Checked then begin
836 Data:='CRLFAlways';
837 end else if RdbCRLF[GC_CRLFCommitAsIs].Checked then begin
838 Data:='CRLFCommitAsIs';
839 end;
840 SetPreviousData(PreviousDataKey,'CRLF Option',Data);
841 end;
844 Uninstaller code
847 function InitializeUninstall:Boolean;
849 FileName,NewName,Msg:String;
850 begin
851 FileName:=ExpandConstant('{app}\bin\ssh-agent.exe');
852 if FileExists(FileName) then begin
853 // Create a temporary copy of the file we try to delete.
854 NewName:=FileName+'.'+IntToStr(1000+Random(9000));
855 Result:=FileCopy(FileName,NewName,True) and DeleteFile(FileName);
857 if not Result then begin
858 Msg:='Line {#emit __LINE__}: Please stop all ssh-agent processes and run uninstall again.';
859 MsgBox(Msg,mbError,MB_OK);
860 Log(Msg);
862 // Clean-up the temporary copy (ignoring any errors).
863 DeleteFile(NewName);
864 end else begin
865 // Clean-up the temporary copy (ignoring any errors).
866 RenameFile(NewName,FileName);
867 end;
868 end else begin
869 Result:=True;
870 end;
871 end;
873 // PreUninstall
875 // Even though the name of this function suggests otherwise most of the
876 // code below is only executed right before the actual uninstallation.
877 // This happens because of the if-guard right in the beginning of this
878 // function.
879 procedure CurUninstallStepChanged(CurUninstallStep:TUninstallStep);
881 AppDir,Command,Msg:String;
882 EnvPath,EnvHome,EnvSSH:TArrayOfString;
883 i:Longint;
884 RootKey:Integer;
885 begin
886 if CurUninstallStep<>usUninstall then begin
887 Exit;
888 end;
891 Modify the environment
893 This must happen no later than usUninstall to make
894 "ChangesEnvironment=yes" not happend before the change!
897 AppDir:=ExpandConstant('{app}');
898 Command:=AppDir+'\setup.ini';
900 // Delete the current user's GIT_SSH and SVN_SSH if we set it.
901 EnvSSH:=GetEnvStrings('GIT_SSH',IsAdminLoggedOn);
902 if (GetArrayLength(EnvSSH)=1) and
903 (CompareStr(RemoveQuotes(EnvSSH[0]),GetIniString('Environment','GIT_SSH','',Command))=0) then begin
904 if not SetEnvStrings('GIT_SSH',IsAdminLoggedOn,True,[]) then begin
905 Msg:='Line {#emit __LINE__}: Unable to revert any possible changes to GIT_SSH.';
906 MsgBox(Msg,mbError,MB_OK);
907 Log(Msg);
908 // This is not a critical error, the user can probably fix it manually,
909 // so we continue.
910 end;
911 end;
913 EnvSSH:=GetEnvStrings('SVN_SSH',IsAdminLoggedOn);
914 if (GetArrayLength(EnvSSH)=1) and
915 (CompareStr(RemoveQuotes(EnvSSH[0]),GetIniString('Environment','SVN_SSH','',Command))=0) then begin
916 if not SetEnvStrings('SVN_SSH',IsAdminLoggedOn,True,[]) then begin
917 Msg:='Line {#emit __LINE__}: Unable to revert any possible changes to SVN_SSH.';
918 MsgBox(Msg,mbError,MB_OK);
919 Log(Msg);
920 // This is not a critical error, the user can probably fix it manually,
921 // so we continue.
922 end;
923 end;
925 // Get the current user's directories in PATH.
926 EnvPath:=GetEnvStrings('PATH',IsAdminLoggedOn);
928 // Remove the installation directory from PATH in any case, even if it
929 // was not added by the installer.
930 for i:=0 to GetArrayLength(EnvPath)-1 do begin
931 if Pos(AppDir+'\',EnvPath[i]+'\')=1 then begin
932 EnvPath[i]:='';
933 end;
934 end;
936 // Reset the current user's directories in PATH.
937 if not SetEnvStrings('PATH',IsAdminLoggedOn,True,EnvPath) then begin
938 Msg:='Line {#emit __LINE__}: Unable to revert any possible changes to PATH.';
939 MsgBox(Msg,mbError,MB_OK);
940 Log(Msg);
941 // This is not a critical error, the user can probably fix it manually,
942 // so we continue.
943 end;
945 // Reset the current user's HOME if we modified it.
946 EnvHome:=GetEnvStrings('HOME',IsAdminLoggedOn);
947 if (GetArrayLength(EnvHome)=1) and
948 (CompareStr(RemoveQuotes(EnvHome[0]),GetIniString('Environment','HOME','',Command))=0) then begin
949 if not SetEnvStrings('HOME',IsAdminLoggedOn,True,[]) then begin
950 Msg:='Line {#emit __LINE__}: Unable to revert any possible changes to HOME.';
951 MsgBox(Msg,mbError,MB_OK);
952 Log(Msg);
953 // This is not a critical error, the user can probably fix it manually,
954 // so we continue.
955 end;
956 end;
958 if FileExists(Command) and (not DeleteFile(Command)) then begin
959 Msg:='Line {#emit __LINE__}: Unable to delete file "'+Command+'".';
960 MsgBox(Msg,mbError,MB_OK);
961 Log(Msg);
962 // This is not a critical error, the user can probably fix it manually,
963 // so we continue.
964 end;
967 Delete the Windows Explorer shell extensions
970 if IsAdminLoggedOn then begin
971 RootKey:=HKEY_LOCAL_MACHINE;
972 end else begin
973 RootKey:=HKEY_CURRENT_USER;
974 end;
976 Command:='';
977 RegQueryStringValue(RootKey,'SOFTWARE\Classes\Directory\shell\git_shell\command','',Command);
978 if Pos(AppDir,Command)>0 then begin
979 if not RegDeleteKeyIncludingSubkeys(RootKey,'SOFTWARE\Classes\Directory\shell\git_shell') then begin
980 Msg:='Line {#emit __LINE__}: Unable to remove "Git Bash Here" shell extension.';
981 MsgBox(Msg,mbError,MB_OK);
982 Log(Msg);
983 // This is not a critical error, the user can probably fix it manually,
984 // so we continue.
985 end;
986 end;
988 Command:='';
989 RegQueryStringValue(RootKey,'SOFTWARE\Classes\Directory\shell\git_gui\command','',Command);
990 if Pos(AppDir,Command)>0 then begin
991 if not RegDeleteKeyIncludingSubkeys(RootKey,'SOFTWARE\Classes\Directory\shell\git_gui') then begin
992 Msg:='Line {#emit __LINE__}: Unable to remove "Git GUI Here" shell extension.';
993 MsgBox(Msg,mbError,MB_OK);
994 Log(Msg);
995 // This is not a critical error, the user can probably fix it manually,
996 // so we continue.
997 end;
998 end;
999 end;