Installer: For style, write IsComponentSelected() in all camel-case
[msysgit.git] / share / WinGit / install.iss
blob3241d97a19036f2998c981a43e2adb12eedef9dc
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 Compression=lzma2/ultra
9 LZMAUseSeparateProcess=yes
10 OutputBaseFilename={#APP_NAME+'-'+APP_VERSION}
11 OutputDir={#GetEnv('USERPROFILE')}
12 SolidCompression=yes
14 ; Uncomment the line below to be able to compile the script from within the IDE.
15 ;SourceDir={#GetEnv('TEMP')}\WinGit
17 ; Installer-related
18 AllowNoIcons=yes
19 AppName={#APP_NAME}
20 AppPublisherURL={#APP_URL}
21 AppVersion={#APP_VERSION}
22 ChangesEnvironment=yes
23 DefaultDirName={pf}\{#APP_NAME}
24 DefaultGroupName={#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\reg; Description: Context menu entries; Flags: exclusive; Types: custom
47 Name: ext\reg\shellhere; Description: Git Bash Here; Types: custom
48 Name: ext\reg\guihere; Description: Git GUI Here; Types: custom
49 Name: ext\cheetah; Description: git-cheetah shell extension (32-bit only); Flags: exclusive; Types: custom
50 Name: assoc; Description: Associate .git* configuration files with the default text editor; Types: custom
51 Name: consolefont; Description: Use a TrueType font in the console (required for proper character encoding); Types: custom
53 [Files]
54 ; Install files that might be in use during setup under a different name.
55 Source: git-cheetah\git_shell_ext.dll; DestDir: {app}\git-cheetah; DestName: git_shell_ext.dll.new; Flags: replacesameversion
57 Source: *; DestDir: {app}; Excludes: \*.bmp, gpl-2.0.rtf, \*.iss, \tmp.*, \bin\*install*, \git-cheetah\git_shell_ext.dll; Flags: recursesubdirs replacesameversion
58 Source: ReleaseNotes.rtf; DestDir: {app}; Flags: isreadme replacesameversion
60 [Icons]
61 Name: {group}\Git GUI; Filename: {app}\bin\wish.exe; Parameters: """{app}\libexec\git-core\git-gui"""; WorkingDir: %HOMEDRIVE%%HOMEPATH%; IconFilename: {app}\etc\git.ico
62 Name: {group}\Git Bash; Filename: {syswow64}\cmd.exe; Parameters: "/c """"{app}\bin\sh.exe"" --login -i"""; WorkingDir: %HOMEDRIVE%%HOMEPATH%; IconFilename: {app}\etc\git.ico
64 [Messages]
65 BeveledLabel={#APP_URL}
66 SetupAppTitle={#APP_NAME} Setup
67 SetupWindowTitle={#APP_NAME} Setup
69 [Registry]
70 ; There is no "Console" key in HKLM.
71 Root: HKCU; Subkey: Console; ValueType: string; ValueName: FaceName; ValueData: Lucida Console; Components: consolefont
72 Root: HKCU; Subkey: Console; ValueType: dword; ValueName: FontFamily; ValueData: $00000036; Components: consolefont
73 Root: HKCU; Subkey: Console; ValueType: dword; ValueName: FontSize; ValueData: $000e0000; Components: consolefont
74 Root: HKCU; Subkey: Console; ValueType: dword; ValueName: FontWeight; ValueData: $00000190; Components: consolefont
76 Root: HKCU; Subkey: Console\Git Bash; ValueType: string; ValueName: FaceName; ValueData: Lucida Console; Flags: createvalueifdoesntexist
77 Root: HKCU; Subkey: Console\Git Bash; ValueType: dword; ValueName: FontFamily; ValueData: $00000036; Flags: createvalueifdoesntexist
78 Root: HKCU; Subkey: Console\Git Bash; ValueType: dword; ValueName: FontSize; ValueData: $000e0000; Flags: createvalueifdoesntexist
79 Root: HKCU; Subkey: Console\Git Bash; ValueType: dword; ValueName: FontWeight; ValueData: $00000190; Flags: createvalueifdoesntexist
81 ; File associations for configuration files that may be contained in a repository (so this does not include ".gitconfig").
82 Root: HKLM; Subkey: Software\Classes\.gitattributes; ValueType: string; ValueData: txtfile; Flags: createvalueifdoesntexist; Check: IsAdminLoggedOn; Components: assoc
83 Root: HKLM; Subkey: Software\Classes\.gitattributes; ValueType: string; ValueName: Content Type; ValueData: text/plain; Flags: createvalueifdoesntexist; Check: IsAdminLoggedOn; Components: assoc
84 Root: HKLM; Subkey: Software\Classes\.gitattributes; ValueType: string; ValueName: PerceivedType; ValueData: text; Flags: createvalueifdoesntexist; Check: IsAdminLoggedOn; Components: assoc
85 Root: HKCU; Subkey: Software\Classes\.gitattributes; ValueType: string; ValueData: txtfile; Flags: createvalueifdoesntexist; Check: not IsAdminLoggedOn; Components: assoc
86 Root: HKCU; Subkey: Software\Classes\.gitattributes; ValueType: string; ValueName: Content Type; ValueData: text/plain; Flags: createvalueifdoesntexist; Check: not IsAdminLoggedOn; Components: assoc
87 Root: HKCU; Subkey: Software\Classes\.gitattributes; ValueType: string; ValueName: PerceivedType; ValueData: text; Flags: createvalueifdoesntexist; Check: not IsAdminLoggedOn; Components: assoc
89 Root: HKLM; Subkey: Software\Classes\.gitignore; ValueType: string; ValueData: txtfile; Flags: createvalueifdoesntexist; Check: IsAdminLoggedOn; Components: assoc
90 Root: HKLM; Subkey: Software\Classes\.gitignore; ValueType: string; ValueName: Content Type; ValueData: text/plain; Flags: createvalueifdoesntexist; Check: IsAdminLoggedOn; Components: assoc
91 Root: HKLM; Subkey: Software\Classes\.gitignore; ValueType: string; ValueName: PerceivedType; ValueData: text; Flags: createvalueifdoesntexist; Check: IsAdminLoggedOn; Components: assoc
92 Root: HKCU; Subkey: Software\Classes\.gitignore; ValueType: string; ValueData: txtfile; Flags: createvalueifdoesntexist; Check: not IsAdminLoggedOn; Components: assoc
93 Root: HKCU; Subkey: Software\Classes\.gitignore; ValueType: string; ValueName: Content Type; ValueData: text/plain; Flags: createvalueifdoesntexist; Check: not IsAdminLoggedOn; Components: assoc
94 Root: HKCU; Subkey: Software\Classes\.gitignore; ValueType: string; ValueName: PerceivedType; ValueData: text; Flags: createvalueifdoesntexist; Check: not IsAdminLoggedOn; Components: assoc
96 Root: HKLM; Subkey: Software\Classes\.gitmodules; ValueType: string; ValueData: txtfile; Flags: createvalueifdoesntexist; Check: IsAdminLoggedOn; Components: assoc
97 Root: HKLM; Subkey: Software\Classes\.gitmodules; ValueType: string; ValueName: Content Type; ValueData: text/plain; Flags: createvalueifdoesntexist; Check: IsAdminLoggedOn; Components: assoc
98 Root: HKLM; Subkey: Software\Classes\.gitmodules; ValueType: string; ValueName: PerceivedType; ValueData: text; Flags: createvalueifdoesntexist; Check: IsAdminLoggedOn; Components: assoc
99 Root: HKCU; Subkey: Software\Classes\.gitmodules; ValueType: string; ValueData: txtfile; Flags: createvalueifdoesntexist; Check: not IsAdminLoggedOn; Components: assoc
100 Root: HKCU; Subkey: Software\Classes\.gitmodules; ValueType: string; ValueName: Content Type; ValueData: text/plain; Flags: createvalueifdoesntexist; Check: not IsAdminLoggedOn; Components: assoc
101 Root: HKCU; Subkey: Software\Classes\.gitmodules; ValueType: string; ValueName: PerceivedType; ValueData: text; Flags: createvalueifdoesntexist; Check: not IsAdminLoggedOn; Components: assoc
103 [UninstallDelete]
104 ; Delete the built-ins.
105 Type: files; Name: {app}\bin\git-*.exe
106 Type: files; Name: {app}\libexec\git-core\git-*.exe
107 Type: files; Name: {app}\libexec\git-core\git.exe
109 ; Delete any (temporary) git-cheetah files.
110 Type: files; Name: {app}\git-cheetah\*.*
112 ; Delete any manually created shortcuts.
113 Type: files; Name: {userappdata}\Microsoft\Internet Explorer\Quick Launch\Git Bash.lnk
114 Type: files; Name: {code:GetShellFolder|desktop}\Git Bash.lnk
115 Type: files; Name: {app}\Git Bash.lnk
117 ; Delete a home directory inside the msysGit directory.
118 Type: dirifempty; Name: {app}\home\{username}
119 Type: dirifempty; Name: {app}\home
121 [Code]
122 #include "helpers.inc.iss"
123 #include "putty.inc.iss"
124 #include "modules.inc.iss"
126 function CreateHardLink(lpFileName,lpExistingFileName:String;lpSecurityAttributes:Integer):Boolean;
127 #ifdef UNICODE
128 external 'CreateHardLinkW@Kernel32.dll stdcall delayload setuponly';
129 #else
130 external 'CreateHardLinkA@Kernel32.dll stdcall delayload setuponly';
131 #endif
133 function CreateSymbolicLink(lpSymlinkFileName,lpTargetFileName:String;dwFlags:DWORD):Boolean;
134 #ifdef UNICODE
135 external 'CreateSymbolicLinkW@Kernel32.dll stdcall delayload setuponly';
136 #else
137 external 'CreateSymbolicLinkA@Kernel32.dll stdcall delayload setuponly';
138 #endif
140 const
141 // Git Path options.
142 GP_BashOnly = 1;
143 GP_Cmd = 2;
144 GP_CmdTools = 3;
146 // Git SSH options.
147 GS_OpenSSH = 1;
148 GS_Plink = 2;
150 // Git line ending conversion options.
151 GC_LFOnly = 1;
152 GC_CRLFAlways = 2;
153 GC_CRLFCommitAsIs = 3;
156 // Wizard page and variables for the Path options.
157 PathPage:TWizardPage;
158 RdbPath:array[GP_BashOnly..GP_CmdTools] of TRadioButton;
160 // Wizard page and variables for the SSH options.
161 PuTTYPage:TWizardPage;
162 RdbSSH:array[GS_OpenSSH..GS_Plink] of TRadioButton;
163 EdtPlink:TEdit;
165 // Wizard page and variables for the line ending conversion options.
166 CRLFPage:TWizardPage;
167 RdbCRLF:array[GC_LFOnly..GC_CRLFCommitAsIs] of TRadioButton;
169 // Wizard page and variables for the processes page.
170 Processes:ProcessList;
171 ProcessesPage:TWizardPage;
172 ProcessesListBox:TListBox;
173 ProcessesRefresh,ContinueButton:TButton;
175 procedure BrowseForPuTTYFolder(Sender:TObject);
177 Path:String;
178 begin
179 Path:=ExtractFilePath(EdtPlink.Text);
180 BrowseForFolder('Please select the PuTTY folder:',Path,False);
181 if FileExists(Path+'\TortoisePlink.exe') then begin
182 EdtPlink.Text:=Path+'\TortoisePlink.exe';
183 RdbSSH[GS_Plink].Checked:=True;
184 end else if FileExists(Path+'\plink.exe') then begin
185 EdtPlink.Text:=Path+'\plink.exe';
186 RdbSSH[GS_Plink].Checked:=True;
187 end else begin
188 MsgBox('Please enter a valid path to "TortoisePlink.exe" or "plink.exe".',mbError,MB_OK);
189 end;
190 end;
192 procedure DeleteContextMenuEntries;
194 AppDir,Command,Msg:String;
195 RootKey:Integer;
196 begin
197 AppDir:=ExpandConstant('{app}');
199 if IsAdminLoggedOn then begin
200 RootKey:=HKEY_LOCAL_MACHINE;
201 end else begin
202 RootKey:=HKEY_CURRENT_USER;
203 end;
205 Command:='';
206 RegQueryStringValue(RootKey,'SOFTWARE\Classes\Directory\shell\git_shell\command','',Command);
207 if Pos(AppDir,Command)>0 then begin
208 if not RegDeleteKeyIncludingSubkeys(RootKey,'SOFTWARE\Classes\Directory\shell\git_shell') then begin
209 Msg:='Line {#__LINE__}: Unable to remove "Git Bash Here" shell extension.';
210 MsgBox(Msg,mbError,MB_OK);
211 Log(Msg);
212 // This is not a critical error, the user can probably fix it manually,
213 // so we continue.
214 end;
215 end;
217 Command:='';
218 RegQueryStringValue(RootKey,'SOFTWARE\Classes\Directory\shell\git_gui\command','',Command);
219 if Pos(AppDir,Command)>0 then begin
220 if not RegDeleteKeyIncludingSubkeys(RootKey,'SOFTWARE\Classes\Directory\shell\git_gui') then begin
221 Msg:='Line {#__LINE__}: Unable to remove "Git GUI Here" shell extension.';
222 MsgBox(Msg,mbError,MB_OK);
223 Log(Msg);
224 // This is not a critical error, the user can probably fix it manually,
225 // so we continue.
226 end;
227 end;
228 end;
230 procedure RefreshProcessList(Sender:TObject);
232 Modules:TArrayOfString;
233 ProcsCloseRequired,ProcsCloseRestart:ProcessList;
234 Found:Boolean;
235 i:Longint;
236 Caption:String;
237 begin
238 SetArrayLength(Modules,2);
239 Modules[0]:=ExpandConstant('{app}\bin\msys-1.0.dll');
240 Modules[1]:=ExpandConstant('{app}\bin\tcl85.dll');
241 Found:=FindProcessesUsingModules(Modules,ProcsCloseRequired);
243 Found:=FindProcessesUsingModule(ExpandConstant('{app}\git-cheetah\git_shell_ext.dll'),ProcsCloseRestart) or Found;
245 // Misuse the "Restartable" flag to indicate which processes are required
246 // to be closed before setup can continue, and which just should be closed
247 // in order to make changes take effect immediately.
248 SetArrayLength(Processes,GetArrayLength(ProcsCloseRequired)+GetArrayLength(ProcsCloseRestart));
249 for i:=0 to GetArrayLength(ProcsCloseRequired)-1 do begin
250 Processes[i]:=ProcsCloseRequired[i];
251 Processes[i].Restartable:=False;
252 end;
253 for i:=0 to GetArrayLength(ProcsCloseRestart)-1 do begin
254 Processes[GetArrayLength(ProcsCloseRequired)+i]:=ProcsCloseRestart[i];
255 Processes[GetArrayLength(ProcsCloseRequired)+i].Restartable:=True;
256 end;
258 ProcessesListBox.Items.Clear;
259 if (Sender=NIL) or Found then begin
260 for i:=0 to GetArrayLength(Processes)-1 do begin
261 Caption:=Processes[i].Name+' (PID '+IntToStr(Processes[i].ID);
262 if not Processes[i].Restartable then begin
263 Caption:=Caption+', closing is required';
264 end;
265 Caption:=Caption+')';
266 ProcessesListBox.Items.Append(Caption);
267 end;
268 end;
270 if ContinueButton<>NIL then begin
271 ContinueButton.Enabled:=(GetArrayLength(ProcsCloseRequired)=0);
272 end;
273 end;
276 Installer code
279 procedure InitializeWizard;
281 i,PrevPageID:Integer;
282 LblGitBash,LblGitCmd,LblGitCmdTools,LblGitCmdToolsWarn:TLabel;
283 LblOpenSSH,LblPlink:TLabel;
284 PuTTYSessions:TArrayOfString;
285 LblLFOnly,LblCRLFAlways,LblCRLFCommitAsIs:TLabel;
286 BtnPlink:TButton;
287 Data:String;
288 begin
289 // Until we have a 64-bit version of git-cheetah, disable it on 64-bit Windows.
290 if isWin64 then begin
291 for i:=0 to WizardForm.ComponentsList.Items.Count-1 do begin
292 Data:=LowerCase(WizardForm.ComponentsList.ItemCaption[i]);
293 if Pos('context',Data)>0 then begin
294 // Select the Registry-based context menu entries.
295 WizardForm.ComponentsList.Checked[i]:=True;
296 end else if Pos('cheetah',Data)>0 then begin
297 // Disable the git-cheetah shell extension.
298 WizardForm.ComponentsList.ItemEnabled[i]:=False;
299 end;
300 end;
301 end;
303 PrevPageID:=wpSelectProgramGroup;
306 * Create a custom page for modifying the environment.
309 PathPage:=CreateCustomPage(
310 PrevPageID,
311 'Adjusting your PATH environment',
312 'How would you like to use Git from the command line?'
314 PrevPageID:=PathPage.ID;
316 // 1st choice
317 RdbPath[GP_BashOnly]:=TRadioButton.Create(PathPage);
318 with RdbPath[GP_BashOnly] do begin
319 Parent:=PathPage.Surface;
320 Caption:='Use Git Bash only';
321 Left:=ScaleX(4);
322 Top:=ScaleY(8);
323 Width:=ScaleX(129);
324 Height:=ScaleY(17);
325 Font.Style:=[fsBold];
326 TabOrder:=0;
327 Checked:=True;
328 end;
329 LblGitBash:=TLabel.Create(PathPage);
330 with LblGitBash do begin
331 Parent:=PathPage.Surface;
332 Caption:=
333 'This is the most conservative choice if you are concerned about the stability' + #13 +
334 'of your system. Your PATH will not be modified.';
335 Left:=ScaleX(28);
336 Top:=ScaleY(32);
337 Width:=ScaleX(405);
338 Height:=ScaleY(26);
339 end;
341 // 2nd choice
342 RdbPath[GP_Cmd]:=TRadioButton.Create(PathPage);
343 with RdbPath[GP_Cmd] do begin
344 Parent:=PathPage.Surface;
345 Caption:='Run Git from the Windows Command Prompt';
346 Left:=ScaleX(4);
347 Top:=ScaleY(76);
348 Width:=ScaleX(281);
349 Height:=ScaleY(17);
350 Font.Style:=[fsBold];
351 TabOrder:=1;
352 end;
353 LblGitCmd:=TLabel.Create(PathPage);
354 with LblGitCmd do begin
355 Parent:=PathPage.Surface;
356 Caption:=
357 'This option is considered safe and no conflicts with other tools are known.' + #13 +
358 'Only Git will be added to your PATH. Use this option if you want to use Git' + #13 +
359 'from a Cygwin Prompt (make sure to not have Cygwin''s Git installed).';
360 Left:=ScaleX(28);
361 Top:=ScaleY(100);
362 Width:=ScaleX(405);
363 Height:=ScaleY(39);
364 end;
366 // 3rd choice
367 RdbPath[GP_CmdTools]:=TRadioButton.Create(PathPage);
368 with RdbPath[GP_CmdTools] do begin
369 Parent:=PathPage.Surface;
370 Caption:='Run Git and included Unix tools from the Windows Command Prompt';
371 Left:=ScaleX(4);
372 Top:=ScaleY(152);
373 Width:=ScaleX(405);
374 Height:=ScaleY(17);
375 Font.Style:=[fsBold];
376 TabOrder:=2;
377 end;
378 LblGitCmdTools:=TLabel.Create(PathPage);
379 with LblGitCmdTools do begin
380 Parent:=PathPage.Surface;
381 Caption:='Both Git and its accompanying Unix tools will be added to your PATH.';
382 Left:=ScaleX(28);
383 Top:=ScaleY(176);
384 Width:=ScaleX(405);
385 Height:=ScaleY(13);
386 end;
387 LblGitCmdToolsWarn:=TLabel.Create(PathPage);
388 with LblGitCmdToolsWarn do begin
389 Parent:=PathPage.Surface;
390 Caption:=
391 'Warning: This will override Windows tools like find.exe and' + #13 +
392 'sort.exe. Select this option only if you understand the implications.';
393 Left:=ScaleX(28);
394 Top:=ScaleY(192);
395 Width:=ScaleX(376);
396 Height:=ScaleY(26);
397 Font.Color:=255;
398 Font.Style:=[fsBold];
399 end;
401 // Restore the setting chosen during a previous install.
402 Data:=GetPreviousData('Path Option','BashOnly');
403 if Data='BashOnly' then begin
404 RdbPath[GP_BashOnly].Checked:=True;
405 end else if Data='Cmd' then begin
406 RdbPath[GP_Cmd].Checked:=True;
407 end else if Data='CmdTools' then begin
408 RdbPath[GP_CmdTools].Checked:=True;
409 end;
412 * Create a custom page for using (Tortoise)Plink instead of OpenSSH
413 * if at least one PuTTY session is found in the Registry.
416 if RegGetSubkeyNames(HKEY_CURRENT_USER,'Software\SimonTatham\PuTTY\Sessions',PuTTYSessions) and (GetArrayLength(PuTTYSessions)>0) then begin
417 PuTTYPage:=CreateCustomPage(
418 PrevPageID,
419 'Choosing the SSH executable',
420 'Which Secure Shell client program would you like Git to use?'
422 PrevPageID:=PuTTYPage.ID;
424 // 1st choice
425 RdbSSH[GS_OpenSSH]:=TRadioButton.Create(PuTTYPage);
426 with RdbSSH[GS_OpenSSH] do begin
427 Parent:=PuTTYPage.Surface;
428 Caption:='Use OpenSSH';
429 Left:=ScaleX(4);
430 Top:=ScaleY(8);
431 Width:=ScaleX(129);
432 Height:=ScaleY(17);
433 Font.Style:=[fsBold];
434 TabOrder:=0;
435 Checked:=True;
436 end;
437 LblOpenSSH:=TLabel.Create(PuTTYPage);
438 with LblOpenSSH do begin
439 Parent:=PuTTYPage.Surface;
440 Caption:=
441 'This uses ssh.exe that comes with Git. The GIT_SSH and SVN_SSH' + #13 +
442 'environment variables will not be modified.';
443 Left:=ScaleX(28);
444 Top:=ScaleY(32);
445 Width:=ScaleX(324);
446 Height:=ScaleY(26);
447 end;
449 // 2nd choice
450 RdbSSH[GS_Plink]:=TRadioButton.Create(PuTTYPage);
451 with RdbSSH[GS_Plink] do begin
452 Parent:=PuTTYPage.Surface;
453 Caption:='Use (Tortoise)Plink';
454 Left:=ScaleX(4);
455 Top:=ScaleY(76);
456 Width:=ScaleX(281);
457 Height:=ScaleY(17);
458 Font.Style:=[fsBold];
459 TabOrder:=1;
460 end;
461 LblPlink:=TLabel.Create(PuTTYPage);
462 with LblPlink do begin
463 Parent:=PuTTYPage.Surface;
464 Caption:=
465 'PuTTY sessions were found in your Registry. You may specify the path' + #13 +
466 'to an existing copy of (Tortoise)Plink.exe from the TortoiseSVN/CVS' + #13 +
467 'or PuTTY applications. The GIT_SSH and SVN_SSH environment' + #13 +
468 'variables will be adjusted to point to the following executable:';
469 Left:=ScaleX(28);
470 Top:=ScaleY(100);
471 Width:=ScaleX(340);
472 Height:=ScaleY(52);
473 end;
474 EdtPlink:=TEdit.Create(PuTTYPage);
475 with EdtPlink do begin
476 Parent:=PuTTYPage.Surface;
477 Text:=GetPuTTYLocation;
478 if not FileExists(Text) then begin
479 Text:='';
480 end;
481 Left:=ScaleX(28);
482 Top:=ScaleY(161);
483 Width:=ScaleX(316);
484 Height:=ScaleY(13);
485 end;
486 BtnPlink:=TButton.Create(PuTTYPage);
487 with BtnPlink do begin
488 Parent:=PuTTYPage.Surface;
489 Caption:='...';
490 OnClick:=@BrowseForPuTTYFolder;
491 Left:=ScaleX(348);
492 Top:=ScaleY(161);
493 Width:=ScaleX(21);
494 Height:=ScaleY(21);
495 end;
497 // Restore the setting chosen during a previous install.
498 Data:=GetPreviousData('SSH Option','OpenSSH');
499 if Data='OpenSSH' then begin
500 RdbSSH[GS_OpenSSH].Checked:=True;
501 end else if Data='Plink' then begin
502 RdbSSH[GS_Plink].Checked:=True;
503 end;
504 end else begin
505 PuTTYPage:=NIL;
506 end;
509 * Create a custom page for the core.autocrlf setting.
512 CRLFPage:=CreateCustomPage(
513 PrevPageID,
514 'Configuring the line ending conversions',
515 'How should Git treat line endings in text files?'
517 PrevPageID:=CRLFPage.ID;
519 // 1st choice
520 RdbCRLF[GC_CRLFAlways]:=TRadioButton.Create(CRLFPage);
521 with RdbCRLF[GC_CRLFAlways] do begin
522 Parent:=CRLFPage.Surface;
523 Caption:='Checkout Windows-style, commit Unix-style line endings';
524 Left:=ScaleX(4);
525 Top:=ScaleY(8);
526 Width:=ScaleX(340);
527 Height:=ScaleY(17);
528 Font.Style:=[fsBold];
529 TabOrder:=0;
530 Checked:=True;
531 end;
532 LblCRLFAlways:=TLabel.Create(CRLFPage);
533 with LblCRLFAlways do begin
534 Parent:=CRLFPage.Surface;
535 Caption:=
536 'Git will convert LF to CRLF when checking out text files. When committing' + #13 +
537 'text files, CRLF will be converted to LF. For cross-platform projects,' + #13 +
538 'this is the recommended setting on Windows ("core.autocrlf" is set to "true").';
539 Left:=ScaleX(28);
540 Top:=ScaleY(32);
541 Width:=ScaleX(372);
542 Height:=ScaleY(47);
543 end;
545 // 2nd choice
546 RdbCRLF[GC_LFOnly]:=TRadioButton.Create(CRLFPage);
547 with RdbCRLF[GC_LFOnly] do begin
548 Parent:=CRLFPage.Surface;
549 Caption:='Checkout as-is, commit Unix-style line endings';
550 Left:=ScaleX(4);
551 Top:=ScaleY(80);
552 Width:=ScaleX(340);
553 Height:=ScaleY(17);
554 Font.Style:=[fsBold];
555 TabOrder:=1;
556 Checked:=False;
557 end;
558 LblLFOnly:=TLabel.Create(CRLFPage);
559 with LblLFOnly do begin
560 Parent:=CRLFPage.Surface;
561 Caption:=
562 'Git will not perform any conversion when checking out text files. When' + #13 +
563 'committing text files, CRLF will be converted to LF. For cross-platform projects,' + #13 +
564 'this is the recommended setting on Unix ("core.autocrlf" is set to "input").';
565 Left:=ScaleX(28);
566 Top:=ScaleY(104);
567 Width:=ScaleX(372);
568 Height:=ScaleY(47);
569 end;
571 // 3rd choice
572 RdbCRLF[GC_CRLFCommitAsIs]:=TRadioButton.Create(CRLFPage);
573 with RdbCRLF[GC_CRLFCommitAsIs] do begin
574 Parent:=CRLFPage.Surface;
575 Caption:='Checkout as-is, commit as-is';
576 Left:=ScaleX(4);
577 Top:=ScaleY(152);
578 Width:=ScaleX(340);
579 Height:=ScaleY(17);
580 Font.Style:=[fsBold];
581 TabOrder:=2;
582 Checked:=False;
583 end;
584 LblCRLFCommitAsIs:=TLabel.Create(CRLFPage);
585 with LblCRLFCommitAsIs do begin
586 Parent:=CRLFPage.Surface;
587 Caption:=
588 'Git will not perform any conversions when checking out or committing' + #13 +
589 'text files. Choosing this option is not recommended for cross-platform' + #13 +
590 'projects ("core.autocrlf" is set to "false").';
591 Left:=ScaleX(28);
592 Top:=ScaleY(176);
593 Width:=ScaleX(372);
594 Height:=ScaleY(47);
595 end;
597 // Restore the setting chosen during a previous install.
598 Data:=GetPreviousData('CRLF Option','CRLFAlways');
599 if Data='LFOnly' then begin
600 RdbCRLF[GC_LFOnly].Checked:=True;
601 end else if Data='CRLFAlways' then begin
602 RdbCRLF[GC_CRLFAlways].Checked:=True;
603 end else if Data='CRLFCommitAsIs' then begin
604 RdbCRLF[GC_CRLFCommitAsIs].Checked:=True;
605 end;
608 * Create a custom page for finding the processes that lock a module.
611 ProcessesPage:=CreateCustomPage(
612 wpPreparing,
613 'Replacing in-use files',
614 'The following applications use files that need to be replaced, please close them.'
617 ProcessesListBox:=TListBox.Create(ProcessesPage);
618 with ProcessesListBox do begin
619 Parent:=ProcessesPage.Surface;
620 Width:=ProcessesPage.SurfaceWidth;
621 Height:=ProcessesPage.SurfaceHeight-ScaleY(8);
622 end;
624 ProcessesRefresh:=TNewButton.Create(WizardForm);
625 with ProcessesRefresh do begin
626 Parent:=WizardForm;
627 Width:=WizardForm.NextButton.Width;
628 Height:=WizardForm.NextButton.Height;
629 Top:=WizardForm.NextButton.Top;
630 Left:=WizardForm.ClientWidth-WizardForm.NextButton.Left-WizardForm.NextButton.Width;
631 Caption:='&Refresh';
632 OnClick:=@RefreshProcessList;
633 end;
635 // This button is only used by the uninstaller.
636 ContinueButton:=NIL;
638 // Initially hide the Refresh button, show it when the process page becomes current.
639 ProcessesRefresh.Hide;
640 end;
642 function ShouldSkipPage(PageID:Integer):Boolean;
643 begin
644 if (ProcessesPage<>NIL) and (PageID=ProcessesPage.ID) then begin
645 // This page is only reached forward (by pressing "Next", never by pressing "Back").
646 RefreshProcessList(NIL);
647 Result:=(GetArrayLength(Processes)=0);
648 end else begin
649 Result:=False;
650 end;
651 end;
653 procedure CurPageChanged(CurPageID:Integer);
654 begin
655 // Show the "Refresh" button only on the processes page.
656 if (ProcessesPage<>NIL) and (CurPageID=ProcessesPage.ID) then begin
657 ProcessesRefresh.Show;
658 end else begin
659 ProcessesRefresh.Hide;
660 end;
661 end;
663 function NextButtonClick(CurPageID:Integer):Boolean;
665 i:Integer;
666 begin
667 Result:=True;
669 if (PuTTYPage<>NIL) and (CurPageID=PuTTYPage.ID) then begin
670 Result:=RdbSSH[GS_OpenSSH].Checked or
671 (RdbSSH[GS_Plink].Checked and FileExists(EdtPlink.Text));
672 if not Result then begin
673 MsgBox('Please enter a valid path to (Tortoise)Plink.exe.',mbError,MB_OK);
674 end;
675 end else if (ProcessesPage<>NIL) and (CurPageID=ProcessesPage.ID) then begin
676 // It would have been nicer to just disable the "Next" button, but the
677 // WizardForm exports the button just read-only.
678 for i:=0 to GetArrayLength(Processes)-1 do begin
679 if not Processes[i].Restartable then begin
680 MsgBox('Setup cannot continue until you close at least those applications in the list that are marked as "closing is required".',mbCriticalError,MB_OK);
681 Result:=False;
682 Exit;
683 end;
684 end;
686 Result:=(GetArrayLength(Processes)=0);
688 if not Result then begin
689 Result:=(MsgBox(
690 'If you continue without closing the listed applications, you will need to log off and on again before changes take effect.' + #13 + #13 +
691 'Are you sure you want to continue anyway?',
692 mbConfirmation,
693 MB_YESNO
694 )=IDYES);
695 end;
696 end;
697 end;
699 // AfterInstall
701 // Even though the name of this procedure suggests otherwise most of the
702 // code below is only executed once after the regular installation code
703 // is finished. This happens because of the if-guard right in the
704 // beginning of this procedure.
705 procedure CurStepChanged(CurStep:TSetupStep);
707 AppDir,FileName,TempName,Cmd,Msg:String;
708 BuiltIns,EnvPath,EnvHome,EnvSSH:TArrayOfString;
709 Count,i:Longint;
710 LinkCreated:Boolean;
711 FindRec:TFindRec;
712 RootKey:Integer;
713 begin
714 if CurStep<>ssPostInstall then begin
715 Exit;
716 end;
718 AppDir:=ExpandConstant('{app}');
721 Create the built-ins
724 // Load the built-ins from a text file.
725 FileName:=ExpandConstant('{app}\{#APP_BUILTINS}');
726 if LoadStringsFromFile(FileName,BuiltIns) then begin
727 Count:=GetArrayLength(BuiltIns)-1;
729 // Delete those scripts from "bin" which have been replaced by built-ins in "libexec\git-core".
730 for i:=0 to Count do begin
731 FileName:=AppDir+'\bin\'+ChangeFileExt(ExtractFileName(BuiltIns[i]),'');
732 if FileExists(FileName) and (not DeleteFile(FileName)) then begin
733 Log('Line {#__LINE__}: Unable to delete script "'+FileName+'", ignoring.');
734 end;
735 end;
737 // Create built-ins as aliases for git.exe.
738 for i:=0 to Count do begin
739 FileName:=AppDir+'\'+BuiltIns[i];
741 // Delete any existing built-in.
742 if FileExists(FileName) and (not DeleteFile(FileName)) then begin
743 Log('Line {#__LINE__}: Unable to delete existing built-in "'+FileName+'", skipping.');
744 continue;
745 end;
748 // This will throw an exception on pre-WinVista systems.
749 LinkCreated:=CreateSymbolicLink(FileName,AppDir+'\bin\git.exe',0);
750 except
751 LinkCreated:=False;
752 Log('Line {#__LINE__}: Creating symbolic link "'+FileName+'" failed, will try a hard link.');
753 end;
755 if not LinkCreated then begin
757 // This will throw an exception on pre-Win2k systems.
758 LinkCreated:=CreateHardLink(FileName,AppDir+'\bin\git.exe',0);
759 except
760 LinkCreated:=False;
761 Log('Line {#__LINE__}: Creating hardlink "'+FileName+'" failed, will try a copy.');
762 end;
763 end;
765 if not LinkCreated then begin
766 if not FileCopy(AppDir+'\bin\git.exe',FileName,False) then begin
767 Log('Line {#__LINE__}: Creating copy "'+FileName+'" failed, giving up.');
768 // This is not a critical error, Git could basically be used without the
769 // aliases for built-ins, so we continue.
770 end;
771 end;
772 end;
774 // Delete any duplicate files in case we are updating from a non-libexec to a libexec directory layout.
775 if FindFirst(AppDir+'\libexec\git-core\*',FindRec) then begin
776 repeat
777 if (FindRec.Attributes and FILE_ATTRIBUTE_DIRECTORY)=0 then begin
778 FileName:=AppDir+'\bin\'+FindRec.name;
779 if (Pos(FindRec.name,'git.exe')<>1) and FileExists(FileName) and (not DeleteFile(FileName)) then begin
780 Log('Line {#__LINE__}: Unable to delete dupe "'+FileName+'", ignoring.');
781 end;
782 end;
783 until not FindNext(FindRec);
784 FindClose(FindRec);
785 end;
786 end else begin
787 Msg:='Line {#__LINE__}: Unable to read file "{#APP_BUILTINS}".';
788 MsgBox(Msg,mbError,MB_OK);
789 Log(Msg);
790 // This is not a critical error, Git could basically be used without the
791 // aliases for built-ins, so we continue.
792 end;
795 Adapt core.autocrlf
798 if RdbCRLF[GC_LFOnly].checked then begin
799 Cmd:='core.autocrlf input';
800 end else if RdbCRLF[GC_CRLFAlways].checked then begin
801 Cmd:='core.autocrlf true';
802 end else begin
803 Cmd:='core.autocrlf false';
804 end;
805 if not Exec(AppDir + '\bin\git.exe', 'config -f gitconfig ' + Cmd,
806 AppDir + '\etc', SW_HIDE, ewWaitUntilTerminated, i) then begin
807 Msg:='Unable to configure the line ending conversion: ' + Cmd;
808 MsgBox(Msg,mbError,MB_OK);
809 Log(Msg);
810 // This is not a critical error, the user can probably fix it manually,
811 // so we continue.
812 end;
815 Modify the environment
817 This must happen no later than ssPostInstall to make
818 "ChangesEnvironment=yes" not happend before the change!
821 FileName:=AppDir+'\setup.ini';
823 // Delete GIT_SSH and SVN_SSH if a previous installation set them (this is required for the GS_OpenSSH case).
824 EnvSSH:=GetEnvStrings('GIT_SSH',IsAdminLoggedOn);
825 if (GetArrayLength(EnvSSH)=1) and
826 (CompareStr(RemoveQuotes(EnvSSH[0]),GetIniString('Environment','GIT_SSH','',FileName))=0) then begin
827 if not SetEnvStrings('GIT_SSH',IsAdminLoggedOn,True,[]) then begin
828 Msg:='Line {#__LINE__}: Unable to reset GIT_SSH prior to install.';
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;
834 end;
836 EnvSSH:=GetEnvStrings('SVN_SSH',IsAdminLoggedOn);
837 if (GetArrayLength(EnvSSH)=1) and
838 (CompareStr(RemoveQuotes(EnvSSH[0]),GetIniString('Environment','SVN_SSH','',FileName))=0) then begin
839 if not SetEnvStrings('SVN_SSH',IsAdminLoggedOn,True,[]) then begin
840 Msg:='Line {#__LINE__}: Unable to reset SVN_SSH prior to install.';
841 MsgBox(Msg,mbError,MB_OK);
842 Log(Msg);
843 // This is not a critical error, the user can probably fix it manually,
844 // so we continue.
845 end;
846 end;
848 if (PuTTYPage<>NIL) and RdbSSH[GS_Plink].Checked then begin
849 SetArrayLength(EnvSSH,1);
850 EnvSSH[0]:=EdtPlink.Text;
852 // Set GIT_SSH as specified by the user.
853 if not SetEnvStrings('GIT_SSH',IsAdminLoggedOn,True,EnvSSH) then begin
854 Msg:='Line {#__LINE__}: Unable to set the GIT_SSH environment variable.';
855 MsgBox(Msg,mbError,MB_OK);
856 Log(Msg);
857 // This is not a critical error, the user can probably fix it manually,
858 // so we continue.
859 end;
861 // Mark that we have changed GIT_SSH by writing its value to a file.
862 if not SetIniString('Environment','GIT_SSH',EnvSSH[0],FileName) then begin
863 Msg:='Line {#__LINE__}: Unable to write to file "'+FileName+'".';
864 MsgBox(Msg,mbError,MB_OK);
865 Log(Msg);
866 // This is not a critical error, though uninstall / reinstall will probably not run cleanly,
867 // so we continue.
868 end;
870 // Set SVN_SSH as specified by the user, but with escaped backslashes and quotes.
871 StringChangeEx(EnvSSH[0],'\','\\',True);
872 EnvSSH[0]:=AddQuotes(EnvSSH[0]);
874 if not SetEnvStrings('SVN_SSH',IsAdminLoggedOn,True,EnvSSH) then begin
875 Msg:='Line {#__LINE__}: Unable to set the SVN_SSH environment variable.';
876 MsgBox(Msg,mbError,MB_OK);
877 Log(Msg);
878 // This is not a critical error, the user can probably fix it manually,
879 // so we continue.
880 end;
882 // Mark that we have changed SVN_SSH by writing its value to a file.
883 if not SetIniString('Environment','SVN_SSH',EnvSSH[0],FileName) then begin
884 Msg:='Line {#__LINE__}: Unable to write to file "'+FileName+'".';
885 MsgBox(Msg,mbError,MB_OK);
886 Log(Msg);
887 // This is not a critical error, though uninstall / reinstall will probably not run cleanly,
888 // so we continue.
889 end;
890 end;
892 // Get the current user's directories in PATH.
893 EnvPath:=GetEnvStrings('PATH',IsAdminLoggedOn);
895 // First, remove the installation directory from PATH in any case.
896 for i:=0 to GetArrayLength(EnvPath)-1 do begin
897 if Pos(AppDir+'\',EnvPath[i]+'\')=1 then begin
898 EnvPath[i]:='';
899 end;
900 end;
902 // Delete HOME if a previous installation modified it.
903 EnvHome:=GetEnvStrings('HOME',IsAdminLoggedOn);
904 if (GetArrayLength(EnvHome)=1) and
905 (CompareStr(RemoveQuotes(EnvHome[0]),GetIniString('Environment','HOME','',FileName))=0) then begin
906 if not SetEnvStrings('HOME',IsAdminLoggedOn,True,[]) then begin
907 Msg:='Line {#__LINE__}: Unable to reset HOME prior to install.';
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 // Modify the PATH variable as requested by the user.
916 if RdbPath[GP_Cmd].Checked or RdbPath[GP_CmdTools].Checked then begin
917 i:=GetArrayLength(EnvPath);
918 SetArrayLength(EnvPath,i+1);
920 // List \cmd before \bin so \cmd has higher priority and programs in
921 // there will be called in favor of those in \bin.
922 EnvPath[i]:=AppDir+'\cmd';
924 if RdbPath[GP_CmdTools].Checked then begin
925 SetArrayLength(EnvPath,i+2);
926 EnvPath[i+1]:=AppDir+'\bin';
928 // Set HOME for the Windows Command Prompt, but only if it has not been set manually before.
929 EnvHome:=GetEnvStrings('HOME',IsAdminLoggedOn);
930 i:=GetArrayLength(EnvHome);
931 if (i=0) or ((i=1) and (Length(EnvHome[0])=0)) then begin
932 SetArrayLength(EnvHome,1);
933 EnvHome[0]:=ExpandConstant('{%HOMEDRIVE}{%HOMEPATH}');
934 if not SetEnvStrings('HOME',IsAdminLoggedOn,True,EnvHome) then begin
935 Msg:='Line {#__LINE__}: Unable to set the HOME environment variable.';
936 MsgBox(Msg,mbError,MB_OK);
937 Log(Msg);
938 // This is not a critical error, the user can probably fix it manually,
939 // so we continue.
940 end;
942 // Mark that we have changed HOME.
943 if not SetIniString('Environment','HOME',EnvHome[0],FileName) then begin
944 Msg:='Line {#__LINE__}: Unable to write to file "'+FileName+'".';
945 MsgBox(Msg,mbError,MB_OK);
946 Log(Msg);
947 // This is not a critical error, though uninstall / reinstall will probably not run cleanly,
948 // so we continue.
949 end;
950 end;
951 end;
952 end;
954 // Set the current user's PATH directories.
955 if not SetEnvStrings('PATH',IsAdminLoggedOn,True,EnvPath) then begin
956 Msg:='Line {#__LINE__}: Unable to set the PATH environment variable.';
957 MsgBox(Msg,mbError,MB_OK);
958 Log(Msg);
959 // This is not a critical error, the user can probably fix it manually,
960 // so we continue.
961 end;
964 Create shortcuts that need to be created regardless of the "Don't create a Start Menu folder" toggle
967 Cmd:=ExpandConstant('{syswow64}\cmd.exe');
968 TempName:='/c ""'+AppDir+'\bin\sh.exe" --login -i"';
969 FileName:=AppDir+'\etc\git.ico';
971 if IsComponentSelected('icons\quicklaunch') then begin
972 CreateShellLink(
973 ExpandConstant('{userappdata}\Microsoft\Internet Explorer\Quick Launch\Git Bash.lnk')
974 , 'Git Bash'
975 , Cmd
976 , TempName
977 , '%HOMEDRIVE%%HOMEPATH%'
978 , FileName
980 , SW_SHOWNORMAL
982 end;
983 if IsComponentSelected('icons\desktop') then begin
984 CreateShellLink(
985 GetShellFolder('desktop')+'\Git Bash.lnk'
986 , 'Git Bash'
987 , Cmd
988 , TempName
989 , '%HOMEDRIVE%%HOMEPATH%'
990 , FileName
992 , SW_SHOWNORMAL
994 end;
996 // Create a special shortcut that does not set a working directory (Note: Since Inno Setup 5.3.11,
997 // passing an empty WorkingDir gets replaced with {sys}, so use '.' instead).
998 // This shortcut is used by "Git Bash.vbs", which in turn is run by the "Git Bash Here" shell extension.
999 CreateShellLink(
1000 AppDir+'\Git Bash.lnk'
1001 , 'Git Bash'
1002 , Cmd
1003 , TempName
1004 , '.'
1005 , FileName
1007 , SW_SHOWNORMAL
1011 Create the Windows Explorer integrations
1014 if IsAdminLoggedOn then begin
1015 RootKey:=HKEY_LOCAL_MACHINE;
1016 end else begin
1017 RootKey:=HKEY_CURRENT_USER;
1018 end;
1020 if IsComponentSelected('ext\reg\shellhere') then begin
1021 if (not RegWriteStringValue(RootKey,'SOFTWARE\Classes\Directory\shell\git_shell','','Git Ba&sh Here')) or
1022 (not RegWriteStringValue(RootKey,'SOFTWARE\Classes\Directory\shell\git_shell\command','','wscript "'+AppDir+'\Git Bash.vbs" "%1"')) then begin
1023 Msg:='Line {#__LINE__}: Unable to create "Git Bash Here" shell extension.';
1024 MsgBox(Msg,mbError,MB_OK);
1025 Log(Msg);
1026 // This is not a critical error, the user can probably fix it manually,
1027 // so we continue.
1028 end;
1029 end;
1031 if IsComponentSelected('ext\reg\guihere') then begin
1032 if (not RegWriteStringValue(RootKey,'SOFTWARE\Classes\Directory\shell\git_gui','','Git &GUI Here')) or
1033 (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
1034 Msg:='Line {#__LINE__}: Unable to create "Git GUI Here" shell extension.';
1035 MsgBox(Msg,mbError,MB_OK);
1036 Log(Msg);
1037 // This is not a critical error, the user can probably fix it manually,
1038 // so we continue.
1039 end;
1040 end;
1042 // It is either the Registry-based context menu entries, or the shell extension.
1043 if IsComponentSelected('ext\cheetah') then begin
1044 DeleteContextMenuEntries;
1046 FileName:=AppDir+'\git-cheetah\git_shell_ext.dll';
1047 if not ReplaceInUseFile(FileName,FileName+'.new',True) then begin
1048 Log('Line {#__LINE__}: Replacing file "'+FileName+'" failed.');
1049 end;
1050 end;
1051 end;
1053 procedure RegisterPreviousData(PreviousDataKey:Integer);
1055 Data:String;
1056 begin
1057 // Git Path options.
1058 Data:='';
1059 if RdbPath[GP_BashOnly].Checked then begin
1060 Data:='BashOnly';
1061 end else if RdbPath[GP_Cmd].Checked then begin
1062 Data:='Cmd';
1063 end else if RdbPath[GP_CmdTools].Checked then begin
1064 Data:='CmdTools';
1065 end;
1066 SetPreviousData(PreviousDataKey,'Path Option',Data);
1068 // Git SSH options.
1069 Data:='';
1070 if (PuTTYPage=NIL) or RdbSSH[GS_OpenSSH].Checked then begin
1071 Data:='OpenSSH';
1072 end else if RdbSSH[GS_Plink].Checked then begin
1073 Data:='Plink';
1074 end;
1075 SetPreviousData(PreviousDataKey,'SSH Option',Data);
1077 // Line ending conversion options.
1078 Data:='';
1079 if RdbCRLF[GC_LFOnly].Checked then begin
1080 Data:='LFOnly';
1081 end else if RdbCRLF[GC_CRLFAlways].Checked then begin
1082 Data:='CRLFAlways';
1083 end else if RdbCRLF[GC_CRLFCommitAsIs].Checked then begin
1084 Data:='CRLFCommitAsIs';
1085 end;
1086 SetPreviousData(PreviousDataKey,'CRLF Option',Data);
1087 end;
1090 Uninstaller code
1093 function InitializeUninstall:Boolean;
1095 Form:TSetupForm;
1096 Info:TLabel;
1097 ExitButton,RefreshButton:TButton;
1098 begin
1099 Result:=True;
1101 Form:=CreateCustomForm;
1103 Form.Caption:='Git Uninstall: Removing in-use files';
1104 Form.ClientWidth:=ScaleX(500);
1105 Form.ClientHeight:=ScaleY(256);
1106 Form.Center;
1108 Info:=TLabel.Create(Form);
1109 with Info do begin
1110 Parent:=Form;
1111 Left:=ScaleX(11);
1112 Top:=ScaleY(11);
1113 AutoSize:=True;
1114 Caption:='The following applications use files that need to be removed, please close them.';
1115 end;
1117 ContinueButton:=TButton.Create(Form);
1118 with ContinueButton do begin
1119 Parent:=Form;
1120 Left:=Form.ClientWidth-ScaleX(75+10);
1121 Top:=Form.ClientHeight-ScaleY(23+10);
1122 Width:=ScaleX(75);
1123 Height:=ScaleY(23);
1124 Caption:='Continue';
1125 ModalResult:=mrOk;
1126 end;
1128 ExitButton:=TButton.Create(Form);
1129 with ExitButton do begin
1130 Parent:=Form;
1131 Left:=ContinueButton.Left-ScaleX(75+6);
1132 Top:=ContinueButton.Top;
1133 Width:=ScaleX(75);
1134 Height:=ScaleY(23);
1135 Caption:='Exit';
1136 ModalResult:=mrCancel;
1137 Cancel:=True;
1138 end;
1140 RefreshButton:=TButton.Create(Form);
1141 with RefreshButton do begin
1142 Parent:=Form;
1143 Left:=ScaleX(10);
1144 Top:=ExitButton.Top;
1145 Width:=ScaleX(75);
1146 Height:=ScaleY(23);
1147 Caption:='Refresh';
1148 OnClick:=@RefreshProcessList;
1149 end;
1151 ProcessesListBox:=TListBox.Create(Form);
1152 with ProcessesListBox do begin
1153 Parent:=Form;
1154 Left:=ScaleX(11);
1155 Top:=Info.Top+Info.Height+11;
1156 Width:=Form.ClientWidth-ScaleX(11*2);
1157 Height:=ContinueButton.Top-ScaleY(11*4);
1158 end;
1160 Form.ActiveControl:=ContinueButton;
1162 RefreshProcessList(NIL);
1163 if GetArrayLength(Processes)>0 then begin
1164 // Now that these dialogs are going to be shown, we should probably
1165 // disable the "Are you sure to remove Git?" confirmation dialog, but
1166 // unfortunately that is not possible with Inno Setup currently.
1167 Result:=(Form.ShowModal()=mrOk);
1169 // Note: The number of processes might have changed during a refresh.
1170 if Result and (GetArrayLength(Processes)>0) then begin
1171 Result:=(MsgBox(
1172 'If you continue without closing the listed applications, you will need to log off and on again to remove some files manually.' + #13 + #13 +
1173 'Are you sure you want to continue anyway?',
1174 mbConfirmation,
1175 MB_YESNO
1176 )=IDYES);
1177 end;
1178 end;
1179 finally
1180 Form.free;
1181 end;
1182 end;
1184 // PreUninstall
1186 // Even though the name of this function suggests otherwise most of the
1187 // code below is only executed right before the actual uninstallation.
1188 // This happens because of the if-guard right in the beginning of this
1189 // function.
1190 procedure CurUninstallStepChanged(CurUninstallStep:TUninstallStep);
1192 AppDir,FileName,Msg:String;
1193 EnvPath,EnvHome,EnvSSH:TArrayOfString;
1194 i:Longint;
1195 begin
1196 if CurUninstallStep<>usUninstall then begin
1197 Exit;
1198 end;
1201 Modify the environment
1203 This must happen no later than usUninstall to make
1204 "ChangesEnvironment=yes" not happend before the change!
1207 AppDir:=ExpandConstant('{app}');
1208 FileName:=AppDir+'\setup.ini';
1210 // Delete the current user's GIT_SSH and SVN_SSH if we set it.
1211 EnvSSH:=GetEnvStrings('GIT_SSH',IsAdminLoggedOn);
1212 if (GetArrayLength(EnvSSH)=1) and
1213 (CompareStr(RemoveQuotes(EnvSSH[0]),GetIniString('Environment','GIT_SSH','',FileName))=0) then begin
1214 if not SetEnvStrings('GIT_SSH',IsAdminLoggedOn,True,[]) then begin
1215 Msg:='Line {#__LINE__}: Unable to revert any possible changes to GIT_SSH.';
1216 MsgBox(Msg,mbError,MB_OK);
1217 Log(Msg);
1218 // This is not a critical error, the user can probably fix it manually,
1219 // so we continue.
1220 end;
1221 end;
1223 EnvSSH:=GetEnvStrings('SVN_SSH',IsAdminLoggedOn);
1224 if (GetArrayLength(EnvSSH)=1) and
1225 (CompareStr(RemoveQuotes(EnvSSH[0]),GetIniString('Environment','SVN_SSH','',FileName))=0) then begin
1226 if not SetEnvStrings('SVN_SSH',IsAdminLoggedOn,True,[]) then begin
1227 Msg:='Line {#__LINE__}: Unable to revert any possible changes to SVN_SSH.';
1228 MsgBox(Msg,mbError,MB_OK);
1229 Log(Msg);
1230 // This is not a critical error, the user can probably fix it manually,
1231 // so we continue.
1232 end;
1233 end;
1235 // Get the current user's directories in PATH.
1236 EnvPath:=GetEnvStrings('PATH',IsAdminLoggedOn);
1238 // Remove the installation directory from PATH in any case, even if it
1239 // was not added by the installer.
1240 for i:=0 to GetArrayLength(EnvPath)-1 do begin
1241 if Pos(AppDir+'\',EnvPath[i]+'\')=1 then begin
1242 EnvPath[i]:='';
1243 end;
1244 end;
1246 // Reset the current user's directories in PATH.
1247 if not SetEnvStrings('PATH',IsAdminLoggedOn,True,EnvPath) then begin
1248 Msg:='Line {#__LINE__}: Unable to revert any possible changes to PATH.';
1249 MsgBox(Msg,mbError,MB_OK);
1250 Log(Msg);
1251 // This is not a critical error, the user can probably fix it manually,
1252 // so we continue.
1253 end;
1255 // Reset the current user's HOME if we modified it.
1256 EnvHome:=GetEnvStrings('HOME',IsAdminLoggedOn);
1257 if (GetArrayLength(EnvHome)=1) and
1258 (CompareStr(RemoveQuotes(EnvHome[0]),GetIniString('Environment','HOME','',FileName))=0) then begin
1259 if not SetEnvStrings('HOME',IsAdminLoggedOn,True,[]) then begin
1260 Msg:='Line {#__LINE__}: Unable to revert any possible changes to HOME.';
1261 MsgBox(Msg,mbError,MB_OK);
1262 Log(Msg);
1263 // This is not a critical error, the user can probably fix it manually,
1264 // so we continue.
1265 end;
1266 end;
1268 if FileExists(FileName) and (not DeleteFile(FileName)) then begin
1269 Msg:='Line {#__LINE__}: Unable to delete file "'+FileName+'".';
1270 MsgBox(Msg,mbError,MB_OK);
1271 Log(Msg);
1272 // This is not a critical error, the user can probably fix it manually,
1273 // so we continue.
1274 end;
1277 Delete the Windows Explorer integrations
1280 DeleteContextMenuEntries;
1282 FileName:=AppDir+'\git-cheetah\git_shell_ext.dll';
1283 if FileExists(FileName) then begin
1284 if not UnregisterServer(Is64BitInstallMode,FileName,False) then begin
1285 Msg:='Line {#__LINE__}: Unable to unregister file "'+FileName+'". Please do it manually by running "regsvr32 /u '+ExtractFileName(FileName)+'".';
1286 MsgBox(Msg,mbError,MB_OK);
1287 Log(Msg);
1288 end;
1290 if not DeleteFile(FileName) then begin
1291 Msg:='Line {#__LINE__}: Unable to delete file "'+FileName+'". Please do it manually after logging off and on again.';
1292 MsgBox(Msg,mbError,MB_OK);
1293 Log(Msg);
1294 end;
1295 end;
1296 end;