aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/cpp
diff options
context:
space:
mode:
authorGravatar Dmitry Lomov <dslomov@google.com>2017-07-19 12:26:39 +0200
committerGravatar Klaus Aehlig <aehlig@google.com>2017-07-19 16:48:24 +0200
commit891f540a1bc6977f25e77a29f24cdcf939fb2e2e (patch)
tree915a969f6f3a0af308339f2361b51562cfb3ce96 /src/main/cpp
parent9d61bad6a0595ffd64faa5d0889d3f9d9ace3fc3 (diff)
Implement bash.exe detection logic.
The logic is as follows: 1) search for msys installation 2) search got git-on-Windows installation 3) search in PATH. This happens on every client startup unless BAZEL_SH enviornment variable is set. My measurements show that the time required for this detection is negligible (<10 msec in the worst case). Change-Id: If130e2491a9df5a23954d303f2ccdb932eeed1db PiperOrigin-RevId: 162466913
Diffstat (limited to 'src/main/cpp')
-rw-r--r--src/main/cpp/blaze.cc21
-rw-r--r--src/main/cpp/blaze_util.cc18
-rw-r--r--src/main/cpp/blaze_util.h8
-rw-r--r--src/main/cpp/blaze_util_platform.h2
-rw-r--r--src/main/cpp/blaze_util_posix.cc4
-rw-r--r--src/main/cpp/blaze_util_windows.cc259
6 files changed, 296 insertions, 16 deletions
diff --git a/src/main/cpp/blaze.cc b/src/main/cpp/blaze.cc
index 3571b236d2..0ac61a0b3e 100644
--- a/src/main/cpp/blaze.cc
+++ b/src/main/cpp/blaze.cc
@@ -248,20 +248,6 @@ class GrpcBlazeServer : public BlazeServer {
////////////////////////////////////////////////////////////////////////
// Logic
-void debug_log(const char *format, ...) {
- if (!globals->options->client_debug) {
- return;
- }
-
- fprintf(stderr, "CLIENT: ");
- va_list arglist;
- va_start(arglist, format);
- vfprintf(stderr, format, arglist);
- va_end(arglist);
- fprintf(stderr, "%s", "\n");
- fflush(stderr);
-}
-
// A devtools_ijar::ZipExtractorProcessor to extract the InstallKeyFile
class GetInstallKeyFileProcessor : public devtools_ijar::ZipExtractorProcessor {
public:
@@ -1241,7 +1227,7 @@ static void ComputeBaseDirectories(const WorkspaceLayout *workspace_layout,
blaze_util::JoinPath(globals->options->output_base, "server/jvm.out");
}
-static void CheckEnvironment() {
+static void CheckEnvironmentOrDie() {
if (!blaze::GetEnv("http_proxy").empty()) {
PrintWarning("ignoring http_proxy in environment.");
blaze::UnsetEnv("http_proxy");
@@ -1283,6 +1269,8 @@ static void CheckEnvironment() {
blaze::SetEnv("LANGUAGE", "en_US.ISO-8859-1");
blaze::SetEnv("LC_ALL", "en_US.ISO-8859-1");
blaze::SetEnv("LC_CTYPE", "en_US.ISO-8859-1");
+
+ blaze::DetectBashOrDie();
}
static string CheckAndGetBinaryPath(const string &argv0) {
@@ -1347,9 +1335,10 @@ int Main(int argc, const char *argv[], WorkspaceLayout *workspace_layout,
globals->binary_path = CheckAndGetBinaryPath(argv[0]);
ParseOptions(argc, argv);
+ blaze::SetDebugLog(globals->options->client_debug);
debug_log("Debug logging active");
- CheckEnvironment();
+ CheckEnvironmentOrDie();
blaze::CreateSecureOutputRoot(globals->options->output_user_root);
const string self_path = GetSelfPath();
diff --git a/src/main/cpp/blaze_util.cc b/src/main/cpp/blaze_util.cc
index be3e0ebfd9..d8a5af6b7b 100644
--- a/src/main/cpp/blaze_util.cc
+++ b/src/main/cpp/blaze_util.cc
@@ -208,4 +208,22 @@ bool AwaitServerProcessTermination(int pid, const string& output_base,
return true;
}
+static bool is_debug_log_enabled = false;
+
+void SetDebugLog(bool enabled) { is_debug_log_enabled = enabled; }
+
+void debug_log(const char *format, ...) {
+ if (!is_debug_log_enabled) {
+ return;
+ }
+
+ fprintf(stderr, "CLIENT: ");
+ va_list arglist;
+ va_start(arglist, format);
+ vfprintf(stderr, format, arglist);
+ va_end(arglist);
+ fprintf(stderr, "%s", "\n");
+ fflush(stderr);
+}
+
} // namespace blaze
diff --git a/src/main/cpp/blaze_util.h b/src/main/cpp/blaze_util.h
index f2c3a2f187..7c85d82dbf 100644
--- a/src/main/cpp/blaze_util.h
+++ b/src/main/cpp/blaze_util.h
@@ -112,6 +112,14 @@ std::string ToString(const T &value) {
return oss.str();
}
+// Control the output of debug information by debug_log.
+// Revisit once client logging is fixed (b/32939567).
+void SetDebugLog(bool enabled);
+
+// Output debug information from client.
+// Revisit once client logging is fixed (b/32939567).
+void debug_log(const char *format, ...);
+
} // namespace blaze
#endif // BAZEL_SRC_MAIN_CPP_BLAZE_UTIL_H_
diff --git a/src/main/cpp/blaze_util_platform.h b/src/main/cpp/blaze_util_platform.h
index b842ae8385..bb69541a6e 100644
--- a/src/main/cpp/blaze_util_platform.h
+++ b/src/main/cpp/blaze_util_platform.h
@@ -230,6 +230,8 @@ int32_t GetExplicitSystemLimit(const int resource);
// raised; false otherwise.
bool UnlimitResources();
+void DetectBashOrDie();
+
} // namespace blaze
#endif // BAZEL_SRC_MAIN_CPP_BLAZE_UTIL_PLATFORM_H_
diff --git a/src/main/cpp/blaze_util_posix.cc b/src/main/cpp/blaze_util_posix.cc
index f5c7241db8..42fa76206c 100644
--- a/src/main/cpp/blaze_util_posix.cc
+++ b/src/main/cpp/blaze_util_posix.cc
@@ -762,4 +762,8 @@ bool UnlimitResources() {
return success;
}
+void DetectBashOrDie() {
+ // do nothing.
+}
+
} // namespace blaze.
diff --git a/src/main/cpp/blaze_util_windows.cc b/src/main/cpp/blaze_util_windows.cc
index 802b3c2395..7f0ca75742 100644
--- a/src/main/cpp/blaze_util_windows.cc
+++ b/src/main/cpp/blaze_util_windows.cc
@@ -1448,4 +1448,263 @@ bool UnlimitResources() {
return true; // Nothing to do so assume success.
}
+static const int MAX_KEY_LENGTH = 255;
+// We do not care about registry values longer than MAX_PATH
+static const int REG_VALUE_BUFFER_SIZE = MAX_PATH;
+
+// Implements heuristics to discover msys2 installation.
+static string GetMsysBash() {
+ HKEY h_uninstall;
+
+ // MSYS2 installer writes its registry into HKCU, although documentation
+ // (https://msdn.microsoft.com/en-us/library/ms954376.aspx)
+ // clearly states that it should go to HKLM.
+ static const char* const key =
+ "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
+ if (RegOpenKeyExA(HKEY_CURRENT_USER, // _In_ HKEY hKey,
+ key, // _In_opt_ LPCTSTR lpSubKey,
+ 0, // _In_ DWORD ulOptions,
+ KEY_ENUMERATE_SUB_KEYS |
+ KEY_QUERY_VALUE, // _In_ REGSAM samDesired,
+ &h_uninstall // _Out_ PHKEY phkResult
+ )) {
+ debug_log("Cannot open HKCU\\%s", key);
+ return string();
+ }
+ AutoHandle auto_uninstall(h_uninstall);
+
+ // Since MSYS2 decided to generate a new product key for each installation,
+ // we enumerate all keys under
+ // HKCU\Software\Microsoft\Windows\CurrentVersion\Uninstall and find the first
+ // with MSYS2 64bit display name.
+ static const char* const msys_display_name = "MSYS2 64bit";
+ DWORD n_subkeys;
+
+ if (RegQueryInfoKey(h_uninstall, // _In_ HKEY hKey,
+ 0, // _Out_opt_ LPTSTR lpClass,
+ 0, // _Inout_opt_ LPDWORD lpcClass,
+ 0, // _Reserved_ LPDWORD lpReserved,
+ &n_subkeys, // _Out_opt_ LPDWORD lpcSubKeys,
+ 0, // _Out_opt_ LPDWORD lpcMaxSubKeyLen,
+ 0, // _Out_opt_ LPDWORD lpcMaxClassLen,
+ 0, // _Out_opt_ LPDWORD lpcValues,
+ 0, // _Out_opt_ LPDWORD lpcMaxValueNameLen,
+ 0, // _Out_opt_ LPDWORD lpcMaxValueLen,
+ 0, // _Out_opt_ LPDWORD lpcbSecurityDescriptor,
+ 0 // _Out_opt_ PFILETIME lpftLastWriteTime
+ )) {
+ debug_log("Cannot query HKCU\\%s", key);
+ return string();
+ }
+
+ for (DWORD key_index = 0; key_index < n_subkeys; key_index++) {
+ char subkey_name[MAX_KEY_LENGTH];
+ if (RegEnumKeyA(h_uninstall, // _In_ HKEY hKey,
+ key_index, // _In_ DWORD dwIndex,
+ subkey_name, // _Out_ LPTSTR lpName,
+ sizeof(subkey_name) // _In_ DWORD cchName
+ )) {
+ debug_log("Cannot get %d subkey of HKCU\\%s", key_index, key);
+ continue; // try next subkey
+ }
+
+ HKEY h_subkey;
+ if (RegOpenKeyEx(h_uninstall, // _In_ HKEY hKey,
+ subkey_name, // _In_opt_ LPCTSTR lpSubKey,
+ 0, // _In_ DWORD ulOptions,
+ KEY_QUERY_VALUE, // _In_ REGSAM samDesired,
+ &h_subkey // _Out_ PHKEY phkResult
+ )) {
+ debug_log("Failed to open subkey HKCU\\%s\\%s", key, subkey_name);
+ continue; // try next subkey
+ }
+ AutoHandle auto_subkey(h_subkey);
+
+ BYTE value[REG_VALUE_BUFFER_SIZE];
+ DWORD value_length = sizeof(value);
+ DWORD value_type;
+
+ if (RegQueryValueEx(h_subkey, // _In_ HKEY hKey,
+ "DisplayName", // _In_opt_ LPCTSTR lpValueName,
+ 0, // _Reserved_ LPDWORD lpReserved,
+ &value_type, // _Out_opt_ LPDWORD lpType,
+ value, // _Out_opt_ LPBYTE lpData,
+ &value_length // _Inout_opt_ LPDWORD lpcbData
+ )) {
+ debug_log("Failed to query DisplayName of HKCU\\%s\\%s", key,
+ subkey_name);
+ continue; // try next subkey
+ }
+
+ if (value_type == REG_SZ &&
+ 0 == memcmp(msys_display_name, value, sizeof(msys_display_name))) {
+ debug_log("Getting install location of HKCU\\%s\\%s", key, subkey_name);
+ BYTE path[REG_VALUE_BUFFER_SIZE];
+ DWORD path_length = sizeof(path);
+ DWORD path_type;
+ if (RegQueryValueEx(
+ h_subkey, // _In_ HKEY hKey,
+ "InstallLocation", // _In_opt_ LPCTSTR lpValueName,
+ 0, // _Reserved_ LPDWORD lpReserved,
+ &path_type, // _Out_opt_ LPDWORD lpType,
+ path, // _Out_opt_ LPBYTE lpData,
+ &path_length // _Inout_opt_ LPDWORD lpcbData
+ )) {
+ debug_log("Failed to query InstallLocation of HKCU\\%s\\%s", key,
+ subkey_name);
+ continue; // try next subkey
+ }
+
+ if (path_length == 0 || path_type != REG_SZ) {
+ debug_log("Zero-length (%d) install location or wrong type (%d)",
+ path_length, path_type);
+ continue; // try next subkey
+ }
+
+ debug_log("Install location of HKCU\\%s\\%s is %s", key, subkey_name,
+ path);
+ string path_as_string(path, path + path_length - 1);
+ string bash_exe = path_as_string + "\\usr\\bin\\bash.exe";
+ if (!blaze_util::PathExists(bash_exe)) {
+ debug_log("%s does not exist", bash_exe.c_str());
+ continue; // try next subkey
+ }
+
+ debug_log("Detected msys bash at %s", bash_exe.c_str());
+ return bash_exe;
+ }
+ }
+ return string();
+}
+
+// Implements heuristics to discover Git-on-Win installation.
+static string GetBashFromGitOnWin() {
+ HKEY h_GitOnWin_uninstall;
+
+ // Well-known registry key for Git-on-Windows.
+ static const char* const key =
+ "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Git_is1";
+ if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, // _In_ HKEY hKey,
+ key, // _In_opt_ LPCTSTR lpSubKey,
+ 0, // _In_ DWORD ulOptions,
+ KEY_QUERY_VALUE, // _In_ REGSAM samDesired,
+ &h_GitOnWin_uninstall // _Out_ PHKEY phkResult
+ )) {
+ debug_log("Cannot open HKCU\\%s", key);
+ return string();
+ }
+ AutoHandle auto_h_GitOnWin_uninstall(h_GitOnWin_uninstall);
+
+ debug_log("Getting install location of HKLM\\%s", key);
+ BYTE path[REG_VALUE_BUFFER_SIZE];
+ DWORD path_length = sizeof(path);
+ DWORD path_type;
+ if (RegQueryValueEx(h_GitOnWin_uninstall, // _In_ HKEY hKey,
+ "InstallLocation", // _In_opt_ LPCTSTR lpValueName,
+ 0, // _Reserved_ LPDWORD lpReserved,
+ &path_type, // _Out_opt_ LPDWORD lpType,
+ path, // _Out_opt_ LPBYTE lpData,
+ &path_length // _Inout_opt_ LPDWORD lpcbData
+ )) {
+ debug_log("Failed to query InstallLocation of HKLM\\%s", key);
+ return string();
+ }
+
+ if (path_length == 0 || path_type != REG_SZ) {
+ debug_log("Zero-length (%d) install location or wrong type (%d)",
+ path_length, path_type);
+ return string();
+ }
+
+ debug_log("Install location of HKLM\\%s is %s", key, path);
+ string path_as_string(path, path + path_length - 1);
+ string bash_exe = path_as_string + "\\usr\\bin\\bash.exe";
+ if (!blaze_util::PathExists(bash_exe)) {
+ debug_log("%s does not exist", bash_exe.c_str());
+ return string();
+ }
+
+ debug_log("Detected msys bash at %s", bash_exe.c_str());
+ return bash_exe;
+}
+
+static string GetBashFromPath() {
+ char found[MAX_PATH];
+ string path_list = blaze::GetEnv("PATH");
+
+ // We do not fully replicate all the quirks of search in PATH.
+ // There is no system function to do so, and that way lies madness.
+ size_t start = 0;
+ do {
+ // This ignores possibly quoted semicolons in PATH etc.
+ size_t end = path_list.find_first_of(";", start);
+ string path = path_list.substr(
+ start, end != string::npos ? end - start : string::npos);
+ // Handle one typical way of quoting (where.exe does not handle this, but
+ // CreateProcess does).
+ if (path.size() > 1 && path[0] == '"' && path[path.size() - 1] == '"') {
+ path = path.substr(1, path.size() - 2);
+ }
+ if (SearchPathA(path.c_str(), // _In_opt_ LPCTSTR lpPath,
+ "bash.exe", // _In_ LPCTSTR lpFileName,
+ 0, // LPCTSTR lpExtension,
+ sizeof(found), // DWORD nBufferLength,
+ found, // _Out_ LPTSTR lpBuffer,
+ 0 // _Out_opt_ LPTSTR *lpFilePart
+ )) {
+ debug_log("bash.exe found on PATH: %s", found);
+ return string(found);
+ }
+ if (end == string::npos) {
+ break;
+ }
+ start = end + 1;
+ } while (true);
+
+ debug_log("bash.exe not found on PATH");
+ return string();
+}
+
+static string LocateBash() {
+ string msys_bash = GetMsysBash();
+ if (!msys_bash.empty()) {
+ return msys_bash;
+ }
+
+ string git_on_win_bash = GetBashFromGitOnWin();
+ if (!git_on_win_bash.empty()) {
+ return git_on_win_bash;
+ }
+
+ return GetBashFromPath();
+}
+
+void DetectBashOrDie() {
+ if (!blaze::GetEnv("BAZEL_SH").empty()) return;
+
+ uint64_t start = blaze::GetMillisecondsMonotonic();
+
+ string bash = LocateBash();
+ uint64_t end = blaze::GetMillisecondsMonotonic();
+ debug_log("BAZEL_SH detection took %lu msec", end - start);
+
+ if (!bash.empty()) {
+ blaze::SetEnv("BAZEL_SH", bash);
+ } else {
+ printf(
+ "Bazel on Windows requires bash.exe and other Unix tools, but we could "
+ "not find them.\n"
+ "If you do not have them installed, the easiest is to install MSYS2 "
+ "from\n"
+ " http://repo.msys2.org/distrib/msys2-x86_64-latest.exe\n"
+ "or git-on-Windows from\n"
+ " https://git-scm.com/download/win\n"
+ "\n"
+ "If you already have bash.exe installed but Bazel cannot find it,\n"
+ "set BAZEL_SH environment variable to it's location:\n"
+ " set BAZEL_SH=c:\\path\\to\\bash.exe\n");
+ exit(1);
+ }
+}
+
} // namespace blaze