Installer: Fix a typo
[msysgit.git] / share / WinGit / install.iss
bloba7899999b451e44ccbdd8e7f97fa2bbc7964727d
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.github.io/'
11 #define APP_BUILTINS 'etc\fileList-builtins.txt'
12 #define APP_BINDIMAGE 'etc\fileList-bindimage.txt'
14 #define PLINK_PATH_ERROR_MSG 'Please enter a valid path to a Plink executable.'
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 custom type to avoid getting the three default types.
61 Name: default; Description: Default installation; Flags: iscustom
63 [Components]
64 Name: icons; Description: Additional icons
65 Name: icons\quicklaunch; Description: In the Quick Launch
66 Name: icons\desktop; Description: On the Desktop
67 Name: ext; Description: Windows Explorer integration; Types: default
68 Name: ext\reg; Description: Simple context menu (Registry based); Flags: exclusive; Types: default
69 Name: ext\reg\shellhere; Description: Git Bash Here; Types: default
70 Name: ext\reg\guihere; Description: Git GUI Here; Types: default
71 Name: ext\cheetah; Description: Advanced context menu (git-cheetah plugin); Flags: exclusive; Types: default
72 Name: assoc; Description: Associate .git* configuration files with the default text editor; Types: default
73 Name: assoc_sh; Description: Associate .sh files to be run with Bash; Types: default
74 Name: consolefont; Description: Use a TrueType font in all console windows (not only for Git Bash)
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; AfterInstall: DeleteFromVirtualStore
79 Source: git-cheetah\git_shell_ext64.dll; DestDir: {app}\git-cheetah; DestName: git_shell_ext64.dll.new; Flags: replacesameversion; Components: ext\cheetah; AfterInstall: DeleteFromVirtualStore
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; AfterInstall: DeleteFromVirtualStore
82 Source: ReleaseNotes.rtf; DestDir: {app}; Flags: isreadme replacesameversion; AfterInstall: DeleteFromVirtualStore
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; OnlyBelowVersion: 6.0
87 Name: {group}\Git Bash; Filename: {app}\bin\sh.exe; Parameters: "--login -i"; WorkingDir: %HOMEDRIVE%%HOMEPATH%; IconFilename: {app}\etc\git.ico; MinVersion: 6.0
89 [Messages]
90 BeveledLabel={#APP_URL}
91 SetupAppTitle={#APP_NAME} Setup
92 SetupWindowTitle={#APP_NAME} Setup
94 [Registry]
95 ; There is no "Console" key in HKLM.
96 Root: HKCU; Subkey: Console; ValueType: string; ValueName: FaceName; ValueData: Lucida Console; Flags: uninsclearvalue; Components: consolefont
97 Root: HKCU; Subkey: Console; ValueType: dword; ValueName: FontFamily; ValueData: $00000036; Components: consolefont
98 Root: HKCU; Subkey: Console; ValueType: dword; ValueName: FontSize; ValueData: $000e0000; Components: consolefont
99 Root: HKCU; Subkey: Console; ValueType: dword; ValueName: FontWeight; ValueData: $00000190; Components: consolefont
101 Root: HKCU; Subkey: Console\Git Bash; ValueType: string; ValueName: FaceName; ValueData: Lucida Console; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty
102 Root: HKCU; Subkey: Console\Git Bash; ValueType: dword; ValueName: FontFamily; ValueData: $00000036; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty
103 Root: HKCU; Subkey: Console\Git Bash; ValueType: dword; ValueName: FontSize; ValueData: $000e0000; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty
104 Root: HKCU; Subkey: Console\Git Bash; ValueType: dword; ValueName: FontWeight; ValueData: $00000190; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty
106 ; Note that we write the Registry values below either to HKLM or to HKCU depending on whether the user running the installer
107 ; is a member of the local Administrators group or not (see the "Check" argument).
109 ; File associations for configuration files that may be contained in a repository (so this does not include ".gitconfig").
110 Root: HKLM; Subkey: Software\Classes\.gitattributes; ValueType: string; ValueData: txtfile; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty; Check: IsAdminLoggedOn; Components: assoc
111 Root: HKLM; Subkey: Software\Classes\.gitattributes; ValueType: string; ValueName: Content Type; ValueData: text/plain; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty; Check: IsAdminLoggedOn; Components: assoc
112 Root: HKLM; Subkey: Software\Classes\.gitattributes; ValueType: string; ValueName: PerceivedType; ValueData: text; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty; Check: IsAdminLoggedOn; Components: assoc
113 Root: HKCU; Subkey: Software\Classes\.gitattributes; ValueType: string; ValueData: txtfile; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty; Check: not IsAdminLoggedOn; Components: assoc
114 Root: HKCU; Subkey: Software\Classes\.gitattributes; ValueType: string; ValueName: Content Type; ValueData: text/plain; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty; Check: not IsAdminLoggedOn; Components: assoc
115 Root: HKCU; Subkey: Software\Classes\.gitattributes; ValueType: string; ValueName: PerceivedType; ValueData: text; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty; Check: not IsAdminLoggedOn; Components: assoc
117 Root: HKLM; Subkey: Software\Classes\.gitignore; ValueType: string; ValueData: txtfile; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty; Check: IsAdminLoggedOn; Components: assoc
118 Root: HKLM; Subkey: Software\Classes\.gitignore; ValueType: string; ValueName: Content Type; ValueData: text/plain; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty; Check: IsAdminLoggedOn; Components: assoc
119 Root: HKLM; Subkey: Software\Classes\.gitignore; ValueType: string; ValueName: PerceivedType; ValueData: text; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty; Check: IsAdminLoggedOn; Components: assoc
120 Root: HKCU; Subkey: Software\Classes\.gitignore; ValueType: string; ValueData: txtfile; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty; Check: not IsAdminLoggedOn; Components: assoc
121 Root: HKCU; Subkey: Software\Classes\.gitignore; ValueType: string; ValueName: Content Type; ValueData: text/plain; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty; Check: not IsAdminLoggedOn; Components: assoc
122 Root: HKCU; Subkey: Software\Classes\.gitignore; ValueType: string; ValueName: PerceivedType; ValueData: text; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty; Check: not IsAdminLoggedOn; Components: assoc
124 Root: HKLM; Subkey: Software\Classes\.gitmodules; ValueType: string; ValueData: txtfile; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty; Check: IsAdminLoggedOn; Components: assoc
125 Root: HKLM; Subkey: Software\Classes\.gitmodules; ValueType: string; ValueName: Content Type; ValueData: text/plain; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty; Check: IsAdminLoggedOn; Components: assoc
126 Root: HKLM; Subkey: Software\Classes\.gitmodules; ValueType: string; ValueName: PerceivedType; ValueData: text; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty; Check: IsAdminLoggedOn; Components: assoc
127 Root: HKCU; Subkey: Software\Classes\.gitmodules; ValueType: string; ValueData: txtfile; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty; Check: not IsAdminLoggedOn; Components: assoc
128 Root: HKCU; Subkey: Software\Classes\.gitmodules; ValueType: string; ValueName: Content Type; ValueData: text/plain; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty; Check: not IsAdminLoggedOn; Components: assoc
129 Root: HKCU; Subkey: Software\Classes\.gitmodules; ValueType: string; ValueName: PerceivedType; ValueData: text; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty; Check: not IsAdminLoggedOn; Components: assoc
131 ; Associate .sh extension with sh.exe so those files are double-clickable,
132 ; startable from cmd.exe, and when files are dropped on them they are passed
133 ; as arguments to the script.
135 ; Install under HKEY_LOCAL_MACHINE if an administrator is installing.
136 Root: HKLM; Subkey: Software\Classes\.sh; ValueType: string; ValueData: sh_auto_file; Flags: createvalueifdoesntexist uninsdeletekeyifempty uninsdeletevalue; Check: IsAdminLoggedOn; Components: assoc_sh
137 Root: HKLM; Subkey: Software\Classes\sh_auto_file; ValueType: string; ValueData: "Shell Script"; Flags: createvalueifdoesntexist uninsdeletekeyifempty uninsdeletevalue; Check: IsAdminLoggedOn; Components: assoc_sh
138 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; OnlyBelowVersion: 6.0
139 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; MinVersion: 6.0
140 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
141 Root: HKLM; Subkey: Software\Classes\sh_auto_file\ShellEx\DropHandler; ValueType: string; ValueData: {#DROP_HANDLER_GUID}; Flags: uninsdeletekeyifempty uninsdeletevalue; Check: IsAdminLoggedOn; Components: assoc_sh
143 ; Install under HKEY_CURRENT_USER if a non-administrator is installing.
144 Root: HKCU; Subkey: Software\Classes\.sh; ValueType: string; ValueData: sh_auto_file; Flags: createvalueifdoesntexist uninsdeletekeyifempty uninsdeletevalue; Check: not IsAdminLoggedOn; Components: assoc_sh
145 Root: HKCU; Subkey: Software\Classes\sh_auto_file; ValueType: string; ValueData: "Shell Script"; Flags: createvalueifdoesntexist uninsdeletekeyifempty uninsdeletevalue; Check: not IsAdminLoggedOn; Components: assoc_sh
146 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; OnlyBelowVersion: 6.0
147 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; MinVersion: 6.0
148 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
149 Root: HKCU; Subkey: Software\Classes\sh_auto_file\ShellEx\DropHandler; ValueType: string; ValueData: {#DROP_HANDLER_GUID}; Flags: uninsdeletekeyifempty uninsdeletevalue; Check: not IsAdminLoggedOn; Components: assoc_sh
151 [UninstallDelete]
152 ; Delete the built-ins.
153 Type: files; Name: {app}\bin\git-*.exe
154 Type: files; Name: {app}\libexec\git-core\git-*.exe
155 Type: files; Name: {app}\libexec\git-core\git.exe
157 ; Delete any (temporary) git-cheetah files.
158 Type: files; Name: {app}\git-cheetah\*.*
160 ; Delete any manually created shortcuts.
161 Type: files; Name: {userappdata}\Microsoft\Internet Explorer\Quick Launch\Git Bash.lnk
162 Type: files; Name: {code:GetShellFolder|desktop}\Git Bash.lnk
163 Type: files; Name: {app}\Git Bash.lnk
165 ; Delete a home directory inside the msysGit directory.
166 Type: dirifempty; Name: {app}\home\{username}
167 Type: dirifempty; Name: {app}\home
169 [Code]
170 #include "helpers.inc.iss"
171 #include "environment.inc.iss"
172 #include "putty.inc.iss"
173 #include "modules.inc.iss"
175 function CreateHardLink(lpFileName,lpExistingFileName:String;lpSecurityAttributes:Integer):Boolean;
176 #ifdef UNICODE
177 external 'CreateHardLinkW@Kernel32.dll stdcall delayload setuponly';
178 #else
179 external 'CreateHardLinkA@Kernel32.dll stdcall delayload setuponly';
180 #endif
182 function BindImageEx(Flags:DWORD;ImageName,DllPath,SymbolPath:AnsiString;StatusRoutine:Integer):Boolean;
183 external 'BindImageEx@Imagehlp.dll stdcall delayload setuponly';
185 const
186 // Git Path options.
187 GP_BashOnly = 1;
188 GP_Cmd = 2;
189 GP_CmdTools = 3;
191 // Git SSH options.
192 GS_OpenSSH = 1;
193 GS_Plink = 2;
195 // Git line ending conversion options.
196 GC_LFOnly = 1;
197 GC_CRLFAlways = 2;
198 GC_CRLFCommitAsIs = 3;
200 // BindImageEx API constants.
201 BIND_NO_BOUND_IMPORTS = $00000001;
202 BIND_NO_UPDATE = $00000002;
203 BIND_ALL_IMAGES = $00000004;
204 BIND_CACHE_IMPORT_DLLS = $00000008;
207 // Wizard page and variables for the Path options.
208 PathPage:TWizardPage;
209 RdbPath:array[GP_BashOnly..GP_CmdTools] of TRadioButton;
211 // Wizard page and variables for the SSH options.
212 PuTTYPage:TWizardPage;
213 RdbSSH:array[GS_OpenSSH..GS_Plink] of TRadioButton;
214 EdtPlink:TEdit;
216 // Wizard page and variables for the line ending conversion options.
217 CRLFPage:TWizardPage;
218 RdbCRLF:array[GC_LFOnly..GC_CRLFCommitAsIs] of TRadioButton;
220 // Wizard page and variables for the processes page.
221 SessionHandle:DWORD;
222 Processes:ProcessList;
223 ProcessesPage:TWizardPage;
224 ProcessesListBox:TListBox;
225 ProcessesRefresh,ContinueButton:TButton;
228 Specific helper functions
231 procedure BrowseForPuTTYFolder(Sender:TObject);
233 Name:String;
234 begin
235 if GetOpenFileName(
236 'Please select a Plink executable'
237 , Name
238 , ExtractFilePath(EdtPlink.Text)
239 , 'Executable Files|*.exe'
240 , 'exe'
242 then begin
243 if IsPlinkExecutable(Name) then begin
244 EdtPlink.Text:=Name;
245 RdbSSH[GS_Plink].Checked:=True;
246 end else begin
247 // This message box only gets triggered on interactive use, so it
248 // does not need to be suppressible for silent installations.
249 MsgBox('{#PLINK_PATH_ERROR_MSG}',mbError,MB_OK);
250 end;
251 end;
252 end;
254 procedure DeleteContextMenuEntries;
256 AppDir,Command,Msg:String;
257 RootKey,i:Integer;
258 Keys:TArrayOfString;
259 begin
260 AppDir:=ExpandConstant('{app}');
262 if IsAdminLoggedOn then begin
263 RootKey:=HKEY_LOCAL_MACHINE;
264 end else begin
265 RootKey:=HKEY_CURRENT_USER;
266 end;
268 SetArrayLength(Keys,4);
269 Keys[0]:='SOFTWARE\Classes\Directory\shell\git_shell';
270 Keys[1]:='SOFTWARE\Classes\Directory\Background\shell\git_shell';
271 Keys[2]:='SOFTWARE\Classes\Directory\shell\git_gui';
272 Keys[3]:='SOFTWARE\Classes\Directory\Background\shell\git_gui';
274 for i:=0 to Length(Keys)-1 do begin
275 Command:='';
276 RegQueryStringValue(RootKey,Keys[i]+'\command','',Command);
277 if Pos(AppDir,Command)>0 then begin
278 if not RegDeleteKeyIncludingSubkeys(RootKey,Keys[i]) then begin
279 Msg:='Line {#__LINE__}: Unable to remove "Git Bash / GUI Here" shell extension.';
281 // This is not a critical error, so just notify the user and continue.
282 SuppressibleMsgBox(Msg,mbError,MB_OK,IDOK);
283 Log(Msg);
284 end;
285 end;
286 end;
287 end;
289 procedure RefreshProcessList(Sender:TObject);
291 Version:TWindowsVersion;
292 Modules:TArrayOfString;
293 ProcsCloseRequired,ProcsCloseOptional:ProcessList;
294 i:Longint;
295 Caption:String;
296 ManualClosingRequired:Boolean;
297 begin
298 GetWindowsVersionEx(Version);
300 // Use the Restart Manager API when installing the shell extension on Windows Vista and above.
301 if Version.Major>=6 then begin
302 SetArrayLength(Modules,5);
303 Modules[0]:=ExpandConstant('{app}\bin\msys-1.0.dll');
304 Modules[1]:=ExpandConstant('{app}\bin\tcl85.dll');
305 Modules[2]:=ExpandConstant('{app}\bin\tk85.dll');
306 Modules[3]:=ExpandConstant('{app}\git-cheetah\git_shell_ext.dll');
307 Modules[4]:=ExpandConstant('{app}\git-cheetah\git_shell_ext64.dll');
308 SessionHandle:=FindProcessesUsingModules(Modules,Processes);
309 end else begin
310 SetArrayLength(Modules,3);
311 Modules[0]:=ExpandConstant('{app}\bin\msys-1.0.dll');
312 Modules[1]:=ExpandConstant('{app}\bin\tcl85.dll');
313 Modules[2]:=ExpandConstant('{app}\bin\tk85.dll');
314 SessionHandle:=FindProcessesUsingModules(Modules,ProcsCloseRequired);
316 SetArrayLength(Modules,2);
317 Modules[0]:=ExpandConstant('{app}\git-cheetah\git_shell_ext.dll');
318 Modules[1]:=ExpandConstant('{app}\git-cheetah\git_shell_ext64.dll');
319 SessionHandle:=FindProcessesUsingModules(Modules,ProcsCloseOptional) or SessionHandle;
321 // Misuse the "Restartable" flag to indicate which processes are required
322 // to be closed before setup can continue, and which just should be closed
323 // in order to make changes take effect immediately.
324 SetArrayLength(Processes,GetArrayLength(ProcsCloseRequired)+GetArrayLength(ProcsCloseOptional));
325 for i:=0 to GetArrayLength(ProcsCloseRequired)-1 do begin
326 Processes[i]:=ProcsCloseRequired[i];
327 Processes[i].Restartable:=False;
328 end;
329 for i:=0 to GetArrayLength(ProcsCloseOptional)-1 do begin
330 Processes[GetArrayLength(ProcsCloseRequired)+i]:=ProcsCloseOptional[i];
331 Processes[GetArrayLength(ProcsCloseRequired)+i].Restartable:=True;
332 end;
333 end;
335 ManualClosingRequired:=False;
337 ProcessesListBox.Items.Clear;
338 if (Sender=NIL) or (SessionHandle>0) then begin
339 for i:=0 to GetArrayLength(Processes)-1 do begin
340 Caption:=Processes[i].Name+' (PID '+IntToStr(Processes[i].ID);
341 if Processes[i].Restartable then begin
342 Caption:=Caption+', closing is optional';
343 end else begin
344 Caption:=Caption+', closing is required';
345 ManualClosingRequired:=True;
346 end;
347 Caption:=Caption+')';
348 ProcessesListBox.Items.Append(Caption);
349 end;
350 end;
352 if ContinueButton<>NIL then begin
353 ContinueButton.Enabled:=not ManualClosingRequired;
354 end;
355 end;
357 procedure SetAndMarkEnvString(Name,Value:String;Expandable:Boolean);
359 Env:TArrayOfString;
360 FileName,Msg:String;
361 begin
362 SetArrayLength(Env,1);
363 Env[0]:=Value;
365 // Try to set the variable as specified by the user.
366 if not SetEnvStrings(Name,Env,Expandable,IsAdminLoggedOn,True) then begin
367 Msg:='Line {#__LINE__}: Unable to set the '+Name+' environment variable.';
369 // This is not a critical error, so just notify the user and continue.
370 SuppressibleMsgBox(Msg,mbError,MB_OK,IDOK);
371 Log(Msg);
372 end else begin
373 // Mark that we have changed the variable by writing its value to a file.
374 FileName:=ExpandConstant('{app}')+'\setup.ini';
375 if not SetIniString('Environment',Name,Value,FileName) then begin
376 Msg:='Line {#__LINE__}: Unable to write to file "'+FileName+'".';
378 // This is not a critical error, so just notify the user and continue.
379 SuppressibleMsgBox(Msg,mbError,MB_OK,IDOK);
380 Log(Msg);
381 end;
382 end;
383 end;
385 procedure DeleteMarkedEnvString(Name:String);
387 Env:TArrayOfString;
388 FileName,Msg:String;
389 begin
390 Env:=GetEnvStrings(Name,IsAdminLoggedOn);
391 FileName:=ExpandConstant('{app}')+'\setup.ini';
393 if (GetArrayLength(Env)=1) and
394 (CompareStr(RemoveQuotes(Env[0]),GetIniString('Environment',Name,'',FileName))=0) then begin
395 if not SetEnvStrings(Name,[],False,IsAdminLoggedOn,True) then begin
396 Msg:='Line {#__LINE__}: Unable to delete the '+Name+' environment variable.';
398 // This is not a critical error, so just notify the user and continue.
399 SuppressibleMsgBox(Msg,mbError,MB_OK,IDOK);
400 Log(Msg);
401 end;
402 end;
403 end;
406 Setup event functions
409 function InitializeSetup:Boolean;
410 begin
411 UpdateInfFilenames;
412 Result:=True;
413 end;
415 procedure InitializeWizard;
417 PrevPageID:Integer;
418 LblGitBash,LblGitCmd,LblGitCmdTools,LblGitCmdToolsWarn:TLabel;
419 LblOpenSSH,LblPlink:TLabel;
420 PuTTYSessions,EnvSSH:TArrayOfString;
421 LblLFOnly,LblCRLFAlways,LblCRLFCommitAsIs:TLabel;
422 BtnPlink:TButton;
423 Data:String;
424 begin
426 PrevPageID:=wpSelectProgramGroup;
429 * Create a custom page for modifying the environment.
432 PathPage:=CreateCustomPage(
433 PrevPageID
434 , 'Adjusting your PATH environment'
435 , 'How would you like to use Git from the command line?'
437 PrevPageID:=PathPage.ID;
439 // 1st choice
440 RdbPath[GP_BashOnly]:=TRadioButton.Create(PathPage);
441 with RdbPath[GP_BashOnly] do begin
442 Parent:=PathPage.Surface;
443 Caption:='Use Git from Git Bash only';
444 Left:=ScaleX(4);
445 Top:=ScaleY(8);
446 Width:=ScaleX(405);
447 Height:=ScaleY(17);
448 Font.Style:=[fsBold];
449 TabOrder:=0;
450 Checked:=True;
451 end;
452 LblGitBash:=TLabel.Create(PathPage);
453 with LblGitBash do begin
454 Parent:=PathPage.Surface;
455 Caption:=
456 'This is the safest choice as your PATH will not be modified at all. You will only be' + #13 +
457 'able to use the Git command line tools from Git Bash.';
458 Left:=ScaleX(28);
459 Top:=ScaleY(32);
460 Width:=ScaleX(405);
461 Height:=ScaleY(26);
462 end;
464 // 2nd choice
465 RdbPath[GP_Cmd]:=TRadioButton.Create(PathPage);
466 with RdbPath[GP_Cmd] do begin
467 Parent:=PathPage.Surface;
468 Caption:='Use Git from the Windows Command Prompt';
469 Left:=ScaleX(4);
470 Top:=ScaleY(76);
471 Width:=ScaleX(405);
472 Height:=ScaleY(17);
473 Font.Style:=[fsBold];
474 TabOrder:=1;
475 end;
476 LblGitCmd:=TLabel.Create(PathPage);
477 with LblGitCmd do begin
478 Parent:=PathPage.Surface;
479 Caption:=
480 'This option is considered safe as it only adds some minimal Git wrappers to your' + #13 +
481 'PATH to avoid cluttering your environment with optional Unix tools. You will be' + #13 +
482 'able to use Git from both Git Bash and the Windows Command Prompt.';
483 Left:=ScaleX(28);
484 Top:=ScaleY(100);
485 Width:=ScaleX(405);
486 Height:=ScaleY(39);
487 end;
489 // 3rd choice
490 RdbPath[GP_CmdTools]:=TRadioButton.Create(PathPage);
491 with RdbPath[GP_CmdTools] do begin
492 Parent:=PathPage.Surface;
493 Caption:='Use Git and optional Unix tools from the Windows Command Prompt';
494 Left:=ScaleX(4);
495 Top:=ScaleY(152);
496 Width:=ScaleX(405);
497 Height:=ScaleY(17);
498 Font.Style:=[fsBold];
499 TabOrder:=2;
500 end;
501 LblGitCmdTools:=TLabel.Create(PathPage);
502 with LblGitCmdTools do begin
503 Parent:=PathPage.Surface;
504 Caption:='Both Git and the optional Unix tools will be added to your PATH.';
505 Left:=ScaleX(28);
506 Top:=ScaleY(176);
507 Width:=ScaleX(405);
508 Height:=ScaleY(13);
509 end;
510 LblGitCmdToolsWarn:=TLabel.Create(PathPage);
511 with LblGitCmdToolsWarn do begin
512 Parent:=PathPage.Surface;
513 Caption:=
514 'Warning: This will override Windows tools like "find" and "sort". Only' + #13 +
515 'use this option if you understand the implications.';
516 Left:=ScaleX(28);
517 Top:=ScaleY(192);
518 Width:=ScaleX(405);
519 Height:=ScaleY(26);
520 Font.Color:=255;
521 Font.Style:=[fsBold];
522 end;
524 // Restore the setting chosen during a previous install.
525 Data:=GetPreviousData('Path Option','BashOnly');
527 // Use settings from the user provided INF.
528 if ShouldLoadInf then begin
529 Data:=LoadInfString('Setup','PathOption','BashOnly');
530 end;
532 if Data='BashOnly' then begin
533 RdbPath[GP_BashOnly].Checked:=True;
534 end else if Data='Cmd' then begin
535 RdbPath[GP_Cmd].Checked:=True;
536 end else if Data='CmdTools' then begin
537 RdbPath[GP_CmdTools].Checked:=True;
538 end;
541 * Create a custom page for using (Tortoise)Plink instead of OpenSSH
542 * if at least one PuTTY session is found in the Registry.
545 if RegGetSubkeyNames(HKEY_CURRENT_USER,'Software\SimonTatham\PuTTY\Sessions',PuTTYSessions) and (GetArrayLength(PuTTYSessions)>0) then begin
546 PuTTYPage:=CreateCustomPage(
547 PrevPageID
548 , 'Choosing the SSH executable'
549 , 'Which Secure Shell client program would you like Git to use?'
551 PrevPageID:=PuTTYPage.ID;
553 // 1st choice
554 RdbSSH[GS_OpenSSH]:=TRadioButton.Create(PuTTYPage);
555 with RdbSSH[GS_OpenSSH] do begin
556 Parent:=PuTTYPage.Surface;
557 Caption:='Use OpenSSH';
558 Left:=ScaleX(4);
559 Top:=ScaleY(8);
560 Width:=ScaleX(405);
561 Height:=ScaleY(17);
562 Font.Style:=[fsBold];
563 TabOrder:=0;
564 Checked:=True;
565 end;
566 LblOpenSSH:=TLabel.Create(PuTTYPage);
567 with LblOpenSSH do begin
568 Parent:=PuTTYPage.Surface;
569 Caption:=
570 'This uses ssh.exe that comes with Git. The GIT_SSH and SVN_SSH' + #13 +
571 'environment variables will not be modified.';
572 Left:=ScaleX(28);
573 Top:=ScaleY(32);
574 Width:=ScaleX(405);
575 Height:=ScaleY(26);
576 end;
578 // 2nd choice
579 RdbSSH[GS_Plink]:=TRadioButton.Create(PuTTYPage);
580 with RdbSSH[GS_Plink] do begin
581 Parent:=PuTTYPage.Surface;
582 Caption:='Use (Tortoise)Plink';
583 Left:=ScaleX(4);
584 Top:=ScaleY(76);
585 Width:=ScaleX(405);
586 Height:=ScaleY(17);
587 Font.Style:=[fsBold];
588 TabOrder:=1;
589 end;
590 LblPlink:=TLabel.Create(PuTTYPage);
591 with LblPlink do begin
592 Parent:=PuTTYPage.Surface;
593 Caption:=
594 'PuTTY sessions were found in your Registry. You may specify the path' + #13 +
595 'to an existing copy of (Tortoise)Plink.exe from the TortoiseGit/SVN/CVS' + #13 +
596 'or PuTTY applications. The GIT_SSH and SVN_SSH environment' + #13 +
597 'variables will be adjusted to point to the following executable:';
598 Left:=ScaleX(28);
599 Top:=ScaleY(100);
600 Width:=ScaleX(405);
601 Height:=ScaleY(52);
602 end;
603 EdtPlink:=TEdit.Create(PuTTYPage);
604 with EdtPlink do begin
605 Parent:=PuTTYPage.Surface;
607 EnvSSH:=GetEnvStrings('GIT_SSH',IsAdminLoggedOn);
608 if (GetArrayLength(EnvSSH)=1) and IsPlinkExecutable(EnvSSH[0]) then begin
609 Text:=EnvSSH[0];
610 end;
611 if not FileExists(Text) then begin
612 Text:=GetPreviousData('Plink Path','');
613 end;
614 if not FileExists(Text) then begin
615 Text:=GuessPlinkExecutable;
616 end;
617 if not FileExists(Text) then begin
618 Text:='';
619 end;
621 Left:=ScaleX(28);
622 Top:=ScaleY(161);
623 Width:=ScaleX(316);
624 Height:=ScaleY(13);
625 end;
626 BtnPlink:=TButton.Create(PuTTYPage);
627 with BtnPlink do begin
628 Parent:=PuTTYPage.Surface;
629 Caption:='...';
630 OnClick:=@BrowseForPuTTYFolder;
631 Left:=ScaleX(348);
632 Top:=ScaleY(161);
633 Width:=ScaleX(21);
634 Height:=ScaleY(21);
635 end;
637 // Restore the setting chosen during a previous install.
638 Data:=GetPreviousData('SSH Option','OpenSSH');
640 // Use settings from the user provided INF.
641 if ShouldLoadInf then begin
642 Data:=LoadInfString('Setup','SSHOption','OpenSSH');
643 end;
645 if Data='OpenSSH' then begin
646 RdbSSH[GS_OpenSSH].Checked:=True;
647 end else if Data='Plink' then begin
648 RdbSSH[GS_Plink].Checked:=True;
649 end;
650 end else begin
651 PuTTYPage:=NIL;
652 end;
655 * Create a custom page for the core.autocrlf setting.
658 CRLFPage:=CreateCustomPage(
659 PrevPageID
660 , 'Configuring the line ending conversions'
661 , 'How should Git treat line endings in text files?'
663 PrevPageID:=CRLFPage.ID;
665 // 1st choice
666 RdbCRLF[GC_CRLFAlways]:=TRadioButton.Create(CRLFPage);
667 with RdbCRLF[GC_CRLFAlways] do begin
668 Parent:=CRLFPage.Surface;
669 Caption:='Checkout Windows-style, commit Unix-style line endings';
670 Left:=ScaleX(4);
671 Top:=ScaleY(8);
672 Width:=ScaleX(405);
673 Height:=ScaleY(17);
674 Font.Style:=[fsBold];
675 TabOrder:=0;
676 Checked:=True;
677 end;
678 LblCRLFAlways:=TLabel.Create(CRLFPage);
679 with LblCRLFAlways do begin
680 Parent:=CRLFPage.Surface;
681 Caption:=
682 'Git will convert LF to CRLF when checking out text files. When committing' + #13 +
683 'text files, CRLF will be converted to LF. For cross-platform projects,' + #13 +
684 'this is the recommended setting on Windows ("core.autocrlf" is set to "true").';
685 Left:=ScaleX(28);
686 Top:=ScaleY(32);
687 Width:=ScaleX(405);
688 Height:=ScaleY(47);
689 end;
691 // 2nd choice
692 RdbCRLF[GC_LFOnly]:=TRadioButton.Create(CRLFPage);
693 with RdbCRLF[GC_LFOnly] do begin
694 Parent:=CRLFPage.Surface;
695 Caption:='Checkout as-is, commit Unix-style line endings';
696 Left:=ScaleX(4);
697 Top:=ScaleY(80);
698 Width:=ScaleX(405);
699 Height:=ScaleY(17);
700 Font.Style:=[fsBold];
701 TabOrder:=1;
702 Checked:=False;
703 end;
704 LblLFOnly:=TLabel.Create(CRLFPage);
705 with LblLFOnly do begin
706 Parent:=CRLFPage.Surface;
707 Caption:=
708 'Git will not perform any conversion when checking out text files. When' + #13 +
709 'committing text files, CRLF will be converted to LF. For cross-platform projects,' + #13 +
710 'this is the recommended setting on Unix ("core.autocrlf" is set to "input").';
711 Left:=ScaleX(28);
712 Top:=ScaleY(104);
713 Width:=ScaleX(405);
714 Height:=ScaleY(47);
715 end;
717 // 3rd choice
718 RdbCRLF[GC_CRLFCommitAsIs]:=TRadioButton.Create(CRLFPage);
719 with RdbCRLF[GC_CRLFCommitAsIs] do begin
720 Parent:=CRLFPage.Surface;
721 Caption:='Checkout as-is, commit as-is';
722 Left:=ScaleX(4);
723 Top:=ScaleY(152);
724 Width:=ScaleX(405);
725 Height:=ScaleY(17);
726 Font.Style:=[fsBold];
727 TabOrder:=2;
728 Checked:=False;
729 end;
730 LblCRLFCommitAsIs:=TLabel.Create(CRLFPage);
731 with LblCRLFCommitAsIs do begin
732 Parent:=CRLFPage.Surface;
733 Caption:=
734 'Git will not perform any conversions when checking out or committing' + #13 +
735 'text files. Choosing this option is not recommended for cross-platform' + #13 +
736 'projects ("core.autocrlf" is set to "false").';
737 Left:=ScaleX(28);
738 Top:=ScaleY(176);
739 Width:=ScaleX(405);
740 Height:=ScaleY(47);
741 end;
743 // Restore the setting chosen during a previous install.
744 Data:=GetPreviousData('CRLF Option','CRLFAlways');
746 // Use settings from the user provided INF.
747 if ShouldLoadInf then begin
748 Data:=LoadInfString('Setup','CRLFOption','CRLFAlways');
749 end;
751 if Data='LFOnly' then begin
752 RdbCRLF[GC_LFOnly].Checked:=True;
753 end else if Data='CRLFAlways' then begin
754 RdbCRLF[GC_CRLFAlways].Checked:=True;
755 end else if Data='CRLFCommitAsIs' then begin
756 RdbCRLF[GC_CRLFCommitAsIs].Checked:=True;
757 end;
760 * Create a custom page for finding the processes that lock a module.
763 ProcessesPage:=CreateCustomPage(
764 wpPreparing
765 , 'Replacing in-use files'
766 , 'The following applications use files that need to be replaced, please close them.'
769 ProcessesListBox:=TListBox.Create(ProcessesPage);
770 with ProcessesListBox do begin
771 Parent:=ProcessesPage.Surface;
772 Width:=ProcessesPage.SurfaceWidth;
773 Height:=ProcessesPage.SurfaceHeight-ScaleY(8);
774 end;
776 ProcessesRefresh:=TNewButton.Create(WizardForm);
777 with ProcessesRefresh do begin
778 Parent:=WizardForm;
779 Width:=WizardForm.CancelButton.Width;
780 Height:=WizardForm.CancelButton.Height;
781 Top:=WizardForm.CancelButton.Top;
782 Left:=WizardForm.ClientWidth-(WizardForm.CancelButton.Left+WizardForm.CancelButton.Width);
783 Caption:='&Refresh';
784 OnClick:=@RefreshProcessList;
785 end;
787 // This button is only used by the uninstaller.
788 ContinueButton:=NIL;
790 // Initially hide the Refresh button, show it when the process page becomes current.
791 ProcessesRefresh.Hide;
792 end;
794 function ShouldSkipPage(PageID:Integer):Boolean;
795 begin
796 if (ProcessesPage<>NIL) and (PageID=ProcessesPage.ID) then begin
797 // This page is only reached forward (by pressing "Next", never by pressing "Back").
798 RefreshProcessList(NIL);
799 Result:=(GetArrayLength(Processes)=0);
800 end else begin
801 Result:=False;
802 end;
803 end;
805 procedure CurPageChanged(CurPageID:Integer);
806 begin
807 if CurPageID=wpInfoBefore then begin
808 if WizardForm.NextButton.Enabled then begin
809 // By default, do not show a blinking cursor for InfoBeforeFile.
810 WizardForm.ActiveControl:=WizardForm.NextButton;
811 end;
812 end else if CurPageID=wpSelectDir then begin
813 if not IsDirWritable(WizardDirValue) then begin
814 // If the default directory is not writable, choose another default that most likely is.
815 // This will be checked later again when the user clicks "Next".
816 WizardForm.DirEdit.Text:=ExpandConstant('{userpf}\{#APP_NAME}');
817 end;
818 end else if (ProcessesPage<>NIL) and (CurPageID=ProcessesPage.ID) then begin
819 // Show the "Refresh" button only on the processes page.
820 ProcessesRefresh.Show;
821 end else begin
822 ProcessesRefresh.Hide;
823 end;
824 end;
826 function NextButtonClick(CurPageID:Integer):Boolean;
828 i:Integer;
829 Version:TWindowsVersion;
830 begin
831 // On a silent install, if your NextButtonClick function returns False
832 // prior to installation starting, Setup will exit automatically.
833 Result:=True;
835 if CurPageID=wpSelectDir then begin
836 if not IsDirWritable(WizardDirValue) then begin
837 SuppressibleMsgBox(
838 'The specified installation directory does not seem to be writable. ' +
839 + 'Please choose another directory or restart setup as a user with sufficient permissions.'
840 , mbCriticalError
841 , MB_OK
842 , IDOK
844 Result:=False;
845 Exit;
846 end;
847 end;
849 if (PuTTYPage<>NIL) and (CurPageID=PuTTYPage.ID) then begin
850 Result:=RdbSSH[GS_OpenSSH].Checked or
851 (RdbSSH[GS_Plink].Checked and FileExists(EdtPlink.Text));
852 if not Result then begin
853 SuppressibleMsgBox('{#PLINK_PATH_ERROR_MSG}',mbError,MB_OK,IDOK);
854 end;
855 end else if (ProcessesPage<>NIL) and (CurPageID=ProcessesPage.ID) then begin
856 // It would have been nicer to just disable the "Next" button, but the
857 // WizardForm exports the button just read-only.
858 for i:=0 to GetArrayLength(Processes)-1 do begin
859 if not Processes[i].Restartable then begin
860 SuppressibleMsgBox(
861 'Setup cannot continue until you close at least those applications in the list that are marked as "closing is required".'
862 , mbCriticalError
863 , MB_OK
864 , IDOK
866 Result:=False;
867 Exit;
868 end;
869 end;
871 Result:=(GetArrayLength(Processes)=0);
873 if not Result then begin
874 GetWindowsVersionEx(Version);
875 if Version.Major>=6 then begin
876 Result:=(SuppressibleMsgBox(
877 'If you continue without closing the listed applications they will be closed and restarted automatically.' + #13 + #13 +
878 'Are you sure you want to continue?'
879 , mbConfirmation
880 , MB_YESNO
881 , IDNO
882 )=IDYES);
883 end else begin
884 Result:=(SuppressibleMsgBox(
885 'If you continue without closing the listed applications you will need to log off and on again before changes take effect.' + #13 + #13 +
886 'Are you sure you want to continue anyway?'
887 , mbConfirmation
888 , MB_YESNO
889 , IDNO
890 )=IDYES);
891 end;
892 end;
893 end;
894 end;
896 procedure CurStepChanged(CurStep:TSetupStep);
898 AppDir,DllPath,FileName,TempName,Cmd,Msg:String;
899 BuiltIns,ImageNames,EnvPath,EnvHome:TArrayOfString;
900 Count,i:Longint;
901 LinkCreated:Boolean;
902 FindRec:TFindRec;
903 RootKey:Integer;
904 Version:TWindowsVersion;
905 begin
906 if CurStep=ssInstall then begin
907 // Shutdown locking processes just before the actual installation starts.
908 if SessionHandle>0 then try
909 RmShutdown(SessionHandle,RmShutdownOnlyRegistered,0);
910 except
911 Log('Line {#__LINE__}: RmShutdown not supported.');
912 end;
914 Exit;
915 end;
917 // Make sure the code below is only executed just after the actual installation finishes.
918 if CurStep<>ssPostInstall then begin
919 Exit;
920 end;
922 AppDir:=ExpandConstant('{app}');
925 Bind the imported function addresses
929 DllPath:=ExpandConstant('{app}\bin;{sys}');
931 // Load the list of images from a text file.
932 FileName:=AppDir+'\{#APP_BINDIMAGE}';
933 if LoadStringsFromFile(FileName,ImageNames) then begin
934 Count:=GetArrayLength(ImageNames)-1;
935 for i:=0 to Count do begin
936 FileName:=AppDir+'\'+ImageNames[i];
937 if not BindImageEx(BIND_NO_BOUND_IMPORTS or BIND_CACHE_IMPORT_DLLS,FileName,DllPath,'',0) then begin
938 Log('Line {#__LINE__}: Error calling BindImageEx for "'+FileName+'".');
939 end;
940 end;
941 end;
942 except
943 Log('Line {#__LINE__}: An exception occurred while calling BindImageEx.');
944 end;
947 Create the built-ins
950 // Load the built-ins from a text file.
951 FileName:=AppDir+'\{#APP_BUILTINS}';
952 if LoadStringsFromFile(FileName,BuiltIns) then begin
953 Count:=GetArrayLength(BuiltIns)-1;
955 // Delete those scripts from "bin" which have been replaced by built-ins in "libexec\git-core".
956 for i:=0 to Count do begin
957 FileName:=AppDir+'\bin\'+ChangeFileExt(ExtractFileName(BuiltIns[i]),'');
958 if FileExists(FileName) and (not DeleteFile(FileName)) then begin
959 Log('Line {#__LINE__}: Unable to delete script "'+FileName+'", ignoring.');
960 end;
961 end;
963 // Create built-ins as aliases for git.exe.
964 for i:=0 to Count do begin
965 FileName:=AppDir+'\'+BuiltIns[i];
967 // Delete any existing built-in.
968 if FileExists(FileName) and (not DeleteFile(FileName)) then begin
969 Log('Line {#__LINE__}: Unable to delete existing built-in "'+FileName+'", skipping.');
970 continue;
971 end;
974 // This will throw an exception on pre-Win2k systems.
975 LinkCreated:=CreateHardLink(FileName,AppDir+'\bin\git.exe',0);
976 except
977 LinkCreated:=False;
978 Log('Line {#__LINE__}: Creating hardlink "'+FileName+'" failed, will try a copy.');
979 end;
981 if not LinkCreated then begin
982 if not FileCopy(AppDir+'\bin\git.exe',FileName,False) then begin
983 Log('Line {#__LINE__}: Creating copy "'+FileName+'" failed, giving up.');
984 // This is not a critical error, Git could basically be used without the
985 // aliases for built-ins, so we continue.
986 end;
987 end;
988 end;
990 // Delete any duplicate files in case we are updating from a non-libexec to a libexec directory layout.
991 if FindFirst(AppDir+'\libexec\git-core\*',FindRec) then begin
992 repeat
993 if (FindRec.Attributes and FILE_ATTRIBUTE_DIRECTORY)=0 then begin
994 FileName:=AppDir+'\bin\'+FindRec.name;
995 if (Pos(FindRec.name,'git.exe')<>1) and FileExists(FileName) and (not DeleteFile(FileName)) then begin
996 Log('Line {#__LINE__}: Unable to delete dupe "'+FileName+'", ignoring.');
997 end;
998 end;
999 until not FindNext(FindRec);
1000 FindClose(FindRec);
1001 end;
1002 end else begin
1003 Msg:='Line {#__LINE__}: Unable to read file "{#APP_BUILTINS}".';
1005 // This is in fact a critical error, but "Abort" does not work during ssPostInstall anymore and
1006 // we have no other way of aborting the installation, so just notify the user and continue.
1007 SuppressibleMsgBox(Msg,mbError,MB_OK,IDOK);
1008 Log(Msg);
1009 end;
1012 Adapt core.autocrlf
1015 if RdbCRLF[GC_LFOnly].checked then begin
1016 Cmd:='core.autocrlf input';
1017 end else if RdbCRLF[GC_CRLFAlways].checked then begin
1018 Cmd:='core.autocrlf true';
1019 end else begin
1020 Cmd:='core.autocrlf false';
1021 end;
1022 if not Exec(AppDir + '\bin\git.exe', 'config -f gitconfig ' + Cmd,
1023 AppDir + '\etc', SW_HIDE, ewWaitUntilTerminated, i) then begin
1024 Msg:='Unable to configure the line ending conversion: ' + Cmd;
1026 // This is not a critical error, so just notify the user and continue.
1027 SuppressibleMsgBox(Msg,mbError,MB_OK,IDOK);
1028 Log(Msg);
1029 end;
1032 Modify the environment
1034 This must happen no later than ssPostInstall to make
1035 "ChangesEnvironment=yes" not happend before the change!
1038 // Delete GIT_SSH and SVN_SSH if a previous installation set them (this is required for the GS_OpenSSH case).
1039 DeleteMarkedEnvString('GIT_SSH');
1040 DeleteMarkedEnvString('SVN_SSH');
1042 if (PuTTYPage<>NIL) and RdbSSH[GS_Plink].Checked then begin
1043 SetAndMarkEnvString('GIT_SSH',EdtPlink.Text,True);
1044 SetAndMarkEnvString('SVN_SSH',EdtPlink.Text,True);
1045 end;
1047 // Get the current user's directories in PATH.
1048 EnvPath:=GetEnvStrings('PATH',IsAdminLoggedOn);
1050 // First, remove the installation directory from PATH in any case.
1051 for i:=0 to GetArrayLength(EnvPath)-1 do begin
1052 if Pos(AppDir+'\',EnvPath[i]+'\')=1 then begin
1053 EnvPath[i]:='';
1054 end;
1055 end;
1057 // Modify the PATH variable as requested by the user.
1058 if RdbPath[GP_Cmd].Checked or RdbPath[GP_CmdTools].Checked then begin
1059 i:=GetArrayLength(EnvPath);
1060 SetArrayLength(EnvPath,i+1);
1062 // List \cmd before \bin so \cmd has higher priority and programs in
1063 // there will be called in favor of those in \bin.
1064 EnvPath[i]:=AppDir+'\cmd';
1066 if RdbPath[GP_CmdTools].Checked then begin
1067 SetArrayLength(EnvPath,i+2);
1068 EnvPath[i+1]:=AppDir+'\bin';
1069 end;
1070 end;
1072 // Set the current user's PATH directories.
1073 if not SetEnvStrings('PATH',EnvPath,True,IsAdminLoggedOn,True) then begin
1074 Msg:='Line {#__LINE__}: Unable to set the PATH environment variable.';
1076 // This is not a critical error, so just notify the user and continue.
1077 SuppressibleMsgBox(Msg,mbError,MB_OK,IDOK);
1078 Log(Msg);
1079 end;
1082 Create shortcuts that need to be created regardless of the "Don't create a Start Menu folder" toggle
1085 GetWindowsVersionEx(Version);
1086 if Version.Major<6 then begin
1087 Cmd:=ExpandConstant('{syswow64}\cmd.exe');
1088 TempName:='/c ""'+AppDir+'\bin\sh.exe" --login -i"';
1089 end else begin
1090 Cmd:=AppDir+'\bin\sh.exe';
1091 TempName:='--login -i';
1092 end;
1093 FileName:=AppDir+'\etc\git.ico';
1095 if IsComponentSelected('icons\quicklaunch') then begin
1096 CreateShellLink(
1097 ExpandConstant('{userappdata}\Microsoft\Internet Explorer\Quick Launch\Git Bash.lnk')
1098 , 'Git Bash'
1099 , Cmd
1100 , TempName
1101 , '%HOMEDRIVE%%HOMEPATH%'
1102 , FileName
1104 , SW_SHOWNORMAL
1106 end;
1108 if IsComponentSelected('icons\desktop') then begin
1109 CreateShellLink(
1110 GetShellFolder('desktop')+'\Git Bash.lnk'
1111 , 'Git Bash'
1112 , Cmd
1113 , TempName
1114 , '%HOMEDRIVE%%HOMEPATH%'
1115 , FileName
1117 , SW_SHOWNORMAL
1119 end;
1122 Create the Windows Explorer integrations
1125 if IsAdminLoggedOn then begin
1126 RootKey:=HKEY_LOCAL_MACHINE;
1127 end else begin
1128 RootKey:=HKEY_CURRENT_USER;
1129 end;
1131 if IsComponentSelected('ext\reg\shellhere') then begin
1132 Msg:='Git Ba&sh Here';
1133 Cmd:='"'+ExpandConstant('{syswow64}')+'\wscript" "'+AppDir+'\Git Bash.vbs" "%1"';
1134 if (not RegWriteStringValue(RootKey,'SOFTWARE\Classes\Directory\shell\git_shell','',Msg)) or
1135 (not RegWriteStringValue(RootKey,'SOFTWARE\Classes\Directory\shell\git_shell\command','',Cmd)) or
1136 (StringChangeEx(Cmd,'%1','%v',false)<>1) or
1137 (not RegWriteStringValue(RootKey,'SOFTWARE\Classes\Directory\Background\shell\git_shell','',Msg)) or
1138 (not RegWriteStringValue(RootKey,'SOFTWARE\Classes\Directory\Background\shell\git_shell\command','',Cmd)) then
1139 begin
1140 Msg:='Line {#__LINE__}: Unable to create "Git Bash Here" shell extension.';
1142 // This is not a critical error, so just notify the user and continue.
1143 SuppressibleMsgBox(Msg,mbError,MB_OK,IDOK);
1144 Log(Msg);
1145 end;
1146 end;
1148 if IsComponentSelected('ext\reg\guihere') then begin
1149 Msg:='Git &GUI Here';
1150 Cmd:='"'+AppDir+'\bin\wish.exe" "'+AppDir+'\libexec\git-core\git-gui" "--working-dir" "%1"';
1151 if (not RegWriteStringValue(RootKey,'SOFTWARE\Classes\Directory\shell\git_gui','',Msg)) or
1152 (not RegWriteStringValue(RootKey,'SOFTWARE\Classes\Directory\shell\git_gui\command','',Cmd)) or
1153 (StringChangeEx(Cmd,'%1','%v',false)<>1) or
1154 (not RegWriteStringValue(RootKey,'SOFTWARE\Classes\Directory\Background\shell\git_gui','',Msg)) or
1155 (not RegWriteStringValue(RootKey,'SOFTWARE\Classes\Directory\Background\shell\git_gui\command','',Cmd))
1156 then begin
1157 Msg:='Line {#__LINE__}: Unable to create "Git GUI Here" shell extension.';
1159 // This is not a critical error, so just notify the user and continue.
1160 SuppressibleMsgBox(Msg,mbError,MB_OK,IDOK);
1161 Log(Msg);
1162 end;
1163 end;
1165 // It is either the Registry-based context menu entries, or the shell extension.
1166 if IsComponentSelected('ext\cheetah') then begin
1167 DeleteContextMenuEntries;
1169 if isWin64 then begin
1170 FileName:=AppDir+'\git-cheetah\git_shell_ext64.dll';
1171 end else begin
1172 FileName:=AppDir+'\git-cheetah\git_shell_ext.dll';
1173 end;
1174 if not ReplaceInUseFile(FileName,FileName+'.new',True,Msg) then begin
1175 // This is in fact a critical error, but "Abort" does not work during ssPostInstall anymore and
1176 // we have no other way of aborting the installation, so just notify the user and continue.
1177 SuppressibleMsgBox(Msg,mbError,MB_OK,IDOK);
1178 Log('Line {#__LINE__}: Replacing file "'+FileName+'" failed.');
1179 end;
1180 end;
1183 Restart any processes that were shut down via the Restart Manager
1186 if SessionHandle>0 then try
1187 RmRestart(SessionHandle,0,0);
1188 RmEndSession(SessionHandle);
1189 except
1190 Log('Line {#__LINE__}: RmRestart not supported.');
1191 end;
1192 end;
1194 procedure RegisterPreviousData(PreviousDataKey:Integer);
1196 Data:String;
1197 begin
1198 // Git Path options.
1199 Data:='';
1200 if RdbPath[GP_BashOnly].Checked then begin
1201 Data:='BashOnly';
1202 end else if RdbPath[GP_Cmd].Checked then begin
1203 Data:='Cmd';
1204 end else if RdbPath[GP_CmdTools].Checked then begin
1205 Data:='CmdTools';
1206 end;
1207 SetPreviousData(PreviousDataKey,'Path Option',Data);
1208 if ShouldSaveInf then begin
1209 SaveInfString('Setup','PathOption',Data);
1210 end;
1212 // Git SSH options.
1213 Data:='';
1214 if (PuTTYPage=NIL) or RdbSSH[GS_OpenSSH].Checked then begin
1215 Data:='OpenSSH';
1216 end else if RdbSSH[GS_Plink].Checked then begin
1217 Data:='Plink';
1218 SetPreviousData(PreviousDataKey,'Plink Path',EdtPlink.Text);
1219 if ShouldSaveInf then begin
1220 SaveInfString('Setup','PlinkPath',EdtPlink.Text);
1221 end;
1222 end;
1223 SetPreviousData(PreviousDataKey,'SSH Option',Data);
1224 if ShouldSaveInf then begin
1225 SaveInfString('Setup','SSHOption',Data);
1226 end;
1228 // Line ending conversion options.
1229 Data:='';
1230 if RdbCRLF[GC_LFOnly].Checked then begin
1231 Data:='LFOnly';
1232 end else if RdbCRLF[GC_CRLFAlways].Checked then begin
1233 Data:='CRLFAlways';
1234 end else if RdbCRLF[GC_CRLFCommitAsIs].Checked then begin
1235 Data:='CRLFCommitAsIs';
1236 end;
1237 SetPreviousData(PreviousDataKey,'CRLF Option',Data);
1238 if ShouldSaveInf then begin
1239 SaveInfString('Setup','CRLFOption',Data);
1240 end;
1241 end;
1244 Uninstall event functions
1247 function InitializeUninstall:Boolean;
1249 Form:TSetupForm;
1250 Info:TLabel;
1251 ExitButton,RefreshButton:TButton;
1252 begin
1253 Result:=True;
1255 Form:=CreateCustomForm;
1257 Form.Caption:='Git Uninstall: Removing in-use files';
1258 Form.ClientWidth:=ScaleX(500);
1259 Form.ClientHeight:=ScaleY(256);
1260 Form.Center;
1262 Info:=TLabel.Create(Form);
1263 with Info do begin
1264 Parent:=Form;
1265 Left:=ScaleX(11);
1266 Top:=ScaleY(11);
1267 AutoSize:=True;
1268 Caption:='The following applications use files that need to be removed, please close them.';
1269 end;
1271 ContinueButton:=TButton.Create(Form);
1272 with ContinueButton do begin
1273 Parent:=Form;
1274 Left:=Form.ClientWidth-ScaleX(75+10);
1275 Top:=Form.ClientHeight-ScaleY(23+10);
1276 Width:=ScaleX(75);
1277 Height:=ScaleY(23);
1278 Caption:='Continue';
1279 ModalResult:=mrOk;
1280 end;
1282 ExitButton:=TButton.Create(Form);
1283 with ExitButton do begin
1284 Parent:=Form;
1285 Left:=ContinueButton.Left-ScaleX(75+6);
1286 Top:=ContinueButton.Top;
1287 Width:=ScaleX(75);
1288 Height:=ScaleY(23);
1289 Caption:='Exit';
1290 ModalResult:=mrCancel;
1291 Cancel:=True;
1292 end;
1294 RefreshButton:=TButton.Create(Form);
1295 with RefreshButton do begin
1296 Parent:=Form;
1297 Left:=ScaleX(10);
1298 Top:=ExitButton.Top;
1299 Width:=ScaleX(75);
1300 Height:=ScaleY(23);
1301 Caption:='Refresh';
1302 OnClick:=@RefreshProcessList;
1303 end;
1305 ProcessesListBox:=TListBox.Create(Form);
1306 with ProcessesListBox do begin
1307 Parent:=Form;
1308 Left:=ScaleX(11);
1309 Top:=Info.Top+Info.Height+11;
1310 Width:=Form.ClientWidth-ScaleX(11*2);
1311 Height:=ContinueButton.Top-ScaleY(11*4);
1312 end;
1314 Form.ActiveControl:=ContinueButton;
1316 RefreshProcessList(NIL);
1317 if GetArrayLength(Processes)>0 then begin
1318 // Now that these dialogs are going to be shown, we should probably
1319 // disable the "Are you sure to remove Git?" confirmation dialog, but
1320 // unfortunately that is not possible with Inno Setup currently.
1321 Result:=(Form.ShowModal()=mrOk);
1323 // Note: The number of processes might have changed during a refresh.
1324 if Result and (GetArrayLength(Processes)>0) then begin
1325 Result:=(SuppressibleMsgBox(
1326 'If you continue without closing the listed applications, you will need to log off and on again to remove some files manually.' + #13 + #13 +
1327 'Are you sure you want to continue anyway?'
1328 , mbConfirmation
1329 , MB_YESNO
1330 , IDNO
1331 )=IDYES);
1332 end;
1333 end;
1334 finally
1335 Form.free;
1336 end;
1337 end;
1339 // PreUninstall
1341 // Even though the name of this function suggests otherwise most of the
1342 // code below is only executed right before the actual uninstallation.
1343 // This happens because of the if-guard right in the beginning of this
1344 // function.
1345 procedure CurUninstallStepChanged(CurUninstallStep:TUninstallStep);
1347 AppDir,FileName,Msg:String;
1348 EnvPath:TArrayOfString;
1349 i:Longint;
1350 begin
1351 if CurUninstallStep<>usUninstall then begin
1352 Exit;
1353 end;
1355 // Reset the console font (the FontType is reset in the Registry section).
1356 if IsComponentInstalled('consolefont') then begin
1357 if SuppressibleMsgBox('Do you want to revert the TrueType font setting for all console windows?',mbConfirmation,MB_YESNO,IDYES)=IDYES then begin
1358 RegWriteDWordValue(HKEY_CURRENT_USER,'Console','FontFamily',0);
1359 RegWriteDWordValue(HKEY_CURRENT_USER,'Console','FontSize',0);
1360 RegWriteDWordValue(HKEY_CURRENT_USER,'Console','FontWeight',0);
1361 end;
1362 end;
1365 Modify the environment
1367 This must happen no later than usUninstall to make
1368 "ChangesEnvironment=yes" not happend before the change!
1371 AppDir:=ExpandConstant('{app}');
1372 FileName:=AppDir+'\setup.ini';
1374 // Delete the current user's GIT_SSH and SVN_SSH if we set it.
1375 DeleteMarkedEnvString('GIT_SSH');
1376 DeleteMarkedEnvString('SVN_SSH');
1378 // Get the current user's directories in PATH.
1379 EnvPath:=GetEnvStrings('PATH',IsAdminLoggedOn);
1381 // Remove the installation directory from PATH in any case, even if it
1382 // was not added by the installer.
1383 for i:=0 to GetArrayLength(EnvPath)-1 do begin
1384 if Pos(AppDir+'\',EnvPath[i]+'\')=1 then begin
1385 EnvPath[i]:='';
1386 end;
1387 end;
1389 // Reset the current user's directories in PATH.
1390 if not SetEnvStrings('PATH',EnvPath,True,IsAdminLoggedOn,True) then begin
1391 Msg:='Line {#__LINE__}: Unable to revert any possible changes to PATH.';
1393 // This is not a critical error, so just notify the user and continue.
1394 SuppressibleMsgBox(Msg,mbError,MB_OK,IDOK);
1395 Log(Msg);
1396 end;
1398 if FileExists(FileName) and (not DeleteFile(FileName)) then begin
1399 Msg:='Line {#__LINE__}: Unable to delete file "'+FileName+'".';
1401 // This is not a critical error, so just notify the user and continue.
1402 SuppressibleMsgBox(Msg,mbError,MB_OK,IDOK);
1403 Log(Msg);
1404 end;
1407 Delete the Windows Explorer integrations
1410 DeleteContextMenuEntries;
1412 if isWin64 then begin
1413 FileName:=AppDir+'\git-cheetah\git_shell_ext64.dll';
1414 end else begin
1415 FileName:=AppDir+'\git-cheetah\git_shell_ext.dll';
1416 end;
1417 if FileExists(FileName) then begin
1418 if not UnregisterServer(Is64BitInstallMode,FileName,False) then begin
1419 Msg:='Line {#__LINE__}: Unable to unregister file "'+FileName+'". Please do it manually by running "regsvr32 /u '+ExtractFileName(FileName)+'".';
1421 // This is not a critical error, so just notify the user and continue.
1422 SuppressibleMsgBox(Msg,mbError,MB_OK,IDOK);
1423 Log(Msg);
1424 end;
1426 if not DeleteFile(FileName) then begin
1427 Msg:='Line {#__LINE__}: Unable to delete file "'+FileName+'". Please do it manually after logging off and on again.';
1429 // This is not a critical error, so just notify the user and continue.
1430 SuppressibleMsgBox(Msg,mbError,MB_OK,IDOK);
1431 Log(Msg);
1432 end;
1433 end;
1434 end;