Installer: By default, do not show a blinking cursor for InfoBeforeFile
[msysgit.git] / share / WinGit / install.iss
blob01b6ebaa295f0db02ac009297ef9d362e68db83a
1 ; Uncomment the line below to be able to compile the script from within the IDE.
2 ;#define COMPILE_FROM_IDE
4 #define APP_NAME 'Git'
5 #ifdef COMPILE_FROM_IDE
6 #define APP_VERSION 'Snapshot'
7 #else
8 #define APP_VERSION '%APPVERSION%'
9 #endif
10 #define APP_URL 'http://msysgit.googlecode.com/'
11 #define APP_BUILTINS 'etc\fileList-builtins.txt'
12 #define APP_BINDIMAGE 'etc\fileList-bindimage.txt'
14 #define PLINK_PATH_ERROR_MSG 'Please enter a valid path to (Tortoise)Plink.exe.'
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 procedure DeleteFromVirtualStore;
177 VirtualStore,FileName:String;
178 DriveChars:Integer;
179 begin
180 VirtualStore:=AddBackslash(ExpandConstant('{localappdata}'))+'VirtualStore';
181 FileName:=ExpandConstant(CurrentFileName);
182 DriveChars:=Length(ExtractFileDrive(FileName));
183 if DriveChars>0 then begin
184 Delete(FileName,1,DriveChars);
185 FileName:=VirtualStore+FileName;
186 if FileExists(FileName) and (not DeleteFile(FileName)) then begin
187 Log('Line {#__LINE__}: Unable delete "'+FileName+'".');
188 // This is not a critical error, the user can probably fix it manually,
189 // so we continue.
190 end;
191 end;
192 end;
194 function CreateHardLink(lpFileName,lpExistingFileName:String;lpSecurityAttributes:Integer):Boolean;
195 #ifdef UNICODE
196 external 'CreateHardLinkW@Kernel32.dll stdcall delayload setuponly';
197 #else
198 external 'CreateHardLinkA@Kernel32.dll stdcall delayload setuponly';
199 #endif
201 function BindImageEx(Flags:DWORD;ImageName,DllPath,SymbolPath:AnsiString;StatusRoutine:Integer):Boolean;
202 external 'BindImageEx@Imagehlp.dll stdcall delayload setuponly';
204 const
205 // Git Path options.
206 GP_BashOnly = 1;
207 GP_Cmd = 2;
208 GP_CmdTools = 3;
210 // Git SSH options.
211 GS_OpenSSH = 1;
212 GS_Plink = 2;
214 // Git line ending conversion options.
215 GC_LFOnly = 1;
216 GC_CRLFAlways = 2;
217 GC_CRLFCommitAsIs = 3;
219 // BindImageEx API constants.
220 BIND_NO_BOUND_IMPORTS = $00000001;
221 BIND_NO_UPDATE = $00000002;
222 BIND_ALL_IMAGES = $00000004;
223 BIND_CACHE_IMPORT_DLLS = $00000008;
226 // Wizard page and variables for the Path options.
227 PathPage:TWizardPage;
228 RdbPath:array[GP_BashOnly..GP_CmdTools] of TRadioButton;
230 // Wizard page and variables for the SSH options.
231 PuTTYPage:TWizardPage;
232 RdbSSH:array[GS_OpenSSH..GS_Plink] of TRadioButton;
233 EdtPlink:TEdit;
235 // Wizard page and variables for the line ending conversion options.
236 CRLFPage:TWizardPage;
237 RdbCRLF:array[GC_LFOnly..GC_CRLFCommitAsIs] of TRadioButton;
239 // Wizard page and variables for the processes page.
240 SessionHandle:DWORD;
241 Processes:ProcessList;
242 ProcessesPage:TWizardPage;
243 ProcessesListBox:TListBox;
244 ProcessesRefresh,ContinueButton:TButton;
246 procedure BrowseForPuTTYFolder(Sender:TObject);
248 Path:String;
249 begin
250 Path:=ExtractFilePath(EdtPlink.Text);
251 BrowseForFolder('Please select the PuTTY folder:',Path,False);
252 if FileExists(Path+'\TortoisePlink.exe') then begin
253 EdtPlink.Text:=Path+'\TortoisePlink.exe';
254 RdbSSH[GS_Plink].Checked:=True;
255 end else if FileExists(Path+'\plink.exe') then begin
256 EdtPlink.Text:=Path+'\plink.exe';
257 RdbSSH[GS_Plink].Checked:=True;
258 end else begin
259 MsgBox('{#PLINK_PATH_ERROR_MSG}',mbError,MB_OK);
260 end;
261 end;
263 procedure DeleteContextMenuEntries;
265 AppDir,Command,Msg:String;
266 RootKey,i:Integer;
267 Keys:TArrayOfString;
268 begin
269 AppDir:=ExpandConstant('{app}');
271 if IsAdminLoggedOn then begin
272 RootKey:=HKEY_LOCAL_MACHINE;
273 end else begin
274 RootKey:=HKEY_CURRENT_USER;
275 end;
277 SetArrayLength(Keys,4);
278 Keys[0]:='SOFTWARE\Classes\Directory\shell\git_shell';
279 Keys[1]:='SOFTWARE\Classes\Directory\Background\shell\git_shell';
280 Keys[2]:='SOFTWARE\Classes\Directory\shell\git_gui';
281 Keys[3]:='SOFTWARE\Classes\Directory\Background\shell\git_gui';
283 for i:=0 to Length(Keys)-1 do begin
284 Command:='';
285 RegQueryStringValue(RootKey,Keys[i]+'\command','',Command);
286 if Pos(AppDir,Command)>0 then begin
287 if not RegDeleteKeyIncludingSubkeys(RootKey,Keys[i]) then begin
288 Msg:='Line {#__LINE__}: Unable to remove "Git Bash / GUI Here" shell extension.';
289 MsgBox(Msg,mbError,MB_OK);
290 Log(Msg);
291 // This is not a critical error, the user can probably fix it manually,
292 // so we continue.
293 end;
294 end;
295 end;
296 end;
298 procedure RefreshProcessList(Sender:TObject);
300 Version:TWindowsVersion;
301 Modules:TArrayOfString;
302 ProcsCloseRequired,ProcsCloseOptional:ProcessList;
303 i:Longint;
304 Caption:String;
305 ManualClosingRequired:Boolean;
306 begin
307 GetWindowsVersionEx(Version);
309 // Use the Restart Manager API when installing the shell extension on Windows Vista and above.
310 if Version.Major>=6 then begin
311 SetArrayLength(Modules,5);
312 Modules[0]:=ExpandConstant('{app}\bin\msys-1.0.dll');
313 Modules[1]:=ExpandConstant('{app}\bin\tcl85.dll');
314 Modules[2]:=ExpandConstant('{app}\bin\tk85.dll');
315 Modules[3]:=ExpandConstant('{app}\git-cheetah\git_shell_ext.dll');
316 Modules[4]:=ExpandConstant('{app}\git-cheetah\git_shell_ext64.dll');
317 SessionHandle:=FindProcessesUsingModules(Modules,Processes);
318 end else begin
319 SetArrayLength(Modules,3);
320 Modules[0]:=ExpandConstant('{app}\bin\msys-1.0.dll');
321 Modules[1]:=ExpandConstant('{app}\bin\tcl85.dll');
322 Modules[2]:=ExpandConstant('{app}\bin\tk85.dll');
323 SessionHandle:=FindProcessesUsingModules(Modules,ProcsCloseRequired);
325 SetArrayLength(Modules,2);
326 Modules[0]:=ExpandConstant('{app}\git-cheetah\git_shell_ext.dll');
327 Modules[1]:=ExpandConstant('{app}\git-cheetah\git_shell_ext64.dll');
328 SessionHandle:=FindProcessesUsingModules(Modules,ProcsCloseOptional) or SessionHandle;
330 // Misuse the "Restartable" flag to indicate which processes are required
331 // to be closed before setup can continue, and which just should be closed
332 // in order to make changes take effect immediately.
333 SetArrayLength(Processes,GetArrayLength(ProcsCloseRequired)+GetArrayLength(ProcsCloseOptional));
334 for i:=0 to GetArrayLength(ProcsCloseRequired)-1 do begin
335 Processes[i]:=ProcsCloseRequired[i];
336 Processes[i].Restartable:=False;
337 end;
338 for i:=0 to GetArrayLength(ProcsCloseOptional)-1 do begin
339 Processes[GetArrayLength(ProcsCloseRequired)+i]:=ProcsCloseOptional[i];
340 Processes[GetArrayLength(ProcsCloseRequired)+i].Restartable:=True;
341 end;
342 end;
344 ManualClosingRequired:=False;
346 ProcessesListBox.Items.Clear;
347 if (Sender=NIL) or (SessionHandle>0) then begin
348 for i:=0 to GetArrayLength(Processes)-1 do begin
349 Caption:=Processes[i].Name+' (PID '+IntToStr(Processes[i].ID);
350 if Processes[i].Restartable then begin
351 Caption:=Caption+', closing is optional';
352 end else begin
353 Caption:=Caption+', closing is required';
354 ManualClosingRequired:=True;
355 end;
356 Caption:=Caption+')';
357 ProcessesListBox.Items.Append(Caption);
358 end;
359 end;
361 if ContinueButton<>NIL then begin
362 ContinueButton.Enabled:=not ManualClosingRequired;
363 end;
364 end;
367 Installer code
370 procedure InitializeWizard;
372 PrevPageID:Integer;
373 LblGitBash,LblGitCmd,LblGitCmdTools,LblGitCmdToolsWarn:TLabel;
374 LblOpenSSH,LblPlink:TLabel;
375 PuTTYSessions:TArrayOfString;
376 LblLFOnly,LblCRLFAlways,LblCRLFCommitAsIs:TLabel;
377 BtnPlink:TButton;
378 Data:String;
379 begin
381 PrevPageID:=wpSelectProgramGroup;
384 * Create a custom page for modifying the environment.
387 PathPage:=CreateCustomPage(
388 PrevPageID,
389 'Adjusting your PATH environment',
390 'How would you like to use Git from the command line?'
392 PrevPageID:=PathPage.ID;
394 // 1st choice
395 RdbPath[GP_BashOnly]:=TRadioButton.Create(PathPage);
396 with RdbPath[GP_BashOnly] do begin
397 Parent:=PathPage.Surface;
398 Caption:='Use Git Bash only';
399 Left:=ScaleX(4);
400 Top:=ScaleY(8);
401 Width:=ScaleX(405);
402 Height:=ScaleY(17);
403 Font.Style:=[fsBold];
404 TabOrder:=0;
405 Checked:=True;
406 end;
407 LblGitBash:=TLabel.Create(PathPage);
408 with LblGitBash do begin
409 Parent:=PathPage.Surface;
410 Caption:=
411 'This is the most conservative choice if you are concerned about the stability' + #13 +
412 'of your system. Your PATH will not be modified.';
413 Left:=ScaleX(28);
414 Top:=ScaleY(32);
415 Width:=ScaleX(405);
416 Height:=ScaleY(26);
417 end;
419 // 2nd choice
420 RdbPath[GP_Cmd]:=TRadioButton.Create(PathPage);
421 with RdbPath[GP_Cmd] do begin
422 Parent:=PathPage.Surface;
423 Caption:='Run Git from the Windows Command Prompt';
424 Left:=ScaleX(4);
425 Top:=ScaleY(76);
426 Width:=ScaleX(405);
427 Height:=ScaleY(17);
428 Font.Style:=[fsBold];
429 TabOrder:=1;
430 end;
431 LblGitCmd:=TLabel.Create(PathPage);
432 with LblGitCmd do begin
433 Parent:=PathPage.Surface;
434 Caption:=
435 'This option is considered safe and no conflicts with other tools are known.' + #13 +
436 'Only Git will be added to your PATH. Use this option if you want to use Git' + #13 +
437 'from a Cygwin Prompt (make sure to not have Cygwin''s Git installed).';
438 Left:=ScaleX(28);
439 Top:=ScaleY(100);
440 Width:=ScaleX(405);
441 Height:=ScaleY(39);
442 end;
444 // 3rd choice
445 RdbPath[GP_CmdTools]:=TRadioButton.Create(PathPage);
446 with RdbPath[GP_CmdTools] do begin
447 Parent:=PathPage.Surface;
448 Caption:='Run Git and included Unix tools from the Windows Command Prompt';
449 Left:=ScaleX(4);
450 Top:=ScaleY(152);
451 Width:=ScaleX(405);
452 Height:=ScaleY(17);
453 Font.Style:=[fsBold];
454 TabOrder:=2;
455 end;
456 LblGitCmdTools:=TLabel.Create(PathPage);
457 with LblGitCmdTools do begin
458 Parent:=PathPage.Surface;
459 Caption:='Both Git and its accompanying Unix tools will be added to your PATH.';
460 Left:=ScaleX(28);
461 Top:=ScaleY(176);
462 Width:=ScaleX(405);
463 Height:=ScaleY(13);
464 end;
465 LblGitCmdToolsWarn:=TLabel.Create(PathPage);
466 with LblGitCmdToolsWarn do begin
467 Parent:=PathPage.Surface;
468 Caption:=
469 'Warning: This will override Windows tools like find.exe and' + #13 +
470 'sort.exe. Select this option only if you understand the implications.';
471 Left:=ScaleX(28);
472 Top:=ScaleY(192);
473 Width:=ScaleX(405);
474 Height:=ScaleY(26);
475 Font.Color:=255;
476 Font.Style:=[fsBold];
477 end;
479 // Restore the setting chosen during a previous install.
480 Data:=GetPreviousData('Path Option','BashOnly');
481 if Data='BashOnly' then begin
482 RdbPath[GP_BashOnly].Checked:=True;
483 end else if Data='Cmd' then begin
484 RdbPath[GP_Cmd].Checked:=True;
485 end else if Data='CmdTools' then begin
486 RdbPath[GP_CmdTools].Checked:=True;
487 end;
490 * Create a custom page for using (Tortoise)Plink instead of OpenSSH
491 * if at least one PuTTY session is found in the Registry.
494 if RegGetSubkeyNames(HKEY_CURRENT_USER,'Software\SimonTatham\PuTTY\Sessions',PuTTYSessions) and (GetArrayLength(PuTTYSessions)>0) then begin
495 PuTTYPage:=CreateCustomPage(
496 PrevPageID,
497 'Choosing the SSH executable',
498 'Which Secure Shell client program would you like Git to use?'
500 PrevPageID:=PuTTYPage.ID;
502 // 1st choice
503 RdbSSH[GS_OpenSSH]:=TRadioButton.Create(PuTTYPage);
504 with RdbSSH[GS_OpenSSH] do begin
505 Parent:=PuTTYPage.Surface;
506 Caption:='Use OpenSSH';
507 Left:=ScaleX(4);
508 Top:=ScaleY(8);
509 Width:=ScaleX(405);
510 Height:=ScaleY(17);
511 Font.Style:=[fsBold];
512 TabOrder:=0;
513 Checked:=True;
514 end;
515 LblOpenSSH:=TLabel.Create(PuTTYPage);
516 with LblOpenSSH do begin
517 Parent:=PuTTYPage.Surface;
518 Caption:=
519 'This uses ssh.exe that comes with Git. The GIT_SSH and SVN_SSH' + #13 +
520 'environment variables will not be modified.';
521 Left:=ScaleX(28);
522 Top:=ScaleY(32);
523 Width:=ScaleX(405);
524 Height:=ScaleY(26);
525 end;
527 // 2nd choice
528 RdbSSH[GS_Plink]:=TRadioButton.Create(PuTTYPage);
529 with RdbSSH[GS_Plink] do begin
530 Parent:=PuTTYPage.Surface;
531 Caption:='Use (Tortoise)Plink';
532 Left:=ScaleX(4);
533 Top:=ScaleY(76);
534 Width:=ScaleX(405);
535 Height:=ScaleY(17);
536 Font.Style:=[fsBold];
537 TabOrder:=1;
538 end;
539 LblPlink:=TLabel.Create(PuTTYPage);
540 with LblPlink do begin
541 Parent:=PuTTYPage.Surface;
542 Caption:=
543 'PuTTY sessions were found in your Registry. You may specify the path' + #13 +
544 'to an existing copy of (Tortoise)Plink.exe from the TortoiseGit/SVN/CVS' + #13 +
545 'or PuTTY applications. The GIT_SSH and SVN_SSH environment' + #13 +
546 'variables will be adjusted to point to the following executable:';
547 Left:=ScaleX(28);
548 Top:=ScaleY(100);
549 Width:=ScaleX(405);
550 Height:=ScaleY(52);
551 end;
552 EdtPlink:=TEdit.Create(PuTTYPage);
553 with EdtPlink do begin
554 Parent:=PuTTYPage.Surface;
555 Text:=GetPreviousData('Plink Path','');
556 if not FileExists(Text) then begin
557 Text:=GetPuTTYLocation;
558 end;
559 if not FileExists(Text) then begin
560 Text:='';
561 end;
562 Left:=ScaleX(28);
563 Top:=ScaleY(161);
564 Width:=ScaleX(316);
565 Height:=ScaleY(13);
566 end;
567 BtnPlink:=TButton.Create(PuTTYPage);
568 with BtnPlink do begin
569 Parent:=PuTTYPage.Surface;
570 Caption:='...';
571 OnClick:=@BrowseForPuTTYFolder;
572 Left:=ScaleX(348);
573 Top:=ScaleY(161);
574 Width:=ScaleX(21);
575 Height:=ScaleY(21);
576 end;
578 // Restore the setting chosen during a previous install.
579 Data:=GetPreviousData('SSH Option','OpenSSH');
580 if Data='OpenSSH' then begin
581 RdbSSH[GS_OpenSSH].Checked:=True;
582 end else if Data='Plink' then begin
583 RdbSSH[GS_Plink].Checked:=True;
584 end;
585 end else begin
586 PuTTYPage:=NIL;
587 end;
590 * Create a custom page for the core.autocrlf setting.
593 CRLFPage:=CreateCustomPage(
594 PrevPageID,
595 'Configuring the line ending conversions',
596 'How should Git treat line endings in text files?'
598 PrevPageID:=CRLFPage.ID;
600 // 1st choice
601 RdbCRLF[GC_CRLFAlways]:=TRadioButton.Create(CRLFPage);
602 with RdbCRLF[GC_CRLFAlways] do begin
603 Parent:=CRLFPage.Surface;
604 Caption:='Checkout Windows-style, commit Unix-style line endings';
605 Left:=ScaleX(4);
606 Top:=ScaleY(8);
607 Width:=ScaleX(405);
608 Height:=ScaleY(17);
609 Font.Style:=[fsBold];
610 TabOrder:=0;
611 Checked:=True;
612 end;
613 LblCRLFAlways:=TLabel.Create(CRLFPage);
614 with LblCRLFAlways do begin
615 Parent:=CRLFPage.Surface;
616 Caption:=
617 'Git will convert LF to CRLF when checking out text files. When committing' + #13 +
618 'text files, CRLF will be converted to LF. For cross-platform projects,' + #13 +
619 'this is the recommended setting on Windows ("core.autocrlf" is set to "true").';
620 Left:=ScaleX(28);
621 Top:=ScaleY(32);
622 Width:=ScaleX(405);
623 Height:=ScaleY(47);
624 end;
626 // 2nd choice
627 RdbCRLF[GC_LFOnly]:=TRadioButton.Create(CRLFPage);
628 with RdbCRLF[GC_LFOnly] do begin
629 Parent:=CRLFPage.Surface;
630 Caption:='Checkout as-is, commit Unix-style line endings';
631 Left:=ScaleX(4);
632 Top:=ScaleY(80);
633 Width:=ScaleX(405);
634 Height:=ScaleY(17);
635 Font.Style:=[fsBold];
636 TabOrder:=1;
637 Checked:=False;
638 end;
639 LblLFOnly:=TLabel.Create(CRLFPage);
640 with LblLFOnly do begin
641 Parent:=CRLFPage.Surface;
642 Caption:=
643 'Git will not perform any conversion when checking out text files. When' + #13 +
644 'committing text files, CRLF will be converted to LF. For cross-platform projects,' + #13 +
645 'this is the recommended setting on Unix ("core.autocrlf" is set to "input").';
646 Left:=ScaleX(28);
647 Top:=ScaleY(104);
648 Width:=ScaleX(405);
649 Height:=ScaleY(47);
650 end;
652 // 3rd choice
653 RdbCRLF[GC_CRLFCommitAsIs]:=TRadioButton.Create(CRLFPage);
654 with RdbCRLF[GC_CRLFCommitAsIs] do begin
655 Parent:=CRLFPage.Surface;
656 Caption:='Checkout as-is, commit as-is';
657 Left:=ScaleX(4);
658 Top:=ScaleY(152);
659 Width:=ScaleX(405);
660 Height:=ScaleY(17);
661 Font.Style:=[fsBold];
662 TabOrder:=2;
663 Checked:=False;
664 end;
665 LblCRLFCommitAsIs:=TLabel.Create(CRLFPage);
666 with LblCRLFCommitAsIs do begin
667 Parent:=CRLFPage.Surface;
668 Caption:=
669 'Git will not perform any conversions when checking out or committing' + #13 +
670 'text files. Choosing this option is not recommended for cross-platform' + #13 +
671 'projects ("core.autocrlf" is set to "false").';
672 Left:=ScaleX(28);
673 Top:=ScaleY(176);
674 Width:=ScaleX(405);
675 Height:=ScaleY(47);
676 end;
678 // Restore the setting chosen during a previous install.
679 Data:=GetPreviousData('CRLF Option','CRLFAlways');
680 if Data='LFOnly' then begin
681 RdbCRLF[GC_LFOnly].Checked:=True;
682 end else if Data='CRLFAlways' then begin
683 RdbCRLF[GC_CRLFAlways].Checked:=True;
684 end else if Data='CRLFCommitAsIs' then begin
685 RdbCRLF[GC_CRLFCommitAsIs].Checked:=True;
686 end;
689 * Create a custom page for finding the processes that lock a module.
692 ProcessesPage:=CreateCustomPage(
693 wpPreparing,
694 'Replacing in-use files',
695 'The following applications use files that need to be replaced, please close them.'
698 ProcessesListBox:=TListBox.Create(ProcessesPage);
699 with ProcessesListBox do begin
700 Parent:=ProcessesPage.Surface;
701 Width:=ProcessesPage.SurfaceWidth;
702 Height:=ProcessesPage.SurfaceHeight-ScaleY(8);
703 end;
705 ProcessesRefresh:=TNewButton.Create(WizardForm);
706 with ProcessesRefresh do begin
707 Parent:=WizardForm;
708 Width:=WizardForm.CancelButton.Width;
709 Height:=WizardForm.CancelButton.Height;
710 Top:=WizardForm.CancelButton.Top;
711 Left:=WizardForm.ClientWidth-(WizardForm.CancelButton.Left+WizardForm.CancelButton.Width);
712 Caption:='&Refresh';
713 OnClick:=@RefreshProcessList;
714 end;
716 // This button is only used by the uninstaller.
717 ContinueButton:=NIL;
719 // Initially hide the Refresh button, show it when the process page becomes current.
720 ProcessesRefresh.Hide;
721 end;
723 function ShouldSkipPage(PageID:Integer):Boolean;
724 begin
725 if (ProcessesPage<>NIL) and (PageID=ProcessesPage.ID) then begin
726 // This page is only reached forward (by pressing "Next", never by pressing "Back").
727 RefreshProcessList(NIL);
728 Result:=(GetArrayLength(Processes)=0);
729 end else begin
730 Result:=False;
731 end;
732 end;
734 procedure CurPageChanged(CurPageID:Integer);
735 begin
736 if CurPageID=wpInfoBefore then begin
737 if WizardForm.NextButton.Enabled then begin
738 // By default, do not show a blinking cursor for InfoBeforeFile.
739 WizardForm.ActiveControl:=WizardForm.NextButton;
740 end;
741 end else if CurPageID=wpSelectDir then begin
742 if not IsDirWritable(WizardDirValue) then begin
743 // If the default directory is not writable, choose another default that most likely is.
744 // This will be checked later again when the user clicks "Next".
745 WizardForm.DirEdit.Text:=ExpandConstant('{userpf}\{#APP_NAME}');
746 end;
747 end else if (ProcessesPage<>NIL) and (CurPageID=ProcessesPage.ID) then begin
748 // Show the "Refresh" button only on the processes page.
749 ProcessesRefresh.Show;
750 end else begin
751 ProcessesRefresh.Hide;
752 end;
753 end;
755 function NextButtonClick(CurPageID:Integer):Boolean;
757 i:Integer;
758 Version:TWindowsVersion;
759 begin
760 Result:=True;
762 if CurPageID=wpSelectDir then begin
763 if not IsDirWritable(WizardDirValue) then begin
764 MsgBox(
765 'The specified installation directory does not seem to be writable. ' +
766 + 'Please choose another directory or restart setup as a user with sufficient permissions.'
767 , mbCriticalError
768 , MB_OK
770 Result:=False;
771 Exit;
772 end;
773 end;
775 if (PuTTYPage<>NIL) and (CurPageID=PuTTYPage.ID) then begin
776 Result:=RdbSSH[GS_OpenSSH].Checked or
777 (RdbSSH[GS_Plink].Checked and FileExists(EdtPlink.Text));
778 if not Result then begin
779 MsgBox('{#PLINK_PATH_ERROR_MSG}',mbError,MB_OK);
780 end;
781 end else if (ProcessesPage<>NIL) and (CurPageID=ProcessesPage.ID) then begin
782 // It would have been nicer to just disable the "Next" button, but the
783 // WizardForm exports the button just read-only.
784 for i:=0 to GetArrayLength(Processes)-1 do begin
785 if not Processes[i].Restartable then begin
786 MsgBox('Setup cannot continue until you close at least those applications in the list that are marked as "closing is required".',mbCriticalError,MB_OK);
787 Result:=False;
788 Exit;
789 end;
790 end;
792 Result:=(GetArrayLength(Processes)=0);
794 if not Result then begin
795 GetWindowsVersionEx(Version);
796 if Version.Major>=6 then begin
797 Result:=(MsgBox(
798 'If you continue without closing the listed applications they will be closed and restarted automatically.' + #13 + #13 +
799 'Are you sure you want to continue?',
800 mbConfirmation,
801 MB_YESNO
802 )=IDYES);
803 end else begin
804 Result:=(MsgBox(
805 'If you continue without closing the listed applications you will need to log off and on again before changes take effect.' + #13 + #13 +
806 'Are you sure you want to continue anyway?',
807 mbConfirmation,
808 MB_YESNO
809 )=IDYES);
810 end;
811 end;
812 end;
813 end;
815 procedure CurStepChanged(CurStep:TSetupStep);
817 AppDir,DllPath,FileName,TempName,Cmd,Msg:String;
818 BuiltIns,ImageNames,EnvPath,EnvHome,EnvSSH:TArrayOfString;
819 Count,i:Longint;
820 LinkCreated:Boolean;
821 FindRec:TFindRec;
822 RootKey:Integer;
823 Version:TWindowsVersion;
824 begin
825 if CurStep=ssInstall then begin
826 // Shutdown locking processes just before the actual installation starts.
827 if SessionHandle>0 then try
828 RmShutdown(SessionHandle,RmShutdownOnlyRegistered,0);
829 except
830 Log('Line {#__LINE__}: RmShutdown not supported.');
831 end;
833 Exit;
834 end;
836 // Make sure the code below is only executed just after the actual installation finishes.
837 if CurStep<>ssPostInstall then begin
838 Exit;
839 end;
841 AppDir:=ExpandConstant('{app}');
844 Bind the imported function addresses
848 DllPath:=ExpandConstant('{app}\bin;{sys}');
850 // Load the list of images from a text file.
851 FileName:=AppDir+'\{#APP_BINDIMAGE}';
852 if LoadStringsFromFile(FileName,ImageNames) then begin
853 Count:=GetArrayLength(ImageNames)-1;
854 for i:=0 to Count do begin
855 FileName:=AppDir+'\'+ImageNames[i];
856 if not BindImageEx(BIND_NO_BOUND_IMPORTS or BIND_CACHE_IMPORT_DLLS,FileName,DllPath,'',0) then begin
857 Log('Line {#__LINE__}: Error calling BindImageEx for "'+FileName+'".');
858 end;
859 end;
860 end;
861 except
862 Log('Line {#__LINE__}: An exception occurred while calling BindImageEx.');
863 end;
866 Create the built-ins
869 // Load the built-ins from a text file.
870 FileName:=AppDir+'\{#APP_BUILTINS}';
871 if LoadStringsFromFile(FileName,BuiltIns) then begin
872 Count:=GetArrayLength(BuiltIns)-1;
874 // Delete those scripts from "bin" which have been replaced by built-ins in "libexec\git-core".
875 for i:=0 to Count do begin
876 FileName:=AppDir+'\bin\'+ChangeFileExt(ExtractFileName(BuiltIns[i]),'');
877 if FileExists(FileName) and (not DeleteFile(FileName)) then begin
878 Log('Line {#__LINE__}: Unable to delete script "'+FileName+'", ignoring.');
879 end;
880 end;
882 // Create built-ins as aliases for git.exe.
883 for i:=0 to Count do begin
884 FileName:=AppDir+'\'+BuiltIns[i];
886 // Delete any existing built-in.
887 if FileExists(FileName) and (not DeleteFile(FileName)) then begin
888 Log('Line {#__LINE__}: Unable to delete existing built-in "'+FileName+'", skipping.');
889 continue;
890 end;
893 // This will throw an exception on pre-Win2k systems.
894 LinkCreated:=CreateHardLink(FileName,AppDir+'\bin\git.exe',0);
895 except
896 LinkCreated:=False;
897 Log('Line {#__LINE__}: Creating hardlink "'+FileName+'" failed, will try a copy.');
898 end;
900 if not LinkCreated then begin
901 if not FileCopy(AppDir+'\bin\git.exe',FileName,False) then begin
902 Log('Line {#__LINE__}: Creating copy "'+FileName+'" failed, giving up.');
903 // This is not a critical error, Git could basically be used without the
904 // aliases for built-ins, so we continue.
905 end;
906 end;
907 end;
909 // Delete any duplicate files in case we are updating from a non-libexec to a libexec directory layout.
910 if FindFirst(AppDir+'\libexec\git-core\*',FindRec) then begin
911 repeat
912 if (FindRec.Attributes and FILE_ATTRIBUTE_DIRECTORY)=0 then begin
913 FileName:=AppDir+'\bin\'+FindRec.name;
914 if (Pos(FindRec.name,'git.exe')<>1) and FileExists(FileName) and (not DeleteFile(FileName)) then begin
915 Log('Line {#__LINE__}: Unable to delete dupe "'+FileName+'", ignoring.');
916 end;
917 end;
918 until not FindNext(FindRec);
919 FindClose(FindRec);
920 end;
921 end else begin
922 Msg:='Line {#__LINE__}: Unable to read file "{#APP_BUILTINS}".';
923 MsgBox(Msg,mbError,MB_OK);
924 Log(Msg);
925 // This is not a critical error, Git could basically be used without the
926 // aliases for built-ins, so we continue.
927 end;
930 Adapt core.autocrlf
933 if RdbCRLF[GC_LFOnly].checked then begin
934 Cmd:='core.autocrlf input';
935 end else if RdbCRLF[GC_CRLFAlways].checked then begin
936 Cmd:='core.autocrlf true';
937 end else begin
938 Cmd:='core.autocrlf false';
939 end;
940 if not Exec(AppDir + '\bin\git.exe', 'config -f gitconfig ' + Cmd,
941 AppDir + '\etc', SW_HIDE, ewWaitUntilTerminated, i) then begin
942 Msg:='Unable to configure the line ending conversion: ' + Cmd;
943 MsgBox(Msg,mbError,MB_OK);
944 Log(Msg);
945 // This is not a critical error, the user can probably fix it manually,
946 // so we continue.
947 end;
950 Modify the environment
952 This must happen no later than ssPostInstall to make
953 "ChangesEnvironment=yes" not happend before the change!
956 FileName:=AppDir+'\setup.ini';
958 // Delete GIT_SSH and SVN_SSH if a previous installation set them (this is required for the GS_OpenSSH case).
959 EnvSSH:=GetEnvStrings('GIT_SSH',IsAdminLoggedOn);
960 if (GetArrayLength(EnvSSH)=1) and
961 (CompareStr(RemoveQuotes(EnvSSH[0]),GetIniString('Environment','GIT_SSH','',FileName))=0) then begin
962 if not SetEnvStrings('GIT_SSH',IsAdminLoggedOn,True,[]) then begin
963 Msg:='Line {#__LINE__}: Unable to reset GIT_SSH prior to install.';
964 MsgBox(Msg,mbError,MB_OK);
965 Log(Msg);
966 // This is not a critical error, the user can probably fix it manually,
967 // so we continue.
968 end;
969 end;
971 EnvSSH:=GetEnvStrings('SVN_SSH',IsAdminLoggedOn);
972 if (GetArrayLength(EnvSSH)=1) and
973 (CompareStr(RemoveQuotes(EnvSSH[0]),GetIniString('Environment','SVN_SSH','',FileName))=0) then begin
974 if not SetEnvStrings('SVN_SSH',IsAdminLoggedOn,True,[]) then begin
975 Msg:='Line {#__LINE__}: Unable to reset SVN_SSH prior to install.';
976 MsgBox(Msg,mbError,MB_OK);
977 Log(Msg);
978 // This is not a critical error, the user can probably fix it manually,
979 // so we continue.
980 end;
981 end;
983 if (PuTTYPage<>NIL) and RdbSSH[GS_Plink].Checked then begin
984 SetArrayLength(EnvSSH,1);
985 EnvSSH[0]:=EdtPlink.Text;
987 // Set GIT_SSH as specified by the user.
988 if not SetEnvStrings('GIT_SSH',IsAdminLoggedOn,True,EnvSSH) then begin
989 Msg:='Line {#__LINE__}: Unable to set the GIT_SSH environment variable.';
990 MsgBox(Msg,mbError,MB_OK);
991 Log(Msg);
992 // This is not a critical error, the user can probably fix it manually,
993 // so we continue.
994 end;
996 // Mark that we have changed GIT_SSH by writing its value to a file.
997 if not SetIniString('Environment','GIT_SSH',EnvSSH[0],FileName) then begin
998 Msg:='Line {#__LINE__}: Unable to write to file "'+FileName+'".';
999 MsgBox(Msg,mbError,MB_OK);
1000 Log(Msg);
1001 // This is not a critical error, though uninstall / reinstall will probably not run cleanly,
1002 // so we continue.
1003 end;
1005 if not SetEnvStrings('SVN_SSH',IsAdminLoggedOn,True,EnvSSH) then begin
1006 Msg:='Line {#__LINE__}: Unable to set the SVN_SSH environment variable.';
1007 MsgBox(Msg,mbError,MB_OK);
1008 Log(Msg);
1009 // This is not a critical error, the user can probably fix it manually,
1010 // so we continue.
1011 end;
1013 // Mark that we have changed SVN_SSH by writing its value to a file.
1014 if not SetIniString('Environment','SVN_SSH',EnvSSH[0],FileName) then begin
1015 Msg:='Line {#__LINE__}: Unable to write to file "'+FileName+'".';
1016 MsgBox(Msg,mbError,MB_OK);
1017 Log(Msg);
1018 // This is not a critical error, though uninstall / reinstall will probably not run cleanly,
1019 // so we continue.
1020 end;
1021 end;
1023 // Get the current user's directories in PATH.
1024 EnvPath:=GetEnvStrings('PATH',IsAdminLoggedOn);
1026 // First, remove the installation directory from PATH in any case.
1027 for i:=0 to GetArrayLength(EnvPath)-1 do begin
1028 if Pos(AppDir+'\',EnvPath[i]+'\')=1 then begin
1029 EnvPath[i]:='';
1030 end;
1031 end;
1033 // Delete HOME if a previous installation modified it.
1034 EnvHome:=GetEnvStrings('HOME',IsAdminLoggedOn);
1035 if (GetArrayLength(EnvHome)=1) and
1036 (CompareStr(RemoveQuotes(EnvHome[0]),GetIniString('Environment','HOME','',FileName))=0) then begin
1037 if not SetEnvStrings('HOME',IsAdminLoggedOn,True,[]) then begin
1038 Msg:='Line {#__LINE__}: Unable to reset HOME prior to install.';
1039 MsgBox(Msg,mbError,MB_OK);
1040 Log(Msg);
1041 // This is not a critical error, the user can probably fix it manually,
1042 // so we continue.
1043 end;
1044 end;
1046 // Modify the PATH variable as requested by the user.
1047 if RdbPath[GP_Cmd].Checked or RdbPath[GP_CmdTools].Checked then begin
1048 i:=GetArrayLength(EnvPath);
1049 SetArrayLength(EnvPath,i+1);
1051 // List \cmd before \bin so \cmd has higher priority and programs in
1052 // there will be called in favor of those in \bin.
1053 EnvPath[i]:=AppDir+'\cmd';
1055 if RdbPath[GP_CmdTools].Checked then begin
1056 SetArrayLength(EnvPath,i+2);
1057 EnvPath[i+1]:=AppDir+'\bin';
1059 // Set HOME for the Windows Command Prompt, but only if it has not been set manually before.
1060 EnvHome:=GetEnvStrings('HOME',IsAdminLoggedOn);
1061 i:=GetArrayLength(EnvHome);
1062 if (i=0) or ((i=1) and (Length(EnvHome[0])=0)) then begin
1063 SetArrayLength(EnvHome,1);
1064 EnvHome[0]:=ExpandConstant('{%HOMEDRIVE}{%HOMEPATH}');
1065 if not SetEnvStrings('HOME',IsAdminLoggedOn,True,EnvHome) then begin
1066 Msg:='Line {#__LINE__}: Unable to set the HOME environment variable.';
1067 MsgBox(Msg,mbError,MB_OK);
1068 Log(Msg);
1069 // This is not a critical error, the user can probably fix it manually,
1070 // so we continue.
1071 end;
1073 // Mark that we have changed HOME.
1074 if not SetIniString('Environment','HOME',EnvHome[0],FileName) then begin
1075 Msg:='Line {#__LINE__}: Unable to write to file "'+FileName+'".';
1076 MsgBox(Msg,mbError,MB_OK);
1077 Log(Msg);
1078 // This is not a critical error, though uninstall / reinstall will probably not run cleanly,
1079 // so we continue.
1080 end;
1081 end;
1082 end;
1083 end;
1085 // Set the current user's PATH directories.
1086 if not SetEnvStrings('PATH',IsAdminLoggedOn,True,EnvPath) then begin
1087 Msg:='Line {#__LINE__}: Unable to set the PATH environment variable.';
1088 MsgBox(Msg,mbError,MB_OK);
1089 Log(Msg);
1090 // This is not a critical error, the user can probably fix it manually,
1091 // so we continue.
1092 end;
1095 Create shortcuts that need to be created regardless of the "Don't create a Start Menu folder" toggle
1098 GetWindowsVersionEx(Version);
1099 if Version.Major<6 then begin
1100 Cmd:=ExpandConstant('{syswow64}\cmd.exe');
1101 TempName:='/c ""'+AppDir+'\bin\sh.exe" --login -i"';
1102 end else begin
1103 Cmd:=AppDir+'\bin\sh.exe';
1104 TempName:='--login -i';
1105 end;
1106 FileName:=AppDir+'\etc\git.ico';
1108 if IsComponentSelected('icons\quicklaunch') then begin
1109 CreateShellLink(
1110 ExpandConstant('{userappdata}\Microsoft\Internet Explorer\Quick Launch\Git Bash.lnk')
1111 , 'Git Bash'
1112 , Cmd
1113 , TempName
1114 , '%HOMEDRIVE%%HOMEPATH%'
1115 , FileName
1117 , SW_SHOWNORMAL
1119 end;
1120 if IsComponentSelected('icons\desktop') then begin
1121 CreateShellLink(
1122 GetShellFolder('desktop')+'\Git Bash.lnk'
1123 , 'Git Bash'
1124 , Cmd
1125 , TempName
1126 , '%HOMEDRIVE%%HOMEPATH%'
1127 , FileName
1129 , SW_SHOWNORMAL
1131 end;
1133 // Create a special shortcut that does not set a working directory (Note: Since Inno Setup 5.3.11,
1134 // passing an empty WorkingDir gets replaced with {sys}, so use '.' instead).
1135 // This shortcut is used by "Git Bash.vbs", which in turn is run by the "Git Bash Here" shell extension.
1136 CreateShellLink(
1137 AppDir+'\Git Bash.lnk'
1138 , 'Git Bash'
1139 , Cmd
1140 , TempName
1141 , '.'
1142 , FileName
1144 , SW_SHOWNORMAL
1148 Create the Windows Explorer integrations
1151 if IsAdminLoggedOn then begin
1152 RootKey:=HKEY_LOCAL_MACHINE;
1153 end else begin
1154 RootKey:=HKEY_CURRENT_USER;
1155 end;
1157 if IsComponentSelected('ext\reg\shellhere') then begin
1158 Msg:='Git Ba&sh Here';
1159 Cmd:='"'+ExpandConstant('{syswow64}')+'\wscript" "'+AppDir+'\Git Bash.vbs" "%1"';
1160 if (not RegWriteStringValue(RootKey,'SOFTWARE\Classes\Directory\shell\git_shell','',Msg)) or
1161 (not RegWriteStringValue(RootKey,'SOFTWARE\Classes\Directory\shell\git_shell\command','',Cmd)) or
1162 (StringChangeEx(Cmd,'%1','%v',false)<>1) or
1163 (not RegWriteStringValue(RootKey,'SOFTWARE\Classes\Directory\Background\shell\git_shell','',Msg)) or
1164 (not RegWriteStringValue(RootKey,'SOFTWARE\Classes\Directory\Background\shell\git_shell\command','',Cmd)) then begin
1165 Msg:='Line {#__LINE__}: Unable to create "Git Bash Here" shell extension.';
1166 MsgBox(Msg,mbError,MB_OK);
1167 Log(Msg);
1168 // This is not a critical error, the user can probably fix it manually,
1169 // so we continue.
1170 end;
1171 end;
1173 if IsComponentSelected('ext\reg\guihere') then begin
1174 Msg:='Git &GUI Here';
1175 Cmd:='"'+AppDir+'\bin\wish.exe" "'+AppDir+'\libexec\git-core\git-gui" "--working-dir" "%1"';
1176 if (not RegWriteStringValue(RootKey,'SOFTWARE\Classes\Directory\shell\git_gui','',Msg)) or
1177 (not RegWriteStringValue(RootKey,'SOFTWARE\Classes\Directory\shell\git_gui\command','',Cmd)) or
1178 (StringChangeEx(Cmd,'%1','%v',false)<>1) or
1179 (not RegWriteStringValue(RootKey,'SOFTWARE\Classes\Directory\Background\shell\git_gui','',Msg)) or
1180 (not RegWriteStringValue(RootKey,'SOFTWARE\Classes\Directory\Background\shell\git_gui\command','',Cmd)) then begin
1181 Msg:='Line {#__LINE__}: Unable to create "Git GUI Here" shell extension.';
1182 MsgBox(Msg,mbError,MB_OK);
1183 Log(Msg);
1184 // This is not a critical error, the user can probably fix it manually,
1185 // so we continue.
1186 end;
1187 end;
1189 // It is either the Registry-based context menu entries, or the shell extension.
1190 if IsComponentSelected('ext\cheetah') then begin
1191 DeleteContextMenuEntries;
1193 if isWin64 then begin
1194 FileName:=AppDir+'\git-cheetah\git_shell_ext64.dll';
1195 end else begin
1196 FileName:=AppDir+'\git-cheetah\git_shell_ext.dll';
1197 end;
1198 if not ReplaceInUseFile(FileName,FileName+'.new',True) then begin
1199 Log('Line {#__LINE__}: Replacing file "'+FileName+'" failed.');
1200 end;
1201 end;
1204 Restart any processes that were shut down via the Restart Manager
1207 if SessionHandle>0 then try
1208 RmRestart(SessionHandle,0,0);
1209 RmEndSession(SessionHandle);
1210 except
1211 Log('Line {#__LINE__}: RmRestart not supported.');
1212 end;
1213 end;
1215 procedure RegisterPreviousData(PreviousDataKey:Integer);
1217 Data:String;
1218 begin
1219 // Git Path options.
1220 Data:='';
1221 if RdbPath[GP_BashOnly].Checked then begin
1222 Data:='BashOnly';
1223 end else if RdbPath[GP_Cmd].Checked then begin
1224 Data:='Cmd';
1225 end else if RdbPath[GP_CmdTools].Checked then begin
1226 Data:='CmdTools';
1227 end;
1228 SetPreviousData(PreviousDataKey,'Path Option',Data);
1230 // Git SSH options.
1231 Data:='';
1232 if (PuTTYPage=NIL) or RdbSSH[GS_OpenSSH].Checked then begin
1233 Data:='OpenSSH';
1234 end else if RdbSSH[GS_Plink].Checked then begin
1235 Data:='Plink';
1236 SetPreviousData(PreviousDataKey,'Plink Path',EdtPlink.Text);
1237 end;
1238 SetPreviousData(PreviousDataKey,'SSH Option',Data);
1240 // Line ending conversion options.
1241 Data:='';
1242 if RdbCRLF[GC_LFOnly].Checked then begin
1243 Data:='LFOnly';
1244 end else if RdbCRLF[GC_CRLFAlways].Checked then begin
1245 Data:='CRLFAlways';
1246 end else if RdbCRLF[GC_CRLFCommitAsIs].Checked then begin
1247 Data:='CRLFCommitAsIs';
1248 end;
1249 SetPreviousData(PreviousDataKey,'CRLF Option',Data);
1250 end;
1253 Uninstaller code
1256 function InitializeUninstall:Boolean;
1258 Form:TSetupForm;
1259 Info:TLabel;
1260 ExitButton,RefreshButton:TButton;
1261 begin
1262 Result:=True;
1264 Form:=CreateCustomForm;
1266 Form.Caption:='Git Uninstall: Removing in-use files';
1267 Form.ClientWidth:=ScaleX(500);
1268 Form.ClientHeight:=ScaleY(256);
1269 Form.Center;
1271 Info:=TLabel.Create(Form);
1272 with Info do begin
1273 Parent:=Form;
1274 Left:=ScaleX(11);
1275 Top:=ScaleY(11);
1276 AutoSize:=True;
1277 Caption:='The following applications use files that need to be removed, please close them.';
1278 end;
1280 ContinueButton:=TButton.Create(Form);
1281 with ContinueButton do begin
1282 Parent:=Form;
1283 Left:=Form.ClientWidth-ScaleX(75+10);
1284 Top:=Form.ClientHeight-ScaleY(23+10);
1285 Width:=ScaleX(75);
1286 Height:=ScaleY(23);
1287 Caption:='Continue';
1288 ModalResult:=mrOk;
1289 end;
1291 ExitButton:=TButton.Create(Form);
1292 with ExitButton do begin
1293 Parent:=Form;
1294 Left:=ContinueButton.Left-ScaleX(75+6);
1295 Top:=ContinueButton.Top;
1296 Width:=ScaleX(75);
1297 Height:=ScaleY(23);
1298 Caption:='Exit';
1299 ModalResult:=mrCancel;
1300 Cancel:=True;
1301 end;
1303 RefreshButton:=TButton.Create(Form);
1304 with RefreshButton do begin
1305 Parent:=Form;
1306 Left:=ScaleX(10);
1307 Top:=ExitButton.Top;
1308 Width:=ScaleX(75);
1309 Height:=ScaleY(23);
1310 Caption:='Refresh';
1311 OnClick:=@RefreshProcessList;
1312 end;
1314 ProcessesListBox:=TListBox.Create(Form);
1315 with ProcessesListBox do begin
1316 Parent:=Form;
1317 Left:=ScaleX(11);
1318 Top:=Info.Top+Info.Height+11;
1319 Width:=Form.ClientWidth-ScaleX(11*2);
1320 Height:=ContinueButton.Top-ScaleY(11*4);
1321 end;
1323 Form.ActiveControl:=ContinueButton;
1325 RefreshProcessList(NIL);
1326 if GetArrayLength(Processes)>0 then begin
1327 // Now that these dialogs are going to be shown, we should probably
1328 // disable the "Are you sure to remove Git?" confirmation dialog, but
1329 // unfortunately that is not possible with Inno Setup currently.
1330 Result:=(Form.ShowModal()=mrOk);
1332 // Note: The number of processes might have changed during a refresh.
1333 if Result and (GetArrayLength(Processes)>0) then begin
1334 Result:=(MsgBox(
1335 'If you continue without closing the listed applications, you will need to log off and on again to remove some files manually.' + #13 + #13 +
1336 'Are you sure you want to continue anyway?',
1337 mbConfirmation,
1338 MB_YESNO
1339 )=IDYES);
1340 end;
1341 end;
1342 finally
1343 Form.free;
1344 end;
1345 end;
1347 // PreUninstall
1349 // Even though the name of this function suggests otherwise most of the
1350 // code below is only executed right before the actual uninstallation.
1351 // This happens because of the if-guard right in the beginning of this
1352 // function.
1353 procedure CurUninstallStepChanged(CurUninstallStep:TUninstallStep);
1355 AppDir,FileName,Msg:String;
1356 EnvPath,EnvHome,EnvSSH:TArrayOfString;
1357 i:Longint;
1358 begin
1359 if CurUninstallStep<>usUninstall then begin
1360 Exit;
1361 end;
1363 // Reset the console font (the FontType is reset in the Registry section).
1364 if IsComponentInstalled('consolefont') then begin
1365 if MsgBox('Do you want to revert the TrueType font setting for all console windows?',mbConfirmation,MB_YESNO)=IDYES then begin
1366 RegWriteDWordValue(HKEY_CURRENT_USER,'Console','FontFamily',0);
1367 RegWriteDWordValue(HKEY_CURRENT_USER,'Console','FontSize',0);
1368 RegWriteDWordValue(HKEY_CURRENT_USER,'Console','FontWeight',0);
1369 end;
1370 end;
1373 Modify the environment
1375 This must happen no later than usUninstall to make
1376 "ChangesEnvironment=yes" not happend before the change!
1379 AppDir:=ExpandConstant('{app}');
1380 FileName:=AppDir+'\setup.ini';
1382 // Delete the current user's GIT_SSH and SVN_SSH if we set it.
1383 EnvSSH:=GetEnvStrings('GIT_SSH',IsAdminLoggedOn);
1384 if (GetArrayLength(EnvSSH)=1) and
1385 (CompareStr(RemoveQuotes(EnvSSH[0]),GetIniString('Environment','GIT_SSH','',FileName))=0) then begin
1386 if not SetEnvStrings('GIT_SSH',IsAdminLoggedOn,True,[]) then begin
1387 Msg:='Line {#__LINE__}: Unable to revert any possible changes to GIT_SSH.';
1388 MsgBox(Msg,mbError,MB_OK);
1389 Log(Msg);
1390 // This is not a critical error, the user can probably fix it manually,
1391 // so we continue.
1392 end;
1393 end;
1395 EnvSSH:=GetEnvStrings('SVN_SSH',IsAdminLoggedOn);
1396 if (GetArrayLength(EnvSSH)=1) and
1397 (CompareStr(RemoveQuotes(EnvSSH[0]),GetIniString('Environment','SVN_SSH','',FileName))=0) then begin
1398 if not SetEnvStrings('SVN_SSH',IsAdminLoggedOn,True,[]) then begin
1399 Msg:='Line {#__LINE__}: Unable to revert any possible changes to SVN_SSH.';
1400 MsgBox(Msg,mbError,MB_OK);
1401 Log(Msg);
1402 // This is not a critical error, the user can probably fix it manually,
1403 // so we continue.
1404 end;
1405 end;
1407 // Get the current user's directories in PATH.
1408 EnvPath:=GetEnvStrings('PATH',IsAdminLoggedOn);
1410 // Remove the installation directory from PATH in any case, even if it
1411 // was not added by the installer.
1412 for i:=0 to GetArrayLength(EnvPath)-1 do begin
1413 if Pos(AppDir+'\',EnvPath[i]+'\')=1 then begin
1414 EnvPath[i]:='';
1415 end;
1416 end;
1418 // Reset the current user's directories in PATH.
1419 if not SetEnvStrings('PATH',IsAdminLoggedOn,True,EnvPath) then begin
1420 Msg:='Line {#__LINE__}: Unable to revert any possible changes to PATH.';
1421 MsgBox(Msg,mbError,MB_OK);
1422 Log(Msg);
1423 // This is not a critical error, the user can probably fix it manually,
1424 // so we continue.
1425 end;
1427 // Reset the current user's HOME if we modified it.
1428 EnvHome:=GetEnvStrings('HOME',IsAdminLoggedOn);
1429 if (GetArrayLength(EnvHome)=1) and
1430 (CompareStr(RemoveQuotes(EnvHome[0]),GetIniString('Environment','HOME','',FileName))=0) then begin
1431 if not SetEnvStrings('HOME',IsAdminLoggedOn,True,[]) then begin
1432 Msg:='Line {#__LINE__}: Unable to revert any possible changes to HOME.';
1433 MsgBox(Msg,mbError,MB_OK);
1434 Log(Msg);
1435 // This is not a critical error, the user can probably fix it manually,
1436 // so we continue.
1437 end;
1438 end;
1440 if FileExists(FileName) and (not DeleteFile(FileName)) then begin
1441 Msg:='Line {#__LINE__}: Unable to delete file "'+FileName+'".';
1442 MsgBox(Msg,mbError,MB_OK);
1443 Log(Msg);
1444 // This is not a critical error, the user can probably fix it manually,
1445 // so we continue.
1446 end;
1449 Delete the Windows Explorer integrations
1452 DeleteContextMenuEntries;
1454 if isWin64 then begin
1455 FileName:=AppDir+'\git-cheetah\git_shell_ext64.dll';
1456 end else begin
1457 FileName:=AppDir+'\git-cheetah\git_shell_ext.dll';
1458 end;
1459 if FileExists(FileName) then begin
1460 if not UnregisterServer(Is64BitInstallMode,FileName,False) then begin
1461 Msg:='Line {#__LINE__}: Unable to unregister file "'+FileName+'". Please do it manually by running "regsvr32 /u '+ExtractFileName(FileName)+'".';
1462 MsgBox(Msg,mbError,MB_OK);
1463 Log(Msg);
1464 end;
1466 if not DeleteFile(FileName) then begin
1467 Msg:='Line {#__LINE__}: Unable to delete file "'+FileName+'". Please do it manually after logging off and on again.';
1468 MsgBox(Msg,mbError,MB_OK);
1469 Log(Msg);
1470 end;
1471 end;
1472 end;