forked from git/git
-
Notifications
You must be signed in to change notification settings - Fork 2.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2974 from derrickstolee/maintenance-and-headless
Include Windows-specific maintenance and headless-git
- Loading branch information
Showing
5 changed files
with
128 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
/* | ||
* headless Git - run Git without opening a console window on Windows | ||
*/ | ||
|
||
#define STRICT | ||
#define WIN32_LEAN_AND_MEAN | ||
#define UNICODE | ||
#define _UNICODE | ||
#include <windows.h> | ||
#include <stdio.h> | ||
#include <stdlib.h> | ||
#include <wchar.h> | ||
|
||
/* | ||
* If `dir` contains the path to a Git exec directory, extend `PATH` to | ||
* include the corresponding `bin/` directory (which is where all those | ||
* `.dll` files needed by `git.exe` are, on Windows). | ||
*/ | ||
static int extend_path(wchar_t *dir, size_t dir_len) | ||
{ | ||
const wchar_t *suffix = L"\\libexec\\git-core"; | ||
size_t suffix_len = wcslen(suffix); | ||
wchar_t *env; | ||
DWORD len; | ||
|
||
if (dir_len < suffix_len) | ||
return 0; | ||
|
||
dir_len -= suffix_len; | ||
if (memcmp(dir + dir_len, suffix, suffix_len * sizeof(wchar_t))) | ||
return 0; | ||
|
||
len = GetEnvironmentVariableW(L"PATH", NULL, 0); | ||
if (!len) | ||
return 0; | ||
|
||
env = _alloca((dir_len + 5 + len) * sizeof(wchar_t)); | ||
wcsncpy(env, dir, dir_len); | ||
wcscpy(env + dir_len, L"\\bin;"); | ||
if (!GetEnvironmentVariableW(L"PATH", env + dir_len + 5, len)) | ||
return 0; | ||
|
||
SetEnvironmentVariableW(L"PATH", env); | ||
return 1; | ||
} | ||
|
||
int WINAPI wWinMain(HINSTANCE instance, HINSTANCE previous_instance, | ||
wchar_t *command_line, int show) | ||
{ | ||
wchar_t git_command_line[32768]; | ||
size_t size = sizeof(git_command_line) / sizeof(wchar_t); | ||
const wchar_t *needs_quotes = L""; | ||
int slash = 0, i; | ||
|
||
STARTUPINFO startup_info = { | ||
.dwFlags = STARTF_USESHOWWINDOW, | ||
.wShowWindow = SW_HIDE, | ||
}; | ||
PROCESS_INFORMATION process_info = { 0 }; | ||
DWORD creation_flags = CREATE_UNICODE_ENVIRONMENT | | ||
CREATE_NEW_CONSOLE | CREATE_NO_WINDOW; | ||
DWORD exit_code; | ||
|
||
/* First, determine the full path of argv[0] */ | ||
for (i = 0; _wpgmptr[i]; i++) | ||
if (_wpgmptr[i] == L' ') | ||
needs_quotes = L"\""; | ||
else if (_wpgmptr[i] == L'\\') | ||
slash = i; | ||
|
||
if (slash + 11 >= sizeof(git_command_line) / sizeof(wchar_t)) | ||
return 127; /* Too long path */ | ||
|
||
/* If it is in Git's exec path, add the bin/ directory to the PATH */ | ||
extend_path(_wpgmptr, slash); | ||
|
||
/* Then, add the full path of `git.exe` as argv[0] */ | ||
i = swprintf_s(git_command_line, size, L"%ls%.*ls\\git.exe%ls", | ||
needs_quotes, slash, _wpgmptr, needs_quotes); | ||
if (i < 0) | ||
return 127; /* Too long path */ | ||
|
||
if (*command_line) { | ||
/* Now, append the command-line arguments */ | ||
i = swprintf_s(git_command_line + i, size - i, | ||
L" %ls", command_line); | ||
if (i < 0) | ||
return 127; | ||
} | ||
|
||
startup_info.cb = sizeof(STARTUPINFO); | ||
|
||
startup_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE); | ||
startup_info.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); | ||
startup_info.hStdError = GetStdHandle(STD_ERROR_HANDLE); | ||
|
||
if (!CreateProcess(NULL, /* infer argv[0] from the command line */ | ||
git_command_line, /* modified command line */ | ||
NULL, /* inherit process handles? */ | ||
NULL, /* inherit thread handles? */ | ||
FALSE, /* handles inheritable? */ | ||
creation_flags, | ||
NULL, /* use this process' environment */ | ||
NULL, /* use this process' working directory */ | ||
&startup_info, &process_info)) | ||
return 129; /* could not start */ | ||
WaitForSingleObject(process_info.hProcess, INFINITE); | ||
if (!GetExitCodeProcess(process_info.hProcess, &exit_code)) { | ||
CloseHandle(process_info.hProcess); | ||
return 130; /* Could not determine exit code? */ | ||
} | ||
|
||
return (int)exit_code; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters