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