Installer: Use a simpler way to uncheck the console font option by default
[msysgit.git] / share / WinGit / install.iss
blobaedf5aa5d351c202e9b7b2fc30f1ebcf0b107931
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 DROP_HANDLER_GUID '{{86C86720-42A0-1069-A2E8-08002B30309D}'
16 [Setup]
17 ; Compiler-related
18 Compression=lzma2/ultra
19 LZMAUseSeparateProcess=yes
20 OutputBaseFilename={#APP_NAME+'-'+APP_VERSION}
21 OutputDir={#GetEnv('USERPROFILE')}
22 SolidCompression=yes
23 #ifdef COMPILE_FROM_IDE
24 SourceDir={#GetEnv('TEMP')}\WinGit
25 #endif
27 ; Installer-related
28 AllowNoIcons=yes
29 AppName={#APP_NAME}
30 AppPublisher=The Git Development Community
31 AppPublisherURL={#APP_URL}
32 AppVersion={#APP_VERSION}
33 ChangesEnvironment=yes
34 DefaultDirName={pf}\{#APP_NAME}
35 DisableDirPage=auto
36 DefaultGroupName={#APP_NAME}
37 DisableProgramGroupPage=auto
38 DisableReadyPage=yes
39 InfoBeforeFile=gpl-2.0.rtf
40 PrivilegesRequired=none
41 UninstallDisplayIcon={app}\etc\git.ico
42 #ifndef COMPILE_FROM_IDE
43 #if Pos('-',APP_VERSION)>0
44 VersionInfoVersion={#Copy(APP_VERSION,1,Pos('-',APP_VERSION)-1)}
45 #else
46 VersionInfoVersion={#APP_VERSION}
47 #endif
48 #endif
50 ; Cosmetic
51 SetupIconFile=etc\git.ico
52 WizardImageBackColor=clWhite
53 WizardImageStretch=no
54 WizardImageFile=git.bmp
55 WizardSmallImageFile=gitsmall.bmp
57 [Types]
58 ; Define a custom type to avoid getting the three default types.
59 Name: default; Description: Default installation; Flags: iscustom
61 [Components]
62 Name: icons; Description: Additional icons; Types: default
63 Name: icons\quicklaunch; Description: In the Quick Launch; Types: default
64 Name: icons\desktop; Description: On the Desktop; Types: default
65 Name: ext; Description: Windows Explorer integration; Types: default
66 Name: ext\reg; Description: Simple context menu (Registry based); Flags: exclusive; Types: default
67 Name: ext\reg\shellhere; Description: Git Bash Here; Types: default
68 Name: ext\reg\guihere; Description: Git GUI Here; Types: default
69 Name: ext\cheetah; Description: Advanced context menu (git-cheetah plugin); Flags: exclusive; Types: default
70 Name: assoc; Description: Associate .git* configuration files with the default text editor; Types: default
71 Name: assoc_sh; Description: Associate .sh files to be run with Bash; Types: default
72 Name: consolefont; Description: Use a TrueType font in all console windows (not only for Git Bash)
74 [Files]
75 ; Install files that might be in use during setup under a different name.
76 Source: git-cheetah\git_shell_ext.dll; DestDir: {app}\git-cheetah; DestName: git_shell_ext.dll.new; Flags: replacesameversion; Components: ext\cheetah; AfterInstall: DeleteFromVirtualStore
77 Source: git-cheetah\git_shell_ext64.dll; DestDir: {app}\git-cheetah; DestName: git_shell_ext64.dll.new; Flags: replacesameversion; Components: ext\cheetah; AfterInstall: DeleteFromVirtualStore
79 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
80 Source: ReleaseNotes.rtf; DestDir: {app}; Flags: isreadme replacesameversion; AfterInstall: DeleteFromVirtualStore
82 [Icons]
83 Name: {group}\Git GUI; Filename: {app}\bin\wish.exe; Parameters: """{app}\libexec\git-core\git-gui"""; WorkingDir: %HOMEDRIVE%%HOMEPATH%; IconFilename: {app}\etc\git.ico
84 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
85 Name: {group}\Git Bash; Filename: {app}\bin\sh.exe; Parameters: "--login -i"; WorkingDir: %HOMEDRIVE%%HOMEPATH%; IconFilename: {app}\etc\git.ico; MinVersion: 6.0
87 [Messages]
88 BeveledLabel={#APP_URL}
89 SetupAppTitle={#APP_NAME} Setup
90 SetupWindowTitle={#APP_NAME} Setup
92 [Registry]
93 ; There is no "Console" key in HKLM.
94 Root: HKCU; Subkey: Console; ValueType: string; ValueName: FaceName; ValueData: Lucida Console; Flags: uninsclearvalue; Components: consolefont
95 Root: HKCU; Subkey: Console; ValueType: dword; ValueName: FontFamily; ValueData: $00000036; Components: consolefont
96 Root: HKCU; Subkey: Console; ValueType: dword; ValueName: FontSize; ValueData: $000e0000; Components: consolefont
97 Root: HKCU; Subkey: Console; ValueType: dword; ValueName: FontWeight; ValueData: $00000190; Components: consolefont
99 Root: HKCU; Subkey: Console\Git Bash; ValueType: string; ValueName: FaceName; ValueData: Lucida Console; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty
100 Root: HKCU; Subkey: Console\Git Bash; ValueType: dword; ValueName: FontFamily; ValueData: $00000036; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty
101 Root: HKCU; Subkey: Console\Git Bash; ValueType: dword; ValueName: FontSize; ValueData: $000e0000; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty
102 Root: HKCU; Subkey: Console\Git Bash; ValueType: dword; ValueName: FontWeight; ValueData: $00000190; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty
104 ; Note that we write the Registry values below either to HKLM or to HKCU depending on whether the user running the installer
105 ; is a member of the local Administrators group or not (see the "Check" argument).
107 ; File associations for configuration files that may be contained in a repository (so this does not include ".gitconfig").
108 Root: HKLM; Subkey: Software\Classes\.gitattributes; ValueType: string; ValueData: txtfile; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty; Check: IsAdminLoggedOn; Components: assoc
109 Root: HKLM; Subkey: Software\Classes\.gitattributes; ValueType: string; ValueName: Content Type; ValueData: text/plain; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty; Check: IsAdminLoggedOn; Components: assoc
110 Root: HKLM; Subkey: Software\Classes\.gitattributes; ValueType: string; ValueName: PerceivedType; ValueData: text; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty; Check: IsAdminLoggedOn; Components: assoc
111 Root: HKCU; Subkey: Software\Classes\.gitattributes; ValueType: string; ValueData: txtfile; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty; Check: not IsAdminLoggedOn; Components: assoc
112 Root: HKCU; Subkey: Software\Classes\.gitattributes; ValueType: string; ValueName: Content Type; ValueData: text/plain; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty; Check: not IsAdminLoggedOn; Components: assoc
113 Root: HKCU; Subkey: Software\Classes\.gitattributes; ValueType: string; ValueName: PerceivedType; ValueData: text; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty; Check: not IsAdminLoggedOn; Components: assoc
115 Root: HKLM; Subkey: Software\Classes\.gitignore; ValueType: string; ValueData: txtfile; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty; Check: IsAdminLoggedOn; Components: assoc
116 Root: HKLM; Subkey: Software\Classes\.gitignore; ValueType: string; ValueName: Content Type; ValueData: text/plain; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty; Check: IsAdminLoggedOn; Components: assoc
117 Root: HKLM; Subkey: Software\Classes\.gitignore; ValueType: string; ValueName: PerceivedType; ValueData: text; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty; Check: IsAdminLoggedOn; Components: assoc
118 Root: HKCU; Subkey: Software\Classes\.gitignore; ValueType: string; ValueData: txtfile; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty; Check: not IsAdminLoggedOn; Components: assoc
119 Root: HKCU; Subkey: Software\Classes\.gitignore; ValueType: string; ValueName: Content Type; ValueData: text/plain; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty; Check: not IsAdminLoggedOn; Components: assoc
120 Root: HKCU; Subkey: Software\Classes\.gitignore; ValueType: string; ValueName: PerceivedType; ValueData: text; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty; Check: not IsAdminLoggedOn; Components: assoc
122 Root: HKLM; Subkey: Software\Classes\.gitmodules; ValueType: string; ValueData: txtfile; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty; Check: IsAdminLoggedOn; Components: assoc
123 Root: HKLM; Subkey: Software\Classes\.gitmodules; ValueType: string; ValueName: Content Type; ValueData: text/plain; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty; Check: IsAdminLoggedOn; Components: assoc
124 Root: HKLM; Subkey: Software\Classes\.gitmodules; ValueType: string; ValueName: PerceivedType; ValueData: text; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty; Check: IsAdminLoggedOn; Components: assoc
125 Root: HKCU; Subkey: Software\Classes\.gitmodules; ValueType: string; ValueData: txtfile; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty; Check: not IsAdminLoggedOn; Components: assoc
126 Root: HKCU; Subkey: Software\Classes\.gitmodules; ValueType: string; ValueName: Content Type; ValueData: text/plain; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty; Check: not IsAdminLoggedOn; Components: assoc
127 Root: HKCU; Subkey: Software\Classes\.gitmodules; ValueType: string; ValueName: PerceivedType; ValueData: text; Flags: createvalueifdoesntexist uninsdeletevalue uninsdeletekeyifempty; Check: not IsAdminLoggedOn; Components: assoc
129 ; Associate .sh extension with sh.exe so those files are double-clickable,
130 ; startable from cmd.exe, and when files are dropped on them they are passed
131 ; as arguments to the script.
133 ; Install under HKEY_LOCAL_MACHINE if an administrator is installing.
134 Root: HKLM; Subkey: Software\Classes\.sh; ValueType: string; ValueData: sh_auto_file; Flags: createvalueifdoesntexist uninsdeletekeyifempty uninsdeletevalue; Check: IsAdminLoggedOn; Components: assoc_sh
135 Root: HKLM; Subkey: Software\Classes\sh_auto_file; ValueType: string; ValueData: "Shell Script"; Flags: createvalueifdoesntexist uninsdeletekeyifempty uninsdeletevalue; Check: IsAdminLoggedOn; Components: assoc_sh
136 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
137 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
138 Root: HKLM; Subkey: Software\Classes\sh_auto_file\DefaultIcon; ValueType: string; ValueData: "%SystemRoot%\System32\shell32.dll,-153"; Flags: createvalueifdoesntexist uninsdeletekeyifempty uninsdeletevalue; Check: IsAdminLoggedOn; Components: assoc_sh
139 Root: HKLM; Subkey: Software\Classes\sh_auto_file\ShellEx\DropHandler; ValueType: string; ValueData: {#DROP_HANDLER_GUID}; Flags: uninsdeletekeyifempty uninsdeletevalue; Check: IsAdminLoggedOn; Components: assoc_sh
141 ; Install under HKEY_CURRENT_USER if a non-administrator is installing.
142 Root: HKCU; Subkey: Software\Classes\.sh; ValueType: string; ValueData: sh_auto_file; Flags: createvalueifdoesntexist uninsdeletekeyifempty uninsdeletevalue; Check: not IsAdminLoggedOn; Components: assoc_sh
143 Root: HKCU; Subkey: Software\Classes\sh_auto_file; ValueType: string; ValueData: "Shell Script"; Flags: createvalueifdoesntexist uninsdeletekeyifempty uninsdeletevalue; Check: not IsAdminLoggedOn; Components: assoc_sh
144 Root: HKCU; Subkey: Software\Classes\sh_auto_file\shell\open\command; ValueType: string; ValueData: "{syswow64}\cmd.exe /C """"{app}\bin\sh.exe"" ""--login"" ""%1"" %*"""; Flags: createvalueifdoesntexist uninsdeletekeyifempty uninsdeletevalue; Check: not IsAdminLoggedOn; Components: assoc_sh; OnlyBelowVersion: 6.0
145 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
146 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
147 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
149 [UninstallDelete]
150 ; Delete the built-ins.
151 Type: files; Name: {app}\bin\git-*.exe
152 Type: files; Name: {app}\libexec\git-core\git-*.exe
153 Type: files; Name: {app}\libexec\git-core\git.exe
155 ; Delete any (temporary) git-cheetah files.
156 Type: files; Name: {app}\git-cheetah\*.*
158 ; Delete any manually created shortcuts.
159 Type: files; Name: {userappdata}\Microsoft\Internet Explorer\Quick Launch\Git Bash.lnk
160 Type: files; Name: {code:GetShellFolder|desktop}\Git Bash.lnk
161 Type: files; Name: {app}\Git Bash.lnk
163 ; Delete a home directory inside the msysGit directory.
164 Type: dirifempty; Name: {app}\home\{username}
165 Type: dirifempty; Name: {app}\home
167 [Code]
168 #include "helpers.inc.iss"
169 #include "environment.inc.iss"
170 #include "putty.inc.iss"
171 #include "modules.inc.iss"
173 procedure DeleteFromVirtualStore;
175 VirtualStore,FileName:String;
176 DriveChars:Integer;
177 begin
178 VirtualStore:=AddBackslash(ExpandConstant('{localappdata}'))+'VirtualStore';
179 FileName:=ExpandConstant(CurrentFileName);
180 DriveChars:=Length(ExtractFileDrive(FileName));
181 if DriveChars>0 then begin
182 Delete(FileName,1,DriveChars);
183 FileName:=VirtualStore+FileName;
184 if FileExists(FileName) and (not DeleteFile(FileName)) then begin
185 Log('Line {#__LINE__}: Unable delete "'+FileName+'".');
186 // This is not a critical error, the user can probably fix it manually,
187 // so we continue.
188 end;
189 end;
190 end;
192 function CreateHardLink(lpFileName,lpExistingFileName:String;lpSecurityAttributes:Integer):Boolean;
193 #ifdef UNICODE
194 external 'CreateHardLinkW@Kernel32.dll stdcall delayload setuponly';
195 #else
196 external 'CreateHardLinkA@Kernel32.dll stdcall delayload setuponly';
197 #endif
199 function BindImageEx(Flags:DWORD;ImageName,DllPath,SymbolPath:AnsiString;StatusRoutine:Integer):Boolean;
200 external 'BindImageEx@Imagehlp.dll stdcall delayload setuponly';
202 const
203 // Git Path options.
204 GP_BashOnly = 1;
205 GP_Cmd = 2;
206 GP_CmdTools = 3;
208 // Git SSH options.
209 GS_OpenSSH = 1;
210 GS_Plink = 2;
212 // Git line ending conversion options.
213 GC_LFOnly = 1;
214 GC_CRLFAlways = 2;
215 GC_CRLFCommitAsIs = 3;
217 // BindImageEx API constants.
218 BIND_NO_BOUND_IMPORTS = $00000001;
219 BIND_NO_UPDATE = $00000002;
220 BIND_ALL_IMAGES = $00000004;
221 BIND_CACHE_IMPORT_DLLS = $00000008;
224 // Wizard page and variables for the Path options.
225 PathPage:TWizardPage;
226 RdbPath:array[GP_BashOnly..GP_CmdTools] of TRadioButton;
228 // Wizard page and variables for the SSH options.
229 PuTTYPage:TWizardPage;
230 RdbSSH:array[GS_OpenSSH..GS_Plink] of TRadioButton;
231 EdtPlink:TEdit;
233 // Wizard page and variables for the line ending conversion options.
234 CRLFPage:TWizardPage;
235 RdbCRLF:array[GC_LFOnly..GC_CRLFCommitAsIs] of TRadioButton;
237 // Wizard page and variables for the processes page.
238 SessionHandle:DWORD;
239 Processes:ProcessList;
240 ProcessesPage:TWizardPage;
241 ProcessesListBox:TListBox;
242 ProcessesRefresh,ContinueButton:TButton;
244 procedure BrowseForPuTTYFolder(Sender:TObject);
246 Path:String;
247 begin
248 Path:=ExtractFilePath(EdtPlink.Text);
249 BrowseForFolder('Please select the PuTTY folder:',Path,False);
250 if FileExists(Path+'\TortoisePlink.exe') then begin
251 EdtPlink.Text:=Path+'\TortoisePlink.exe';
252 RdbSSH[GS_Plink].Checked:=True;
253 end else if FileExists(Path+'\plink.exe') then begin
254 EdtPlink.Text:=Path+'\plink.exe';
255 RdbSSH[GS_Plink].Checked:=True;
256 end else begin
257 MsgBox('Please enter a valid path to "TortoisePlink.exe" or "plink.exe".',mbError,MB_OK);
258 end;
259 end;
261 procedure DeleteContextMenuEntries;
263 AppDir,Command,Msg:String;
264 RootKey,i:Integer;
265 Keys:TArrayOfString;
266 begin
267 AppDir:=ExpandConstant('{app}');
269 if IsAdminLoggedOn then begin
270 RootKey:=HKEY_LOCAL_MACHINE;
271 end else begin
272 RootKey:=HKEY_CURRENT_USER;
273 end;
275 SetArrayLength(Keys,4);
276 Keys[0]:='SOFTWARE\Classes\Directory\shell\git_shell';
277 Keys[1]:='SOFTWARE\Classes\Directory\Background\shell\git_shell';
278 Keys[2]:='SOFTWARE\Classes\Directory\shell\git_gui';
279 Keys[3]:='SOFTWARE\Classes\Directory\Background\shell\git_gui';
281 for i:=0 to Length(Keys)-1 do begin
282 Command:='';
283 RegQueryStringValue(RootKey,Keys[i]+'\command','',Command);
284 if Pos(AppDir,Command)>0 then begin
285 if not RegDeleteKeyIncludingSubkeys(RootKey,Keys[i]) then begin
286 Msg:='Line {#__LINE__}: Unable to remove "Git Bash / GUI Here" shell extension.';
287 MsgBox(Msg,mbError,MB_OK);
288 Log(Msg);
289 // This is not a critical error, the user can probably fix it manually,
290 // so we continue.
291 end;
292 end;
293 end;
294 end;
296 procedure RefreshProcessList(Sender:TObject);
298 Version:TWindowsVersion;
299 Modules:TArrayOfString;
300 ProcsCloseRequired,ProcsCloseOptional:ProcessList;
301 i:Longint;
302 Caption:String;
303 ManualClosingRequired:Boolean;
304 begin
305 GetWindowsVersionEx(Version);
307 // Use the Restart Manager API when installing the shell extension on Windows Vista and above.
308 if Version.Major>=6 then begin
309 SetArrayLength(Modules,5);
310 Modules[0]:=ExpandConstant('{app}\bin\msys-1.0.dll');
311 Modules[1]:=ExpandConstant('{app}\bin\tcl85.dll');
312 Modules[2]:=ExpandConstant('{app}\bin\tk85.dll');
313 Modules[3]:=ExpandConstant('{app}\git-cheetah\git_shell_ext.dll');
314 Modules[4]:=ExpandConstant('{app}\git-cheetah\git_shell_ext64.dll');
315 SessionHandle:=FindProcessesUsingModules(Modules,Processes);
316 end else begin
317 SetArrayLength(Modules,3);
318 Modules[0]:=ExpandConstant('{app}\bin\msys-1.0.dll');
319 Modules[1]:=ExpandConstant('{app}\bin\tcl85.dll');
320 Modules[2]:=ExpandConstant('{app}\bin\tk85.dll');
321 SessionHandle:=FindProcessesUsingModules(Modules,ProcsCloseRequired);
323 SetArrayLength(Modules,2);
324 Modules[0]:=ExpandConstant('{app}\git-cheetah\git_shell_ext.dll');
325 Modules[1]:=ExpandConstant('{app}\git-cheetah\git_shell_ext64.dll');
326 SessionHandle:=FindProcessesUsingModules(Modules,ProcsCloseOptional) or SessionHandle;
328 // Misuse the "Restartable" flag to indicate which processes are required
329 // to be closed before setup can continue, and which just should be closed
330 // in order to make changes take effect immediately.
331 SetArrayLength(Processes,GetArrayLength(ProcsCloseRequired)+GetArrayLength(ProcsCloseOptional));
332 for i:=0 to GetArrayLength(ProcsCloseRequired)-1 do begin
333 Processes[i]:=ProcsCloseRequired[i];
334 Processes[i].Restartable:=False;
335 end;
336 for i:=0 to GetArrayLength(ProcsCloseOptional)-1 do begin
337 Processes[GetArrayLength(ProcsCloseRequired)+i]:=ProcsCloseOptional[i];
338 Processes[GetArrayLength(ProcsCloseRequired)+i].Restartable:=True;
339 end;
340 end;
342 ManualClosingRequired:=False;
344 ProcessesListBox.Items.Clear;
345 if (Sender=NIL) or (SessionHandle>0) then begin
346 for i:=0 to GetArrayLength(Processes)-1 do begin
347 Caption:=Processes[i].Name+' (PID '+IntToStr(Processes[i].ID);
348 if Processes[i].Restartable then begin
349 Caption:=Caption+', closing is optional';
350 end else begin
351 Caption:=Caption+', closing is required';
352 ManualClosingRequired:=True;
353 end;
354 Caption:=Caption+')';
355 ProcessesListBox.Items.Append(Caption);
356 end;
357 end;
359 if ContinueButton<>NIL then begin
360 ContinueButton.Enabled:=not ManualClosingRequired;
361 end;
362 end;
365 Installer code
368 procedure InitializeWizard;
370 PrevPageID:Integer;
371 LblGitBash,LblGitCmd,LblGitCmdTools,LblGitCmdToolsWarn:TLabel;
372 LblOpenSSH,LblPlink:TLabel;
373 PuTTYSessions:TArrayOfString;
374 LblLFOnly,LblCRLFAlways,LblCRLFCommitAsIs:TLabel;
375 BtnPlink:TButton;
376 Data:String;
377 begin
379 PrevPageID:=wpSelectProgramGroup;
382 * Create a custom page for modifying the environment.
385 PathPage:=CreateCustomPage(
386 PrevPageID,
387 'Adjusting your PATH environment',
388 'How would you like to use Git from the command line?'
390 PrevPageID:=PathPage.ID;
392 // 1st choice
393 RdbPath[GP_BashOnly]:=TRadioButton.Create(PathPage);
394 with RdbPath[GP_BashOnly] do begin
395 Parent:=PathPage.Surface;
396 Caption:='Use Git Bash only';
397 Left:=ScaleX(4);
398 Top:=ScaleY(8);
399 Width:=ScaleX(405);
400 Height:=ScaleY(17);
401 Font.Style:=[fsBold];
402 TabOrder:=0;
403 Checked:=True;
404 end;
405 LblGitBash:=TLabel.Create(PathPage);
406 with LblGitBash do begin
407 Parent:=PathPage.Surface;
408 Caption:=
409 'This is the most conservative choice if you are concerned about the stability' + #13 +
410 'of your system. Your PATH will not be modified.';
411 Left:=ScaleX(28);
412 Top:=ScaleY(32);
413 Width:=ScaleX(405);
414 Height:=ScaleY(26);
415 end;
417 // 2nd choice
418 RdbPath[GP_Cmd]:=TRadioButton.Create(PathPage);
419 with RdbPath[GP_Cmd] do begin
420 Parent:=PathPage.Surface;
421 Caption:='Run Git from the Windows Command Prompt';
422 Left:=ScaleX(4);
423 Top:=ScaleY(76);
424 Width:=ScaleX(405);
425 Height:=ScaleY(17);
426 Font.Style:=[fsBold];
427 TabOrder:=1;
428 end;
429 LblGitCmd:=TLabel.Create(PathPage);
430 with LblGitCmd do begin
431 Parent:=PathPage.Surface;
432 Caption:=
433 'This option is considered safe and no conflicts with other tools are known.' + #13 +
434 'Only Git will be added to your PATH. Use this option if you want to use Git' + #13 +
435 'from a Cygwin Prompt (make sure to not have Cygwin''s Git installed).';
436 Left:=ScaleX(28);
437 Top:=ScaleY(100);
438 Width:=ScaleX(405);
439 Height:=ScaleY(39);
440 end;
442 // 3rd choice
443 RdbPath[GP_CmdTools]:=TRadioButton.Create(PathPage);
444 with RdbPath[GP_CmdTools] do begin
445 Parent:=PathPage.Surface;
446 Caption:='Run Git and included Unix tools from the Windows Command Prompt';
447 Left:=ScaleX(4);
448 Top:=ScaleY(152);
449 Width:=ScaleX(405);
450 Height:=ScaleY(17);
451 Font.Style:=[fsBold];
452 TabOrder:=2;
453 end;
454 LblGitCmdTools:=TLabel.Create(PathPage);
455 with LblGitCmdTools do begin
456 Parent:=PathPage.Surface;
457 Caption:='Both Git and its accompanying Unix tools will be added to your PATH.';
458 Left:=ScaleX(28);
459 Top:=ScaleY(176);
460 Width:=ScaleX(405);
461 Height:=ScaleY(13);
462 end;
463 LblGitCmdToolsWarn:=TLabel.Create(PathPage);
464 with LblGitCmdToolsWarn do begin
465 Parent:=PathPage.Surface;
466 Caption:=
467 'Warning: This will override Windows tools like find.exe and' + #13 +
468 'sort.exe. Select this option only if you understand the implications.';
469 Left:=ScaleX(28);
470 Top:=ScaleY(192);
471 Width:=ScaleX(405);
472 Height:=ScaleY(26);
473 Font.Color:=255;
474 Font.Style:=[fsBold];
475 end;
477 // Restore the setting chosen during a previous install.
478 Data:=GetPreviousData('Path Option','BashOnly');
479 if Data='BashOnly' then begin
480 RdbPath[GP_BashOnly].Checked:=True;
481 end else if Data='Cmd' then begin
482 RdbPath[GP_Cmd].Checked:=True;
483 end else if Data='CmdTools' then begin
484 RdbPath[GP_CmdTools].Checked:=True;
485 end;
488 * Create a custom page for using (Tortoise)Plink instead of OpenSSH
489 * if at least one PuTTY session is found in the Registry.
492 if RegGetSubkeyNames(HKEY_CURRENT_USER,'Software\SimonTatham\PuTTY\Sessions',PuTTYSessions) and (GetArrayLength(PuTTYSessions)>0) then begin
493 PuTTYPage:=CreateCustomPage(
494 PrevPageID,
495 'Choosing the SSH executable',
496 'Which Secure Shell client program would you like Git to use?'
498 PrevPageID:=PuTTYPage.ID;
500 // 1st choice
501 RdbSSH[GS_OpenSSH]:=TRadioButton.Create(PuTTYPage);
502 with RdbSSH[GS_OpenSSH] do begin
503 Parent:=PuTTYPage.Surface;
504 Caption:='Use OpenSSH';
505 Left:=ScaleX(4);
506 Top:=ScaleY(8);
507 Width:=ScaleX(405);
508 Height:=ScaleY(17);
509 Font.Style:=[fsBold];
510 TabOrder:=0;
511 Checked:=True;
512 end;
513 LblOpenSSH:=TLabel.Create(PuTTYPage);
514 with LblOpenSSH do begin
515 Parent:=PuTTYPage.Surface;
516 Caption:=
517 'This uses ssh.exe that comes with Git. The GIT_SSH and SVN_SSH' + #13 +
518 'environment variables will not be modified.';
519 Left:=ScaleX(28);
520 Top:=ScaleY(32);
521 Width:=ScaleX(405);
522 Height:=ScaleY(26);
523 end;
525 // 2nd choice
526 RdbSSH[GS_Plink]:=TRadioButton.Create(PuTTYPage);
527 with RdbSSH[GS_Plink] do begin
528 Parent:=PuTTYPage.Surface;
529 Caption:='Use (Tortoise)Plink';
530 Left:=ScaleX(4);
531 Top:=ScaleY(76);
532 Width:=ScaleX(405);
533 Height:=ScaleY(17);
534 Font.Style:=[fsBold];
535 TabOrder:=1;
536 end;
537 LblPlink:=TLabel.Create(PuTTYPage);
538 with LblPlink do begin
539 Parent:=PuTTYPage.Surface;
540 Caption:=
541 'PuTTY sessions were found in your Registry. You may specify the path' + #13 +
542 'to an existing copy of (Tortoise)Plink.exe from the TortoiseGit/SVN/CVS' + #13 +
543 'or PuTTY applications. The GIT_SSH and SVN_SSH environment' + #13 +
544 'variables will be adjusted to point to the following executable:';
545 Left:=ScaleX(28);
546 Top:=ScaleY(100);
547 Width:=ScaleX(405);
548 Height:=ScaleY(52);
549 end;
550 EdtPlink:=TEdit.Create(PuTTYPage);
551 with EdtPlink do begin
552 Parent:=PuTTYPage.Surface;
553 Text:=GetPuTTYLocation;
554 if not FileExists(Text) then begin
555 Text:='';
556 end;
557 Left:=ScaleX(28);
558 Top:=ScaleY(161);
559 Width:=ScaleX(316);
560 Height:=ScaleY(13);
561 end;
562 BtnPlink:=TButton.Create(PuTTYPage);
563 with BtnPlink do begin
564 Parent:=PuTTYPage.Surface;
565 Caption:='...';
566 OnClick:=@BrowseForPuTTYFolder;
567 Left:=ScaleX(348);
568 Top:=ScaleY(161);
569 Width:=ScaleX(21);
570 Height:=ScaleY(21);
571 end;
573 // Restore the setting chosen during a previous install.
574 Data:=GetPreviousData('SSH Option','OpenSSH');
575 if Data='OpenSSH' then begin
576 RdbSSH[GS_OpenSSH].Checked:=True;
577 end else if Data='Plink' then begin
578 RdbSSH[GS_Plink].Checked:=True;
579 end;
580 end else begin
581 PuTTYPage:=NIL;
582 end;
585 * Create a custom page for the core.autocrlf setting.
588 CRLFPage:=CreateCustomPage(
589 PrevPageID,
590 'Configuring the line ending conversions',
591 'How should Git treat line endings in text files?'
593 PrevPageID:=CRLFPage.ID;
595 // 1st choice
596 RdbCRLF[GC_CRLFAlways]:=TRadioButton.Create(CRLFPage);
597 with RdbCRLF[GC_CRLFAlways] do begin
598 Parent:=CRLFPage.Surface;
599 Caption:='Checkout Windows-style, commit Unix-style line endings';
600 Left:=ScaleX(4);
601 Top:=ScaleY(8);
602 Width:=ScaleX(405);
603 Height:=ScaleY(17);
604 Font.Style:=[fsBold];
605 TabOrder:=0;
606 Checked:=True;
607 end;
608 LblCRLFAlways:=TLabel.Create(CRLFPage);
609 with LblCRLFAlways do begin
610 Parent:=CRLFPage.Surface;
611 Caption:=
612 'Git will convert LF to CRLF when checking out text files. When committing' + #13 +
613 'text files, CRLF will be converted to LF. For cross-platform projects,' + #13 +
614 'this is the recommended setting on Windows ("core.autocrlf" is set to "true").';
615 Left:=ScaleX(28);
616 Top:=ScaleY(32);
617 Width:=ScaleX(405);
618 Height:=ScaleY(47);
619 end;
621 // 2nd choice
622 RdbCRLF[GC_LFOnly]:=TRadioButton.Create(CRLFPage);
623 with RdbCRLF[GC_LFOnly] do begin
624 Parent:=CRLFPage.Surface;
625 Caption:='Checkout as-is, commit Unix-style line endings';
626 Left:=ScaleX(4);
627 Top:=ScaleY(80);
628 Width:=ScaleX(405);
629 Height:=ScaleY(17);
630 Font.Style:=[fsBold];
631 TabOrder:=1;
632 Checked:=False;
633 end;
634 LblLFOnly:=TLabel.Create(CRLFPage);
635 with LblLFOnly do begin
636 Parent:=CRLFPage.Surface;
637 Caption:=
638 'Git will not perform any conversion when checking out text files. When' + #13 +
639 'committing text files, CRLF will be converted to LF. For cross-platform projects,' + #13 +
640 'this is the recommended setting on Unix ("core.autocrlf" is set to "input").';
641 Left:=ScaleX(28);
642 Top:=ScaleY(104);
643 Width:=ScaleX(405);
644 Height:=ScaleY(47);
645 end;
647 // 3rd choice
648 RdbCRLF[GC_CRLFCommitAsIs]:=TRadioButton.Create(CRLFPage);
649 with RdbCRLF[GC_CRLFCommitAsIs] do begin
650 Parent:=CRLFPage.Surface;
651 Caption:='Checkout as-is, commit as-is';
652 Left:=ScaleX(4);
653 Top:=ScaleY(152);
654 Width:=ScaleX(405);
655 Height:=ScaleY(17);
656 Font.Style:=[fsBold];
657 TabOrder:=2;
658 Checked:=False;
659 end;
660 LblCRLFCommitAsIs:=TLabel.Create(CRLFPage);
661 with LblCRLFCommitAsIs do begin
662 Parent:=CRLFPage.Surface;
663 Caption:=
664 'Git will not perform any conversions when checking out or committing' + #13 +
665 'text files. Choosing this option is not recommended for cross-platform' + #13 +
666 'projects ("core.autocrlf" is set to "false").';
667 Left:=ScaleX(28);
668 Top:=ScaleY(176);
669 Width:=ScaleX(405);
670 Height:=ScaleY(47);
671 end;
673 // Restore the setting chosen during a previous install.
674 Data:=GetPreviousData('CRLF Option','CRLFAlways');
675 if Data='LFOnly' then begin
676 RdbCRLF[GC_LFOnly].Checked:=True;
677 end else if Data='CRLFAlways' then begin
678 RdbCRLF[GC_CRLFAlways].Checked:=True;
679 end else if Data='CRLFCommitAsIs' then begin
680 RdbCRLF[GC_CRLFCommitAsIs].Checked:=True;
681 end;
684 * Create a custom page for finding the processes that lock a module.
687 ProcessesPage:=CreateCustomPage(
688 wpPreparing,
689 'Replacing in-use files',
690 'The following applications use files that need to be replaced, please close them.'
693 ProcessesListBox:=TListBox.Create(ProcessesPage);
694 with ProcessesListBox do begin
695 Parent:=ProcessesPage.Surface;
696 Width:=ProcessesPage.SurfaceWidth;
697 Height:=ProcessesPage.SurfaceHeight-ScaleY(8);
698 end;
700 ProcessesRefresh:=TNewButton.Create(WizardForm);
701 with ProcessesRefresh do begin
702 Parent:=WizardForm;
703 Width:=WizardForm.CancelButton.Width;
704 Height:=WizardForm.CancelButton.Height;
705 Top:=WizardForm.CancelButton.Top;
706 Left:=WizardForm.ClientWidth-(WizardForm.CancelButton.Left+WizardForm.CancelButton.Width);
707 Caption:='&Refresh';
708 OnClick:=@RefreshProcessList;
709 end;
711 // This button is only used by the uninstaller.
712 ContinueButton:=NIL;
714 // Initially hide the Refresh button, show it when the process page becomes current.
715 ProcessesRefresh.Hide;
716 end;
718 function ShouldSkipPage(PageID:Integer):Boolean;
719 begin
720 if (ProcessesPage<>NIL) and (PageID=ProcessesPage.ID) then begin
721 // This page is only reached forward (by pressing "Next", never by pressing "Back").
722 RefreshProcessList(NIL);
723 Result:=(GetArrayLength(Processes)=0);
724 end else begin
725 Result:=False;
726 end;
727 end;
729 procedure CurPageChanged(CurPageID:Integer);
730 begin
731 if CurPageID=wpSelectDir then begin
732 if not IsDirWritable(WizardDirValue) then begin
733 // If the default directory is not writable, choose another default that most likely is.
734 // This will be checked later again when the user clicks "Next".
735 WizardForm.DirEdit.Text:=ExpandConstant('{userpf}\{#APP_NAME}');
736 end;
737 end;
739 // Show the "Refresh" button only on the processes page.
740 if (ProcessesPage<>NIL) and (CurPageID=ProcessesPage.ID) then begin
741 ProcessesRefresh.Show;
742 end else begin
743 ProcessesRefresh.Hide;
744 end;
745 end;
747 function NextButtonClick(CurPageID:Integer):Boolean;
749 i:Integer;
750 Version:TWindowsVersion;
751 begin
752 Result:=True;
754 if CurPageID=wpSelectDir then begin
755 if not IsDirWritable(WizardDirValue) then begin
756 MsgBox(
757 'The specified installation directory does not seem to be writable. ' +
758 + 'Please choose another directory or restart setup as a user with sufficient permissions.'
759 , mbCriticalError
760 , MB_OK
762 Result:=False;
763 Exit;
764 end;
765 end;
767 if (PuTTYPage<>NIL) and (CurPageID=PuTTYPage.ID) then begin
768 Result:=RdbSSH[GS_OpenSSH].Checked or
769 (RdbSSH[GS_Plink].Checked and FileExists(EdtPlink.Text));
770 if not Result then begin
771 MsgBox('Please enter a valid path to (Tortoise)Plink.exe.',mbError,MB_OK);
772 end;
773 end else if (ProcessesPage<>NIL) and (CurPageID=ProcessesPage.ID) then begin
774 // It would have been nicer to just disable the "Next" button, but the
775 // WizardForm exports the button just read-only.
776 for i:=0 to GetArrayLength(Processes)-1 do begin
777 if not Processes[i].Restartable then begin
778 MsgBox('Setup cannot continue until you close at least those applications in the list that are marked as "closing is required".',mbCriticalError,MB_OK);
779 Result:=False;
780 Exit;
781 end;
782 end;
784 Result:=(GetArrayLength(Processes)=0);
786 if not Result then begin
787 GetWindowsVersionEx(Version);
788 if Version.Major>=6 then begin
789 Result:=(MsgBox(
790 'If you continue without closing the listed applications they will be closed and restarted automatically.' + #13 + #13 +
791 'Are you sure you want to continue?',
792 mbConfirmation,
793 MB_YESNO
794 )=IDYES);
795 end else begin
796 Result:=(MsgBox(
797 'If you continue without closing the listed applications you will need to log off and on again before changes take effect.' + #13 + #13 +
798 'Are you sure you want to continue anyway?',
799 mbConfirmation,
800 MB_YESNO
801 )=IDYES);
802 end;
803 end;
804 end;
805 end;
807 procedure CurStepChanged(CurStep:TSetupStep);
809 AppDir,DllPath,FileName,TempName,Cmd,Msg:String;
810 BuiltIns,ImageNames,EnvPath,EnvHome,EnvSSH:TArrayOfString;
811 Count,i:Longint;
812 LinkCreated:Boolean;
813 FindRec:TFindRec;
814 RootKey:Integer;
815 Version:TWindowsVersion;
816 begin
817 if CurStep=ssInstall then begin
818 // Shutdown locking processes just before the actual installation starts.
819 if SessionHandle>0 then try
820 RmShutdown(SessionHandle,RmShutdownOnlyRegistered,0);
821 except
822 Log('Line {#__LINE__}: RmShutdown not supported.');
823 end;
825 Exit;
826 end;
828 // Make sure the code below is only executed just after the actual installation finishes.
829 if CurStep<>ssPostInstall then begin
830 Exit;
831 end;
833 AppDir:=ExpandConstant('{app}');
836 Bind the imported function addresses
840 DllPath:=ExpandConstant('{app}\bin;{sys}');
842 // Load the list of images from a text file.
843 FileName:=AppDir+'\{#APP_BINDIMAGE}';
844 if LoadStringsFromFile(FileName,ImageNames) then begin
845 Count:=GetArrayLength(ImageNames)-1;
846 for i:=0 to Count do begin
847 FileName:=AppDir+'\'+ImageNames[i];
848 if not BindImageEx(BIND_NO_BOUND_IMPORTS or BIND_CACHE_IMPORT_DLLS,FileName,DllPath,'',0) then begin
849 Log('Line {#__LINE__}: Error calling BindImageEx for "'+FileName+'".');
850 end;
851 end;
852 end;
853 except
854 Log('Line {#__LINE__}: An exception occurred while calling BindImageEx.');
855 end;
858 Create the built-ins
861 // Load the built-ins from a text file.
862 FileName:=AppDir+'\{#APP_BUILTINS}';
863 if LoadStringsFromFile(FileName,BuiltIns) then begin
864 Count:=GetArrayLength(BuiltIns)-1;
866 // Delete those scripts from "bin" which have been replaced by built-ins in "libexec\git-core".
867 for i:=0 to Count do begin
868 FileName:=AppDir+'\bin\'+ChangeFileExt(ExtractFileName(BuiltIns[i]),'');
869 if FileExists(FileName) and (not DeleteFile(FileName)) then begin
870 Log('Line {#__LINE__}: Unable to delete script "'+FileName+'", ignoring.');
871 end;
872 end;
874 // Create built-ins as aliases for git.exe.
875 for i:=0 to Count do begin
876 FileName:=AppDir+'\'+BuiltIns[i];
878 // Delete any existing built-in.
879 if FileExists(FileName) and (not DeleteFile(FileName)) then begin
880 Log('Line {#__LINE__}: Unable to delete existing built-in "'+FileName+'", skipping.');
881 continue;
882 end;
885 // This will throw an exception on pre-Win2k systems.
886 LinkCreated:=CreateHardLink(FileName,AppDir+'\bin\git.exe',0);
887 except
888 LinkCreated:=False;
889 Log('Line {#__LINE__}: Creating hardlink "'+FileName+'" failed, will try a copy.');
890 end;
892 if not LinkCreated then begin
893 if not FileCopy(AppDir+'\bin\git.exe',FileName,False) then begin
894 Log('Line {#__LINE__}: Creating copy "'+FileName+'" failed, giving up.');
895 // This is not a critical error, Git could basically be used without the
896 // aliases for built-ins, so we continue.
897 end;
898 end;
899 end;
901 // Delete any duplicate files in case we are updating from a non-libexec to a libexec directory layout.
902 if FindFirst(AppDir+'\libexec\git-core\*',FindRec) then begin
903 repeat
904 if (FindRec.Attributes and FILE_ATTRIBUTE_DIRECTORY)=0 then begin
905 FileName:=AppDir+'\bin\'+FindRec.name;
906 if (Pos(FindRec.name,'git.exe')<>1) and FileExists(FileName) and (not DeleteFile(FileName)) then begin
907 Log('Line {#__LINE__}: Unable to delete dupe "'+FileName+'", ignoring.');
908 end;
909 end;
910 until not FindNext(FindRec);
911 FindClose(FindRec);
912 end;
913 end else begin
914 Msg:='Line {#__LINE__}: Unable to read file "{#APP_BUILTINS}".';
915 MsgBox(Msg,mbError,MB_OK);
916 Log(Msg);
917 // This is not a critical error, Git could basically be used without the
918 // aliases for built-ins, so we continue.
919 end;
922 Adapt core.autocrlf
925 if RdbCRLF[GC_LFOnly].checked then begin
926 Cmd:='core.autocrlf input';
927 end else if RdbCRLF[GC_CRLFAlways].checked then begin
928 Cmd:='core.autocrlf true';
929 end else begin
930 Cmd:='core.autocrlf false';
931 end;
932 if not Exec(AppDir + '\bin\git.exe', 'config -f gitconfig ' + Cmd,
933 AppDir + '\etc', SW_HIDE, ewWaitUntilTerminated, i) then begin
934 Msg:='Unable to configure the line ending conversion: ' + Cmd;
935 MsgBox(Msg,mbError,MB_OK);
936 Log(Msg);
937 // This is not a critical error, the user can probably fix it manually,
938 // so we continue.
939 end;
942 Modify the environment
944 This must happen no later than ssPostInstall to make
945 "ChangesEnvironment=yes" not happend before the change!
948 FileName:=AppDir+'\setup.ini';
950 // Delete GIT_SSH and SVN_SSH if a previous installation set them (this is required for the GS_OpenSSH case).
951 EnvSSH:=GetEnvStrings('GIT_SSH',IsAdminLoggedOn);
952 if (GetArrayLength(EnvSSH)=1) and
953 (CompareStr(RemoveQuotes(EnvSSH[0]),GetIniString('Environment','GIT_SSH','',FileName))=0) then begin
954 if not SetEnvStrings('GIT_SSH',IsAdminLoggedOn,True,[]) then begin
955 Msg:='Line {#__LINE__}: Unable to reset GIT_SSH prior to install.';
956 MsgBox(Msg,mbError,MB_OK);
957 Log(Msg);
958 // This is not a critical error, the user can probably fix it manually,
959 // so we continue.
960 end;
961 end;
963 EnvSSH:=GetEnvStrings('SVN_SSH',IsAdminLoggedOn);
964 if (GetArrayLength(EnvSSH)=1) and
965 (CompareStr(RemoveQuotes(EnvSSH[0]),GetIniString('Environment','SVN_SSH','',FileName))=0) then begin
966 if not SetEnvStrings('SVN_SSH',IsAdminLoggedOn,True,[]) then begin
967 Msg:='Line {#__LINE__}: Unable to reset SVN_SSH prior to install.';
968 MsgBox(Msg,mbError,MB_OK);
969 Log(Msg);
970 // This is not a critical error, the user can probably fix it manually,
971 // so we continue.
972 end;
973 end;
975 if (PuTTYPage<>NIL) and RdbSSH[GS_Plink].Checked then begin
976 SetArrayLength(EnvSSH,1);
977 EnvSSH[0]:=EdtPlink.Text;
979 // Set GIT_SSH as specified by the user.
980 if not SetEnvStrings('GIT_SSH',IsAdminLoggedOn,True,EnvSSH) then begin
981 Msg:='Line {#__LINE__}: Unable to set the GIT_SSH environment variable.';
982 MsgBox(Msg,mbError,MB_OK);
983 Log(Msg);
984 // This is not a critical error, the user can probably fix it manually,
985 // so we continue.
986 end;
988 // Mark that we have changed GIT_SSH by writing its value to a file.
989 if not SetIniString('Environment','GIT_SSH',EnvSSH[0],FileName) then begin
990 Msg:='Line {#__LINE__}: Unable to write to file "'+FileName+'".';
991 MsgBox(Msg,mbError,MB_OK);
992 Log(Msg);
993 // This is not a critical error, though uninstall / reinstall will probably not run cleanly,
994 // so we continue.
995 end;
997 if not SetEnvStrings('SVN_SSH',IsAdminLoggedOn,True,EnvSSH) then begin
998 Msg:='Line {#__LINE__}: Unable to set the SVN_SSH environment variable.';
999 MsgBox(Msg,mbError,MB_OK);
1000 Log(Msg);
1001 // This is not a critical error, the user can probably fix it manually,
1002 // so we continue.
1003 end;
1005 // Mark that we have changed SVN_SSH by writing its value to a file.
1006 if not SetIniString('Environment','SVN_SSH',EnvSSH[0],FileName) then begin
1007 Msg:='Line {#__LINE__}: Unable to write to file "'+FileName+'".';
1008 MsgBox(Msg,mbError,MB_OK);
1009 Log(Msg);
1010 // This is not a critical error, though uninstall / reinstall will probably not run cleanly,
1011 // so we continue.
1012 end;
1013 end;
1015 // Get the current user's directories in PATH.
1016 EnvPath:=GetEnvStrings('PATH',IsAdminLoggedOn);
1018 // First, remove the installation directory from PATH in any case.
1019 for i:=0 to GetArrayLength(EnvPath)-1 do begin
1020 if Pos(AppDir+'\',EnvPath[i]+'\')=1 then begin
1021 EnvPath[i]:='';
1022 end;
1023 end;
1025 // Delete HOME if a previous installation modified it.
1026 EnvHome:=GetEnvStrings('HOME',IsAdminLoggedOn);
1027 if (GetArrayLength(EnvHome)=1) and
1028 (CompareStr(RemoveQuotes(EnvHome[0]),GetIniString('Environment','HOME','',FileName))=0) then begin
1029 if not SetEnvStrings('HOME',IsAdminLoggedOn,True,[]) then begin
1030 Msg:='Line {#__LINE__}: Unable to reset HOME prior to install.';
1031 MsgBox(Msg,mbError,MB_OK);
1032 Log(Msg);
1033 // This is not a critical error, the user can probably fix it manually,
1034 // so we continue.
1035 end;
1036 end;
1038 // Modify the PATH variable as requested by the user.
1039 if RdbPath[GP_Cmd].Checked or RdbPath[GP_CmdTools].Checked then begin
1040 i:=GetArrayLength(EnvPath);
1041 SetArrayLength(EnvPath,i+1);
1043 // List \cmd before \bin so \cmd has higher priority and programs in
1044 // there will be called in favor of those in \bin.
1045 EnvPath[i]:=AppDir+'\cmd';
1047 if RdbPath[GP_CmdTools].Checked then begin
1048 SetArrayLength(EnvPath,i+2);
1049 EnvPath[i+1]:=AppDir+'\bin';
1051 // Set HOME for the Windows Command Prompt, but only if it has not been set manually before.
1052 EnvHome:=GetEnvStrings('HOME',IsAdminLoggedOn);
1053 i:=GetArrayLength(EnvHome);
1054 if (i=0) or ((i=1) and (Length(EnvHome[0])=0)) then begin
1055 SetArrayLength(EnvHome,1);
1056 EnvHome[0]:=ExpandConstant('{%HOMEDRIVE}{%HOMEPATH}');
1057 if not SetEnvStrings('HOME',IsAdminLoggedOn,True,EnvHome) then begin
1058 Msg:='Line {#__LINE__}: Unable to set the HOME environment variable.';
1059 MsgBox(Msg,mbError,MB_OK);
1060 Log(Msg);
1061 // This is not a critical error, the user can probably fix it manually,
1062 // so we continue.
1063 end;
1065 // Mark that we have changed HOME.
1066 if not SetIniString('Environment','HOME',EnvHome[0],FileName) then begin
1067 Msg:='Line {#__LINE__}: Unable to write to file "'+FileName+'".';
1068 MsgBox(Msg,mbError,MB_OK);
1069 Log(Msg);
1070 // This is not a critical error, though uninstall / reinstall will probably not run cleanly,
1071 // so we continue.
1072 end;
1073 end;
1074 end;
1075 end;
1077 // Set the current user's PATH directories.
1078 if not SetEnvStrings('PATH',IsAdminLoggedOn,True,EnvPath) then begin
1079 Msg:='Line {#__LINE__}: Unable to set the PATH environment variable.';
1080 MsgBox(Msg,mbError,MB_OK);
1081 Log(Msg);
1082 // This is not a critical error, the user can probably fix it manually,
1083 // so we continue.
1084 end;
1087 Create shortcuts that need to be created regardless of the "Don't create a Start Menu folder" toggle
1090 GetWindowsVersionEx(Version);
1091 if Version.Major<6 then begin
1092 Cmd:=ExpandConstant('{syswow64}\cmd.exe');
1093 TempName:='/c ""'+AppDir+'\bin\sh.exe" --login -i"';
1094 end else begin
1095 Cmd:=AppDir+'\bin\sh.exe';
1096 TempName:='--login -i';
1097 end;
1098 FileName:=AppDir+'\etc\git.ico';
1100 if IsComponentSelected('icons\quicklaunch') then begin
1101 CreateShellLink(
1102 ExpandConstant('{userappdata}\Microsoft\Internet Explorer\Quick Launch\Git Bash.lnk')
1103 , 'Git Bash'
1104 , Cmd
1105 , TempName
1106 , '%HOMEDRIVE%%HOMEPATH%'
1107 , FileName
1109 , SW_SHOWNORMAL
1111 end;
1112 if IsComponentSelected('icons\desktop') then begin
1113 CreateShellLink(
1114 GetShellFolder('desktop')+'\Git Bash.lnk'
1115 , 'Git Bash'
1116 , Cmd
1117 , TempName
1118 , '%HOMEDRIVE%%HOMEPATH%'
1119 , FileName
1121 , SW_SHOWNORMAL
1123 end;
1125 // Create a special shortcut that does not set a working directory (Note: Since Inno Setup 5.3.11,
1126 // passing an empty WorkingDir gets replaced with {sys}, so use '.' instead).
1127 // This shortcut is used by "Git Bash.vbs", which in turn is run by the "Git Bash Here" shell extension.
1128 CreateShellLink(
1129 AppDir+'\Git Bash.lnk'
1130 , 'Git Bash'
1131 , Cmd
1132 , TempName
1133 , '.'
1134 , FileName
1136 , SW_SHOWNORMAL
1140 Create the Windows Explorer integrations
1143 if IsAdminLoggedOn then begin
1144 RootKey:=HKEY_LOCAL_MACHINE;
1145 end else begin
1146 RootKey:=HKEY_CURRENT_USER;
1147 end;
1149 if IsComponentSelected('ext\reg\shellhere') then begin
1150 Msg:='Git Ba&sh Here';
1151 Cmd:='"'+ExpandConstant('{syswow64}')+'\wscript" "'+AppDir+'\Git Bash.vbs" "%1"';
1152 if (not RegWriteStringValue(RootKey,'SOFTWARE\Classes\Directory\shell\git_shell','',Msg)) or
1153 (not RegWriteStringValue(RootKey,'SOFTWARE\Classes\Directory\shell\git_shell\command','',Cmd)) or
1154 (StringChangeEx(Cmd,'%1','%v',false)<>1) or
1155 (not RegWriteStringValue(RootKey,'SOFTWARE\Classes\Directory\Background\shell\git_shell','',Msg)) or
1156 (not RegWriteStringValue(RootKey,'SOFTWARE\Classes\Directory\Background\shell\git_shell\command','',Cmd)) then begin
1157 Msg:='Line {#__LINE__}: Unable to create "Git Bash Here" shell extension.';
1158 MsgBox(Msg,mbError,MB_OK);
1159 Log(Msg);
1160 // This is not a critical error, the user can probably fix it manually,
1161 // so we continue.
1162 end;
1163 end;
1165 if IsComponentSelected('ext\reg\guihere') then begin
1166 Msg:='Git &GUI Here';
1167 Cmd:='"'+AppDir+'\bin\wish.exe" "'+AppDir+'\libexec\git-core\git-gui" "--working-dir" "%1"';
1168 if (not RegWriteStringValue(RootKey,'SOFTWARE\Classes\Directory\shell\git_gui','',Msg)) or
1169 (not RegWriteStringValue(RootKey,'SOFTWARE\Classes\Directory\shell\git_gui\command','',Cmd)) or
1170 (StringChangeEx(Cmd,'%1','%v',false)<>1) or
1171 (not RegWriteStringValue(RootKey,'SOFTWARE\Classes\Directory\Background\shell\git_gui','',Msg)) or
1172 (not RegWriteStringValue(RootKey,'SOFTWARE\Classes\Directory\Background\shell\git_gui\command','',Cmd)) then begin
1173 Msg:='Line {#__LINE__}: Unable to create "Git GUI Here" shell extension.';
1174 MsgBox(Msg,mbError,MB_OK);
1175 Log(Msg);
1176 // This is not a critical error, the user can probably fix it manually,
1177 // so we continue.
1178 end;
1179 end;
1181 // It is either the Registry-based context menu entries, or the shell extension.
1182 if IsComponentSelected('ext\cheetah') then begin
1183 DeleteContextMenuEntries;
1185 if isWin64 then begin
1186 FileName:=AppDir+'\git-cheetah\git_shell_ext64.dll';
1187 end else begin
1188 FileName:=AppDir+'\git-cheetah\git_shell_ext.dll';
1189 end;
1190 if not ReplaceInUseFile(FileName,FileName+'.new',True) then begin
1191 Log('Line {#__LINE__}: Replacing file "'+FileName+'" failed.');
1192 end;
1193 end;
1196 Restart any processes that were shut down via the Restart Manager
1199 if SessionHandle>0 then try
1200 RmRestart(SessionHandle,0,0);
1201 RmEndSession(SessionHandle);
1202 except
1203 Log('Line {#__LINE__}: RmRestart not supported.');
1204 end;
1205 end;
1207 procedure RegisterPreviousData(PreviousDataKey:Integer);
1209 Data:String;
1210 begin
1211 // Git Path options.
1212 Data:='';
1213 if RdbPath[GP_BashOnly].Checked then begin
1214 Data:='BashOnly';
1215 end else if RdbPath[GP_Cmd].Checked then begin
1216 Data:='Cmd';
1217 end else if RdbPath[GP_CmdTools].Checked then begin
1218 Data:='CmdTools';
1219 end;
1220 SetPreviousData(PreviousDataKey,'Path Option',Data);
1222 // Git SSH options.
1223 Data:='';
1224 if (PuTTYPage=NIL) or RdbSSH[GS_OpenSSH].Checked then begin
1225 Data:='OpenSSH';
1226 end else if RdbSSH[GS_Plink].Checked then begin
1227 Data:='Plink';
1228 end;
1229 SetPreviousData(PreviousDataKey,'SSH Option',Data);
1231 // Line ending conversion options.
1232 Data:='';
1233 if RdbCRLF[GC_LFOnly].Checked then begin
1234 Data:='LFOnly';
1235 end else if RdbCRLF[GC_CRLFAlways].Checked then begin
1236 Data:='CRLFAlways';
1237 end else if RdbCRLF[GC_CRLFCommitAsIs].Checked then begin
1238 Data:='CRLFCommitAsIs';
1239 end;
1240 SetPreviousData(PreviousDataKey,'CRLF Option',Data);
1241 end;
1244 Uninstaller code
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:=(MsgBox(
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 )=IDYES);
1331 end;
1332 end;
1333 finally
1334 Form.free;
1335 end;
1336 end;
1338 // PreUninstall
1340 // Even though the name of this function suggests otherwise most of the
1341 // code below is only executed right before the actual uninstallation.
1342 // This happens because of the if-guard right in the beginning of this
1343 // function.
1344 procedure CurUninstallStepChanged(CurUninstallStep:TUninstallStep);
1346 AppDir,FileName,Msg:String;
1347 EnvPath,EnvHome,EnvSSH:TArrayOfString;
1348 i:Longint;
1349 begin
1350 if CurUninstallStep<>usUninstall then begin
1351 Exit;
1352 end;
1354 // Reset the console font (the FontType is reset in the Registry section).
1355 if IsComponentInstalled('consolefont') then begin
1356 if MsgBox('Do you want to revert the TrueType font setting for all console windows?',mbConfirmation,MB_YESNO)=IDYES then begin
1357 RegWriteDWordValue(HKEY_CURRENT_USER,'Console','FontFamily',0);
1358 RegWriteDWordValue(HKEY_CURRENT_USER,'Console','FontSize',0);
1359 RegWriteDWordValue(HKEY_CURRENT_USER,'Console','FontWeight',0);
1360 end;
1361 end;
1364 Modify the environment
1366 This must happen no later than usUninstall to make
1367 "ChangesEnvironment=yes" not happend before the change!
1370 AppDir:=ExpandConstant('{app}');
1371 FileName:=AppDir+'\setup.ini';
1373 // Delete the current user's GIT_SSH and SVN_SSH if we set it.
1374 EnvSSH:=GetEnvStrings('GIT_SSH',IsAdminLoggedOn);
1375 if (GetArrayLength(EnvSSH)=1) and
1376 (CompareStr(RemoveQuotes(EnvSSH[0]),GetIniString('Environment','GIT_SSH','',FileName))=0) then begin
1377 if not SetEnvStrings('GIT_SSH',IsAdminLoggedOn,True,[]) then begin
1378 Msg:='Line {#__LINE__}: Unable to revert any possible changes to GIT_SSH.';
1379 MsgBox(Msg,mbError,MB_OK);
1380 Log(Msg);
1381 // This is not a critical error, the user can probably fix it manually,
1382 // so we continue.
1383 end;
1384 end;
1386 EnvSSH:=GetEnvStrings('SVN_SSH',IsAdminLoggedOn);
1387 if (GetArrayLength(EnvSSH)=1) and
1388 (CompareStr(RemoveQuotes(EnvSSH[0]),GetIniString('Environment','SVN_SSH','',FileName))=0) then begin
1389 if not SetEnvStrings('SVN_SSH',IsAdminLoggedOn,True,[]) then begin
1390 Msg:='Line {#__LINE__}: Unable to revert any possible changes to SVN_SSH.';
1391 MsgBox(Msg,mbError,MB_OK);
1392 Log(Msg);
1393 // This is not a critical error, the user can probably fix it manually,
1394 // so we continue.
1395 end;
1396 end;
1398 // Get the current user's directories in PATH.
1399 EnvPath:=GetEnvStrings('PATH',IsAdminLoggedOn);
1401 // Remove the installation directory from PATH in any case, even if it
1402 // was not added by the installer.
1403 for i:=0 to GetArrayLength(EnvPath)-1 do begin
1404 if Pos(AppDir+'\',EnvPath[i]+'\')=1 then begin
1405 EnvPath[i]:='';
1406 end;
1407 end;
1409 // Reset the current user's directories in PATH.
1410 if not SetEnvStrings('PATH',IsAdminLoggedOn,True,EnvPath) then begin
1411 Msg:='Line {#__LINE__}: Unable to revert any possible changes to PATH.';
1412 MsgBox(Msg,mbError,MB_OK);
1413 Log(Msg);
1414 // This is not a critical error, the user can probably fix it manually,
1415 // so we continue.
1416 end;
1418 // Reset the current user's HOME if we modified it.
1419 EnvHome:=GetEnvStrings('HOME',IsAdminLoggedOn);
1420 if (GetArrayLength(EnvHome)=1) and
1421 (CompareStr(RemoveQuotes(EnvHome[0]),GetIniString('Environment','HOME','',FileName))=0) then begin
1422 if not SetEnvStrings('HOME',IsAdminLoggedOn,True,[]) then begin
1423 Msg:='Line {#__LINE__}: Unable to revert any possible changes to HOME.';
1424 MsgBox(Msg,mbError,MB_OK);
1425 Log(Msg);
1426 // This is not a critical error, the user can probably fix it manually,
1427 // so we continue.
1428 end;
1429 end;
1431 if FileExists(FileName) and (not DeleteFile(FileName)) then begin
1432 Msg:='Line {#__LINE__}: Unable to delete file "'+FileName+'".';
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;
1440 Delete the Windows Explorer integrations
1443 DeleteContextMenuEntries;
1445 if isWin64 then begin
1446 FileName:=AppDir+'\git-cheetah\git_shell_ext64.dll';
1447 end else begin
1448 FileName:=AppDir+'\git-cheetah\git_shell_ext.dll';
1449 end;
1450 if FileExists(FileName) then begin
1451 if not UnregisterServer(Is64BitInstallMode,FileName,False) then begin
1452 Msg:='Line {#__LINE__}: Unable to unregister file "'+FileName+'". Please do it manually by running "regsvr32 /u '+ExtractFileName(FileName)+'".';
1453 MsgBox(Msg,mbError,MB_OK);
1454 Log(Msg);
1455 end;
1457 if not DeleteFile(FileName) then begin
1458 Msg:='Line {#__LINE__}: Unable to delete file "'+FileName+'". Please do it manually after logging off and on again.';
1459 MsgBox(Msg,mbError,MB_OK);
1460 Log(Msg);
1461 end;
1462 end;
1463 end;