Installer: Detect TortoisePLink from TortoiseGit
[msysgit.git] / share / WinGit / install.iss
blobecb52654417ddbbeb946bf336512b404571b403a
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'
5 #define APP_BINDIMAGE 'etc\fileList-bindimage.txt'
7 #define COMP_CONSOLE_FONT 'Use a TrueType font in all console windows (not only for Git Bash)'
9 #define DROP_HANDLER_GUID '{{86C86720-42A0-1069-A2E8-08002B30309D}}'
11 [Setup]
12 ; Compiler-related
13 Compression=lzma2/ultra
14 LZMAUseSeparateProcess=yes
15 OutputBaseFilename={#APP_NAME+'-'+APP_VERSION}
16 OutputDir={#GetEnv('USERPROFILE')}
17 SolidCompression=yes
19 ; Uncomment the line below to be able to compile the script from within the IDE.
20 ;SourceDir={#GetEnv('TEMP')}\WinGit
22 ; Installer-related
23 AllowNoIcons=yes
24 AppName={#APP_NAME}
25 AppPublisherURL={#APP_URL}
26 AppVersion={#APP_VERSION}
27 ChangesEnvironment=yes
28 DefaultDirName={pf}\{#APP_NAME}
29 DefaultGroupName={#APP_NAME}
30 DisableReadyPage=yes
31 InfoBeforeFile=gpl-2.0.rtf
32 PrivilegesRequired=none
33 UninstallDisplayIcon=etc\git.ico
35 ; Cosmetic
36 SetupIconFile=etc\git.ico
37 WizardImageBackColor=clWhite
38 WizardImageStretch=no
39 WizardImageFile=git.bmp
40 WizardSmallImageFile=gitsmall.bmp
42 [Types]
43 ; Define a dummy type to avoid getting the default ones.
44 Name: custom; Description: Custom installation; Flags: iscustom
46 [Components]
47 Name: icons; Description: Additional icons; Types: custom
48 Name: icons\quicklaunch; Description: In the Quick Launch; Types: custom
49 Name: icons\desktop; Description: On the Desktop; Types: custom
50 Name: ext; Description: Windows Explorer integration; Types: custom
51 Name: ext\reg; Description: Simple context menu (Registry based); Flags: exclusive; Types: custom
52 Name: ext\reg\shellhere; Description: Git Bash Here; Types: custom
53 Name: ext\reg\guihere; Description: Git GUI Here; Types: custom
54 Name: ext\cheetah; Description: Advanced context menu (git-cheetah plugin); Flags: exclusive; Types: custom
55 Name: assoc; Description: Associate .git* configuration files with the default text editor; Types: custom
56 Name: assoc_sh; Description: Associate .sh files to be run with Bash; Types: custom
57 Name: consolefont; Description: {#COMP_CONSOLE_FONT}; Types: custom
59 [Files]
60 ; Install files that might be in use during setup under a different name.
61 Source: git-cheetah\git_shell_ext.dll; DestDir: {app}\git-cheetah; DestName: git_shell_ext.dll.new; Flags: replacesameversion; Components: ext\cheetah
62 Source: git-cheetah\git_shell_ext64.dll; DestDir: {app}\git-cheetah; DestName: git_shell_ext64.dll.new; Flags: replacesameversion; Components: ext\cheetah
64 Source: *; DestDir: {app}; Excludes: \*.bmp, gpl-2.0.rtf, \*.iss, \tmp.*, \bin\*install*, \git-cheetah\git_shell_ext.dll, \git-cheetah\git_shell_ext64.dll; Flags: recursesubdirs replacesameversion
65 Source: ReleaseNotes.rtf; DestDir: {app}; Flags: isreadme replacesameversion
67 [Icons]
68 Name: {group}\Git GUI; Filename: {app}\bin\wish.exe; Parameters: """{app}\libexec\git-core\git-gui"""; WorkingDir: %HOMEDRIVE%%HOMEPATH%; IconFilename: {app}\etc\git.ico
69 Name: {group}\Git Bash; Filename: {syswow64}\cmd.exe; Parameters: "/c """"{app}\bin\sh.exe"" --login -i"""; WorkingDir: %HOMEDRIVE%%HOMEPATH%; IconFilename: {app}\etc\git.ico
71 [Messages]
72 BeveledLabel={#APP_URL}
73 SetupAppTitle={#APP_NAME} Setup
74 SetupWindowTitle={#APP_NAME} Setup
76 [Registry]
77 ; There is no "Console" key in HKLM.
78 Root: HKCU; Subkey: Console; ValueType: string; ValueName: FaceName; ValueData: Lucida Console; Flags: uninsclearvalue; Components: consolefont
79 Root: HKCU; Subkey: Console; ValueType: dword; ValueName: FontFamily; ValueData: $00000036; Components: consolefont
80 Root: HKCU; Subkey: Console; ValueType: dword; ValueName: FontSize; ValueData: $000e0000; Components: consolefont
81 Root: HKCU; Subkey: Console; ValueType: dword; ValueName: FontWeight; ValueData: $00000190; Components: consolefont
83 Root: HKCU; Subkey: Console\Git Bash; ValueType: string; ValueName: FaceName; ValueData: Lucida Console; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty
84 Root: HKCU; Subkey: Console\Git Bash; ValueType: dword; ValueName: FontFamily; ValueData: $00000036; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty
85 Root: HKCU; Subkey: Console\Git Bash; ValueType: dword; ValueName: FontSize; ValueData: $000e0000; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty
86 Root: HKCU; Subkey: Console\Git Bash; ValueType: dword; ValueName: FontWeight; ValueData: $00000190; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty
88 ; Note that we write the Registry values below either to HKLM or to HKCU depending on whether the user running the installer
89 ; is a member of the local Administrators group or not (see the "Check" argument).
91 ; File associations for configuration files that may be contained in a repository (so this does not include ".gitconfig").
92 Root: HKLM; Subkey: Software\Classes\.gitattributes; ValueType: string; ValueData: txtfile; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty; Check: IsAdminLoggedOn; Components: assoc
93 Root: HKLM; Subkey: Software\Classes\.gitattributes; ValueType: string; ValueName: Content Type; ValueData: text/plain; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty; Check: IsAdminLoggedOn; Components: assoc
94 Root: HKLM; Subkey: Software\Classes\.gitattributes; ValueType: string; ValueName: PerceivedType; ValueData: text; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty; Check: IsAdminLoggedOn; Components: assoc
95 Root: HKCU; Subkey: Software\Classes\.gitattributes; ValueType: string; ValueData: txtfile; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty; Check: not IsAdminLoggedOn; Components: assoc
96 Root: HKCU; Subkey: Software\Classes\.gitattributes; ValueType: string; ValueName: Content Type; ValueData: text/plain; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty; Check: not IsAdminLoggedOn; Components: assoc
97 Root: HKCU; Subkey: Software\Classes\.gitattributes; ValueType: string; ValueName: PerceivedType; ValueData: text; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty; Check: not IsAdminLoggedOn; Components: assoc
99 Root: HKLM; Subkey: Software\Classes\.gitignore; ValueType: string; ValueData: txtfile; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty; Check: IsAdminLoggedOn; Components: assoc
100 Root: HKLM; Subkey: Software\Classes\.gitignore; ValueType: string; ValueName: Content Type; ValueData: text/plain; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty; Check: IsAdminLoggedOn; Components: assoc
101 Root: HKLM; Subkey: Software\Classes\.gitignore; ValueType: string; ValueName: PerceivedType; ValueData: text; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty; Check: IsAdminLoggedOn; Components: assoc
102 Root: HKCU; Subkey: Software\Classes\.gitignore; ValueType: string; ValueData: txtfile; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty; Check: not IsAdminLoggedOn; Components: assoc
103 Root: HKCU; Subkey: Software\Classes\.gitignore; ValueType: string; ValueName: Content Type; ValueData: text/plain; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty; Check: not IsAdminLoggedOn; Components: assoc
104 Root: HKCU; Subkey: Software\Classes\.gitignore; ValueType: string; ValueName: PerceivedType; ValueData: text; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty; Check: not IsAdminLoggedOn; Components: assoc
106 Root: HKLM; Subkey: Software\Classes\.gitmodules; ValueType: string; ValueData: txtfile; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty; Check: IsAdminLoggedOn; Components: assoc
107 Root: HKLM; Subkey: Software\Classes\.gitmodules; ValueType: string; ValueName: Content Type; ValueData: text/plain; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty; Check: IsAdminLoggedOn; Components: assoc
108 Root: HKLM; Subkey: Software\Classes\.gitmodules; ValueType: string; ValueName: PerceivedType; ValueData: text; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty; Check: IsAdminLoggedOn; Components: assoc
109 Root: HKCU; Subkey: Software\Classes\.gitmodules; ValueType: string; ValueData: txtfile; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty; Check: not IsAdminLoggedOn; Components: assoc
110 Root: HKCU; Subkey: Software\Classes\.gitmodules; ValueType: string; ValueName: Content Type; ValueData: text/plain; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty; Check: not IsAdminLoggedOn; Components: assoc
111 Root: HKCU; Subkey: Software\Classes\.gitmodules; ValueType: string; ValueName: PerceivedType; ValueData: text; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty; Check: not IsAdminLoggedOn; Components: assoc
113 ; Associate .sh extension with sh.exe so those files are double-clickable,
114 ; startable from cmd.exe, and when files are dropped on them they are passed
115 ; as arguments to the script.
117 ; Install under HKEY_LOCAL_MACHINE if an administrator is installing.
118 Root: HKLM; Subkey: Software\Classes\.sh; ValueType: string; ValueData: sh_auto_file; Flags: createvalueifdoesntexist uninsdeletekeyifempty uninsdeletevalue; Check: IsAdminLoggedOn; Components: assoc_sh
119 Root: HKLM; Subkey: Software\Classes\sh_auto_file; ValueType: string; ValueData: "Shell Script"; Flags: createvalueifdoesntexist uninsdeletekeyifempty uninsdeletevalue; Check: IsAdminLoggedOn; Components: assoc_sh
120 Root: HKLM; Subkey: Software\Classes\sh_auto_file\shell\open\command; ValueType: string; ValueData: "{syswow64}\cmd.exe /C """"{app}\bin\sh.exe"" ""--login"" ""%1"" %*"""; Flags: createvalueifdoesntexist uninsdeletekeyifempty uninsdeletevalue; Check: IsAdminLoggedOn; Components: assoc_sh
121 Root: HKLM; Subkey: Software\Classes\sh_auto_file\DefaultIcon; ValueType: string; ValueData: "%SystemRoot%\System32\shell32.dll,-153"; Flags: createvalueifdoesntexist uninsdeletekeyifempty uninsdeletevalue; Check: IsAdminLoggedOn; Components: assoc_sh
122 Root: HKLM; Subkey: Software\Classes\sh_auto_file\ShellEx\DropHandler; ValueType: string; ValueData: {#DROP_HANDLER_GUID}; Flags: createvalueifdoesntexist uninsdeletekeyifempty uninsdeletevalue; Check: IsAdminLoggedOn; Components: assoc_sh
124 ; Install under HKEY_CURRENT_USER if a non-administrator is installing.
125 Root: HKCU; Subkey: Software\Classes\.sh; ValueType: string; ValueData: sh_auto_file; Flags: createvalueifdoesntexist uninsdeletekeyifempty uninsdeletevalue; Check: not IsAdminLoggedOn; Components: assoc_sh
126 Root: HKCU; Subkey: Software\Classes\sh_auto_file; ValueType: string; ValueData: "Shell Script"; Flags: createvalueifdoesntexist uninsdeletekeyifempty uninsdeletevalue; Check: not IsAdminLoggedOn; Components: assoc_sh
127 Root: HKCU; Subkey: Software\Classes\sh_auto_file\shell\open\command; ValueType: string; ValueData: "{syswow64}\cmd.exe /C """"{app}\bin\sh.exe"" ""--login"" ""%1"" %*"""; Flags: createvalueifdoesntexist uninsdeletekeyifempty uninsdeletevalue; Check: not IsAdminLoggedOn; Components: assoc_sh
128 Root: HKCU; Subkey: Software\Classes\sh_auto_file\DefaultIcon; ValueType: string; ValueData: "%SystemRoot%\System32\shell32.dll,-153"; Flags: createvalueifdoesntexist uninsdeletekeyifempty uninsdeletevalue; Check: not IsAdminLoggedOn; Components: assoc_sh
129 Root: HKCU; Subkey: Software\Classes\sh_auto_file\ShellEx\DropHandler; ValueType: string; ValueData: {#DROP_HANDLER_GUID}; Flags: createvalueifdoesntexist uninsdeletekeyifempty uninsdeletevalue; Check: not IsAdminLoggedOn; Components: assoc_sh
131 [UninstallDelete]
132 ; Delete the built-ins.
133 Type: files; Name: {app}\bin\git-*.exe
134 Type: files; Name: {app}\libexec\git-core\git-*.exe
135 Type: files; Name: {app}\libexec\git-core\git.exe
137 ; Delete any (temporary) git-cheetah files.
138 Type: files; Name: {app}\git-cheetah\*.*
140 ; Delete any manually created shortcuts.
141 Type: files; Name: {userappdata}\Microsoft\Internet Explorer\Quick Launch\Git Bash.lnk
142 Type: files; Name: {code:GetShellFolder|desktop}\Git Bash.lnk
143 Type: files; Name: {app}\Git Bash.lnk
145 ; Delete a home directory inside the msysGit directory.
146 Type: dirifempty; Name: {app}\home\{username}
147 Type: dirifempty; Name: {app}\home
149 [Code]
150 #include "helpers.inc.iss"
151 #include "environment.inc.iss"
152 #include "putty.inc.iss"
153 #include "modules.inc.iss"
155 function CreateHardLink(lpFileName,lpExistingFileName:String;lpSecurityAttributes:Integer):Boolean;
156 #ifdef UNICODE
157 external 'CreateHardLinkW@Kernel32.dll stdcall delayload setuponly';
158 #else
159 external 'CreateHardLinkA@Kernel32.dll stdcall delayload setuponly';
160 #endif
162 function BindImageEx(Flags:DWORD;ImageName,DllPath,SymbolPath:AnsiString;StatusRoutine:Integer):Boolean;
163 external 'BindImageEx@Imagehlp.dll stdcall delayload setuponly';
165 const
166 // Git Path options.
167 GP_BashOnly = 1;
168 GP_Cmd = 2;
169 GP_CmdTools = 3;
171 // Git SSH options.
172 GS_OpenSSH = 1;
173 GS_Plink = 2;
175 // Git line ending conversion options.
176 GC_LFOnly = 1;
177 GC_CRLFAlways = 2;
178 GC_CRLFCommitAsIs = 3;
180 // BindImageEx API constants.
181 BIND_NO_BOUND_IMPORTS = $00000001;
182 BIND_NO_UPDATE = $00000002;
183 BIND_ALL_IMAGES = $00000004;
184 BIND_CACHE_IMPORT_DLLS = $00000008;
187 // Wizard page and variables for the Path options.
188 PathPage:TWizardPage;
189 RdbPath:array[GP_BashOnly..GP_CmdTools] of TRadioButton;
191 // Wizard page and variables for the SSH options.
192 PuTTYPage:TWizardPage;
193 RdbSSH:array[GS_OpenSSH..GS_Plink] of TRadioButton;
194 EdtPlink:TEdit;
196 // Wizard page and variables for the line ending conversion options.
197 CRLFPage:TWizardPage;
198 RdbCRLF:array[GC_LFOnly..GC_CRLFCommitAsIs] of TRadioButton;
200 // Wizard page and variables for the processes page.
201 SessionHandle:DWORD;
202 Processes:ProcessList;
203 ProcessesPage:TWizardPage;
204 ProcessesListBox:TListBox;
205 ProcessesRefresh,ContinueButton:TButton;
207 procedure BrowseForPuTTYFolder(Sender:TObject);
209 Path:String;
210 begin
211 Path:=ExtractFilePath(EdtPlink.Text);
212 BrowseForFolder('Please select the PuTTY folder:',Path,False);
213 if FileExists(Path+'\TortoisePlink.exe') then begin
214 EdtPlink.Text:=Path+'\TortoisePlink.exe';
215 RdbSSH[GS_Plink].Checked:=True;
216 end else if FileExists(Path+'\plink.exe') then begin
217 EdtPlink.Text:=Path+'\plink.exe';
218 RdbSSH[GS_Plink].Checked:=True;
219 end else begin
220 MsgBox('Please enter a valid path to "TortoisePlink.exe" or "plink.exe".',mbError,MB_OK);
221 end;
222 end;
224 procedure DeleteContextMenuEntries;
226 AppDir,Command,Msg:String;
227 RootKey:Integer;
228 begin
229 AppDir:=ExpandConstant('{app}');
231 if IsAdminLoggedOn then begin
232 RootKey:=HKEY_LOCAL_MACHINE;
233 end else begin
234 RootKey:=HKEY_CURRENT_USER;
235 end;
237 Command:='';
238 RegQueryStringValue(RootKey,'SOFTWARE\Classes\Directory\shell\git_shell\command','',Command);
239 if Pos(AppDir,Command)>0 then begin
240 if not RegDeleteKeyIncludingSubkeys(RootKey,'SOFTWARE\Classes\Directory\shell\git_shell') then begin
241 Msg:='Line {#__LINE__}: Unable to remove "Git Bash Here" shell extension.';
242 MsgBox(Msg,mbError,MB_OK);
243 Log(Msg);
244 // This is not a critical error, the user can probably fix it manually,
245 // so we continue.
246 end;
247 end;
249 Command:='';
250 RegQueryStringValue(RootKey,'SOFTWARE\Classes\Directory\shell\git_gui\command','',Command);
251 if Pos(AppDir,Command)>0 then begin
252 if not RegDeleteKeyIncludingSubkeys(RootKey,'SOFTWARE\Classes\Directory\shell\git_gui') then begin
253 Msg:='Line {#__LINE__}: Unable to remove "Git GUI Here" shell extension.';
254 MsgBox(Msg,mbError,MB_OK);
255 Log(Msg);
256 // This is not a critical error, the user can probably fix it manually,
257 // so we continue.
258 end;
259 end;
260 end;
262 procedure RefreshProcessList(Sender:TObject);
264 Version:TWindowsVersion;
265 Modules:TArrayOfString;
266 ProcsCloseRequired,ProcsCloseOptional:ProcessList;
267 i:Longint;
268 Caption:String;
269 ManualClosingRequired:Boolean;
270 begin
271 GetWindowsVersionEx(Version);
273 // Use the Restart Manager API when installing the shell extension on Windows Vista and above.
274 if Version.Major>=6 then begin
275 SetArrayLength(Modules,5);
276 Modules[0]:=ExpandConstant('{app}\bin\msys-1.0.dll');
277 Modules[1]:=ExpandConstant('{app}\bin\tcl85.dll');
278 Modules[2]:=ExpandConstant('{app}\bin\tk85.dll');
279 Modules[3]:=ExpandConstant('{app}\git-cheetah\git_shell_ext.dll');
280 Modules[4]:=ExpandConstant('{app}\git-cheetah\git_shell_ext64.dll');
281 SessionHandle:=FindProcessesUsingModules(Modules,Processes);
282 end else begin
283 SetArrayLength(Modules,3);
284 Modules[0]:=ExpandConstant('{app}\bin\msys-1.0.dll');
285 Modules[1]:=ExpandConstant('{app}\bin\tcl85.dll');
286 Modules[2]:=ExpandConstant('{app}\bin\tk85.dll');
287 SessionHandle:=FindProcessesUsingModules(Modules,ProcsCloseRequired);
289 SetArrayLength(Modules,2);
290 Modules[0]:=ExpandConstant('{app}\git-cheetah\git_shell_ext.dll');
291 Modules[1]:=ExpandConstant('{app}\git-cheetah\git_shell_ext64.dll');
292 SessionHandle:=FindProcessesUsingModules(Modules,ProcsCloseOptional) or SessionHandle;
294 // Misuse the "Restartable" flag to indicate which processes are required
295 // to be closed before setup can continue, and which just should be closed
296 // in order to make changes take effect immediately.
297 SetArrayLength(Processes,GetArrayLength(ProcsCloseRequired)+GetArrayLength(ProcsCloseOptional));
298 for i:=0 to GetArrayLength(ProcsCloseRequired)-1 do begin
299 Processes[i]:=ProcsCloseRequired[i];
300 Processes[i].Restartable:=False;
301 end;
302 for i:=0 to GetArrayLength(ProcsCloseOptional)-1 do begin
303 Processes[GetArrayLength(ProcsCloseRequired)+i]:=ProcsCloseOptional[i];
304 Processes[GetArrayLength(ProcsCloseRequired)+i].Restartable:=True;
305 end;
306 end;
308 ManualClosingRequired:=False;
310 ProcessesListBox.Items.Clear;
311 if (Sender=NIL) or (SessionHandle>0) then begin
312 for i:=0 to GetArrayLength(Processes)-1 do begin
313 Caption:=Processes[i].Name+' (PID '+IntToStr(Processes[i].ID);
314 if Processes[i].Restartable then begin
315 Caption:=Caption+', closing is optional';
316 end else begin
317 Caption:=Caption+', closing is required';
318 ManualClosingRequired:=True;
319 end;
320 Caption:=Caption+')';
321 ProcessesListBox.Items.Append(Caption);
322 end;
323 end;
325 if ContinueButton<>NIL then begin
326 ContinueButton.Enabled:=not ManualClosingRequired;
327 end;
328 end;
331 Installer code
334 procedure InitializeWizard;
336 i,PrevPageID:Integer;
337 LblGitBash,LblGitCmd,LblGitCmdTools,LblGitCmdToolsWarn:TLabel;
338 LblOpenSSH,LblPlink:TLabel;
339 PuTTYSessions:TArrayOfString;
340 LblLFOnly,LblCRLFAlways,LblCRLFCommitAsIs:TLabel;
341 BtnPlink:TButton;
342 Data:String;
343 begin
345 PrevPageID:=wpSelectProgramGroup;
348 * Create a custom page for modifying the environment.
351 PathPage:=CreateCustomPage(
352 PrevPageID,
353 'Adjusting your PATH environment',
354 'How would you like to use Git from the command line?'
356 PrevPageID:=PathPage.ID;
358 // 1st choice
359 RdbPath[GP_BashOnly]:=TRadioButton.Create(PathPage);
360 with RdbPath[GP_BashOnly] do begin
361 Parent:=PathPage.Surface;
362 Caption:='Use Git Bash only';
363 Left:=ScaleX(4);
364 Top:=ScaleY(8);
365 Width:=ScaleX(129);
366 Height:=ScaleY(17);
367 Font.Style:=[fsBold];
368 TabOrder:=0;
369 Checked:=True;
370 end;
371 LblGitBash:=TLabel.Create(PathPage);
372 with LblGitBash do begin
373 Parent:=PathPage.Surface;
374 Caption:=
375 'This is the most conservative choice if you are concerned about the stability' + #13 +
376 'of your system. Your PATH will not be modified.';
377 Left:=ScaleX(28);
378 Top:=ScaleY(32);
379 Width:=ScaleX(405);
380 Height:=ScaleY(26);
381 end;
383 // 2nd choice
384 RdbPath[GP_Cmd]:=TRadioButton.Create(PathPage);
385 with RdbPath[GP_Cmd] do begin
386 Parent:=PathPage.Surface;
387 Caption:='Run Git from the Windows Command Prompt';
388 Left:=ScaleX(4);
389 Top:=ScaleY(76);
390 Width:=ScaleX(281);
391 Height:=ScaleY(17);
392 Font.Style:=[fsBold];
393 TabOrder:=1;
394 end;
395 LblGitCmd:=TLabel.Create(PathPage);
396 with LblGitCmd do begin
397 Parent:=PathPage.Surface;
398 Caption:=
399 'This option is considered safe and no conflicts with other tools are known.' + #13 +
400 'Only Git will be added to your PATH. Use this option if you want to use Git' + #13 +
401 'from a Cygwin Prompt (make sure to not have Cygwin''s Git installed).';
402 Left:=ScaleX(28);
403 Top:=ScaleY(100);
404 Width:=ScaleX(405);
405 Height:=ScaleY(39);
406 end;
408 // 3rd choice
409 RdbPath[GP_CmdTools]:=TRadioButton.Create(PathPage);
410 with RdbPath[GP_CmdTools] do begin
411 Parent:=PathPage.Surface;
412 Caption:='Run Git and included Unix tools from the Windows Command Prompt';
413 Left:=ScaleX(4);
414 Top:=ScaleY(152);
415 Width:=ScaleX(405);
416 Height:=ScaleY(17);
417 Font.Style:=[fsBold];
418 TabOrder:=2;
419 end;
420 LblGitCmdTools:=TLabel.Create(PathPage);
421 with LblGitCmdTools do begin
422 Parent:=PathPage.Surface;
423 Caption:='Both Git and its accompanying Unix tools will be added to your PATH.';
424 Left:=ScaleX(28);
425 Top:=ScaleY(176);
426 Width:=ScaleX(405);
427 Height:=ScaleY(13);
428 end;
429 LblGitCmdToolsWarn:=TLabel.Create(PathPage);
430 with LblGitCmdToolsWarn do begin
431 Parent:=PathPage.Surface;
432 Caption:=
433 'Warning: This will override Windows tools like find.exe and' + #13 +
434 'sort.exe. Select this option only if you understand the implications.';
435 Left:=ScaleX(28);
436 Top:=ScaleY(192);
437 Width:=ScaleX(376);
438 Height:=ScaleY(26);
439 Font.Color:=255;
440 Font.Style:=[fsBold];
441 end;
443 // Restore the setting chosen during a previous install.
444 Data:=GetPreviousData('Path Option','BashOnly');
445 if Data='BashOnly' then begin
446 RdbPath[GP_BashOnly].Checked:=True;
447 end else if Data='Cmd' then begin
448 RdbPath[GP_Cmd].Checked:=True;
449 end else if Data='CmdTools' then begin
450 RdbPath[GP_CmdTools].Checked:=True;
451 end;
454 * Create a custom page for using (Tortoise)Plink instead of OpenSSH
455 * if at least one PuTTY session is found in the Registry.
458 if RegGetSubkeyNames(HKEY_CURRENT_USER,'Software\SimonTatham\PuTTY\Sessions',PuTTYSessions) and (GetArrayLength(PuTTYSessions)>0) then begin
459 PuTTYPage:=CreateCustomPage(
460 PrevPageID,
461 'Choosing the SSH executable',
462 'Which Secure Shell client program would you like Git to use?'
464 PrevPageID:=PuTTYPage.ID;
466 // 1st choice
467 RdbSSH[GS_OpenSSH]:=TRadioButton.Create(PuTTYPage);
468 with RdbSSH[GS_OpenSSH] do begin
469 Parent:=PuTTYPage.Surface;
470 Caption:='Use OpenSSH';
471 Left:=ScaleX(4);
472 Top:=ScaleY(8);
473 Width:=ScaleX(129);
474 Height:=ScaleY(17);
475 Font.Style:=[fsBold];
476 TabOrder:=0;
477 Checked:=True;
478 end;
479 LblOpenSSH:=TLabel.Create(PuTTYPage);
480 with LblOpenSSH do begin
481 Parent:=PuTTYPage.Surface;
482 Caption:=
483 'This uses ssh.exe that comes with Git. The GIT_SSH and SVN_SSH' + #13 +
484 'environment variables will not be modified.';
485 Left:=ScaleX(28);
486 Top:=ScaleY(32);
487 Width:=ScaleX(324);
488 Height:=ScaleY(26);
489 end;
491 // 2nd choice
492 RdbSSH[GS_Plink]:=TRadioButton.Create(PuTTYPage);
493 with RdbSSH[GS_Plink] do begin
494 Parent:=PuTTYPage.Surface;
495 Caption:='Use (Tortoise)Plink';
496 Left:=ScaleX(4);
497 Top:=ScaleY(76);
498 Width:=ScaleX(281);
499 Height:=ScaleY(17);
500 Font.Style:=[fsBold];
501 TabOrder:=1;
502 end;
503 LblPlink:=TLabel.Create(PuTTYPage);
504 with LblPlink do begin
505 Parent:=PuTTYPage.Surface;
506 Caption:=
507 'PuTTY sessions were found in your Registry. You may specify the path' + #13 +
508 'to an existing copy of (Tortoise)Plink.exe from the TortoiseGit/SVN/CVS' + #13 +
509 'or PuTTY applications. The GIT_SSH and SVN_SSH environment' + #13 +
510 'variables will be adjusted to point to the following executable:';
511 Left:=ScaleX(28);
512 Top:=ScaleY(100);
513 Width:=ScaleX(340);
514 Height:=ScaleY(52);
515 end;
516 EdtPlink:=TEdit.Create(PuTTYPage);
517 with EdtPlink do begin
518 Parent:=PuTTYPage.Surface;
519 Text:=GetPuTTYLocation;
520 if not FileExists(Text) then begin
521 Text:='';
522 end;
523 Left:=ScaleX(28);
524 Top:=ScaleY(161);
525 Width:=ScaleX(316);
526 Height:=ScaleY(13);
527 end;
528 BtnPlink:=TButton.Create(PuTTYPage);
529 with BtnPlink do begin
530 Parent:=PuTTYPage.Surface;
531 Caption:='...';
532 OnClick:=@BrowseForPuTTYFolder;
533 Left:=ScaleX(348);
534 Top:=ScaleY(161);
535 Width:=ScaleX(21);
536 Height:=ScaleY(21);
537 end;
539 // Restore the setting chosen during a previous install.
540 Data:=GetPreviousData('SSH Option','OpenSSH');
541 if Data='OpenSSH' then begin
542 RdbSSH[GS_OpenSSH].Checked:=True;
543 end else if Data='Plink' then begin
544 RdbSSH[GS_Plink].Checked:=True;
545 end;
546 end else begin
547 PuTTYPage:=NIL;
548 end;
551 * Create a custom page for the core.autocrlf setting.
554 CRLFPage:=CreateCustomPage(
555 PrevPageID,
556 'Configuring the line ending conversions',
557 'How should Git treat line endings in text files?'
559 PrevPageID:=CRLFPage.ID;
561 // 1st choice
562 RdbCRLF[GC_CRLFAlways]:=TRadioButton.Create(CRLFPage);
563 with RdbCRLF[GC_CRLFAlways] do begin
564 Parent:=CRLFPage.Surface;
565 Caption:='Checkout Windows-style, commit Unix-style line endings';
566 Left:=ScaleX(4);
567 Top:=ScaleY(8);
568 Width:=ScaleX(340);
569 Height:=ScaleY(17);
570 Font.Style:=[fsBold];
571 TabOrder:=0;
572 Checked:=True;
573 end;
574 LblCRLFAlways:=TLabel.Create(CRLFPage);
575 with LblCRLFAlways do begin
576 Parent:=CRLFPage.Surface;
577 Caption:=
578 'Git will convert LF to CRLF when checking out text files. When committing' + #13 +
579 'text files, CRLF will be converted to LF. For cross-platform projects,' + #13 +
580 'this is the recommended setting on Windows ("core.autocrlf" is set to "true").';
581 Left:=ScaleX(28);
582 Top:=ScaleY(32);
583 Width:=ScaleX(380);
584 Height:=ScaleY(47);
585 end;
587 // 2nd choice
588 RdbCRLF[GC_LFOnly]:=TRadioButton.Create(CRLFPage);
589 with RdbCRLF[GC_LFOnly] do begin
590 Parent:=CRLFPage.Surface;
591 Caption:='Checkout as-is, commit Unix-style line endings';
592 Left:=ScaleX(4);
593 Top:=ScaleY(80);
594 Width:=ScaleX(340);
595 Height:=ScaleY(17);
596 Font.Style:=[fsBold];
597 TabOrder:=1;
598 Checked:=False;
599 end;
600 LblLFOnly:=TLabel.Create(CRLFPage);
601 with LblLFOnly do begin
602 Parent:=CRLFPage.Surface;
603 Caption:=
604 'Git will not perform any conversion when checking out text files. When' + #13 +
605 'committing text files, CRLF will be converted to LF. For cross-platform projects,' + #13 +
606 'this is the recommended setting on Unix ("core.autocrlf" is set to "input").';
607 Left:=ScaleX(28);
608 Top:=ScaleY(104);
609 Width:=ScaleX(380);
610 Height:=ScaleY(47);
611 end;
613 // 3rd choice
614 RdbCRLF[GC_CRLFCommitAsIs]:=TRadioButton.Create(CRLFPage);
615 with RdbCRLF[GC_CRLFCommitAsIs] do begin
616 Parent:=CRLFPage.Surface;
617 Caption:='Checkout as-is, commit as-is';
618 Left:=ScaleX(4);
619 Top:=ScaleY(152);
620 Width:=ScaleX(340);
621 Height:=ScaleY(17);
622 Font.Style:=[fsBold];
623 TabOrder:=2;
624 Checked:=False;
625 end;
626 LblCRLFCommitAsIs:=TLabel.Create(CRLFPage);
627 with LblCRLFCommitAsIs do begin
628 Parent:=CRLFPage.Surface;
629 Caption:=
630 'Git will not perform any conversions when checking out or committing' + #13 +
631 'text files. Choosing this option is not recommended for cross-platform' + #13 +
632 'projects ("core.autocrlf" is set to "false").';
633 Left:=ScaleX(28);
634 Top:=ScaleY(176);
635 Width:=ScaleX(380);
636 Height:=ScaleY(47);
637 end;
639 // Restore the setting chosen during a previous install.
640 Data:=GetPreviousData('CRLF Option','CRLFAlways');
641 if Data='LFOnly' then begin
642 RdbCRLF[GC_LFOnly].Checked:=True;
643 end else if Data='CRLFAlways' then begin
644 RdbCRLF[GC_CRLFAlways].Checked:=True;
645 end else if Data='CRLFCommitAsIs' then begin
646 RdbCRLF[GC_CRLFCommitAsIs].Checked:=True;
647 end;
650 * Create a custom page for finding the processes that lock a module.
653 ProcessesPage:=CreateCustomPage(
654 wpPreparing,
655 'Replacing in-use files',
656 'The following applications use files that need to be replaced, please close them.'
659 ProcessesListBox:=TListBox.Create(ProcessesPage);
660 with ProcessesListBox do begin
661 Parent:=ProcessesPage.Surface;
662 Width:=ProcessesPage.SurfaceWidth;
663 Height:=ProcessesPage.SurfaceHeight-ScaleY(8);
664 end;
666 ProcessesRefresh:=TNewButton.Create(WizardForm);
667 with ProcessesRefresh do begin
668 Parent:=WizardForm;
669 Width:=WizardForm.CancelButton.Width;
670 Height:=WizardForm.CancelButton.Height;
671 Top:=WizardForm.CancelButton.Top;
672 Left:=WizardForm.ClientWidth-(WizardForm.CancelButton.Left+WizardForm.CancelButton.Width);
673 Caption:='&Refresh';
674 OnClick:=@RefreshProcessList;
675 end;
677 // This button is only used by the uninstaller.
678 ContinueButton:=NIL;
680 // Initially hide the Refresh button, show it when the process page becomes current.
681 ProcessesRefresh.Hide;
682 end;
684 function ShouldSkipPage(PageID:Integer):Boolean;
685 begin
686 if (ProcessesPage<>NIL) and (PageID=ProcessesPage.ID) then begin
687 // This page is only reached forward (by pressing "Next", never by pressing "Back").
688 RefreshProcessList(NIL);
689 Result:=(GetArrayLength(Processes)=0);
690 end else begin
691 Result:=False;
692 end;
693 end;
695 procedure CurPageChanged(CurPageID:Integer);
697 i:Integer;
698 begin
699 // Uncheck the console font option by default.
700 if CurPageID=wpSelectComponents then begin
701 for i:=0 to WizardForm.ComponentsList.Items.Count-1 do begin
702 if WizardForm.ComponentsList.ItemCaption[i]='{#COMP_CONSOLE_FONT}' then begin
703 WizardForm.ComponentsList.Checked[i]:=False;
704 Break;
705 end;
706 end;
707 end;
709 // Show the "Refresh" button only on the processes page.
710 if (ProcessesPage<>NIL) and (CurPageID=ProcessesPage.ID) then begin
711 ProcessesRefresh.Show;
712 end else begin
713 ProcessesRefresh.Hide;
714 end;
715 end;
717 function NextButtonClick(CurPageID:Integer):Boolean;
719 i:Integer;
720 Version:TWindowsVersion;
721 begin
722 Result:=True;
724 if (PuTTYPage<>NIL) and (CurPageID=PuTTYPage.ID) then begin
725 Result:=RdbSSH[GS_OpenSSH].Checked or
726 (RdbSSH[GS_Plink].Checked and FileExists(EdtPlink.Text));
727 if not Result then begin
728 MsgBox('Please enter a valid path to (Tortoise)Plink.exe.',mbError,MB_OK);
729 end;
730 end else if (ProcessesPage<>NIL) and (CurPageID=ProcessesPage.ID) then begin
731 // It would have been nicer to just disable the "Next" button, but the
732 // WizardForm exports the button just read-only.
733 for i:=0 to GetArrayLength(Processes)-1 do begin
734 if not Processes[i].Restartable then begin
735 MsgBox('Setup cannot continue until you close at least those applications in the list that are marked as "closing is required".',mbCriticalError,MB_OK);
736 Result:=False;
737 Exit;
738 end;
739 end;
741 Result:=(GetArrayLength(Processes)=0);
743 if not Result then begin
744 GetWindowsVersionEx(Version);
745 if Version.Major>=6 then begin
746 Result:=(MsgBox(
747 'If you continue without closing the listed applications they will be closed and restarted automatically.' + #13 + #13 +
748 'Are you sure you want to continue?',
749 mbConfirmation,
750 MB_YESNO
751 )=IDYES);
752 end else begin
753 Result:=(MsgBox(
754 'If you continue without closing the listed applications you will need to log off and on again before changes take effect.' + #13 + #13 +
755 'Are you sure you want to continue anyway?',
756 mbConfirmation,
757 MB_YESNO
758 )=IDYES);
759 end;
760 end;
761 end;
762 end;
764 procedure CurStepChanged(CurStep:TSetupStep);
766 AppDir,DllPath,FileName,TempName,Cmd,Msg:String;
767 BuiltIns,ImageNames,EnvPath,EnvHome,EnvSSH:TArrayOfString;
768 Count,i:Longint;
769 LinkCreated:Boolean;
770 FindRec:TFindRec;
771 RootKey:Integer;
772 begin
773 if CurStep=ssInstall then begin
774 // Shutdown locking processes just before the actual installation starts.
775 if SessionHandle>0 then try
776 RmShutdown(SessionHandle,RmShutdownOnlyRegistered,0);
777 except
778 Log('Line {#__LINE__}: RmShutdown not supported.');
779 end;
781 Exit;
782 end;
784 // Make sure the code below is only executed just after the actual installation finishes.
785 if CurStep<>ssPostInstall then begin
786 Exit;
787 end;
789 AppDir:=ExpandConstant('{app}');
792 Bind the imported function addresses
796 DllPath:=ExpandConstant('{app}\bin;{sys}');
798 // Load the list of images from a text file.
799 FileName:=AppDir+'\{#APP_BINDIMAGE}';
800 if LoadStringsFromFile(FileName,ImageNames) then begin
801 Count:=GetArrayLength(ImageNames)-1;
802 for i:=0 to Count do begin
803 FileName:=AppDir+'\'+ImageNames[i];
804 if not BindImageEx(BIND_NO_BOUND_IMPORTS or BIND_CACHE_IMPORT_DLLS,FileName,DllPath,'',0) then begin
805 Log('Line {#__LINE__}: Error calling BindImageEx for "'+FileName+'".');
806 end;
807 end;
808 end;
809 except
810 Log('Line {#__LINE__}: An exception occurred while calling BindImageEx.');
811 end;
814 Create the built-ins
817 // Load the built-ins from a text file.
818 FileName:=AppDir+'\{#APP_BUILTINS}';
819 if LoadStringsFromFile(FileName,BuiltIns) then begin
820 Count:=GetArrayLength(BuiltIns)-1;
822 // Delete those scripts from "bin" which have been replaced by built-ins in "libexec\git-core".
823 for i:=0 to Count do begin
824 FileName:=AppDir+'\bin\'+ChangeFileExt(ExtractFileName(BuiltIns[i]),'');
825 if FileExists(FileName) and (not DeleteFile(FileName)) then begin
826 Log('Line {#__LINE__}: Unable to delete script "'+FileName+'", ignoring.');
827 end;
828 end;
830 // Create built-ins as aliases for git.exe.
831 for i:=0 to Count do begin
832 FileName:=AppDir+'\'+BuiltIns[i];
834 // Delete any existing built-in.
835 if FileExists(FileName) and (not DeleteFile(FileName)) then begin
836 Log('Line {#__LINE__}: Unable to delete existing built-in "'+FileName+'", skipping.');
837 continue;
838 end;
841 // This will throw an exception on pre-Win2k systems.
842 LinkCreated:=CreateHardLink(FileName,AppDir+'\bin\git.exe',0);
843 except
844 LinkCreated:=False;
845 Log('Line {#__LINE__}: Creating hardlink "'+FileName+'" failed, will try a copy.');
846 end;
848 if not LinkCreated then begin
849 if not FileCopy(AppDir+'\bin\git.exe',FileName,False) then begin
850 Log('Line {#__LINE__}: Creating copy "'+FileName+'" failed, giving up.');
851 // This is not a critical error, Git could basically be used without the
852 // aliases for built-ins, so we continue.
853 end;
854 end;
855 end;
857 // Delete any duplicate files in case we are updating from a non-libexec to a libexec directory layout.
858 if FindFirst(AppDir+'\libexec\git-core\*',FindRec) then begin
859 repeat
860 if (FindRec.Attributes and FILE_ATTRIBUTE_DIRECTORY)=0 then begin
861 FileName:=AppDir+'\bin\'+FindRec.name;
862 if (Pos(FindRec.name,'git.exe')<>1) and FileExists(FileName) and (not DeleteFile(FileName)) then begin
863 Log('Line {#__LINE__}: Unable to delete dupe "'+FileName+'", ignoring.');
864 end;
865 end;
866 until not FindNext(FindRec);
867 FindClose(FindRec);
868 end;
869 end else begin
870 Msg:='Line {#__LINE__}: Unable to read file "{#APP_BUILTINS}".';
871 MsgBox(Msg,mbError,MB_OK);
872 Log(Msg);
873 // This is not a critical error, Git could basically be used without the
874 // aliases for built-ins, so we continue.
875 end;
878 Adapt core.autocrlf
881 if RdbCRLF[GC_LFOnly].checked then begin
882 Cmd:='core.autocrlf input';
883 end else if RdbCRLF[GC_CRLFAlways].checked then begin
884 Cmd:='core.autocrlf true';
885 end else begin
886 Cmd:='core.autocrlf false';
887 end;
888 if not Exec(AppDir + '\bin\git.exe', 'config -f gitconfig ' + Cmd,
889 AppDir + '\etc', SW_HIDE, ewWaitUntilTerminated, i) then begin
890 Msg:='Unable to configure the line ending conversion: ' + Cmd;
891 MsgBox(Msg,mbError,MB_OK);
892 Log(Msg);
893 // This is not a critical error, the user can probably fix it manually,
894 // so we continue.
895 end;
898 Modify the environment
900 This must happen no later than ssPostInstall to make
901 "ChangesEnvironment=yes" not happend before the change!
904 FileName:=AppDir+'\setup.ini';
906 // Delete GIT_SSH and SVN_SSH if a previous installation set them (this is required for the GS_OpenSSH case).
907 EnvSSH:=GetEnvStrings('GIT_SSH',IsAdminLoggedOn);
908 if (GetArrayLength(EnvSSH)=1) and
909 (CompareStr(RemoveQuotes(EnvSSH[0]),GetIniString('Environment','GIT_SSH','',FileName))=0) then begin
910 if not SetEnvStrings('GIT_SSH',IsAdminLoggedOn,True,[]) then begin
911 Msg:='Line {#__LINE__}: Unable to reset GIT_SSH prior to install.';
912 MsgBox(Msg,mbError,MB_OK);
913 Log(Msg);
914 // This is not a critical error, the user can probably fix it manually,
915 // so we continue.
916 end;
917 end;
919 EnvSSH:=GetEnvStrings('SVN_SSH',IsAdminLoggedOn);
920 if (GetArrayLength(EnvSSH)=1) and
921 (CompareStr(RemoveQuotes(EnvSSH[0]),GetIniString('Environment','SVN_SSH','',FileName))=0) then begin
922 if not SetEnvStrings('SVN_SSH',IsAdminLoggedOn,True,[]) then begin
923 Msg:='Line {#__LINE__}: Unable to reset SVN_SSH prior to install.';
924 MsgBox(Msg,mbError,MB_OK);
925 Log(Msg);
926 // This is not a critical error, the user can probably fix it manually,
927 // so we continue.
928 end;
929 end;
931 if (PuTTYPage<>NIL) and RdbSSH[GS_Plink].Checked then begin
932 SetArrayLength(EnvSSH,1);
933 EnvSSH[0]:=EdtPlink.Text;
935 // Set GIT_SSH as specified by the user.
936 if not SetEnvStrings('GIT_SSH',IsAdminLoggedOn,True,EnvSSH) then begin
937 Msg:='Line {#__LINE__}: Unable to set the GIT_SSH environment variable.';
938 MsgBox(Msg,mbError,MB_OK);
939 Log(Msg);
940 // This is not a critical error, the user can probably fix it manually,
941 // so we continue.
942 end;
944 // Mark that we have changed GIT_SSH by writing its value to a file.
945 if not SetIniString('Environment','GIT_SSH',EnvSSH[0],FileName) then begin
946 Msg:='Line {#__LINE__}: Unable to write to file "'+FileName+'".';
947 MsgBox(Msg,mbError,MB_OK);
948 Log(Msg);
949 // This is not a critical error, though uninstall / reinstall will probably not run cleanly,
950 // so we continue.
951 end;
953 if not SetEnvStrings('SVN_SSH',IsAdminLoggedOn,True,EnvSSH) then begin
954 Msg:='Line {#__LINE__}: Unable to set the SVN_SSH environment variable.';
955 MsgBox(Msg,mbError,MB_OK);
956 Log(Msg);
957 // This is not a critical error, the user can probably fix it manually,
958 // so we continue.
959 end;
961 // Mark that we have changed SVN_SSH by writing its value to a file.
962 if not SetIniString('Environment','SVN_SSH',EnvSSH[0],FileName) then begin
963 Msg:='Line {#__LINE__}: Unable to write to file "'+FileName+'".';
964 MsgBox(Msg,mbError,MB_OK);
965 Log(Msg);
966 // This is not a critical error, though uninstall / reinstall will probably not run cleanly,
967 // so we continue.
968 end;
969 end;
971 // Get the current user's directories in PATH.
972 EnvPath:=GetEnvStrings('PATH',IsAdminLoggedOn);
974 // First, remove the installation directory from PATH in any case.
975 for i:=0 to GetArrayLength(EnvPath)-1 do begin
976 if Pos(AppDir+'\',EnvPath[i]+'\')=1 then begin
977 EnvPath[i]:='';
978 end;
979 end;
981 // Delete HOME if a previous installation modified it.
982 EnvHome:=GetEnvStrings('HOME',IsAdminLoggedOn);
983 if (GetArrayLength(EnvHome)=1) and
984 (CompareStr(RemoveQuotes(EnvHome[0]),GetIniString('Environment','HOME','',FileName))=0) then begin
985 if not SetEnvStrings('HOME',IsAdminLoggedOn,True,[]) then begin
986 Msg:='Line {#__LINE__}: Unable to reset HOME prior to install.';
987 MsgBox(Msg,mbError,MB_OK);
988 Log(Msg);
989 // This is not a critical error, the user can probably fix it manually,
990 // so we continue.
991 end;
992 end;
994 // Modify the PATH variable as requested by the user.
995 if RdbPath[GP_Cmd].Checked or RdbPath[GP_CmdTools].Checked then begin
996 i:=GetArrayLength(EnvPath);
997 SetArrayLength(EnvPath,i+1);
999 // List \cmd before \bin so \cmd has higher priority and programs in
1000 // there will be called in favor of those in \bin.
1001 EnvPath[i]:=AppDir+'\cmd';
1003 if RdbPath[GP_CmdTools].Checked then begin
1004 SetArrayLength(EnvPath,i+2);
1005 EnvPath[i+1]:=AppDir+'\bin';
1007 // Set HOME for the Windows Command Prompt, but only if it has not been set manually before.
1008 EnvHome:=GetEnvStrings('HOME',IsAdminLoggedOn);
1009 i:=GetArrayLength(EnvHome);
1010 if (i=0) or ((i=1) and (Length(EnvHome[0])=0)) then begin
1011 SetArrayLength(EnvHome,1);
1012 EnvHome[0]:=ExpandConstant('{%HOMEDRIVE}{%HOMEPATH}');
1013 if not SetEnvStrings('HOME',IsAdminLoggedOn,True,EnvHome) then begin
1014 Msg:='Line {#__LINE__}: Unable to set the HOME environment variable.';
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 // Mark that we have changed HOME.
1022 if not SetIniString('Environment','HOME',EnvHome[0],FileName) then begin
1023 Msg:='Line {#__LINE__}: Unable to write to file "'+FileName+'".';
1024 MsgBox(Msg,mbError,MB_OK);
1025 Log(Msg);
1026 // This is not a critical error, though uninstall / reinstall will probably not run cleanly,
1027 // so we continue.
1028 end;
1029 end;
1030 end;
1031 end;
1033 // Set the current user's PATH directories.
1034 if not SetEnvStrings('PATH',IsAdminLoggedOn,True,EnvPath) then begin
1035 Msg:='Line {#__LINE__}: Unable to set the PATH environment variable.';
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 Create shortcuts that need to be created regardless of the "Don't create a Start Menu folder" toggle
1046 Cmd:=ExpandConstant('{syswow64}\cmd.exe');
1047 TempName:='/c ""'+AppDir+'\bin\sh.exe" --login -i"';
1048 FileName:=AppDir+'\etc\git.ico';
1050 if IsComponentSelected('icons\quicklaunch') then begin
1051 CreateShellLink(
1052 ExpandConstant('{userappdata}\Microsoft\Internet Explorer\Quick Launch\Git Bash.lnk')
1053 , 'Git Bash'
1054 , Cmd
1055 , TempName
1056 , '%HOMEDRIVE%%HOMEPATH%'
1057 , FileName
1059 , SW_SHOWNORMAL
1061 end;
1062 if IsComponentSelected('icons\desktop') then begin
1063 CreateShellLink(
1064 GetShellFolder('desktop')+'\Git Bash.lnk'
1065 , 'Git Bash'
1066 , Cmd
1067 , TempName
1068 , '%HOMEDRIVE%%HOMEPATH%'
1069 , FileName
1071 , SW_SHOWNORMAL
1073 end;
1075 // Create a special shortcut that does not set a working directory (Note: Since Inno Setup 5.3.11,
1076 // passing an empty WorkingDir gets replaced with {sys}, so use '.' instead).
1077 // This shortcut is used by "Git Bash.vbs", which in turn is run by the "Git Bash Here" shell extension.
1078 CreateShellLink(
1079 AppDir+'\Git Bash.lnk'
1080 , 'Git Bash'
1081 , Cmd
1082 , TempName
1083 , '.'
1084 , FileName
1086 , SW_SHOWNORMAL
1090 Create the Windows Explorer integrations
1093 if IsAdminLoggedOn then begin
1094 RootKey:=HKEY_LOCAL_MACHINE;
1095 end else begin
1096 RootKey:=HKEY_CURRENT_USER;
1097 end;
1099 if IsComponentSelected('ext\reg\shellhere') then begin
1100 if (not RegWriteStringValue(RootKey,'SOFTWARE\Classes\Directory\shell\git_shell','','Git Ba&sh Here')) or
1101 (not RegWriteStringValue(RootKey,'SOFTWARE\Classes\Directory\shell\git_shell\command','','"'+ExpandConstant('{syswow64}')+'\wscript" "'+AppDir+'\Git Bash.vbs" "%1"')) then begin
1102 Msg:='Line {#__LINE__}: Unable to create "Git Bash Here" shell extension.';
1103 MsgBox(Msg,mbError,MB_OK);
1104 Log(Msg);
1105 // This is not a critical error, the user can probably fix it manually,
1106 // so we continue.
1107 end;
1108 end;
1110 if IsComponentSelected('ext\reg\guihere') then begin
1111 if (not RegWriteStringValue(RootKey,'SOFTWARE\Classes\Directory\shell\git_gui','','Git &GUI Here')) or
1112 (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
1113 Msg:='Line {#__LINE__}: Unable to create "Git GUI Here" shell extension.';
1114 MsgBox(Msg,mbError,MB_OK);
1115 Log(Msg);
1116 // This is not a critical error, the user can probably fix it manually,
1117 // so we continue.
1118 end;
1119 end;
1121 // It is either the Registry-based context menu entries, or the shell extension.
1122 if IsComponentSelected('ext\cheetah') then begin
1123 DeleteContextMenuEntries;
1125 if isWin64 then begin
1126 FileName:=AppDir+'\git-cheetah\git_shell_ext64.dll';
1127 end else begin
1128 FileName:=AppDir+'\git-cheetah\git_shell_ext.dll';
1129 end;
1130 if not ReplaceInUseFile(FileName,FileName+'.new',True) then begin
1131 Log('Line {#__LINE__}: Replacing file "'+FileName+'" failed.');
1132 end;
1133 end;
1136 Restart any processes that were shut down via the Restart Manager
1139 if SessionHandle>0 then try
1140 RmRestart(SessionHandle,0,0);
1141 RmEndSession(SessionHandle);
1142 except
1143 Log('Line {#__LINE__}: RmRestart not supported.');
1144 end;
1145 end;
1147 procedure RegisterPreviousData(PreviousDataKey:Integer);
1149 Data:String;
1150 begin
1151 // Git Path options.
1152 Data:='';
1153 if RdbPath[GP_BashOnly].Checked then begin
1154 Data:='BashOnly';
1155 end else if RdbPath[GP_Cmd].Checked then begin
1156 Data:='Cmd';
1157 end else if RdbPath[GP_CmdTools].Checked then begin
1158 Data:='CmdTools';
1159 end;
1160 SetPreviousData(PreviousDataKey,'Path Option',Data);
1162 // Git SSH options.
1163 Data:='';
1164 if (PuTTYPage=NIL) or RdbSSH[GS_OpenSSH].Checked then begin
1165 Data:='OpenSSH';
1166 end else if RdbSSH[GS_Plink].Checked then begin
1167 Data:='Plink';
1168 end;
1169 SetPreviousData(PreviousDataKey,'SSH Option',Data);
1171 // Line ending conversion options.
1172 Data:='';
1173 if RdbCRLF[GC_LFOnly].Checked then begin
1174 Data:='LFOnly';
1175 end else if RdbCRLF[GC_CRLFAlways].Checked then begin
1176 Data:='CRLFAlways';
1177 end else if RdbCRLF[GC_CRLFCommitAsIs].Checked then begin
1178 Data:='CRLFCommitAsIs';
1179 end;
1180 SetPreviousData(PreviousDataKey,'CRLF Option',Data);
1181 end;
1184 Uninstaller code
1187 function InitializeUninstall:Boolean;
1189 Form:TSetupForm;
1190 Info:TLabel;
1191 ExitButton,RefreshButton:TButton;
1192 begin
1193 Result:=True;
1195 Form:=CreateCustomForm;
1197 Form.Caption:='Git Uninstall: Removing in-use files';
1198 Form.ClientWidth:=ScaleX(500);
1199 Form.ClientHeight:=ScaleY(256);
1200 Form.Center;
1202 Info:=TLabel.Create(Form);
1203 with Info do begin
1204 Parent:=Form;
1205 Left:=ScaleX(11);
1206 Top:=ScaleY(11);
1207 AutoSize:=True;
1208 Caption:='The following applications use files that need to be removed, please close them.';
1209 end;
1211 ContinueButton:=TButton.Create(Form);
1212 with ContinueButton do begin
1213 Parent:=Form;
1214 Left:=Form.ClientWidth-ScaleX(75+10);
1215 Top:=Form.ClientHeight-ScaleY(23+10);
1216 Width:=ScaleX(75);
1217 Height:=ScaleY(23);
1218 Caption:='Continue';
1219 ModalResult:=mrOk;
1220 end;
1222 ExitButton:=TButton.Create(Form);
1223 with ExitButton do begin
1224 Parent:=Form;
1225 Left:=ContinueButton.Left-ScaleX(75+6);
1226 Top:=ContinueButton.Top;
1227 Width:=ScaleX(75);
1228 Height:=ScaleY(23);
1229 Caption:='Exit';
1230 ModalResult:=mrCancel;
1231 Cancel:=True;
1232 end;
1234 RefreshButton:=TButton.Create(Form);
1235 with RefreshButton do begin
1236 Parent:=Form;
1237 Left:=ScaleX(10);
1238 Top:=ExitButton.Top;
1239 Width:=ScaleX(75);
1240 Height:=ScaleY(23);
1241 Caption:='Refresh';
1242 OnClick:=@RefreshProcessList;
1243 end;
1245 ProcessesListBox:=TListBox.Create(Form);
1246 with ProcessesListBox do begin
1247 Parent:=Form;
1248 Left:=ScaleX(11);
1249 Top:=Info.Top+Info.Height+11;
1250 Width:=Form.ClientWidth-ScaleX(11*2);
1251 Height:=ContinueButton.Top-ScaleY(11*4);
1252 end;
1254 Form.ActiveControl:=ContinueButton;
1256 RefreshProcessList(NIL);
1257 if GetArrayLength(Processes)>0 then begin
1258 // Now that these dialogs are going to be shown, we should probably
1259 // disable the "Are you sure to remove Git?" confirmation dialog, but
1260 // unfortunately that is not possible with Inno Setup currently.
1261 Result:=(Form.ShowModal()=mrOk);
1263 // Note: The number of processes might have changed during a refresh.
1264 if Result and (GetArrayLength(Processes)>0) then begin
1265 Result:=(MsgBox(
1266 'If you continue without closing the listed applications, you will need to log off and on again to remove some files manually.' + #13 + #13 +
1267 'Are you sure you want to continue anyway?',
1268 mbConfirmation,
1269 MB_YESNO
1270 )=IDYES);
1271 end;
1272 end;
1273 finally
1274 Form.free;
1275 end;
1276 end;
1278 // PreUninstall
1280 // Even though the name of this function suggests otherwise most of the
1281 // code below is only executed right before the actual uninstallation.
1282 // This happens because of the if-guard right in the beginning of this
1283 // function.
1284 procedure CurUninstallStepChanged(CurUninstallStep:TUninstallStep);
1286 AppDir,FileName,Msg:String;
1287 EnvPath,EnvHome,EnvSSH:TArrayOfString;
1288 i:Longint;
1289 begin
1290 if CurUninstallStep<>usUninstall then begin
1291 Exit;
1292 end;
1294 // Reset the console font (the FontType is reset in the Registry section).
1295 if IsComponentInstalled('consolefont') then begin
1296 if MsgBox('Do you want to revert the TrueType font setting for all console windows?',mbConfirmation,MB_YESNO)=IDYES then begin
1297 RegWriteDWordValue(HKEY_CURRENT_USER,'Console','FontFamily',0);
1298 RegWriteDWordValue(HKEY_CURRENT_USER,'Console','FontSize',0);
1299 RegWriteDWordValue(HKEY_CURRENT_USER,'Console','FontWeight',0);
1300 end;
1301 end;
1304 Modify the environment
1306 This must happen no later than usUninstall to make
1307 "ChangesEnvironment=yes" not happend before the change!
1310 AppDir:=ExpandConstant('{app}');
1311 FileName:=AppDir+'\setup.ini';
1313 // Delete the current user's GIT_SSH and SVN_SSH if we set it.
1314 EnvSSH:=GetEnvStrings('GIT_SSH',IsAdminLoggedOn);
1315 if (GetArrayLength(EnvSSH)=1) and
1316 (CompareStr(RemoveQuotes(EnvSSH[0]),GetIniString('Environment','GIT_SSH','',FileName))=0) then begin
1317 if not SetEnvStrings('GIT_SSH',IsAdminLoggedOn,True,[]) then begin
1318 Msg:='Line {#__LINE__}: Unable to revert any possible changes to GIT_SSH.';
1319 MsgBox(Msg,mbError,MB_OK);
1320 Log(Msg);
1321 // This is not a critical error, the user can probably fix it manually,
1322 // so we continue.
1323 end;
1324 end;
1326 EnvSSH:=GetEnvStrings('SVN_SSH',IsAdminLoggedOn);
1327 if (GetArrayLength(EnvSSH)=1) and
1328 (CompareStr(RemoveQuotes(EnvSSH[0]),GetIniString('Environment','SVN_SSH','',FileName))=0) then begin
1329 if not SetEnvStrings('SVN_SSH',IsAdminLoggedOn,True,[]) then begin
1330 Msg:='Line {#__LINE__}: Unable to revert any possible changes to SVN_SSH.';
1331 MsgBox(Msg,mbError,MB_OK);
1332 Log(Msg);
1333 // This is not a critical error, the user can probably fix it manually,
1334 // so we continue.
1335 end;
1336 end;
1338 // Get the current user's directories in PATH.
1339 EnvPath:=GetEnvStrings('PATH',IsAdminLoggedOn);
1341 // Remove the installation directory from PATH in any case, even if it
1342 // was not added by the installer.
1343 for i:=0 to GetArrayLength(EnvPath)-1 do begin
1344 if Pos(AppDir+'\',EnvPath[i]+'\')=1 then begin
1345 EnvPath[i]:='';
1346 end;
1347 end;
1349 // Reset the current user's directories in PATH.
1350 if not SetEnvStrings('PATH',IsAdminLoggedOn,True,EnvPath) then begin
1351 Msg:='Line {#__LINE__}: Unable to revert any possible changes to PATH.';
1352 MsgBox(Msg,mbError,MB_OK);
1353 Log(Msg);
1354 // This is not a critical error, the user can probably fix it manually,
1355 // so we continue.
1356 end;
1358 // Reset the current user's HOME if we modified it.
1359 EnvHome:=GetEnvStrings('HOME',IsAdminLoggedOn);
1360 if (GetArrayLength(EnvHome)=1) and
1361 (CompareStr(RemoveQuotes(EnvHome[0]),GetIniString('Environment','HOME','',FileName))=0) then begin
1362 if not SetEnvStrings('HOME',IsAdminLoggedOn,True,[]) then begin
1363 Msg:='Line {#__LINE__}: Unable to revert any possible changes to HOME.';
1364 MsgBox(Msg,mbError,MB_OK);
1365 Log(Msg);
1366 // This is not a critical error, the user can probably fix it manually,
1367 // so we continue.
1368 end;
1369 end;
1371 if FileExists(FileName) and (not DeleteFile(FileName)) then begin
1372 Msg:='Line {#__LINE__}: Unable to delete file "'+FileName+'".';
1373 MsgBox(Msg,mbError,MB_OK);
1374 Log(Msg);
1375 // This is not a critical error, the user can probably fix it manually,
1376 // so we continue.
1377 end;
1380 Delete the Windows Explorer integrations
1383 DeleteContextMenuEntries;
1385 if isWin64 then begin
1386 FileName:=AppDir+'\git-cheetah\git_shell_ext64.dll';
1387 end else begin
1388 FileName:=AppDir+'\git-cheetah\git_shell_ext.dll';
1389 end;
1390 if FileExists(FileName) then begin
1391 if not UnregisterServer(Is64BitInstallMode,FileName,False) then begin
1392 Msg:='Line {#__LINE__}: Unable to unregister file "'+FileName+'". Please do it manually by running "regsvr32 /u '+ExtractFileName(FileName)+'".';
1393 MsgBox(Msg,mbError,MB_OK);
1394 Log(Msg);
1395 end;
1397 if not DeleteFile(FileName) then begin
1398 Msg:='Line {#__LINE__}: Unable to delete file "'+FileName+'". Please do it manually after logging off and on again.';
1399 MsgBox(Msg,mbError,MB_OK);
1400 Log(Msg);
1401 end;
1402 end;
1403 end;