Skip to content

Commit d002525

Browse files
committed
Merge pull request #34 from dscho/git-wrapper
Use msysGit's `git-wrapper` instead of the builtins
2 parents 42d76bb + 5727569 commit d002525

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
@@ -1655,11 +1655,17 @@ version.sp version.s version.o: EXTRA_CPPFLAGS = \
16551655
'-DGIT_VERSION="$(GIT_VERSION)"' \
16561656
'-DGIT_USER_AGENT=$(GIT_USER_AGENT_CQ_SQ)'
16571657

1658+
ifeq (,$(BUILT_IN_WRAPPER))
16581659
$(BUILT_INS): git$X
16591660
$(QUIET_BUILT_IN)$(RM) $@ && \
16601661
ln $< $@ 2>/dev/null || \
16611662
ln -s $< $@ 2>/dev/null || \
16621663
cp $< $@
1664+
else
1665+
$(BUILT_INS): $(BUILT_IN_WRAPPER)
1666+
$(QUIET_BUILT_IN)$(RM) $@ && \
1667+
cp $< $@
1668+
endif
16631669

16641670
common-cmds.h: ./generate-cmdlist.sh command-list.txt
16651671

@@ -2222,6 +2228,24 @@ profile-install: profile
22222228
profile-fast-install: profile-fast
22232229
$(MAKE) install
22242230

2231+
ifeq (,$(BUILT_IN_WRAPPER))
2232+
LN_OR_CP_BUILT_IN_BINDIR = \
2233+
test -z "$(NO_INSTALL_HARDLINKS)" && \
2234+
ln "$$bindir/git$X" "$$bindir/$$p" 2>/dev/null || \
2235+
ln -s "git$X" "$$bindir/$$p" 2>/dev/null || \
2236+
cp "$$bindir/git$X" "$$bindir/$$p" || exit;
2237+
LN_OR_CP_BUILT_IN_EXECDIR = \
2238+
test -z "$(NO_INSTALL_HARDLINKS)" && \
2239+
ln "$$exectir/git$X" "$$exectir/$$p" 2>/dev/null || \
2240+
ln -s "git$X" "$$exectir/$$p" 2>/dev/null || \
2241+
cp "$$exectir/git$X" "$$exectir/$$p" || exit;
2242+
else
2243+
LN_OR_CP_BUILT_IN_BINDIR = \
2244+
cp "$(BUILT_IN_WRAPPER)" "$$bindir/$$p" || exit;
2245+
LN_OR_CP_BUILT_IN_EXECDIR = \
2246+
cp "$(BUILT_IN_WRAPPER)" "$$execdir/$$p" || exit;
2247+
endif
2248+
22252249
install: all
22262250
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)'
22272251
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
@@ -2260,17 +2284,11 @@ endif
22602284
} && \
22612285
for p in $(filter $(install_bindir_programs),$(BUILT_INS)); do \
22622286
$(RM) "$$bindir/$$p" && \
2263-
test -z "$(NO_INSTALL_HARDLINKS)" && \
2264-
ln "$$bindir/git$X" "$$bindir/$$p" 2>/dev/null || \
2265-
ln -s "git$X" "$$bindir/$$p" 2>/dev/null || \
2266-
cp "$$bindir/git$X" "$$bindir/$$p" || exit; \
2287+
$(LN_OR_CP_BUILT_IN_BINDIR) \
22672288
done && \
22682289
for p in $(BUILT_INS); do \
22692290
$(RM) "$$execdir/$$p" && \
2270-
test -z "$(NO_INSTALL_HARDLINKS)" && \
2271-
ln "$$execdir/git$X" "$$execdir/$$p" 2>/dev/null || \
2272-
ln -s "git$X" "$$execdir/$$p" 2>/dev/null || \
2273-
cp "$$execdir/git$X" "$$execdir/$$p" || exit; \
2291+
$(LN_OR_CP_BUILT_IN_EXECDIR) \
22742292
done && \
22752293
remote_curl_aliases="$(REMOTE_CURL_ALIASES)" && \
22762294
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 <[email protected]>
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
@@ -561,6 +561,15 @@ else
561561
else
562562
NO_CURL = YesPlease
563563
endif
564+
OTHER_PROGRAMS += git-wrapper$(X)
565+
BUILT_IN_WRAPPER = git-wrapper$(X)
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)