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