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