mirror of
https://github.com/git/git
synced 2024-11-05 18:59:29 +00:00
Merge branch 'js/mingw-redirect-std-handles' into maint
MinGW updates. * js/mingw-redirect-std-handles: mingw: document the standard handle redirection mingw: optionally redirect stderr/stdout via the same handle mingw: add experimental feature to redirect standard handles
This commit is contained in:
commit
74ef46558e
3 changed files with 88 additions and 0 deletions
|
@ -709,6 +709,24 @@ of clones and fetches.
|
|||
the background which do not want to cause lock contention with
|
||||
other operations on the repository. Defaults to `1`.
|
||||
|
||||
`GIT_REDIRECT_STDIN`::
|
||||
`GIT_REDIRECT_STDOUT`::
|
||||
`GIT_REDIRECT_STDERR`::
|
||||
Windows-only: allow redirecting the standard input/output/error
|
||||
handles to paths specified by the environment variables. This is
|
||||
particularly useful in multi-threaded applications where the
|
||||
canonical way to pass standard handles via `CreateProcess()` is
|
||||
not an option because it would require the handles to be marked
|
||||
inheritable (and consequently *every* spawned process would
|
||||
inherit them, possibly blocking regular Git operations). The
|
||||
primary intended use case is to use named pipes for communication
|
||||
(e.g. `\\.\pipe\my-git-stdin-123`).
|
||||
+
|
||||
Two special values are supported: `off` will simply close the
|
||||
corresponding standard handle, and if `GIT_REDIRECT_STDERR` is
|
||||
`2>&1`, standard error will be redirected to the same handle as
|
||||
standard output.
|
||||
|
||||
Discussion[[Discussion]]
|
||||
------------------------
|
||||
|
||||
|
|
|
@ -2139,6 +2139,62 @@ static char *wcstoutfdup_startup(char *buffer, const wchar_t *wcs, size_t len)
|
|||
return memcpy(malloc_startup(len), buffer, len);
|
||||
}
|
||||
|
||||
static void maybe_redirect_std_handle(const wchar_t *key, DWORD std_id, int fd,
|
||||
DWORD desired_access, DWORD flags)
|
||||
{
|
||||
DWORD create_flag = fd ? OPEN_ALWAYS : OPEN_EXISTING;
|
||||
wchar_t buf[MAX_PATH];
|
||||
DWORD max = ARRAY_SIZE(buf);
|
||||
HANDLE handle;
|
||||
DWORD ret = GetEnvironmentVariableW(key, buf, max);
|
||||
|
||||
if (!ret || ret >= max)
|
||||
return;
|
||||
|
||||
/* make sure this does not leak into child processes */
|
||||
SetEnvironmentVariableW(key, NULL);
|
||||
if (!wcscmp(buf, L"off")) {
|
||||
close(fd);
|
||||
handle = GetStdHandle(std_id);
|
||||
if (handle != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(handle);
|
||||
return;
|
||||
}
|
||||
if (std_id == STD_ERROR_HANDLE && !wcscmp(buf, L"2>&1")) {
|
||||
handle = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
if (handle == INVALID_HANDLE_VALUE) {
|
||||
close(fd);
|
||||
handle = GetStdHandle(std_id);
|
||||
if (handle != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(handle);
|
||||
} else {
|
||||
int new_fd = _open_osfhandle((intptr_t)handle, O_BINARY);
|
||||
SetStdHandle(std_id, handle);
|
||||
dup2(new_fd, fd);
|
||||
/* do *not* close the new_fd: that would close stdout */
|
||||
}
|
||||
return;
|
||||
}
|
||||
handle = CreateFileW(buf, desired_access, 0, NULL, create_flag,
|
||||
flags, NULL);
|
||||
if (handle != INVALID_HANDLE_VALUE) {
|
||||
int new_fd = _open_osfhandle((intptr_t)handle, O_BINARY);
|
||||
SetStdHandle(std_id, handle);
|
||||
dup2(new_fd, fd);
|
||||
close(new_fd);
|
||||
}
|
||||
}
|
||||
|
||||
static void maybe_redirect_std_handles(void)
|
||||
{
|
||||
maybe_redirect_std_handle(L"GIT_REDIRECT_STDIN", STD_INPUT_HANDLE, 0,
|
||||
GENERIC_READ, FILE_ATTRIBUTE_NORMAL);
|
||||
maybe_redirect_std_handle(L"GIT_REDIRECT_STDOUT", STD_OUTPUT_HANDLE, 1,
|
||||
GENERIC_WRITE, FILE_ATTRIBUTE_NORMAL);
|
||||
maybe_redirect_std_handle(L"GIT_REDIRECT_STDERR", STD_ERROR_HANDLE, 2,
|
||||
GENERIC_WRITE, FILE_FLAG_NO_BUFFERING);
|
||||
}
|
||||
|
||||
void mingw_startup(void)
|
||||
{
|
||||
int i, maxlen, argc;
|
||||
|
@ -2146,6 +2202,8 @@ void mingw_startup(void)
|
|||
wchar_t **wenv, **wargv;
|
||||
_startupinfo si;
|
||||
|
||||
maybe_redirect_std_handles();
|
||||
|
||||
/* get wide char arguments and environment */
|
||||
si.newmode = 0;
|
||||
if (__wgetmainargs(&argc, &wargv, &wenv, _CRT_glob, &si) < 0)
|
||||
|
|
|
@ -453,4 +453,16 @@ test_expect_success 're-init from a linked worktree' '
|
|||
)
|
||||
'
|
||||
|
||||
test_expect_success MINGW 'redirect std handles' '
|
||||
GIT_REDIRECT_STDOUT=output.txt git rev-parse --git-dir &&
|
||||
test .git = "$(cat output.txt)" &&
|
||||
test -z "$(GIT_REDIRECT_STDOUT=off git rev-parse --git-dir)" &&
|
||||
test_must_fail env \
|
||||
GIT_REDIRECT_STDOUT=output.txt \
|
||||
GIT_REDIRECT_STDERR="2>&1" \
|
||||
git rev-parse --git-dir --verify refs/invalid &&
|
||||
printf ".git\nfatal: Needed a single revision\n" >expect &&
|
||||
test_cmp expect output.txt
|
||||
'
|
||||
|
||||
test_done
|
||||
|
|
Loading…
Reference in a new issue