2 #define APP_VERSION
'%APPVERSION%'
3 #define APP_URL
'http://code.google.com/p/msysgit/'
4 #define APP_BUILTINS
'etc\fileList-builtins.txt'
8 InternalCompressLevel
=max
9 OutputBaseFilename
={#emit APP_NAME+'-'+APP_VERSION}
15 AppName
={#emit APP_NAME}
16 AppPublisherURL
={#emit APP_URL}
17 AppVersion
={#emit APP_VERSION}
18 AppVerName
={#emit APP_NAME+' '+APP_VERSION}
19 ChangesEnvironment
=yes
20 DefaultDirName
={pf}\
{#emit APP_NAME}
21 DefaultGroupName
={#emit APP_NAME}
23 LicenseFile
=gpl
-2.0.rtf
24 PrivilegesRequired
=none
25 UninstallDisplayIcon
=etc\git
.ico
28 SetupIconFile
=etc\git
.ico
29 WizardSmallImageFile
=git
.bmp
32 Name
: quicklaunchicon; Description
: "Create a &Quick Launch icon"; GroupDescription
: "Additional icons:"; Flags
: checkedonce
33 Name
: desktopicon; Description
: "Create a &Desktop icon"; GroupDescription
: "Additional icons:"; Flags
: checkedonce
34 Name
: shellextension
; Description
: "Add ""Git Ba&sh Here"""; GroupDescription
: "Windows Explorer integration:"; Flags
: checkedonce
35 Name
: guiextension
; Description
: "Add ""Git &GUI Here"""; GroupDescription
: "Windows Explorer integration:"; Flags
: checkedonce
38 Source
: "*"; DestDir
: "{app}"; Excludes
: "\*.bmp, gpl-2.0.rtf, \install.*, \tmp.*, \bin\*install*"; Flags
: recursesubdirs
39 Source
: ReleaseNotes
.rtf
; DestDir
: "{app}"; Flags
: isreadme
42 Name
: "{group}\Git GUI"; Filename
: "{app}\bin\wish.exe"; Parameters
: """{app}\bin\git-gui"""; WorkingDir
: "%USERPROFILE%"; IconFilename
: "{app}\etc\git.ico"
43 Name
: "{group}\Git Bash"; Filename
: "{syswow64}\cmd.exe"; Parameters
: "/c """"{app}\bin\sh.exe"" --login -i"""; WorkingDir
: "%USERPROFILE%"; IconFilename
: "{app}\etc\git.ico"
44 Name
: "{group}\Uninstall Git"; Filename
: "{uninstallexe}"
45 Name
: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\Git Bash"; Filename
: "{syswow64}\cmd.exe"; Parameters
: "/c """"{app}\bin\sh.exe"" --login -i"""; WorkingDir
: "%USERPROFILE%"; IconFilename
: "{app}\etc\git.ico"; Tasks
: quicklaunchicon
46 Name
: "{code:GetShellFolder|desktop}\Git Bash"; Filename
: "{syswow64}\cmd.exe"; Parameters
: "/c """"{app}\bin\sh.exe"" --login -i"""; WorkingDir
: "%USERPROFILE%"; IconFilename
: "{app}\etc\git.ico"; Tasks
: desktopicon
49 BeveledLabel
={#emit APP_URL}
50 SetupAppTitle
={#emit APP_NAME} Setup
51 SetupWindowTitle
={#emit APP_NAME} Setup
54 Type: files; Name
: "{app}\bin\git-*.exe"
55 Type: dirifempty; Name
: "{app}\home\{username}"
56 Type: dirifempty; Name
: "{app}\home"
63 function GetShellFolder(Param
:string):string;
65 if IsAdminLoggedOn
then begin
66 Param
:='{common'+Param
+'}';
68 Param
:='{user'+Param
+'}';
70 Result
:=ExpandConstant(Param
);
73 function CreateHardLink(lpFileName
,lpExistingFileName
:string;lpSecurityAttributes
:Integer):Boolean;
74 external 'CreateHardLinkA@Kernel32.dll';
76 function GetEnvStrings(VarName
:string;AllUsers
:Boolean):TArrayOfString
;
84 // See http
://www
.jrsoftware
.org
/isfaq
.php#env
85 if AllUsers
then begin
86 // We ignore errors here
. The resulting
array of strings will be empty
.
87 RegQueryStringValue(HKEY_LOCAL_MACHINE
,'SYSTEM\CurrentControlSet\Control\Session Manager\Environment',VarName
,Path
);
89 // We ignore errors here
. The resulting
array of strings will be empty
.
90 RegQueryStringValue(HKEY_CURRENT_USER
,'Environment',VarName
,Path
);
93 // Make sure we have at least one semicolon
.
96 // Split the directories
in PATH into an
array of strings
.
98 SetArrayLength(Result
,0);
102 SetArrayLength(Result
,i
+1);
104 Result
[i
]:=Copy(Path
,1,p
-1);
107 Path
:=Copy(Path
,p
+1,Length(Path
));
112 function SetEnvStrings(VarName
:string;AllUsers
,DeleteIfEmpty
:Boolean;DirStrings
:TArrayOfString
):Boolean;
117 // Merge all non
-empty directory strings into a PATH variable
.
119 for i
:=0 to GetArrayLength(DirStrings
)-1 do begin
120 if Length(DirStrings
[i
])>0 then begin
121 if Length(Path
)>0 then begin
122 Path
:=Path
+';'+DirStrings
[i
];
129 // See http
://www
.jrsoftware
.org
/isfaq
.php#env
130 if AllUsers
then begin
131 KeyName
:='SYSTEM\CurrentControlSet\Control\Session Manager\Environment';
132 if DeleteIfEmpty
and (Length(Path
)=0) then begin
133 Result
:=(not RegValueExists(HKEY_LOCAL_MACHINE
,KeyName
,VarName
))
134 or RegDeleteValue(HKEY_LOCAL_MACHINE
,KeyName
,VarName
);
136 Result
:=RegWriteStringValue(HKEY_LOCAL_MACHINE
,KeyName
,VarName
,Path
);
139 KeyName
:='Environment';
140 if DeleteIfEmpty
and (Length(Path
)=0) then begin
141 Result
:=(not RegValueExists(HKEY_CURRENT_USER
,KeyName
,VarName
))
142 or RegDeleteValue(HKEY_CURRENT_USER
,KeyName
,VarName
);
144 Result
:=RegWriteStringValue(HKEY_CURRENT_USER
,KeyName
,VarName
,Path
);
155 RdbGitBash
,RdbGitCmd
,RdbGitCmdTools
:TRadioButton
;
157 procedure InitializeWizard
;
159 LblGitBash
,LblGitCmd
,LblGitCmdTools
,LblGitCmdToolsWarn
:TLabel
;
161 // Create a custom page
for modifying the environment
.
162 EnvPage
:=CreateCustomPage(
164 'Adjusting your PATH environment',
165 'How would you like to use Git from the command line?'
169 RdbGitBash
:=TRadioButton
.Create(EnvPage
);
170 with RdbGitBash
do begin
171 Parent
:=EnvPage
.Surface
;
172 Caption
:='Use Git Bash only';
177 Font
.Style
:=[fsBold
];
181 LblGitBash
:=TLabel
.Create(EnvPage
);
182 with LblGitBash
do begin
183 Parent
:=EnvPage
.Surface
;
185 'This is the most conservative choice if you are concerned about the' + #
13 +
186 'stability of your system. Your PATH will not be modified.';
194 RdbGitCmd
:=TRadioButton
.Create(EnvPage
);
195 with RdbGitCmd
do begin
196 Parent
:=EnvPage
.Surface
;
197 Caption
:='Run Git from the Windows Command Prompt';
202 Font
.Style
:=[fsBold
];
205 LblGitCmd
:=TLabel
.Create(EnvPage
);
206 with LblGitCmd
do begin
207 Parent
:=EnvPage
.Surface
;
209 'This option is considered safe and no conflicts with other tools are' + #
13 +
210 'known. Only Git will be added to your PATH.';
218 RdbGitCmdTools
:=TRadioButton
.Create(EnvPage
);
219 with RdbGitCmdTools
do begin
220 Parent
:=EnvPage
.Surface
;
221 Caption
:='Run Git and included Unix tools from the Windows Command Prompt';
226 Font
.Style
:=[fsBold
];
229 LblGitCmdTools
:=TLabel
.Create(EnvPage
);
230 with LblGitCmdTools
do begin
231 Parent
:=EnvPage
.Surface
;
232 Caption
:='Both Git and the Unix tools will be added to your PATH.';
238 LblGitCmdToolsWarn
:=TLabel
.Create(EnvPage
);
239 with LblGitCmdToolsWarn
do begin
240 Parent
:=EnvPage
.Surface
;
242 'Warning: This will override Windows tools like find.exe and' + #
13 +
243 'sort.exe. Select this option only if you understand the implications.';
249 Font
.Style
:=[fsBold
];
253 procedure CurStepChanged(CurStep
:TSetupStep
);
255 AppDir
,FileName
,Cmd
,Msg
:string;
256 BuiltIns
,EnvPath
,EnvHome
:TArrayOfString
;
261 if CurStep
<>ssPostInstall
then begin
265 AppDir
:=ExpandConstant('{app}');
271 // Load the built
-ins from a
text file.
272 FileName
:=ExpandConstant('{app}\'+'{#emit APP_BUILTINS}');
273 if LoadStringsFromFile(FileName,BuiltIns) then begin
274 // Check if we are running on NTFS.
276 if SetNTFSCompression(AppDir+'\bin\git
.exe
',true) then begin
277 IsNTFS:=SetNTFSCompression(AppDir+'\bin\git
.exe
',false);
280 Count:=GetArrayLength(BuiltIns)-1;
282 // Delete all scripts as they might have been replaced by built-ins by now.
283 for i:=0 to Count do begin
284 FileName:=ChangeFileExt(AppDir+'\'+BuiltIns
[i
],'');
285 if (FileExists(FileName
) and (not DeleteFile(FileName
))) then begin
286 Log('Line {#emit __LINE__}: Unable to delete script "'+FileName
+'", ignoring.');
290 // Map the built
-ins
to git
.exe
.
292 Log('Line {#emit __LINE__}: Partition seems to be NTFS, trying to create built-in aliases as hard links.');
294 for i
:=0 to Count
do begin
295 FileName
:=AppDir
+'\'+BuiltIns[i];
297 // On non-NTFS partitions, create hard links.
298 if (FileExists(FileName) and (not DeleteFile(FileName)))
299 or (not CreateHardLink(FileName,AppDir+'\bin\git
.exe
',0)) then begin
300 Log('Line
{#emit __LINE__}: Unable
to create hard link
"'+FileName+'", will
try to copy
files.');
306 Log('Line
{#emit __LINE__}: Successfully created built
-in aliases
as hard links
.');
309 // The fallback is to copy the files.
310 if not IsNTFS then begin
311 Log('Line
{#emit __LINE__}: Trying
to create built
-in aliases
as file copies
.');
313 for i:=0 to Count do begin
314 FileName:=AppDir+'\'+BuiltIns
[i
];
316 // On non
-NTFS partitions
, copy simply the
files (overwriting existing ones
).
317 if not FileCopy(AppDir
+'\bin\git.exe',FileName
,false) then begin
318 Msg
:='Line {#emit __LINE__}: Unable to create file copy "'+FileName
+'".';
319 MsgBox(Msg
,mbError
,MB_OK
);
321 // This
is not a critical error
, Git could basically be used without the
322 // aliases
for built
-ins
, so we continue
.
326 Log('Line {#emit __LINE__}: Successfully created built-in aliases as file copies.');
329 Msg
:='Line {#emit __LINE__}: Unable to read file "{#emit APP_BUILTINS}".';
330 MsgBox(Msg
,mbError
,MB_OK
);
332 // This
is not a critical error
, Git could basically be used without the
333 // aliases
for built
-ins
, so we continue
.
338 Modify the environment
340 This must happen no later than ssPostInstall to make
341 "ChangesEnvironment=yes" not happend before the change!
344 // Get the current user
's directories in PATH.
345 EnvPath:=GetEnvStrings('PATH
',IsAdminLoggedOn);
347 // First, remove the installation directory from PATH in any case.
348 for i:=0 to GetArrayLength(EnvPath)-1 do begin
349 if Pos(AppDir,EnvPath[i])=1 then begin
354 // Delete HOME if a previous installation modified it.
355 EnvHome:=GetEnvStrings('HOME
',IsAdminLoggedOn);
356 if (GetArrayLength(EnvHome)=1) and
357 (CompareStr(EnvHome[0],GetIniString('Environment
','HOME
','',AppDir+'\setup
.ini
'))=0) then begin
358 if not SetEnvStrings('HOME
',IsAdminLoggedOn,True,[]) then begin
359 Msg:='Line
{#emit __LINE__}: Unable
to reset HOME prior
to install
.';
360 MsgBox(Msg,mbError,MB_OK);
362 // This is not a critical error, the user can probably fix it manually,
367 // Modify the PATH variable as requested by the user.
368 if RdbGitCmd.Checked or RdbGitCmdTools.Checked then begin
369 i:=GetArrayLength(EnvPath);
370 SetArrayLength(EnvPath,i+1);
372 // List \cmd before \bin so \cmd has higher priority and programs in
373 // there will be called in favor of those in \bin.
374 EnvPath[i]:=ExpandConstant('{app}\cmd
');
376 if RdbGitCmdTools.Checked then begin
377 SetArrayLength(EnvPath,i+2);
378 EnvPath[i+1]:=ExpandConstant('{app}\bin
');
380 // Set HOME for the Windows Command Prompt.
381 EnvHome:=GetEnvStrings('HOME
',IsAdminLoggedOn);
382 i:=GetArrayLength(EnvHome);
383 if (i=0) or ((i=1) and (Length(EnvHome[0])=0)) then begin
384 SetArrayLength(EnvHome,1);
385 EnvHome[0]:=ExpandConstant('{%USERPROFILE}');
386 if not SetEnvStrings('HOME
',IsAdminLoggedOn,True,EnvHome) then begin
387 Msg:='Line
{#emit __LINE__}: Unable
to set the HOME environment variable
.';
388 MsgBox(Msg,mbError,MB_OK);
390 // This is not a critical error, the user can probably fix it manually,
394 // Mark that we have changed HOME.
395 FileName:=AppDir+'\setup
.ini
';
396 if not SetIniString('Environment
','HOME
',EnvHome[0],FileName) then begin
397 Msg:='Line
{#emit __LINE__}: Unable
to write
to file "'+FileName+'".';
398 MsgBox(Msg,mbError,MB_OK);
400 // This is not a critical error, though uninstall / reinstall will probably not run cleanly,
407 // Set the current user's PATH directories
.
408 if not SetEnvStrings('PATH',IsAdminLoggedOn
,True,EnvPath
) then begin
409 Msg
:='Line {#emit __LINE__}: Unable to set the PATH environment variable.';
410 MsgBox(Msg
,mbError
,MB_OK
);
412 // This
is not a critical error
, the user can probably fix it manually
,
417 Create the Windows Explorer shell extensions
420 if IsAdminLoggedOn
then begin
421 RootKey
:=HKEY_LOCAL_MACHINE
;
423 RootKey
:=HKEY_CURRENT_USER
;
426 if IsTaskSelected('shellextension') then begin
427 Cmd
:=ExpandConstant('"{syswow64}\cmd.exe"');
428 if (not RegWriteStringValue(RootKey
,'SOFTWARE\Classes\Directory\shell\git_shell','','Git Ba&sh Here'))
429 or (not RegWriteStringValue(RootKey
,'SOFTWARE\Classes\Directory\shell\git_shell\command','',Cmd
+' /c "pushd "%1" && "'+AppDir
+'\bin\sh.exe" --login -i"')) then begin
430 Msg
:='Line {#emit __LINE__}: Unable to create "Git Bash Here" shell extension.';
431 MsgBox(Msg
,mbError
,MB_OK
);
433 // This
is not a critical error
, the user can probably fix it manually
,
438 if IsTaskSelected('guiextension') then begin
439 if (not RegWriteStringValue(RootKey
,'SOFTWARE\Classes\Directory\shell\git_gui','','Git &GUI Here'))
440 or (not RegWriteStringValue(RootKey
,'SOFTWARE\Classes\Directory\shell\git_gui\command','','"'+AppDir
+'\bin\wish.exe" "'+AppDir
+'\bin\git-gui" "--working-dir" "%1"')) then begin
441 Msg
:='Line {#emit __LINE__}: Unable to create "Git GUI Here" shell extension.';
442 MsgBox(Msg
,mbError
,MB_OK
);
444 // This
is not a critical error
, the user can probably fix it manually
,
454 function InitializeUninstall
:Boolean;
456 FileName
,NewName
,Msg
:string;
458 FileName
:=ExpandConstant('{app}')+'\bin\ssh-agent.exe';
459 if FileExists(FileName
) then begin
460 // Create a temporary copy
of the
file we
try to delete
.
461 NewName
:=FileName
+'.'+IntToStr(1000+Random(9000));
462 Result
:=FileCopy(FileName
,NewName
,True) and DeleteFile(FileName
);
464 if not Result
then begin
465 Msg
:='Line {#emit __LINE__}: Please stop all ssh-agent processes and run uninstall again.';
466 MsgBox(Msg
,mbError
,MB_OK
);
469 // Clean
-up the temporary
copy (ignoring any errors
).
472 // Clean
-up the temporary
copy (ignoring any errors
).
473 RenameFile(NewName
,FileName
);
480 procedure CurUninstallStepChanged(CurUninstallStep
:TUninstallStep
);
482 AppDir
,Command
,Msg
:string;
483 EnvPath
,EnvHome
:TArrayOfString
;
487 if CurUninstallStep
<>usUninstall
then begin
492 Modify the environment
494 This must happen no later than usUninstall to make
495 "ChangesEnvironment=yes" not happend before the change!
498 AppDir
:=ExpandConstant('{app}');
500 // Get the current user
's directories in PATH.
501 EnvPath:=GetEnvStrings('PATH
',IsAdminLoggedOn);
503 // Remove the installation directory from PATH in any case, even if it
504 // was not added by the installer.
505 for i:=0 to GetArrayLength(EnvPath)-1 do begin
506 if Pos(AppDir,EnvPath[i])=1 then begin
511 // Reset the current user's directories
in PATH
.
512 if not SetEnvStrings('PATH',IsAdminLoggedOn
,True,EnvPath
) then begin
513 Msg
:='Line {#emit __LINE__}: Unable to revert any possible changes to PATH.';
514 MsgBox(Msg
,mbError
,MB_OK
);
516 // This
is not a critical error
, the user can probably fix it manually
,
520 // Reset the current user
's HOME if we modified it.
521 EnvHome:=GetEnvStrings('HOME
',IsAdminLoggedOn);
522 if (GetArrayLength(EnvHome)=1) and
523 (CompareStr(EnvHome[0],GetIniString('Environment
','HOME
','',AppDir+'\setup
.ini
'))=0) then begin
524 if not SetEnvStrings('HOME
',IsAdminLoggedOn,True,[]) then begin
525 Msg:='Line
{#emit __LINE__}: Unable
to revert any possible changes
to HOME
.';
526 MsgBox(Msg,mbError,MB_OK);
528 // This is not a critical error, the user can probably fix it manually,
533 Command:=AppDir+'\setup
.ini
';
534 if (FileExists(Command) and (not DeleteFile(Command))) then begin
535 Msg:='Line
{#emit __LINE__}: Unable
to delete
file "'+Command+'".';
536 MsgBox(Msg,mbError,MB_OK);
538 // This is not a critical error, the user can probably fix it manually,
543 Delete the Windows Explorer shell extensions
546 if IsAdminLoggedOn then begin
547 RootKey:=HKEY_LOCAL_MACHINE;
549 RootKey:=HKEY_CURRENT_USER;
553 RegQueryStringValue(RootKey,'SOFTWARE\Classes\Directory\shell\git_shell\command
','',Command);
554 if Pos(AppDir,Command)>0 then begin
555 if not RegDeleteKeyIncludingSubkeys(RootKey,'SOFTWARE\Classes\Directory\shell\git_shell
') then begin
556 Msg:='Line
{#emit __LINE__}: Unable
to remove
"Git Bash Here" shell extension
.';
557 MsgBox(Msg,mbError,MB_OK);
559 // This is not a critical error, the user can probably fix it manually,
565 RegQueryStringValue(RootKey,'SOFTWARE\Classes\Directory\shell\git_gui\command
','',Command);
566 if Pos(AppDir,Command)>0 then begin
567 if not RegDeleteKeyIncludingSubkeys(RootKey,'SOFTWARE\Classes\Directory\shell\git_gui
') then begin
568 Msg:='Line
{#emit __LINE__}: Unable
to remove
"Git GUI Here" shell extension
.';
569 MsgBox(Msg,mbError,MB_OK);
571 // This is not a critical error, the user can probably fix it manually,