Skip to content

Commit 5fb2a13

Browse files
committed
Merge pull request #34 from dscho/git-wrapper
Use msysGit's `git-wrapper` instead of the builtins
2 parents ba105aa + 498ae57 commit 5fb2a13

File tree

3 files changed

+268
-8
lines changed

3 files changed

+268
-8
lines changed

Makefile

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1672,11 +1672,17 @@ version.sp version.s version.o: EXTRA_CPPFLAGS = \
16721672
'-DGIT_VERSION="$(GIT_VERSION)"' \
16731673
'-DGIT_USER_AGENT=$(GIT_USER_AGENT_CQ_SQ)'
16741674

1675+
ifeq (,$(BUILT_IN_WRAPPER))
16751676
$(BUILT_INS): git$X
16761677
$(QUIET_BUILT_IN)$(RM) $@ && \
16771678
ln $< $@ 2>/dev/null || \
16781679
ln -s $< $@ 2>/dev/null || \
16791680
cp $< $@
1681+
else
1682+
$(BUILT_INS): $(BUILT_IN_WRAPPER)
1683+
$(QUIET_BUILT_IN)$(RM) $@ && \
1684+
cp $< $@
1685+
endif
16801686

16811687
common-cmds.h: ./generate-cmdlist.sh command-list.txt
16821688

@@ -2239,6 +2245,24 @@ profile-install: profile
22392245
profile-fast-install: profile-fast
22402246
$(MAKE) install
22412247

2248+
ifeq (,$(BUILT_IN_WRAPPER))
2249+
LN_OR_CP_BUILT_IN_BINDIR = \
2250+
test -z "$(NO_INSTALL_HARDLINKS)" && \
2251+
ln "$$bindir/git$X" "$$bindir/$$p" 2>/dev/null || \
2252+
ln -s "git$X" "$$bindir/$$p" 2>/dev/null || \
2253+
cp "$$bindir/git$X" "$$bindir/$$p" || exit;
2254+
LN_OR_CP_BUILT_IN_EXECDIR = \
2255+
test -z "$(NO_INSTALL_HARDLINKS)" && \
2256+
ln "$$exectir/git$X" "$$exectir/$$p" 2>/dev/null || \
2257+
ln -s "git$X" "$$exectir/$$p" 2>/dev/null || \
2258+
cp "$$exectir/git$X" "$$exectir/$$p" || exit;
2259+
else
2260+
LN_OR_CP_BUILT_IN_BINDIR = \
2261+
cp "$(BUILT_IN_WRAPPER)" "$$bindir/$$p" || exit;
2262+
LN_OR_CP_BUILT_IN_EXECDIR = \
2263+
cp "$(BUILT_IN_WRAPPER)" "$$execdir/$$p" || exit;
2264+
endif
2265+
22422266
install: all
22432267
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)'
22442268
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
@@ -2277,17 +2301,11 @@ endif
22772301
} && \
22782302
for p in $(filter $(install_bindir_programs),$(BUILT_INS)); do \
22792303
$(RM) "$$bindir/$$p" && \
2280-
test -z "$(NO_INSTALL_HARDLINKS)" && \
2281-
ln "$$bindir/git$X" "$$bindir/$$p" 2>/dev/null || \
2282-
ln -s "git$X" "$$bindir/$$p" 2>/dev/null || \
2283-
cp "$$bindir/git$X" "$$bindir/$$p" || exit; \
2304+
$(LN_OR_CP_BUILT_IN_BINDIR) \
22842305
done && \
22852306
for p in $(BUILT_INS); do \
22862307
$(RM) "$$execdir/$$p" && \
2287-
test -z "$(NO_INSTALL_HARDLINKS)" && \
2288-
ln "$$execdir/git$X" "$$execdir/$$p" 2>/dev/null || \
2289-
ln -s "git$X" "$$execdir/$$p" 2>/dev/null || \
2290-
cp "$$execdir/git$X" "$$execdir/$$p" || exit; \
2308+
$(LN_OR_CP_BUILT_IN_EXECDIR) \
22912309
done && \
22922310
remote_curl_aliases="$(REMOTE_CURL_ALIASES)" && \
22932311
for p in $$remote_curl_aliases; do \

compat/win32/git-wrapper.c

Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
/*
2+
* git-wrapper - replace cmd\git.cmd with an executable
3+
*
4+
* Copyright (C) 2012 Pat Thoyts <patthoyts@users.sourceforge.net>
5+
*/
6+
7+
#define STRICT
8+
#define WIN32_LEAN_AND_MEAN
9+
#define UNICODE
10+
#define _UNICODE
11+
#include <windows.h>
12+
#include <shlwapi.h>
13+
#include <shellapi.h>
14+
#include <stdio.h>
15+
16+
static void print_error(LPCWSTR prefix, DWORD error_number)
17+
{
18+
LPWSTR buffer = NULL;
19+
DWORD count = 0;
20+
21+
count = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER
22+
| FORMAT_MESSAGE_FROM_SYSTEM
23+
| FORMAT_MESSAGE_IGNORE_INSERTS,
24+
NULL, error_number, LANG_NEUTRAL,
25+
(LPTSTR)&buffer, 0, NULL);
26+
if (count < 1)
27+
count = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER
28+
| FORMAT_MESSAGE_FROM_STRING
29+
| FORMAT_MESSAGE_ARGUMENT_ARRAY,
30+
L"Code 0x%1!08x!",
31+
0, LANG_NEUTRAL, (LPTSTR)&buffer, 0,
32+
(va_list*)&error_number);
33+
fwprintf(stderr, L"%s: %s", prefix, buffer);
34+
LocalFree((HLOCAL)buffer);
35+
}
36+
37+
static void setup_environment(LPWSTR exepath)
38+
{
39+
int len;
40+
LPWSTR path2 = NULL;
41+
42+
/* if not set, set TERM to msys */
43+
if (!GetEnvironmentVariable(L"TERM", NULL, 0))
44+
SetEnvironmentVariable(L"TERM", L"msys");
45+
46+
/* if not set, set PLINK_PROTOCOL to ssh */
47+
if (!GetEnvironmentVariable(L"PLINK_PROTOCOL", NULL, 0))
48+
SetEnvironmentVariable(L"PLINK_PROTOCOL", L"ssh");
49+
50+
/* set HOME to %HOMEDRIVE%%HOMEPATH% or %USERPROFILE%
51+
* With roaming profiles: HOMEPATH is the roaming location and
52+
* USERPROFILE is the local location
53+
*/
54+
if (!GetEnvironmentVariable(L"HOME", NULL, 0)) {
55+
LPWSTR e = NULL;
56+
len = GetEnvironmentVariable(L"HOMEPATH", NULL, 0);
57+
if (len == 0) {
58+
len = GetEnvironmentVariable(L"USERPROFILE", NULL, 0);
59+
if (len != 0) {
60+
e = (LPWSTR)malloc(len * sizeof(WCHAR));
61+
GetEnvironmentVariable(L"USERPROFILE", e, len);
62+
SetEnvironmentVariable(L"HOME", e);
63+
free(e);
64+
}
65+
}
66+
else {
67+
int n;
68+
len += GetEnvironmentVariable(L"HOMEDRIVE", NULL, 0);
69+
e = (LPWSTR)malloc(sizeof(WCHAR) * (len + 2));
70+
n = GetEnvironmentVariable(L"HOMEDRIVE", e, len);
71+
GetEnvironmentVariable(L"HOMEPATH", &e[n], len-n);
72+
SetEnvironmentVariable(L"HOME", e);
73+
free(e);
74+
}
75+
}
76+
77+
/* extend the PATH */
78+
len = GetEnvironmentVariable(L"PATH", NULL, 0);
79+
len = sizeof(WCHAR) * (len + 2 * MAX_PATH);
80+
path2 = (LPWSTR)malloc(len);
81+
wcscpy(path2, exepath);
82+
PathAppend(path2, L"bin;");
83+
/* should do this only if it exists */
84+
wcscat(path2, exepath);
85+
PathAppend(path2, L"mingw\\bin;");
86+
GetEnvironmentVariable(L"PATH", &path2[wcslen(path2)],
87+
(len/sizeof(WCHAR))-wcslen(path2));
88+
SetEnvironmentVariable(L"PATH", path2);
89+
free(path2);
90+
91+
}
92+
93+
/*
94+
* Fix up the command line to call git.exe
95+
* We have to be very careful about quoting here so we just
96+
* trim off the first argument and replace it leaving the rest
97+
* untouched.
98+
*/
99+
static LPWSTR fixup_commandline(LPWSTR exepath, LPWSTR *exep, int *wait,
100+
LPWSTR builtin, int builtin_len)
101+
{
102+
int wargc = 0, gui = 0;
103+
LPWSTR cmd = NULL, cmdline = NULL;
104+
LPWSTR *wargv = NULL, p = NULL;
105+
106+
cmdline = GetCommandLine();
107+
wargv = CommandLineToArgvW(cmdline, &wargc);
108+
cmd = (LPWSTR)malloc(sizeof(WCHAR) *
109+
(wcslen(cmdline) + builtin_len + 1 + MAX_PATH));
110+
if (wargc > 1 && wcsicmp(L"gui", wargv[1]) == 0) {
111+
*wait = 0;
112+
if (wargc > 2 && wcsicmp(L"citool", wargv[2]) == 0) {
113+
*wait = 1;
114+
wcscpy(cmd, L"git.exe");
115+
}
116+
else {
117+
WCHAR script[MAX_PATH];
118+
gui = 1;
119+
wcscpy(script, exepath);
120+
PathAppend(script,
121+
L"libexec\\git-core\\git-gui");
122+
PathQuoteSpaces(script);
123+
wcscpy(cmd, L"wish.exe ");
124+
wcscat(cmd, script);
125+
wcscat(cmd, L" --");
126+
/* find the module from the commandline */
127+
*exep = NULL;
128+
}
129+
}
130+
else if (builtin)
131+
_swprintf(cmd, L"%s\\%s %.*s",
132+
exepath, L"git.exe", builtin_len, builtin);
133+
else
134+
wcscpy(cmd, L"git.exe");
135+
136+
/* append all after first space after the initial parameter */
137+
p = wcschr(&cmdline[wcslen(wargv[0])], L' ');
138+
if (p && *p) {
139+
/* for git gui subcommands, remove the 'gui' word */
140+
if (gui) {
141+
while (*p == L' ') ++p;
142+
p = wcschr(p, L' ');
143+
}
144+
if (p && *p)
145+
wcscat(cmd, p);
146+
}
147+
LocalFree(wargv);
148+
149+
return cmd;
150+
}
151+
152+
int main(void)
153+
{
154+
int r = 1, wait = 1, builtin_len = -1;
155+
WCHAR exepath[MAX_PATH], exe[MAX_PATH];
156+
LPWSTR cmd = NULL, exep = exe, builtin = NULL, basename;
157+
UINT codepage = 0;
158+
159+
/* get the installation location */
160+
GetModuleFileName(NULL, exepath, MAX_PATH);
161+
if (!PathRemoveFileSpec(exepath)) {
162+
fwprintf(stderr, L"Invalid executable path: %s\n", exepath);
163+
ExitProcess(1);
164+
}
165+
basename = exepath + wcslen(exepath) + 1;
166+
if (!wcsncmp(basename, L"git-", 4)) {
167+
/* Call a builtin */
168+
builtin = basename + 4;
169+
builtin_len = wcslen(builtin);
170+
if (!wcscmp(builtin + builtin_len - 4, L".exe"))
171+
builtin_len -= 4;
172+
173+
/* set the default exe module */
174+
wcscpy(exe, exepath);
175+
PathAppend(exe, L"git.exe");
176+
}
177+
else if (!wcscmp(basename, L"git.exe")) {
178+
if (!PathRemoveFileSpec(exepath)) {
179+
fwprintf(stderr,
180+
L"Invalid executable path: %s\n", exepath);
181+
ExitProcess(1);
182+
}
183+
184+
/* set the default exe module */
185+
wcscpy(exe, exepath);
186+
PathAppend(exe, L"bin\\git.exe");
187+
}
188+
189+
if (!builtin)
190+
setup_environment(exepath);
191+
cmd = fixup_commandline(exepath, &exep, &wait, builtin, builtin_len);
192+
193+
/* set the console to ANSI/GUI codepage */
194+
codepage = GetConsoleCP();
195+
SetConsoleCP(GetACP());
196+
197+
{
198+
STARTUPINFO si;
199+
PROCESS_INFORMATION pi;
200+
BOOL br = FALSE;
201+
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
202+
ZeroMemory(&si, sizeof(STARTUPINFO));
203+
si.cb = sizeof(STARTUPINFO);
204+
br = CreateProcess(/* module: null means use command line */
205+
exep,
206+
cmd, /* modified command line */
207+
NULL, /* process handle inheritance */
208+
NULL, /* thread handle inheritance */
209+
TRUE, /* handles inheritable? */
210+
CREATE_UNICODE_ENVIRONMENT,
211+
NULL, /* environment: use parent */
212+
NULL, /* starting directory: use parent */
213+
&si, &pi);
214+
if (br) {
215+
if (wait)
216+
WaitForSingleObject(pi.hProcess, INFINITE);
217+
if (!GetExitCodeProcess(pi.hProcess, (DWORD *)&r))
218+
print_error(L"error reading exit code",
219+
GetLastError());
220+
CloseHandle(pi.hProcess);
221+
}
222+
else {
223+
print_error(L"error launching git", GetLastError());
224+
r = 1;
225+
}
226+
}
227+
228+
free(cmd);
229+
230+
/* reset the console codepage */
231+
SetConsoleCP(codepage);
232+
ExitProcess(r);
233+
}

config.mak.uname

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -524,6 +524,8 @@ ifneq (,$(findstring MINGW,$(uname_S)))
524524
NATIVE_CRLF = YesPlease
525525
X = .exe
526526
SPARSE_FLAGS = -Wno-one-bit-signed-bitfield
527+
OTHER_PROGRAMS += git-wrapper$(X)
528+
BUILT_IN_WRAPPER = git-wrapper$(X)
527529
ifneq (,$(wildcard ../THIS_IS_MSYSGIT))
528530
htmldir = share/doc/git/$(firstword $(subst -, ,$(GIT_VERSION)))/html
529531
prefix =
@@ -561,6 +563,13 @@ else
561563
else
562564
NO_CURL = YesPlease
563565
endif
566+
567+
git-wrapper$(X): compat/win32/git-wrapper.o git.res
568+
$(QUIET_LINK)$(CC) -Wall -s -o $@ $^ -lshell32 -lshlwapi
569+
570+
compat/win32/git-wrapper.o: %.o: %.c
571+
$(QUIET_CC)$(CC) -o $*.o -c -Wall -Wwrite-strings $<
572+
564573
endif
565574
endif
566575
ifeq ($(uname_S),QNX)

0 commit comments

Comments
 (0)