diff options
Diffstat (limited to 'src/tools/launcher')
-rw-r--r-- | src/tools/launcher/bash_launcher.cc | 2 | ||||
-rw-r--r-- | src/tools/launcher/bash_launcher.h | 2 | ||||
-rw-r--r-- | src/tools/launcher/java_launcher.cc | 276 | ||||
-rw-r--r-- | src/tools/launcher/java_launcher.h | 66 | ||||
-rw-r--r-- | src/tools/launcher/launcher.cc | 40 | ||||
-rw-r--r-- | src/tools/launcher/launcher.h | 24 | ||||
-rw-r--r-- | src/tools/launcher/python_launcher.cc | 2 | ||||
-rw-r--r-- | src/tools/launcher/python_launcher.h | 2 | ||||
-rw-r--r-- | src/tools/launcher/util/launcher_util.cc | 26 | ||||
-rw-r--r-- | src/tools/launcher/util/launcher_util.h | 14 | ||||
-rw-r--r-- | src/tools/launcher/util/launcher_util_test.cc | 18 |
11 files changed, 459 insertions, 13 deletions
diff --git a/src/tools/launcher/bash_launcher.cc b/src/tools/launcher/bash_launcher.cc index 3e41ac152a..01d9511c74 100644 --- a/src/tools/launcher/bash_launcher.cc +++ b/src/tools/launcher/bash_launcher.cc @@ -26,6 +26,8 @@ using std::ostringstream; using std::string; using std::vector; +static constexpr const char* BASH_BIN_PATH = "bash_bin_path"; + ExitCode BashBinaryLauncher::Launch() { string bash_binary = this->GetLaunchInfoByKey(BASH_BIN_PATH); // If specified bash binary path doesn't exist, then fall back to diff --git a/src/tools/launcher/bash_launcher.h b/src/tools/launcher/bash_launcher.h index 659c144c39..758735561e 100644 --- a/src/tools/launcher/bash_launcher.h +++ b/src/tools/launcher/bash_launcher.h @@ -20,8 +20,6 @@ namespace bazel { namespace launcher { -static constexpr const char* BASH_BIN_PATH = "bash_bin_path"; - class BashBinaryLauncher : public BinaryLauncherBase { public: BashBinaryLauncher(const LaunchDataParser::LaunchInfo& launch_info, int argc, diff --git a/src/tools/launcher/java_launcher.cc b/src/tools/launcher/java_launcher.cc index ce626d347e..b8c0bdbd43 100644 --- a/src/tools/launcher/java_launcher.cc +++ b/src/tools/launcher/java_launcher.cc @@ -12,14 +12,286 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include <sstream> +#include <string> +#include <vector> + #include "src/tools/launcher/java_launcher.h" +#include "src/tools/launcher/util/launcher_util.h" namespace bazel { namespace launcher { +using std::getline; +using std::ofstream; +using std::ostringstream; +using std::string; +using std::stringstream; +using std::vector; + +// The runfile path of java binary, eg. local_jdk/bin/java.exe +static constexpr const char* JAVA_BIN_PATH = "java_bin_path"; +static constexpr const char* JAR_BIN_PATH = "jar_bin_path"; +static constexpr const char* CLASSPATH = "classpath"; +static constexpr const char* JAVA_START_CLASS = "java_start_class"; +static constexpr const char* JVM_FLAGS = "jvm_flags"; + +// Check if a string start with a certain prefix. +// If it's true, store the substring without the prefix in value. +// If value is quoted, then remove the quotes. +static bool GetFlagValue(const string& str, const string& prefix, + string* value_ptr) { + if (str.compare(0, prefix.length(), prefix)) { + return false; + } + string& value = *value_ptr; + value = str.substr(prefix.length()); + int len = value.length(); + if (len >= 2 && value[0] == '"' && value[len - 1] == '"') { + value = value.substr(1, len - 2); + } + return true; +} + +// Parses one launcher flag and updates this object's state accordingly. +// +// Returns true if the flag is a valid launcher flag; false otherwise. +bool JavaBinaryLauncher::ProcessWrapperArgument(const string& argument) { + string flag_value; + if (argument.compare("--debug") == 0) { + string default_jvm_debug_port; + if (GetEnv("DEFAULT_JVM_DEBUG_PORT", &default_jvm_debug_port)) { + this->jvm_debug_port = default_jvm_debug_port; + } else { + this->jvm_debug_port = "5005"; + } + } else if (GetFlagValue(argument, "--debug=", &flag_value)) { + this->jvm_debug_port = flag_value; + } else if (GetFlagValue(argument, "--main_advice=", &flag_value)) { + this->main_advice = flag_value; + } else if (GetFlagValue(argument, "--main_advice_classpath=", &flag_value)) { + this->main_advice_classpath = flag_value; + } else if (GetFlagValue(argument, "--jvm_flag=", &flag_value)) { + this->jvm_flags_cmdline.push_back(flag_value); + } else if (GetFlagValue(argument, "--jvm_flags=", &flag_value)) { + stringstream flag_value_ss(flag_value); + string item; + while (getline(flag_value_ss, item, ' ')) { + this->jvm_flags_cmdline.push_back(item); + } + } else if (argument.compare("--singlejar") == 0) { + this->singlejar = true; + } else if (argument.compare("--print_javabin") == 0) { + this->print_javabin = true; + } else if (GetFlagValue(argument, "--classpath_limit=", &flag_value)) { + this->classpath_limit = std::stoi(flag_value); + } else { + return false; + } + return true; +} + +vector<string> JavaBinaryLauncher::ProcessesCommandLine() { + vector<string> args; + bool first = 1; + for (const auto& arg : this->GetCommandlineArguments()) { + // Skip the first arugment. + if (first) { + first = 0; + continue; + } + string flag_value; + // TODO(pcloudy): Should rename this flag to --native_launcher_flag. + // But keep it as it is for now to be consistent with the shell script + // launcher. + if (GetFlagValue(arg, "--wrapper_script_flag=", &flag_value)) { + if (!ProcessWrapperArgument(flag_value)) { + die("invalid wrapper argument '%s'", arg); + } + } else if (!args.empty() || !ProcessWrapperArgument(arg)) { + args.push_back(arg); + } + } + return args; +} + +string JavaBinaryLauncher::CreateClasspathJar(const string& classpath) { + static constexpr const char* URI_PREFIX = "file:/"; + ostringstream manifest_classpath; + manifest_classpath << "Class-Path:"; + stringstream classpath_ss(classpath); + string path; + while (getline(classpath_ss, path, ';')) { + manifest_classpath << ' '; + manifest_classpath << URI_PREFIX; + for (const auto& x : path) { + if (x == ' ') { + manifest_classpath << "%20"; + } else { + manifest_classpath << x; + } + } + } + + string binary_base_path = + GetBinaryPathWithoutExtension(this->GetCommandlineArguments()[0]); + string jar_manifest_file_path = binary_base_path + ".jar_manifest"; + ofstream jar_manifest_file(jar_manifest_file_path); + jar_manifest_file << "Manifest-Version: 1.0\n"; + // No line in the MANIFEST.MF file may be longer than 72 bytes. + // A space prefix indicates the line is still the content of the last + // attribute. + string manifest_classpath_str = manifest_classpath.str(); + for (size_t i = 0; i < manifest_classpath_str.length(); i += 71) { + if (i > 0) { + jar_manifest_file << " "; + } + jar_manifest_file << manifest_classpath_str.substr(i, 71) << "\n"; + } + jar_manifest_file.close(); + + // Create the command for generating classpath jar. + // We pass the command to cmd.exe to use redirection for suppressing output. + string manifest_jar_path = binary_base_path + "-classpath.jar"; + string jar_bin = this->Rlocation(this->GetLaunchInfoByKey(JAR_BIN_PATH), + /*need_workspace_name =*/false); + vector<string> arguments; + arguments.push_back("/c"); + + ostringstream jar_command; + jar_command << jar_bin << " cvfm "; + jar_command << manifest_jar_path << " "; + jar_command << jar_manifest_file_path << " "; + jar_command << "> nul"; + arguments.push_back(jar_command.str()); + + if (this->LaunchProcess("cmd.exe", arguments) != 0) { + die("Couldn't create classpath jar: %s", manifest_jar_path.c_str()); + } + + return manifest_jar_path; +} + ExitCode JavaBinaryLauncher::Launch() { - // TODO(pcloudy): Implement Java launcher - return 0; + // Parse the original command line. + vector<string> remaining_args = this->ProcessesCommandLine(); + + // Set JAVA_RUNFILES + string java_runfiles; + if (!GetEnv("JAVA_RUNFILES", &java_runfiles)) { + java_runfiles = this->GetRunfilesPath(); + } + SetEnv("JAVA_RUNFILES", java_runfiles); + + // Print Java binary path if needed + string java_bin = this->Rlocation(this->GetLaunchInfoByKey(JAVA_BIN_PATH), + /*need_workspace_name =*/false); + if (this->print_javabin || + this->GetLaunchInfoByKey(JAVA_START_CLASS) == "--print_javabin") { + printf("%s\n", java_bin.c_str()); + return 0; + } + + ostringstream classpath; + + // Run deploy jar if needed, otherwise generate the CLASSPATH by rlocation. + if (this->singlejar) { + string deploy_jar = + GetBinaryPathWithoutExtension(this->GetCommandlineArguments()[0]) + + "_deploy.jar"; + if (!DoesFilePathExist(deploy_jar.c_str())) { + die("Option --singlejar was passed, but %s does not exist.\n (You may " + "need to build it explicitly.)", + deploy_jar.c_str()); + } + classpath << deploy_jar << ';'; + } else { + // Add main advice classpath if exists + if (!this->main_advice_classpath.empty()) { + classpath << this->main_advice_classpath << ';'; + } + string path; + stringstream classpath_ss(this->GetLaunchInfoByKey(CLASSPATH)); + while (getline(classpath_ss, path, ';')) { + classpath << this->Rlocation(path) << ';'; + } + } + + // Set jvm debug options + ostringstream jvm_debug_flags; + if (!this->jvm_debug_port.empty()) { + string jvm_debug_suspend; + if (!GetEnv("DEFAULT_JVM_DEBUG_SUSPEND", &jvm_debug_suspend)) { + jvm_debug_suspend = "y"; + } + jvm_debug_flags << "-agentlib:jdwp=transport=dt_socket,server=y"; + jvm_debug_flags << ",suspend=" << jvm_debug_suspend; + jvm_debug_flags << ",address=" << jvm_debug_port; + + string value; + if (GetEnv("PERSISTENT_TEST_RUNNER", &value) && value == "true") { + jvm_debug_flags << ",quiet=y"; + } + } + + // Get jvm flags from JVM_FLAGS environment variable and JVM_FLAGS launch info + vector<string> jvm_flags; + string jvm_flags_env; + GetEnv("JVM_FLAGS", &jvm_flags_env); + string flag; + stringstream jvm_flags_env_ss(jvm_flags_env); + while (getline(jvm_flags_env_ss, flag, ' ')) { + jvm_flags.push_back(flag); + } + stringstream jvm_flags_launch_info_ss(this->GetLaunchInfoByKey(JVM_FLAGS)); + while (getline(jvm_flags_launch_info_ss, flag, ' ')) { + jvm_flags.push_back(flag); + } + + // Check if TEST_TMPDIR is available to use for scratch. + string test_tmpdir; + if (GetEnv("TEST_TMPDIR", &test_tmpdir) && + DoesDirectoryPathExist(test_tmpdir.c_str())) { + jvm_flags.push_back("-Djava.io.tmpdir=" + test_tmpdir); + } + + // Construct the final command line arguments + vector<string> arguments; + // Add classpath flags + arguments.push_back("-classpath"); + // Check if CLASSPATH is over classpath length limit. + // If it does, then we create a classpath jar to pass CLASSPATH value. + string classpath_str = classpath.str(); + if (classpath_str.length() > this->classpath_limit) { + arguments.push_back(CreateClasspathJar(classpath_str)); + } else { + arguments.push_back(classpath_str); + } + // Add JVM debug flags + string jvm_debug_flags_str = jvm_debug_flags.str(); + if (!jvm_debug_flags_str.empty()) { + arguments.push_back(jvm_debug_flags_str); + } + // Add JVM flags parsed from env and launch info. + for (const auto& arg : jvm_flags) { + arguments.push_back(arg); + } + // Add JVM flags parsed from command line. + for (const auto& arg : this->jvm_flags_cmdline) { + arguments.push_back(arg); + } + // Add main advice class + if (!this->main_advice.empty()) { + arguments.push_back(this->main_advice); + } + // Add java start class + arguments.push_back(this->GetLaunchInfoByKey(JAVA_START_CLASS)); + // Add the remaininng arguements, they will be passed to the program. + for (const auto& arg : remaining_args) { + arguments.push_back(arg); + } + + return this->LaunchProcess(java_bin, arguments); } } // namespace launcher diff --git a/src/tools/launcher/java_launcher.h b/src/tools/launcher/java_launcher.h index 5ffe5881ab..896aacd74a 100644 --- a/src/tools/launcher/java_launcher.h +++ b/src/tools/launcher/java_launcher.h @@ -15,17 +15,81 @@ #ifndef BAZEL_SRC_TOOLS_LAUNCHER_JAVA_LAUNCHER_H_ #define BAZEL_SRC_TOOLS_LAUNCHER_JAVA_LAUNCHER_H_ +#include <string> +#include <vector> + #include "src/tools/launcher/launcher.h" namespace bazel { namespace launcher { +// Windows per-arg limit is MAX_ARG_STRLEN == 8k, +// here we use a slightly smaller value. +static const int MAX_ARG_STRLEN = 7000; + class JavaBinaryLauncher : public BinaryLauncherBase { public: JavaBinaryLauncher(const LaunchDataParser::LaunchInfo& launch_info, int argc, char* argv[]) - : BinaryLauncherBase(launch_info, argc, argv){} + : BinaryLauncherBase(launch_info, argc, argv), + singlejar(false), + print_javabin(false), + classpath_limit(MAX_ARG_STRLEN) {} ExitCode Launch(); + + private: + // If present, these flags should either be at the beginning of the command + // line, or they should be wrapped in a --wrapper_script_flag=FLAG argument. + // + // --debug Launch the JVM in remote debugging mode listening + // --debug=<port> to the specified port or the port set in the + // DEFAULT_JVM_DEBUG_PORT environment variable (e.g. + // 'export DEFAULT_JVM_DEBUG_PORT=8000') or else the + // default port of 5005. The JVM starts suspended + // unless the DEFAULT_JVM_DEBUG_SUSPEND environment + // variable is set to 'n'. + // --main_advice=<class> Run an alternate main class with the usual main + // program and arguments appended as arguments. + // --main_advice_classpath=<classpath> + // Prepend additional class path entries. + // --jvm_flag=<flag> Pass <flag> to the "java" command itself. + // <flag> may contain spaces. Can be used multiple + // times. + // --jvm_flags=<flags> Pass space-separated flags to the "java" command + // itself. Can be used multiple times. + // --singlejar Start the program from the packed-up deployment + // jar rather than from the classpath. + // --print_javabin Print the location of java executable binary and + // exit. + // --classpath_limit=<length> + // Specify the maximum classpath length. If the + // classpath is shorter, this script passes it to Java + // as a command line flag, otherwise it creates a + // classpath jar. + // + // The remainder of the command line is passed to the program. + bool ProcessWrapperArgument(const std::string& argument); + + // Parse arguments sequentially until the first unrecognized arg is + // encountered. Scan the remaining args for --wrapper_script_flag=X options + // and process them. + // + // Return the remaining arguments that should be passed to the program. + std::vector<std::string> ProcessesCommandLine(); + + std::string jvm_debug_port; + std::string main_advice; + std::string main_advice_classpath; + std::vector<std::string> jvm_flags_cmdline; + bool singlejar; + bool print_javabin; + int classpath_limit; + + // Create a classpath jar to pass CLASSPATH value when its length is over + // limit. + // + // Return the path of the classpath jar created. + std::string CreateClasspathJar(const std::string& classpath); }; } // namespace launcher diff --git a/src/tools/launcher/launcher.cc b/src/tools/launcher/launcher.cc index 8e82542fb4..b981761da6 100644 --- a/src/tools/launcher/launcher.cc +++ b/src/tools/launcher/launcher.cc @@ -67,6 +67,13 @@ string BinaryLauncherBase::FindManifestFile(const char* argv0) { die("Couldn't find MANIFEST file under %s.runfiles\\", binary.c_str()); } +string BinaryLauncherBase::GetRunfilesPath() const { + string runfiles_path = + GetBinaryPathWithExtension(this->commandline_arguments[0]) + ".runfiles"; + std::replace(runfiles_path.begin(), runfiles_path.end(), '/', '\\'); + return runfiles_path; +} + void BinaryLauncherBase::ParseManifestFile(ManifestFileMap* manifest_file_map, const string& manifest_path) { // TODO(laszlocsomor): prefix manifest_path with the longpath prefix. @@ -90,11 +97,16 @@ void BinaryLauncherBase::ParseManifestFile(ManifestFileMap* manifest_file_map, } } -string BinaryLauncherBase::Rlocation(const string& path) const { - auto entry = manifest_file_map.find(this->workspace_name + "/" + path); +string BinaryLauncherBase::Rlocation(const string& path, + bool need_workspace_name) const { + string query_path = path; + if (need_workspace_name) { + query_path = this->workspace_name + "/" + path; + } + auto entry = manifest_file_map.find(query_path); if (entry == manifest_file_map.end()) { die("Rlocation failed on %s, path doesn't exist in MANIFEST file", - path.c_str()); + query_path.c_str()); } return entry->second; } @@ -132,10 +144,28 @@ void BinaryLauncherBase::CreateCommandLine( result->cmdline[MAX_CMDLINE_LENGTH - 1] = 0; } +bool BinaryLauncherBase::PrintLauncherCommandLine( + const string& executable, const vector<string>& arguments) const { + bool has_print_cmd_flag = false; + for (const auto& arg : arguments) { + has_print_cmd_flag |= (arg == "--print_launcher_command"); + } + if (has_print_cmd_flag) { + printf("%s\n", executable.c_str()); + for (const auto& arg : arguments) { + printf("%s\n", arg.c_str()); + } + } + return has_print_cmd_flag; +} + ExitCode BinaryLauncherBase::LaunchProcess( const string& executable, const vector<string>& arguments) const { - SetEnvironmentVariableA("RUNFILES_MANIFEST_ONLY", "1"); - SetEnvironmentVariableA("RUNFILES_MANIFEST_FILE", manifest_file.c_str()); + if (PrintLauncherCommandLine(executable, arguments)) { + return 0; + } + SetEnv("RUNFILES_MANIFEST_ONLY", "1"); + SetEnv("RUNFILES_MANIFEST_FILE", manifest_file); CmdLine cmdline; CreateCommandLine(&cmdline, executable, arguments); PROCESS_INFORMATION processInfo = {0}; diff --git a/src/tools/launcher/launcher.h b/src/tools/launcher/launcher.h index 3ba8ca4723..1915b36455 100644 --- a/src/tools/launcher/launcher.h +++ b/src/tools/launcher/launcher.h @@ -49,9 +49,17 @@ class BinaryLauncherBase { const std::vector<std::string>& GetCommandlineArguments() const; // Map a runfile path to its absolute path. - std::string Rlocation(const std::string& path) const; + // + // If need_workspace_name is true, then this method prepend workspace name to + // path before doing rlocation. + // If need_workspace_name is false, then this method uses path directly. + // The default value of need_workspace_name is true. + std::string Rlocation(const std::string& path, + bool need_workspace_name = true) const; // Lauch a process with given executable and command line arguments. + // If --print_launcher_command exists in arguments, then we print the full + // command line instead of launching the real process. // // exectuable: the binary to be executed. // arguments: the command line arguments to be passed to the exectuable, @@ -62,6 +70,12 @@ class BinaryLauncherBase { // A launch function to be implemented for a specific language. virtual ExitCode Launch() = 0; + // Return the runfiles directory of this binary. + // + // The method appends ".exe.runfiles" to the first command line argument, + // converts forward slashes to back slashes, then returns that. + std::string GetRunfilesPath() const; + private: // A map to store all the launch information. const LaunchDataParser::LaunchInfo& launch_info; @@ -79,6 +93,14 @@ class BinaryLauncherBase { // A map to store all entries of the manifest file. std::unordered_map<std::string, std::string> manifest_file_map; + // If --print_launcher_command is presented in arguments, + // then print the command line. + // + // Return true if command line is printed. + bool PrintLauncherCommandLine( + const std::string& executable, + const std::vector<std::string>& arguments) const; + // Create a command line to be passed to Windows CreateProcessA API. // // exectuable: the binary to be executed. diff --git a/src/tools/launcher/python_launcher.cc b/src/tools/launcher/python_launcher.cc index 5131243a69..b5e65f9187 100644 --- a/src/tools/launcher/python_launcher.cc +++ b/src/tools/launcher/python_launcher.cc @@ -24,6 +24,8 @@ namespace launcher { using std::string; using std::vector; +static constexpr const char* PYTHON_BIN_PATH = "python_bin_path"; + ExitCode PythonBinaryLauncher::Launch() { string python_binary = this->GetLaunchInfoByKey(PYTHON_BIN_PATH); // If specified python binary path doesn't exist, then fall back to diff --git a/src/tools/launcher/python_launcher.h b/src/tools/launcher/python_launcher.h index d909ea6bcd..1a21ca308e 100644 --- a/src/tools/launcher/python_launcher.h +++ b/src/tools/launcher/python_launcher.h @@ -20,8 +20,6 @@ namespace bazel { namespace launcher { -static constexpr const char* PYTHON_BIN_PATH = "python_bin_path"; - class PythonBinaryLauncher : public BinaryLauncherBase { public: PythonBinaryLauncher(const LaunchDataParser::LaunchInfo& launch_info, diff --git a/src/tools/launcher/util/launcher_util.cc b/src/tools/launcher/util/launcher_util.cc index 247c7050c5..bc3eddb284 100644 --- a/src/tools/launcher/util/launcher_util.cc +++ b/src/tools/launcher/util/launcher_util.cc @@ -76,6 +76,15 @@ bool DoesFilePathExist(const char* path) { !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)); } +bool DoesDirectoryPathExist(const char* path) { + // TODO(laszlocsomor): convert `path` to (const wchar_t*), add longpath-prefix + // and use GetFileAttributesW. + DWORD dwAttrib = GetFileAttributesA(path); + + return (dwAttrib != INVALID_FILE_ATTRIBUTES && + (dwAttrib & FILE_ATTRIBUTE_DIRECTORY)); +} + string GetBinaryPathWithoutExtension(const string& binary) { if (binary.find(".exe", binary.size() - 4) != string::npos) { return binary.substr(0, binary.length() - 4); @@ -120,5 +129,22 @@ string GetEscapedArgument(const string& argument) { return escaped_arg.str(); } +// An environment variable has a maximum size limit of 32,767 characters +// https://msdn.microsoft.com/en-us/library/ms683188.aspx +static const int BUFFER_SIZE = 32767; + +bool GetEnv(const string& env_name, string* value) { + char buffer[BUFFER_SIZE]; + if (!GetEnvironmentVariableA(env_name.c_str(), buffer, BUFFER_SIZE)) { + return false; + } + *value = buffer; + return true; +} + +bool SetEnv(const string& env_name, const string& value) { + return SetEnvironmentVariableA(env_name.c_str(), value.c_str()); +} + } // namespace launcher } // namespace bazel diff --git a/src/tools/launcher/util/launcher_util.h b/src/tools/launcher/util/launcher_util.h index 669ea1dbfc..e5583006c0 100644 --- a/src/tools/launcher/util/launcher_util.h +++ b/src/tools/launcher/util/launcher_util.h @@ -50,6 +50,20 @@ std::string GetEscapedArgument(const std::string& argument); // Check if a file exists at a given path. bool DoesFilePathExist(const char* path); +// Check if a directory exists at a given path. +bool DoesDirectoryPathExist(const char* path); + +// Get the value of a specific environment variable +// +// Return true if succeeded and the result is stored in buffer. +// Return false if the environment variable doesn't exist or the value is empty. +bool GetEnv(const std::string& env_name, std::string* buffer); + +// Set the value of a specific environment variable +// +// Return true if succeeded, otherwise false. +bool SetEnv(const std::string& env_name, const std::string& value); + } // namespace launcher } // namespace bazel diff --git a/src/tools/launcher/util/launcher_util_test.cc b/src/tools/launcher/util/launcher_util_test.cc index b895b65c9c..9d03849a83 100644 --- a/src/tools/launcher/util/launcher_util_test.cc +++ b/src/tools/launcher/util/launcher_util_test.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include <windows.h> #include <cstdlib> #include <fstream> #include <iostream> @@ -90,5 +91,22 @@ TEST_F(LaunchUtilTest, DoesFilePathExistTest) { ASSERT_FALSE(DoesFilePathExist(file2.c_str())); } +TEST_F(LaunchUtilTest, DoesDirectoryPathExistTest) { + string dir1 = GetTmpDir() + "/dir1"; + string dir2 = GetTmpDir() + "/dir2"; + CreateDirectory(dir1.c_str(), NULL); + ASSERT_TRUE(DoesDirectoryPathExist(dir1.c_str())); + ASSERT_FALSE(DoesDirectoryPathExist(dir2.c_str())); +} + +TEST_F(LaunchUtilTest, SetAndGetEnvTest) { + ASSERT_TRUE(SetEnv("foo", "bar")); + string value; + ASSERT_TRUE(GetEnv("foo", &value)); + ASSERT_EQ(value, "bar"); + SetEnv("FOO", ""); + ASSERT_FALSE(GetEnv("FOO", &value)); +} + } // namespace launcher } // namespace bazel |