|
4 | 4 | #include <array> |
5 | 5 | #include <cstdio> |
6 | 6 | #include <cstring> |
| 7 | +#include <cwchar> |
7 | 8 | #include <sstream> |
8 | 9 | #include <stdexcept> |
9 | 10 | #include <thread> |
@@ -84,7 +85,38 @@ namespace gitReview |
84 | 85 | into.append(buf, static_cast<size_t>(n)); |
85 | 86 | } |
86 | 87 |
|
87 | | - static GitRunResult runGitImpl(const std::string &repoRoot, const std::vector<std::string> &args, const std::string *stdinData) |
| 88 | + static bool isEnvName(const wchar_t *entry, const wchar_t *name) |
| 89 | + { |
| 90 | + const size_t nameLen = wcslen(name); |
| 91 | + return _wcsnicmp(entry, name, nameLen) == 0 && entry[nameLen] == L'='; |
| 92 | + } |
| 93 | + |
| 94 | + static std::vector<wchar_t> makeNoTerminalPromptEnvironment() |
| 95 | + { |
| 96 | + std::vector<wchar_t> block; |
| 97 | + LPWCH raw = GetEnvironmentStringsW(); |
| 98 | + if (!raw) |
| 99 | + return block; |
| 100 | + |
| 101 | + for (LPWCH p = raw; *p; p += wcslen(p) + 1) |
| 102 | + { |
| 103 | + if (isEnvName(p, L"GIT_TERMINAL_PROMPT") || isEnvName(p, L"GCM_INTERACTIVE")) |
| 104 | + continue; |
| 105 | + const size_t len = wcslen(p); |
| 106 | + block.insert(block.end(), p, p + len + 1); |
| 107 | + } |
| 108 | + FreeEnvironmentStringsW(raw); |
| 109 | + |
| 110 | + const wchar_t gitPrompt[] = L"GIT_TERMINAL_PROMPT=0"; |
| 111 | + const wchar_t gcmInteractive[] = L"GCM_INTERACTIVE=never"; |
| 112 | + block.insert(block.end(), gitPrompt, gitPrompt + wcslen(gitPrompt) + 1); |
| 113 | + block.insert(block.end(), gcmInteractive, gcmInteractive + wcslen(gcmInteractive) + 1); |
| 114 | + block.push_back(L'\0'); |
| 115 | + return block; |
| 116 | + } |
| 117 | + |
| 118 | + static GitRunResult runGitImpl(const std::string &repoRoot, const std::vector<std::string> &args, const std::string *stdinData, |
| 119 | + bool noTerminalPrompt) |
88 | 120 | { |
89 | 121 | GitRunResult result; |
90 | 122 |
|
@@ -138,8 +170,12 @@ namespace gitReview |
138 | 170 | PROCESS_INFORMATION pi{}; |
139 | 171 | std::vector<wchar_t> cmdBuf(cmdLine.begin(), cmdLine.end()); |
140 | 172 | cmdBuf.push_back(L'\0'); |
| 173 | + std::vector<wchar_t> envBlock; |
| 174 | + if (noTerminalPrompt) |
| 175 | + envBlock = makeNoTerminalPromptEnvironment(); |
141 | 176 |
|
142 | | - const BOOL ok = CreateProcessW(nullptr, cmdBuf.data(), nullptr, nullptr, TRUE, CREATE_NO_WINDOW, nullptr, nullptr, &si, &pi); |
| 177 | + const BOOL ok = CreateProcessW(nullptr, cmdBuf.data(), nullptr, nullptr, TRUE, CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT, |
| 178 | + noTerminalPrompt && !envBlock.empty() ? envBlock.data() : nullptr, nullptr, &si, &pi); |
143 | 179 |
|
144 | 180 | CloseHandle(hStdoutWrite); |
145 | 181 | CloseHandle(hStderrWrite); |
@@ -191,7 +227,8 @@ namespace gitReview |
191 | 227 | #else |
192 | 228 | // ── POSIX helpers ──────────────────────────────────────────────── |
193 | 229 |
|
194 | | - static GitRunResult runGitImpl(const std::string &repoRoot, const std::vector<std::string> &args, const std::string *stdinData) |
| 230 | + static GitRunResult runGitImpl(const std::string &repoRoot, const std::vector<std::string> &args, const std::string *stdinData, |
| 231 | + bool noTerminalPrompt) |
195 | 232 | { |
196 | 233 | GitRunResult result; |
197 | 234 |
|
@@ -250,6 +287,21 @@ namespace gitReview |
250 | 287 | dup2(inPipe[0], STDIN_FILENO); |
251 | 288 | close(inPipe[0]); |
252 | 289 | } |
| 290 | + else if (noTerminalPrompt) |
| 291 | + { |
| 292 | + const int devNull = open("/dev/null", O_RDONLY); |
| 293 | + if (devNull >= 0) |
| 294 | + { |
| 295 | + dup2(devNull, STDIN_FILENO); |
| 296 | + close(devNull); |
| 297 | + } |
| 298 | + } |
| 299 | + |
| 300 | + if (noTerminalPrompt) |
| 301 | + { |
| 302 | + setenv("GIT_TERMINAL_PROMPT", "0", 1); |
| 303 | + setenv("GCM_INTERACTIVE", "never", 1); |
| 304 | + } |
253 | 305 |
|
254 | 306 | std::vector<std::string> argvStorage; |
255 | 307 | argvStorage.reserve(args.size() + 3); |
@@ -328,12 +380,17 @@ namespace gitReview |
328 | 380 |
|
329 | 381 | GitRunResult runGit(const std::string &repoRoot, const std::vector<std::string> &args) |
330 | 382 | { |
331 | | - return runGitImpl(repoRoot, args, nullptr); |
| 383 | + return runGitImpl(repoRoot, args, nullptr, false); |
332 | 384 | } |
333 | 385 |
|
334 | 386 | GitRunResult runGitWithStdin(const std::string &repoRoot, const std::vector<std::string> &args, const std::string &stdinData) |
335 | 387 | { |
336 | | - return runGitImpl(repoRoot, args, &stdinData); |
| 388 | + return runGitImpl(repoRoot, args, &stdinData, false); |
| 389 | + } |
| 390 | + |
| 391 | + GitRunResult runGitNoTerminalPrompt(const std::string &repoRoot, const std::vector<std::string> &args) |
| 392 | + { |
| 393 | + return runGitImpl(repoRoot, args, nullptr, true); |
337 | 394 | } |
338 | 395 |
|
339 | 396 | std::string redactGitOutput(const std::string &text) |
|
0 commit comments