diff options
author | Yun Peng <pcloudy@google.com> | 2018-06-25 05:35:50 -0700 |
---|---|---|
committer | Copybara-Service <copybara-piper@google.com> | 2018-06-25 05:36:55 -0700 |
commit | 40f5a773e97d0e389838becd3fe0a8ab43853999 (patch) | |
tree | 2c2aec321caa559b43787281fd097a7545eacc28 /src/tools | |
parent | d753745d58fc45fcb50623073829644812083da0 (diff) |
Windows: Native launcher now works with unicode.
The native launcher can now launch Java and Bash binary in
directory with non-English characters.
Unfortunately, python doesn't support running python zip file under
directory with non-English characters. eg. python ./??/bin.zip will
still fail.
See https://github.com/bazelbuild/bazel/issues/4473
Change-Id: I77fe9cdaabffc2e0d25c7097da5c0c9333a9c4a3
PiperOrigin-RevId: 201939391
Diffstat (limited to 'src/tools')
-rw-r--r-- | src/tools/launcher/bash_launcher.cc | 20 | ||||
-rw-r--r-- | src/tools/launcher/bash_launcher.h | 4 | ||||
-rw-r--r-- | src/tools/launcher/java_launcher.cc | 276 | ||||
-rw-r--r-- | src/tools/launcher/java_launcher.h | 18 | ||||
-rw-r--r-- | src/tools/launcher/launcher.cc | 132 | ||||
-rw-r--r-- | src/tools/launcher/launcher.h | 44 | ||||
-rw-r--r-- | src/tools/launcher/launcher_main.cc | 14 | ||||
-rw-r--r-- | src/tools/launcher/python_launcher.cc | 10 | ||||
-rw-r--r-- | src/tools/launcher/python_launcher.h | 4 | ||||
-rw-r--r-- | src/tools/launcher/util/data_parser.cc | 14 | ||||
-rw-r--r-- | src/tools/launcher/util/data_parser.h | 4 | ||||
-rw-r--r-- | src/tools/launcher/util/data_parser_test.cc | 6 | ||||
-rw-r--r-- | src/tools/launcher/util/launcher_util.cc | 131 | ||||
-rw-r--r-- | src/tools/launcher/util/launcher_util.h | 39 | ||||
-rw-r--r-- | src/tools/launcher/util/launcher_util_test.cc | 185 |
15 files changed, 465 insertions, 436 deletions
diff --git a/src/tools/launcher/bash_launcher.cc b/src/tools/launcher/bash_launcher.cc index 2692c17b35..cd714abc38 100644 --- a/src/tools/launcher/bash_launcher.cc +++ b/src/tools/launcher/bash_launcher.cc @@ -22,33 +22,33 @@ namespace bazel { namespace launcher { -using std::ostringstream; -using std::string; using std::vector; +using std::wostringstream; +using std::wstring; static constexpr const char* BASH_BIN_PATH = "bash_bin_path"; ExitCode BashBinaryLauncher::Launch() { - string bash_binary = this->GetLaunchInfoByKey(BASH_BIN_PATH); + wstring bash_binary = this->GetLaunchInfoByKey(BASH_BIN_PATH); // If specified bash binary path doesn't exist, then fall back to // bash.exe and hope it's in PATH. if (!DoesFilePathExist(bash_binary.c_str())) { - bash_binary = "bash.exe"; + bash_binary = L"bash.exe"; } - vector<string> origin_args = this->GetCommandlineArguments(); - ostringstream bash_command; - string bash_main_file = GetBinaryPathWithoutExtension(origin_args[0]); + vector<wstring> origin_args = this->GetCommandlineArguments(); + wostringstream bash_command; + wstring bash_main_file = GetBinaryPathWithoutExtension(origin_args[0]); bash_command << GetEscapedArgument(bash_main_file, /*escape_backslash = */ true); for (int i = 1; i < origin_args.size(); i++) { - bash_command << ' '; + bash_command << L' '; bash_command << GetEscapedArgument(origin_args[i], /*escape_backslash = */ true); } - vector<string> args; - args.push_back("-c"); + vector<wstring> args; + args.push_back(L"-c"); args.push_back( GetEscapedArgument(bash_command.str(), /*escape_backslash = */ true)); return this->LaunchProcess(bash_binary, args); diff --git a/src/tools/launcher/bash_launcher.h b/src/tools/launcher/bash_launcher.h index 758735561e..38c9d0e12b 100644 --- a/src/tools/launcher/bash_launcher.h +++ b/src/tools/launcher/bash_launcher.h @@ -23,8 +23,8 @@ namespace launcher { class BashBinaryLauncher : public BinaryLauncherBase { public: BashBinaryLauncher(const LaunchDataParser::LaunchInfo& launch_info, int argc, - char* argv[]) - : BinaryLauncherBase(launch_info, argc, argv){} + wchar_t* argv[]) + : BinaryLauncherBase(launch_info, argc, argv) {} ExitCode Launch(); }; diff --git a/src/tools/launcher/java_launcher.cc b/src/tools/launcher/java_launcher.cc index 053218d4f2..82eeb0bcab 100644 --- a/src/tools/launcher/java_launcher.cc +++ b/src/tools/launcher/java_launcher.cc @@ -30,12 +30,12 @@ namespace bazel { namespace launcher { using std::getline; -using std::ofstream; -using std::ostringstream; using std::string; -using std::stringstream; using std::vector; +using std::wofstream; +using std::wostringstream; using std::wstring; +using std::wstringstream; // The runfile path of java binary, eg. local_jdk/bin/java.exe static constexpr const char* JAVA_BIN_PATH = "java_bin_path"; @@ -47,15 +47,15 @@ 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) { +static bool GetFlagValue(const wstring& str, const wstring& prefix, + wstring* value_ptr) { if (str.compare(0, prefix.length(), prefix)) { return false; } - string& value = *value_ptr; + wstring& value = *value_ptr; value = str.substr(prefix.length()); int len = value.length(); - if (len >= 2 && value[0] == '"' && value[len - 1] == '"') { + if (len >= 2 && value[0] == L'"' && value[len - 1] == L'"') { value = value.substr(1, len - 2); } return true; @@ -64,34 +64,34 @@ static bool GetFlagValue(const string& str, const string& prefix, // 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)) { +bool JavaBinaryLauncher::ProcessWrapperArgument(const wstring& argument) { + wstring flag_value; + if (argument.compare(L"--debug") == 0) { + wstring default_jvm_debug_port; + if (GetEnv(L"DEFAULT_JVM_DEBUG_PORT", &default_jvm_debug_port)) { this->jvm_debug_port = default_jvm_debug_port; } else { - this->jvm_debug_port = "5005"; + this->jvm_debug_port = L"5005"; } - } else if (GetFlagValue(argument, "--debug=", &flag_value)) { + } else if (GetFlagValue(argument, L"--debug=", &flag_value)) { this->jvm_debug_port = flag_value; - } else if (GetFlagValue(argument, "--main_advice=", &flag_value)) { + } else if (GetFlagValue(argument, L"--main_advice=", &flag_value)) { this->main_advice = flag_value; - } else if (GetFlagValue(argument, "--main_advice_classpath=", &flag_value)) { + } else if (GetFlagValue(argument, L"--main_advice_classpath=", &flag_value)) { this->main_advice_classpath = flag_value; - } else if (GetFlagValue(argument, "--jvm_flag=", &flag_value)) { + } else if (GetFlagValue(argument, L"--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, ' ')) { + } else if (GetFlagValue(argument, L"--jvm_flags=", &flag_value)) { + wstringstream flag_value_ss(flag_value); + wstring item; + while (getline(flag_value_ss, item, L' ')) { this->jvm_flags_cmdline.push_back(item); } - } else if (argument.compare("--singlejar") == 0) { + } else if (argument.compare(L"--singlejar") == 0) { this->singlejar = true; - } else if (argument.compare("--print_javabin") == 0) { + } else if (argument.compare(L"--print_javabin") == 0) { this->print_javabin = true; - } else if (GetFlagValue(argument, "--classpath_limit=", &flag_value)) { + } else if (GetFlagValue(argument, L"--classpath_limit=", &flag_value)) { this->classpath_limit = std::stoi(flag_value); } else { return false; @@ -99,8 +99,8 @@ bool JavaBinaryLauncher::ProcessWrapperArgument(const string& argument) { return true; } -vector<string> JavaBinaryLauncher::ProcessesCommandLine() { - vector<string> args; +vector<wstring> JavaBinaryLauncher::ProcessesCommandLine() { + vector<wstring> args; bool first = 1; for (const auto& arg : this->GetCommandlineArguments()) { // Skip the first arugment. @@ -108,13 +108,13 @@ vector<string> JavaBinaryLauncher::ProcessesCommandLine() { first = 0; continue; } - string flag_value; + wstring 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 (GetFlagValue(arg, L"--wrapper_script_flag=", &flag_value)) { if (!ProcessWrapperArgument(flag_value)) { - die("invalid wrapper argument '%s'", arg.c_str()); + die(L"invalid wrapper argument '%s'", arg.c_str()); } } else if (!args.empty() || !ProcessWrapperArgument(arg)) { args.push_back(arg); @@ -124,34 +124,34 @@ vector<string> JavaBinaryLauncher::ProcessesCommandLine() { } // Return an absolute normalized path for the directory of manifest jar -static string GetManifestJarDir(const string& binary_base_path) { - string abs_manifest_jar_dir; - std::size_t slash = binary_base_path.find_last_of("/\\"); - if (slash == string::npos) { - abs_manifest_jar_dir = ""; +static wstring GetManifestJarDir(const wstring& binary_base_path) { + wstring abs_manifest_jar_dir; + std::size_t slash = binary_base_path.find_last_of(L"/\\"); + if (slash == wstring::npos) { + abs_manifest_jar_dir = L""; } else { abs_manifest_jar_dir = binary_base_path.substr(0, slash); } if (!blaze_util::IsAbsolute(binary_base_path)) { - abs_manifest_jar_dir = blaze_util::GetCwd() + "\\" + abs_manifest_jar_dir; + abs_manifest_jar_dir = blaze_util::GetCwdW() + L"\\" + abs_manifest_jar_dir; } - string result; + wstring result; if (!NormalizePath(abs_manifest_jar_dir, &result)) { - die("GetManifestJarDir Failed"); + die(L"GetManifestJarDir Failed"); } return result; } -static void WriteJarClasspath(const string& jar_path, - ostringstream* manifest_classpath) { - *manifest_classpath << ' '; - if (jar_path.find_first_of(" \\") != string::npos) { +static void WriteJarClasspath(const wstring& jar_path, + wostringstream* manifest_classpath) { + *manifest_classpath << L' '; + if (jar_path.find_first_of(L" \\") != wstring::npos) { for (const auto& x : jar_path) { - if (x == ' ') { - *manifest_classpath << "%20"; + if (x == L' ') { + *manifest_classpath << L"%20"; } - if (x == '\\') { - *manifest_classpath << "/"; + if (x == L'\\') { + *manifest_classpath << L"/"; } else { *manifest_classpath << x; } @@ -161,119 +161,117 @@ static void WriteJarClasspath(const string& jar_path, } } -string JavaBinaryLauncher::GetJunctionBaseDir() { - string binary_base_path = +wstring JavaBinaryLauncher::GetJunctionBaseDir() { + wstring binary_base_path = GetBinaryPathWithExtension(this->GetCommandlineArguments()[0]); - string result; - if (!NormalizePath(binary_base_path + ".j", &result)) { - die("Failed to get normalized junction base directory."); + wstring result; + if (!NormalizePath(binary_base_path + L".j", &result)) { + die(L"Failed to get normalized junction base directory."); } return result; } void JavaBinaryLauncher::DeleteJunctionBaseDir() { - string junction_base_dir_norm = GetJunctionBaseDir(); + wstring junction_base_dir_norm = GetJunctionBaseDir(); if (!DoesDirectoryPathExist(junction_base_dir_norm.c_str())) { return; } - vector<string> junctions; - blaze_util::GetAllFilesUnder(junction_base_dir_norm, &junctions); + vector<wstring> junctions; + blaze_util::GetAllFilesUnderW(junction_base_dir_norm, &junctions); for (const auto& junction : junctions) { if (!DeleteDirectoryByPath(junction.c_str())) { - PrintError(GetLastErrorString().c_str()); + PrintError(L"Failed to delete junction directory: %hs", + GetLastErrorString().c_str()); } } if (!DeleteDirectoryByPath(junction_base_dir_norm.c_str())) { - PrintError(GetLastErrorString().c_str()); + PrintError(L"Failed to delete junction directory: %hs", + GetLastErrorString().c_str()); } } -string JavaBinaryLauncher::CreateClasspathJar(const string& classpath) { - string binary_base_path = +wstring JavaBinaryLauncher::CreateClasspathJar(const wstring& classpath) { + wstring binary_base_path = GetBinaryPathWithoutExtension(this->GetCommandlineArguments()[0]); - string abs_manifest_jar_dir_norm = GetManifestJarDir(binary_base_path); + wstring abs_manifest_jar_dir_norm = GetManifestJarDir(binary_base_path); - ostringstream manifest_classpath; - manifest_classpath << "Class-Path:"; - stringstream classpath_ss(classpath); - string path, path_norm; + wostringstream manifest_classpath; + manifest_classpath << L"Class-Path:"; + wstringstream classpath_ss(classpath); + wstring path, path_norm; // A set to store all junctions created. // The key is the target path, the value is the junction path. - std::unordered_map<string, string> jar_dirs; - string junction_base_dir_norm = GetJunctionBaseDir(); + std::unordered_map<wstring, wstring> jar_dirs; + wstring junction_base_dir_norm = GetJunctionBaseDir(); int junction_count = 0; // Make sure the junction base directory doesn't exist already. DeleteJunctionBaseDir(); - blaze_util::MakeDirectories(junction_base_dir_norm, 0755); + blaze_util::MakeDirectoriesW(junction_base_dir_norm, 0755); - while (getline(classpath_ss, path, ';')) { + while (getline(classpath_ss, path, L';')) { if (blaze_util::IsAbsolute(path)) { if (!NormalizePath(path, &path_norm)) { - die("CreateClasspathJar failed"); + die(L"CreateClasspathJar failed"); } // If two paths are under different drives, we should create a junction to // the jar's directory if (path_norm[0] != abs_manifest_jar_dir_norm[0]) { - string jar_dir = GetParentDirFromPath(path_norm); - string jar_base_name = GetBaseNameFromPath(path_norm); - string junction; + wstring jar_dir = GetParentDirFromPath(path_norm); + wstring jar_base_name = GetBaseNameFromPath(path_norm); + wstring junction; auto search = jar_dirs.find(jar_dir); if (search == jar_dirs.end()) { - junction = - junction_base_dir_norm + "\\" + std::to_string(junction_count++); - - wstring wjar_dir( - blaze_util::CstringToWstring(junction.c_str()).get()); - wstring wjunction( - blaze_util::CstringToWstring(jar_dir.c_str()).get()); - wstring werror(bazel::windows::CreateJunction(wjar_dir, wjunction)); - if (!werror.empty()) { - string error(werror.begin(), werror.end()); - die("CreateClasspathJar failed: %s", error.c_str()); + junction = junction_base_dir_norm + L"\\" + + std::to_wstring(junction_count++); + + wstring error(bazel::windows::CreateJunction(junction, jar_dir)); + if (!error.empty()) { + die(L"CreateClasspathJar failed: %s", error.c_str()); } jar_dirs.insert(std::make_pair(jar_dir, junction)); } else { junction = search->second; } - path_norm = junction + "\\" + jar_base_name; + path_norm = junction + L"\\" + jar_base_name; } if (!RelativeTo(path_norm, abs_manifest_jar_dir_norm, &path)) { - die("CreateClasspathJar failed"); + die(L"CreateClasspathJar failed"); } } WriteJarClasspath(path, &manifest_classpath); } - string rand_id = "-" + GetRandomStr(10); - string jar_manifest_file_path = binary_base_path + rand_id + ".jar_manifest"; - ofstream jar_manifest_file(jar_manifest_file_path); - jar_manifest_file << "Manifest-Version: 1.0\n"; + wstring rand_id = L"-" + GetRandomStr(10); + wstring jar_manifest_file_path = + binary_base_path + rand_id + L".jar_manifest"; + wofstream jar_manifest_file(jar_manifest_file_path); + jar_manifest_file << L"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(); + wstring 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 << L" "; } jar_manifest_file << manifest_classpath_str.substr(i, 71) << "\n"; } jar_manifest_file.close(); // Create the command for generating classpath jar. - string manifest_jar_path = binary_base_path + rand_id + "-classpath.jar"; - string jar_bin = this->Rlocation(this->GetLaunchInfoByKey(JAR_BIN_PATH)); - vector<string> arguments; - arguments.push_back("cvfm"); + wstring manifest_jar_path = binary_base_path + rand_id + L"-classpath.jar"; + wstring jar_bin = this->Rlocation(this->GetLaunchInfoByKey(JAR_BIN_PATH)); + vector<wstring> arguments; + arguments.push_back(L"cvfm"); arguments.push_back(manifest_jar_path); arguments.push_back(jar_manifest_file_path); if (this->LaunchProcess(jar_bin, arguments, /* suppressOutput */ true) != 0) { - die("Couldn't create classpath jar: %s", manifest_jar_path.c_str()); + die(L"Couldn't create classpath jar: %s", manifest_jar_path.c_str()); } // Delete jar_manifest_file after classpath jar is created. @@ -284,95 +282,95 @@ string JavaBinaryLauncher::CreateClasspathJar(const string& classpath) { ExitCode JavaBinaryLauncher::Launch() { // Parse the original command line. - vector<string> remaining_args = this->ProcessesCommandLine(); + vector<wstring> remaining_args = this->ProcessesCommandLine(); // Set JAVA_RUNFILES - string java_runfiles; - if (!GetEnv("JAVA_RUNFILES", &java_runfiles)) { + wstring java_runfiles; + if (!GetEnv(L"JAVA_RUNFILES", &java_runfiles)) { java_runfiles = this->GetRunfilesPath(); } - SetEnv("JAVA_RUNFILES", java_runfiles); + SetEnv(L"JAVA_RUNFILES", java_runfiles); // Print Java binary path if needed - string java_bin = this->Rlocation(this->GetLaunchInfoByKey(JAVA_BIN_PATH), - /*need_workspace_name =*/false); + wstring 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()); + this->GetLaunchInfoByKey(JAVA_START_CLASS) == L"--print_javabin") { + wprintf(L"%s\n", java_bin.c_str()); return 0; } - ostringstream classpath; + wostringstream classpath; // Run deploy jar if needed, otherwise generate the CLASSPATH by rlocation. if (this->singlejar) { - string deploy_jar = + wstring deploy_jar = GetBinaryPathWithoutExtension(this->GetCommandlineArguments()[0]) + - "_deploy.jar"; + L"_deploy.jar"; if (!DoesFilePathExist(deploy_jar.c_str())) { - die("Option --singlejar was passed, but %s does not exist.\n (You may " + die(L"Option --singlejar was passed, but %s does not exist.\n (You may " "need to build it explicitly.)", deploy_jar.c_str()); } - classpath << deploy_jar << ';'; + classpath << deploy_jar << L';'; } else { // Add main advice classpath if exists if (!this->main_advice_classpath.empty()) { - classpath << this->main_advice_classpath << ';'; + classpath << this->main_advice_classpath << L';'; } - string path; - stringstream classpath_ss(this->GetLaunchInfoByKey(CLASSPATH)); - while (getline(classpath_ss, path, ';')) { - classpath << this->Rlocation(path) << ';'; + wstring path; + wstringstream classpath_ss(this->GetLaunchInfoByKey(CLASSPATH)); + while (getline(classpath_ss, path, L';')) { + classpath << this->Rlocation(path) << L';'; } } // Set jvm debug options - ostringstream jvm_debug_flags; + wostringstream 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"; + wstring jvm_debug_suspend; + if (!GetEnv(L"DEFAULT_JVM_DEBUG_SUSPEND", &jvm_debug_suspend)) { + jvm_debug_suspend = L"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; + jvm_debug_flags << L"-agentlib:jdwp=transport=dt_socket,server=y"; + jvm_debug_flags << L",suspend=" << jvm_debug_suspend; + jvm_debug_flags << L",address=" << jvm_debug_port; - string value; - if (GetEnv("PERSISTENT_TEST_RUNNER", &value) && value == "true") { - jvm_debug_flags << ",quiet=y"; + wstring value; + if (GetEnv(L"PERSISTENT_TEST_RUNNER", &value) && value == L"true") { + jvm_debug_flags << L",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, ' ')) { + vector<wstring> jvm_flags; + wstring jvm_flags_env; + GetEnv(L"JVM_FLAGS", &jvm_flags_env); + wstring flag; + wstringstream jvm_flags_env_ss(jvm_flags_env); + while (getline(jvm_flags_env_ss, flag, L' ')) { jvm_flags.push_back(flag); } - stringstream jvm_flags_launch_info_ss(this->GetLaunchInfoByKey(JVM_FLAGS)); - while (getline(jvm_flags_launch_info_ss, flag, ' ')) { + wstringstream jvm_flags_launch_info_ss(this->GetLaunchInfoByKey(JVM_FLAGS)); + while (getline(jvm_flags_launch_info_ss, flag, L' ')) { jvm_flags.push_back(flag); } // Check if TEST_TMPDIR is available to use for scratch. - string test_tmpdir; - if (GetEnv("TEST_TMPDIR", &test_tmpdir) && + wstring test_tmpdir; + if (GetEnv(L"TEST_TMPDIR", &test_tmpdir) && DoesDirectoryPathExist(test_tmpdir.c_str())) { - jvm_flags.push_back("-Djava.io.tmpdir=" + test_tmpdir); + jvm_flags.push_back(L"-Djava.io.tmpdir=" + test_tmpdir); } // Construct the final command line arguments - vector<string> arguments; + vector<wstring> arguments; // Add classpath flags - arguments.push_back("-classpath"); + arguments.push_back(L"-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(); - string classpath_jar = ""; + wstring classpath_str = classpath.str(); + wstring classpath_jar = L""; if (classpath_str.length() > this->classpath_limit) { classpath_jar = CreateClasspathJar(classpath_str); arguments.push_back(classpath_jar); @@ -380,7 +378,7 @@ ExitCode JavaBinaryLauncher::Launch() { arguments.push_back(classpath_str); } // Add JVM debug flags - string jvm_debug_flags_str = jvm_debug_flags.str(); + wstring jvm_debug_flags_str = jvm_debug_flags.str(); if (!jvm_debug_flags_str.empty()) { arguments.push_back(jvm_debug_flags_str); } @@ -403,7 +401,7 @@ ExitCode JavaBinaryLauncher::Launch() { arguments.push_back(arg); } - vector<string> escaped_arguments; + vector<wstring> escaped_arguments; // Quote the arguments if having spaces for (const auto& arg : arguments) { escaped_arguments.push_back( diff --git a/src/tools/launcher/java_launcher.h b/src/tools/launcher/java_launcher.h index 93366b3a8a..d02a7165db 100644 --- a/src/tools/launcher/java_launcher.h +++ b/src/tools/launcher/java_launcher.h @@ -30,7 +30,7 @@ static const int MAX_ARG_STRLEN = 7000; class JavaBinaryLauncher : public BinaryLauncherBase { public: JavaBinaryLauncher(const LaunchDataParser::LaunchInfo& launch_info, int argc, - char* argv[]) + wchar_t* argv[]) : BinaryLauncherBase(launch_info, argc, argv), singlejar(false), print_javabin(false), @@ -68,19 +68,19 @@ class JavaBinaryLauncher : public BinaryLauncherBase { // classpath jar. // // The remainder of the command line is passed to the program. - bool ProcessWrapperArgument(const std::string& argument); + bool ProcessWrapperArgument(const std::wstring& 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::vector<std::wstring> ProcessesCommandLine(); - std::string jvm_debug_port; - std::string main_advice; - std::string main_advice_classpath; - std::vector<std::string> jvm_flags_cmdline; + std::wstring jvm_debug_port; + std::wstring main_advice; + std::wstring main_advice_classpath; + std::vector<std::wstring> jvm_flags_cmdline; bool singlejar; bool print_javabin; int classpath_limit; @@ -89,11 +89,11 @@ class JavaBinaryLauncher : public BinaryLauncherBase { // limit. // // Return the path of the classpath jar created. - std::string CreateClasspathJar(const std::string& classpath); + std::wstring CreateClasspathJar(const std::wstring& classpath); // Creat a directory based on the binary path, all the junctions will be // generated under this directory. - std::string GetJunctionBaseDir(); + std::wstring GetJunctionBaseDir(); // Delete all the junction directory and all the junctions under it. void DeleteJunctionBaseDir(); diff --git a/src/tools/launcher/launcher.cc b/src/tools/launcher/launcher.cc index 9bcc3642c2..b663c2cc77 100644 --- a/src/tools/launcher/launcher.cc +++ b/src/tools/launcher/launcher.cc @@ -21,6 +21,7 @@ #include <vector> #include "src/main/cpp/util/path_platform.h" +#include "src/main/cpp/util/strings.h" #include "src/tools/launcher/launcher.h" #include "src/tools/launcher/util/data_parser.h" #include "src/tools/launcher/util/launcher_util.h" @@ -29,25 +30,26 @@ namespace bazel { namespace launcher { using std::ifstream; -using std::ostringstream; using std::string; using std::unordered_map; using std::vector; +using std::wostringstream; +using std::wstring; -static std::string GetRunfilesDir(const char* argv0) { - string runfiles_dir; +static wstring GetRunfilesDir(const wchar_t* argv0) { + wstring runfiles_dir; // If RUNFILES_DIR is already set (probably we are either in a test or in a // data dependency) then use it. - if (GetEnv("RUNFILES_DIR", &runfiles_dir)) { + if (GetEnv(L"RUNFILES_DIR", &runfiles_dir)) { return runfiles_dir; } // Otherwise this is probably a top-level non-test binary (e.g. a genrule // tool) and should look for its runfiles beside the executable. - return GetBinaryPathWithExtension(argv0) + ".runfiles"; + return GetBinaryPathWithExtension(argv0) + L".runfiles"; } BinaryLauncherBase::BinaryLauncherBase( - const LaunchDataParser::LaunchInfo& _launch_info, int argc, char* argv[]) + const LaunchDataParser::LaunchInfo& _launch_info, int argc, wchar_t* argv[]) : launch_info(_launch_info), manifest_file(FindManifestFile(argv[0])), runfiles_dir(GetRunfilesDir(argv[0])), @@ -58,22 +60,22 @@ BinaryLauncherBase::BinaryLauncherBase( // Prefer to use the runfiles manifest, if it exists, but otherwise the // runfiles directory will be used by default. On Windows, the manifest is // used locally, and the runfiles directory is used remotely. - if (manifest_file != "") { + if (!manifest_file.empty()) { ParseManifestFile(&manifest_file_map, manifest_file); } } -static bool FindManifestFileImpl(const char* argv0, string* result) { +static bool FindManifestFileImpl(const wchar_t* argv0, wstring* result) { // If this binary X runs as the data-dependency of some other binary Y, then // X has no runfiles manifest/directory and should use Y's. - if (GetEnv("RUNFILES_MANIFEST_FILE", result) && + if (GetEnv(L"RUNFILES_MANIFEST_FILE", result) && DoesFilePathExist(result->c_str())) { return true; } - string directory; - if (GetEnv("RUNFILES_DIR", &directory)) { - *result = directory + "/MANIFEST"; + wstring directory; + if (GetEnv(L"RUNFILES_DIR", &directory)) { + *result = directory + L"/MANIFEST"; if (DoesFilePathExist(result->c_str())) { return true; } @@ -82,13 +84,13 @@ static bool FindManifestFileImpl(const char* argv0, string* result) { // If this binary X runs by itself (not as a data-dependency of another // binary), then look for the manifest in a runfiles directory next to the // main binary, then look for it (the manifest) next to the main binary. - directory = GetBinaryPathWithExtension(argv0) + ".runfiles"; - *result = directory + "/MANIFEST"; + directory = GetBinaryPathWithExtension(argv0) + L".runfiles"; + *result = directory + L"/MANIFEST"; if (DoesFilePathExist(result->c_str())) { return true; } - *result = directory + "_manifest"; + *result = directory + L"_manifest"; if (DoesFilePathExist(result->c_str())) { return true; } @@ -96,10 +98,10 @@ static bool FindManifestFileImpl(const char* argv0, string* result) { return false; } -string BinaryLauncherBase::FindManifestFile(const char* argv0) { - string manifest_file; +wstring BinaryLauncherBase::FindManifestFile(const wchar_t* argv0) { + wstring manifest_file; if (!FindManifestFileImpl(argv0, &manifest_file)) { - return ""; + return L""; } // The path will be set as the RUNFILES_MANIFEST_FILE envvar and used by the // shell script, so let's convert backslashes to forward slashes. @@ -107,35 +109,36 @@ string BinaryLauncherBase::FindManifestFile(const char* argv0) { return manifest_file; } -string BinaryLauncherBase::GetRunfilesPath() const { - string runfiles_path = - GetBinaryPathWithExtension(this->commandline_arguments[0]) + ".runfiles"; - std::replace(runfiles_path.begin(), runfiles_path.end(), '/', '\\'); +wstring BinaryLauncherBase::GetRunfilesPath() const { + wstring runfiles_path = + GetBinaryPathWithExtension(this->commandline_arguments[0]) + L".runfiles"; + std::replace(runfiles_path.begin(), runfiles_path.end(), L'/', L'\\'); return runfiles_path; } void BinaryLauncherBase::ParseManifestFile(ManifestFileMap* manifest_file_map, - const string& manifest_path) { + const wstring& manifest_path) { ifstream manifest_file(AsAbsoluteWindowsPath(manifest_path.c_str()).c_str()); if (!manifest_file) { - die("Couldn't open MANIFEST file: %s", manifest_path.c_str()); + die(L"Couldn't open MANIFEST file: %s", manifest_path.c_str()); } string line; while (getline(manifest_file, line)) { size_t space_pos = line.find_first_of(' '); if (space_pos == string::npos) { - die("Wrong MANIFEST format at line: %s", line.c_str()); + die(L"Wrong MANIFEST format at line: %s", line.c_str()); } - string key = line.substr(0, space_pos); - string value = line.substr(space_pos + 1); + wstring wline = blaze_util::CstringToWstring(line); + wstring key = wline.substr(0, space_pos); + wstring value = wline.substr(space_pos + 1); manifest_file_map->insert(make_pair(key, value)); } } -string BinaryLauncherBase::Rlocation(const string& path, - bool need_workspace_name) const { +wstring BinaryLauncherBase::Rlocation(const wstring& path, + bool need_workspace_name) const { // If the manifest file map is empty, then we're using the runfiles directory // instead. if (manifest_file_map.empty()) { @@ -143,106 +146,111 @@ string BinaryLauncherBase::Rlocation(const string& path, return path; } - string query_path = runfiles_dir; + wstring query_path = runfiles_dir; if (need_workspace_name) { - query_path += "/" + this->workspace_name; + query_path += L"/" + this->workspace_name; } - query_path += "/" + path; + query_path += L"/" + path; return query_path; } - string query_path = path; + wstring query_path = path; if (need_workspace_name) { - query_path = this->workspace_name + "/" + path; + query_path = this->workspace_name + L"/" + 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", + die(L"Rlocation failed on %s, path doesn't exist in MANIFEST file", query_path.c_str()); } return entry->second; } -string BinaryLauncherBase::GetLaunchInfoByKey(const string& key) { +wstring BinaryLauncherBase::Rlocation(const string& path, + bool need_workspace_name) const { + return this->Rlocation(blaze_util::CstringToWstring(path), + need_workspace_name); +} + +wstring BinaryLauncherBase::GetLaunchInfoByKey(const string& key) { auto item = launch_info.find(key); if (item == launch_info.end()) { - die("Cannot find key \"%s\" from launch data.\n", key.c_str()); + die(L"Cannot find key \"%hs\" from launch data.\n", key.c_str()); } return item->second; } -const vector<string>& BinaryLauncherBase::GetCommandlineArguments() const { +const vector<wstring>& BinaryLauncherBase::GetCommandlineArguments() const { return this->commandline_arguments; } void BinaryLauncherBase::CreateCommandLine( - CmdLine* result, const string& executable, - const vector<string>& arguments) const { - ostringstream cmdline; - cmdline << '\"' << executable << '\"'; + CmdLine* result, const wstring& executable, + const vector<wstring>& arguments) const { + wostringstream cmdline; + cmdline << L'\"' << executable << L'\"'; for (const auto& s : arguments) { - cmdline << ' ' << s; + cmdline << L' ' << s; } - string cmdline_str = cmdline.str(); + wstring cmdline_str = cmdline.str(); if (cmdline_str.size() >= MAX_CMDLINE_LENGTH) { - die("Command line too long: %s", cmdline_str.c_str()); + die(L"Command line too long: %s", cmdline_str.c_str()); } // Copy command line into a mutable buffer. // CreateProcess is allowed to mutate its command line argument. - strncpy(result->cmdline, cmdline_str.c_str(), MAX_CMDLINE_LENGTH - 1); + wcsncpy(result->cmdline, cmdline_str.c_str(), MAX_CMDLINE_LENGTH - 1); result->cmdline[MAX_CMDLINE_LENGTH - 1] = 0; } bool BinaryLauncherBase::PrintLauncherCommandLine( - const string& executable, const vector<string>& arguments) const { + const wstring& executable, const vector<wstring>& arguments) const { bool has_print_cmd_flag = false; for (const auto& arg : arguments) { - has_print_cmd_flag |= (arg == "--print_launcher_command"); + has_print_cmd_flag |= (arg == L"--print_launcher_command"); } if (has_print_cmd_flag) { - printf("%s\n", executable.c_str()); + wprintf(L"%s\n", executable.c_str()); for (const auto& arg : arguments) { - printf("%s\n", arg.c_str()); + wprintf(L"%s\n", arg.c_str()); } } return has_print_cmd_flag; } -ExitCode BinaryLauncherBase::LaunchProcess(const string& executable, - const vector<string>& arguments, +ExitCode BinaryLauncherBase::LaunchProcess(const wstring& executable, + const vector<wstring>& arguments, bool suppressOutput) const { if (PrintLauncherCommandLine(executable, arguments)) { return 0; } - if (manifest_file != "") { - SetEnv("RUNFILES_MANIFEST_ONLY", "1"); - SetEnv("RUNFILES_MANIFEST_FILE", manifest_file); + if (!manifest_file.empty()) { + SetEnv(L"RUNFILES_MANIFEST_ONLY", L"1"); + SetEnv(L"RUNFILES_MANIFEST_FILE", manifest_file); } else { - SetEnv("RUNFILES_DIR", runfiles_dir); + SetEnv(L"RUNFILES_DIR", runfiles_dir); } CmdLine cmdline; CreateCommandLine(&cmdline, executable, arguments); PROCESS_INFORMATION processInfo = {0}; - STARTUPINFOA startupInfo = {0}; + STARTUPINFOW startupInfo = {0}; startupInfo.cb = sizeof(startupInfo); - BOOL ok = CreateProcessA( + BOOL ok = CreateProcessW( /* lpApplicationName */ NULL, /* lpCommandLine */ cmdline.cmdline, /* lpProcessAttributes */ NULL, /* lpThreadAttributes */ NULL, /* bInheritHandles */ FALSE, /* dwCreationFlags */ - suppressOutput ? CREATE_NO_WINDOW // no console window => no output - : 0, + suppressOutput ? CREATE_NO_WINDOW // no console window => no output + : 0, /* lpEnvironment */ NULL, /* lpCurrentDirectory */ NULL, /* lpStartupInfo */ &startupInfo, /* lpProcessInformation */ &processInfo); if (!ok) { - PrintError("Cannot launch process: %s\nReason: %s", - cmdline.cmdline, + PrintError(L"Cannot launch process: %s\nReason: %hs", cmdline.cmdline, GetLastErrorString().c_str()); return GetLastError(); } diff --git a/src/tools/launcher/launcher.h b/src/tools/launcher/launcher.h index 4dca6e000d..107ac17795 100644 --- a/src/tools/launcher/launcher.h +++ b/src/tools/launcher/launcher.h @@ -32,21 +32,21 @@ static constexpr const char* WORKSPACE_NAME = "workspace_name"; static const int MAX_CMDLINE_LENGTH = 32768; struct CmdLine { - char cmdline[MAX_CMDLINE_LENGTH]; + wchar_t cmdline[MAX_CMDLINE_LENGTH]; }; class BinaryLauncherBase { - typedef std::unordered_map<std::string, std::string> ManifestFileMap; + typedef std::unordered_map<std::wstring, std::wstring> ManifestFileMap; public: BinaryLauncherBase(const LaunchDataParser::LaunchInfo& launch_info, int argc, - char* argv[]); + wchar_t* argv[]); // Get launch information based on a launch info key. - std::string GetLaunchInfoByKey(const std::string& key); + std::wstring GetLaunchInfoByKey(const std::string& key); // Get the original command line arguments passed to this binary. - const std::vector<std::string>& GetCommandlineArguments() const; + const std::vector<std::wstring>& GetCommandlineArguments() const; // Map a runfile path to its absolute path. // @@ -54,8 +54,10 @@ class BinaryLauncherBase { // 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; + std::wstring Rlocation(const std::wstring& path, + bool need_workspace_name = true) const; + std::wstring 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 @@ -65,8 +67,8 @@ class BinaryLauncherBase { // arguments: the command line arguments to be passed to the exectuable, // it doesn't include the exectuable itself. // The arguments are expected to be quoted if having spaces. - ExitCode LaunchProcess(const std::string& executable, - const std::vector<std::string>& arguments, + ExitCode LaunchProcess(const std::wstring& executable, + const std::vector<std::wstring>& arguments, bool suppressOutput = false) const; // A launch function to be implemented for a specific language. @@ -76,54 +78,54 @@ class BinaryLauncherBase { // // The method appends ".exe.runfiles" to the first command line argument, // converts forward slashes to back slashes, then returns that. - std::string GetRunfilesPath() const; + std::wstring GetRunfilesPath() const; private: // A map to store all the launch information. const LaunchDataParser::LaunchInfo& launch_info; // Absolute path to the runfiles manifest file, if one exists. - const std::string manifest_file; + const std::wstring manifest_file; // Path to the runfiles directory, if one exists. - const std::string runfiles_dir; + const std::wstring runfiles_dir; // The commandline arguments recieved. // The first argument is the path of this launcher itself. - std::vector<std::string> commandline_arguments; + std::vector<std::wstring> commandline_arguments; // The workspace name of the repository this target belongs to. - const std::string workspace_name; + const std::wstring workspace_name; // A map to store all entries of the manifest file. - std::unordered_map<std::string, std::string> manifest_file_map; + ManifestFileMap 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; + const std::wstring& executable, + const std::vector<std::wstring>& arguments) const; // Create a command line to be passed to Windows CreateProcessA API. // // exectuable: the binary to be executed. // arguments: the command line arguments to be passed to the exectuable, // it doesn't include the exectuable itself. - void CreateCommandLine(CmdLine* result, const std::string& executable, - const std::vector<std::string>& arguments) const; + void CreateCommandLine(CmdLine* result, const std::wstring& executable, + const std::vector<std::wstring>& arguments) const; // Find manifest file of the binary. // // Expect the manifest file to be at // 1. <path>/<to>/<binary>/<target_name>.runfiles/MANIFEST // or 2. <path>/<to>/<binary>/<target_name>.runfiles_manifest - static std::string FindManifestFile(const char* argv0); + static std::wstring FindManifestFile(const wchar_t* argv0); // Parse manifest file into a map static void ParseManifestFile(ManifestFileMap* manifest_file_map, - const std::string& manifest_path); + const std::wstring& manifest_path); }; } // namespace launcher diff --git a/src/tools/launcher/launcher_main.cc b/src/tools/launcher/launcher_main.cc index 6f9133b6f2..5e0e142e2e 100644 --- a/src/tools/launcher/launcher_main.cc +++ b/src/tools/launcher/launcher_main.cc @@ -33,30 +33,30 @@ using bazel::launcher::die; using std::make_unique; using std::unique_ptr; -int main(int argc, char* argv[]) { +int wmain(int argc, wchar_t* argv[]) { LaunchDataParser::LaunchInfo launch_info; if (!LaunchDataParser::GetLaunchInfo(GetBinaryPathWithExtension(argv[0]), &launch_info)) { - die("Failed to parse launch info."); + die(L"Failed to parse launch info."); } auto result = launch_info.find(BINARY_TYPE); if (result == launch_info.end()) { - die("Cannot find key \"%s\" from launch data.", BINARY_TYPE); + die(L"Cannot find key \"%hs\" from launch data.", BINARY_TYPE); } unique_ptr<BinaryLauncherBase> binary_launcher; - if (result->second == "Python") { + if (result->second == L"Python") { binary_launcher = make_unique<PythonBinaryLauncher>(launch_info, argc, argv); - } else if (result->second == "Bash") { + } else if (result->second == L"Bash") { binary_launcher = make_unique<BashBinaryLauncher>(launch_info, argc, argv); - } else if (result->second == "Java") { + } else if (result->second == L"Java") { binary_launcher = make_unique<JavaBinaryLauncher>(launch_info, argc, argv); } else { - die("Unknown binary type, cannot launch anything."); + die(L"Unknown binary type, cannot launch anything."); } return binary_launcher->Launch(); diff --git a/src/tools/launcher/python_launcher.cc b/src/tools/launcher/python_launcher.cc index 08533ffe74..a0f8775923 100644 --- a/src/tools/launcher/python_launcher.cc +++ b/src/tools/launcher/python_launcher.cc @@ -21,21 +21,21 @@ namespace bazel { namespace launcher { -using std::string; using std::vector; +using std::wstring; static constexpr const char* PYTHON_BIN_PATH = "python_bin_path"; ExitCode PythonBinaryLauncher::Launch() { - string python_binary = this->GetLaunchInfoByKey(PYTHON_BIN_PATH); + wstring python_binary = this->GetLaunchInfoByKey(PYTHON_BIN_PATH); // If specified python binary path doesn't exist, then fall back to // python.exe and hope it's in PATH. if (!DoesFilePathExist(python_binary.c_str())) { - python_binary = "python.exe"; + python_binary = L"python.exe"; } - vector<string> args = this->GetCommandlineArguments(); - string python_zip_file = GetBinaryPathWithoutExtension(args[0]) + ".zip"; + vector<wstring> args = this->GetCommandlineArguments(); + wstring python_zip_file = GetBinaryPathWithoutExtension(args[0]) + L".zip"; // Replace the first argument with python zip file path args[0] = python_zip_file; diff --git a/src/tools/launcher/python_launcher.h b/src/tools/launcher/python_launcher.h index 1a21ca308e..ab624da240 100644 --- a/src/tools/launcher/python_launcher.h +++ b/src/tools/launcher/python_launcher.h @@ -23,8 +23,8 @@ namespace launcher { class PythonBinaryLauncher : public BinaryLauncherBase { public: PythonBinaryLauncher(const LaunchDataParser::LaunchInfo& launch_info, - int argc, char* argv[]) - : BinaryLauncherBase(launch_info, argc, argv){} + int argc, wchar_t* argv[]) + : BinaryLauncherBase(launch_info, argc, argv) {} ExitCode Launch(); }; diff --git a/src/tools/launcher/util/data_parser.cc b/src/tools/launcher/util/data_parser.cc index 98c8b1daf6..cb77abefed 100644 --- a/src/tools/launcher/util/data_parser.cc +++ b/src/tools/launcher/util/data_parser.cc @@ -17,6 +17,7 @@ #include <string> #include <unordered_map> +#include "src/main/cpp/util/strings.h" #include "src/tools/launcher/util/data_parser.h" #include "src/tools/launcher/util/launcher_util.h" @@ -28,6 +29,7 @@ using std::ios; using std::make_unique; using std::string; using std::unique_ptr; +using std::wstring; int64_t LaunchDataParser::ReadDataSize(ifstream* binary) { int64_t data_size; @@ -63,34 +65,34 @@ bool LaunchDataParser::ParseLaunchData(LaunchInfo* launch_info, end++; } if (equal == -1) { - PrintError("Cannot find equal symbol in line: %s", + PrintError(L"Cannot find equal symbol in line: %hs", string(launch_data + start, end - start).c_str()); return false; } else if (start == equal) { - PrintError("Key is empty string in line: %s", + PrintError(L"Key is empty string in line: %hs", string(launch_data + start, end - start).c_str()); return false; } else { string key(launch_data + start, equal - start); string value(launch_data + equal + 1, end - equal - 1); if (launch_info->find(key) != launch_info->end()) { - PrintError("Duplicated launch info key: %s", key.c_str()); + PrintError(L"Duplicated launch info key: %hs", key.c_str()); return false; } - launch_info->insert(make_pair(key, value)); + launch_info->insert(make_pair(key, blaze_util::CstringToWstring(value))); } start = end + 1; } return true; } -bool LaunchDataParser::GetLaunchInfo(const string& binary_path, +bool LaunchDataParser::GetLaunchInfo(const wstring& binary_path, LaunchInfo* launch_info) { unique_ptr<ifstream> binary = make_unique<ifstream>(binary_path, ios::binary | ios::in); int64_t data_size = ReadDataSize(binary.get()); if (data_size == 0) { - PrintError("No data appended, cannot launch anything!"); + PrintError(L"No data appended, cannot launch anything!"); return false; } unique_ptr<char[]> launch_data(new char[data_size]); diff --git a/src/tools/launcher/util/data_parser.h b/src/tools/launcher/util/data_parser.h index ecaf12a9b9..586da42fbe 100644 --- a/src/tools/launcher/util/data_parser.h +++ b/src/tools/launcher/util/data_parser.h @@ -25,10 +25,10 @@ namespace launcher { class LaunchDataParser { public: - typedef std::unordered_map<std::string, std::string> LaunchInfo; + typedef std::unordered_map<std::string, std::wstring> LaunchInfo; LaunchDataParser() = delete; ~LaunchDataParser() = delete; - static bool GetLaunchInfo(const std::string& binary_path, + static bool GetLaunchInfo(const std::wstring& binary_path, LaunchInfo* launch_info); private: diff --git a/src/tools/launcher/util/data_parser_test.cc b/src/tools/launcher/util/data_parser_test.cc index 1adaf3aebd..be270aa3c3 100644 --- a/src/tools/launcher/util/data_parser_test.cc +++ b/src/tools/launcher/util/data_parser_test.cc @@ -18,6 +18,7 @@ #include <memory> #include <vector> +#include "src/main/cpp/util/strings.h" #include "src/tools/launcher/util/data_parser.h" #include "gtest/gtest.h" #include "src/tools/launcher/util/launcher_util.h" @@ -89,7 +90,8 @@ class LaunchDataParserTest : public ::testing::Test { static bool ParseBinaryFile( const string& binary_file, LaunchDataParser::LaunchInfo* parsed_launch_info) { - if (LaunchDataParser::GetLaunchInfo(binary_file, parsed_launch_info)) { + if (LaunchDataParser::GetLaunchInfo( + blaze_util::CstringToWstring(binary_file), parsed_launch_info)) { return true; } exit(-1); @@ -100,7 +102,7 @@ class LaunchDataParserTest : public ::testing::Test { if (item == parsed_launch_info->end()) { return "Cannot find key: " + key; } - return item->second; + return blaze_util::WstringToString(item->second); } string test_tmpdir; diff --git a/src/tools/launcher/util/launcher_util.cc b/src/tools/launcher/util/launcher_util.cc index 3509ce3287..f14009caea 100644 --- a/src/tools/launcher/util/launcher_util.cc +++ b/src/tools/launcher/util/launcher_util.cc @@ -14,6 +14,8 @@ // For rand_s function, https://msdn.microsoft.com/en-us/library/sxtz2fa8.aspx #define _CRT_RAND_S +#include <fcntl.h> +#include <io.h> #include <stdarg.h> #include <stdio.h> #include <stdlib.h> @@ -29,10 +31,10 @@ namespace bazel { namespace launcher { -using std::ostringstream; using std::string; -using std::wstring; using std::stringstream; +using std::wostringstream; +using std::wstring; string GetLastErrorString() { DWORD last_error = GetLastError(); @@ -53,88 +55,99 @@ string GetLastErrorString() { return result.str(); } -void die(const char* format, ...) { +void die(const wchar_t* format, ...) { + // Set translation mode to _O_U8TEXT so that we can display + // error message containing unicode correctly. + _setmode(_fileno(stderr), _O_U8TEXT); va_list ap; va_start(ap, format); - fputs("LAUNCHER ERROR: ", stderr); - vfprintf(stderr, format, ap); + fputws(L"LAUNCHER ERROR: ", stderr); + vfwprintf(stderr, format, ap); va_end(ap); - fputc('\n', stderr); + fputwc(L'\n', stderr); exit(1); } -void PrintError(const char* format, ...) { +void PrintError(const wchar_t* format, ...) { + // Set translation mode to _O_U8TEXT so that we can display + // error message containing unicode correctly. + // _setmode returns -1 if it fails to set the mode. + int previous_mode = _setmode(_fileno(stderr), _O_U8TEXT); va_list ap; va_start(ap, format); - fputs("LAUNCHER ERROR: ", stderr); - vfprintf(stderr, format, ap); + fputws(L"LAUNCHER ERROR: ", stderr); + vfwprintf(stderr, format, ap); va_end(ap); - fputc('\n', stderr); + fputwc(L'\n', stderr); + // Set translation mode back to the original one if it's changed. + if (previous_mode != -1) { + _setmode(_fileno(stderr), previous_mode); + } } -wstring AsAbsoluteWindowsPath(const char* path) { +wstring AsAbsoluteWindowsPath(const wchar_t* path) { wstring wpath; string error; if (!blaze_util::AsAbsoluteWindowsPath(path, &wpath, &error)) { - die("Couldn't convert %s to absolute Windows path: %s", path, + die(L"Couldn't convert %s to absolute Windows path: %hs", path, error.c_str()); } return wpath; } -bool DoesFilePathExist(const char* path) { +bool DoesFilePathExist(const wchar_t* path) { DWORD dwAttrib = GetFileAttributesW(AsAbsoluteWindowsPath(path).c_str()); return (dwAttrib != INVALID_FILE_ATTRIBUTES && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)); } -bool DoesDirectoryPathExist(const char* path) { +bool DoesDirectoryPathExist(const wchar_t* path) { DWORD dwAttrib = GetFileAttributesW(AsAbsoluteWindowsPath(path).c_str()); return (dwAttrib != INVALID_FILE_ATTRIBUTES && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY)); } -bool DeleteFileByPath(const char* path) { +bool DeleteFileByPath(const wchar_t* path) { return DeleteFileW(AsAbsoluteWindowsPath(path).c_str()); } -bool DeleteDirectoryByPath(const char* path) { +bool DeleteDirectoryByPath(const wchar_t* path) { return RemoveDirectoryW(AsAbsoluteWindowsPath(path).c_str()); } -string GetBinaryPathWithoutExtension(const string& binary) { - if (binary.find(".exe", binary.size() - 4) != string::npos) { +wstring GetBinaryPathWithoutExtension(const wstring& binary) { + if (binary.find(L".exe", binary.size() - 4) != wstring::npos) { return binary.substr(0, binary.length() - 4); } return binary; } -string GetBinaryPathWithExtension(const string& binary) { - return GetBinaryPathWithoutExtension(binary) + ".exe"; +wstring GetBinaryPathWithExtension(const wstring& binary) { + return GetBinaryPathWithoutExtension(binary) + L".exe"; } -string GetEscapedArgument(const string& argument, bool escape_backslash) { - string escaped_arg; +wstring GetEscapedArgument(const wstring& argument, bool escape_backslash) { + wstring escaped_arg; // escaped_arg will be at least this long escaped_arg.reserve(argument.size()); - bool has_space = argument.find_first_of(' ') != string::npos; + bool has_space = argument.find_first_of(L' ') != wstring::npos; if (has_space) { - escaped_arg += '\"'; + escaped_arg += L'\"'; } - for (const char ch : argument) { + for (const wchar_t ch : argument) { switch (ch) { - case '"': + case L'"': // Escape double quotes - escaped_arg += "\\\""; + escaped_arg += L"\\\""; break; - case '\\': + case L'\\': // Escape back slashes if escape_backslash is true - escaped_arg += (escape_backslash ? "\\\\" : "\\"); + escaped_arg += (escape_backslash ? L"\\\\" : L"\\"); break; default: @@ -143,7 +156,7 @@ string GetEscapedArgument(const string& argument, bool escape_backslash) { } if (has_space) { - escaped_arg += '\"'; + escaped_arg += L'\"'; } return escaped_arg; } @@ -152,54 +165,54 @@ string GetEscapedArgument(const string& argument, bool escape_backslash) { // 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)) { +bool GetEnv(const wstring& env_name, wstring* value) { + wchar_t buffer[BUFFER_SIZE]; + if (!GetEnvironmentVariableW(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()); +bool SetEnv(const wstring& env_name, const wstring& value) { + return SetEnvironmentVariableW(env_name.c_str(), value.c_str()); } -string GetRandomStr(size_t len) { - static const char alphabet[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; - string rand_str; +wstring GetRandomStr(size_t len) { + static const wchar_t alphabet[] = + L"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + wstring rand_str; rand_str.reserve(len); unsigned int x; for (size_t i = 0; i < len; i++) { rand_s(&x); - rand_str += alphabet[x % strlen(alphabet)]; + rand_str += alphabet[x % wcslen(alphabet)]; } return rand_str; } -bool NormalizePath(const string& path, string* result) { +bool NormalizePath(const wstring& path, wstring* result) { string error; if (!blaze_util::AsWindowsPath(path, result, &error)) { - PrintError("Failed to normalize %s: %s", path.c_str(), error.c_str()); + PrintError(L"Failed to normalize %s: %hs", path.c_str(), error.c_str()); return false; } std::transform(result->begin(), result->end(), result->begin(), ::tolower); return true; } -string GetBaseNameFromPath(const string& path) { - return path.substr(path.find_last_of("\\/") + 1); +wstring GetBaseNameFromPath(const wstring& path) { + return path.substr(path.find_last_of(L"\\/") + 1); } -string GetParentDirFromPath(const string& path) { - return path.substr(0, path.find_last_of("\\/")); +wstring GetParentDirFromPath(const wstring& path) { + return path.substr(0, path.find_last_of(L"\\/")); } -bool RelativeTo(const string& path, const string& base, string* result) { +bool RelativeTo(const wstring& path, const wstring& base, wstring* result) { if (blaze_util::IsAbsolute(path) != blaze_util::IsAbsolute(base)) { PrintError( - "Cannot calculate relative path from an absolute and a non-absolute" + L"Cannot calculate relative path from an absolute and a non-absolute" " path.\npath = %s\nbase = %s", path.c_str(), base.c_str()); return false; @@ -208,7 +221,7 @@ bool RelativeTo(const string& path, const string& base, string* result) { if (blaze_util::IsAbsolute(path) && blaze_util::IsAbsolute(base) && path[0] != base[0]) { PrintError( - "Cannot calculate relative path from absolute path under different " + L"Cannot calculate relative path from absolute path under different " "drives." "\npath = %s\nbase = %s", path.c_str(), base.c_str()); @@ -218,21 +231,21 @@ bool RelativeTo(const string& path, const string& base, string* result) { // Record the back slash position after the last matched path fragment int pos = 0; int back_slash_pos = -1; - while (path[pos] == base[pos] && base[pos] != '\0') { - if (path[pos] == '\\') { + while (path[pos] == base[pos] && base[pos] != L'\0') { + if (path[pos] == L'\\') { back_slash_pos = pos; } pos++; } - if (base[pos] == '\0' && path[pos] == '\0') { + if (base[pos] == L'\0' && path[pos] == L'\0') { // base == path in this case - result->assign(""); + result->assign(L""); return true; } - if ((base[pos] == '\0' && path[pos] == '\\') || - (base[pos] == '\\' && path[pos] == '\0')) { + if ((base[pos] == L'\0' && path[pos] == L'\\') || + (base[pos] == L'\\' && path[pos] == L'\0')) { // In this case, one of the paths is the parent of another one. // We should move back_slash_pos to the end of the shorter path. // eg. path = c:\foo\bar, base = c:\foo => back_slash_pos = 6 @@ -240,7 +253,7 @@ bool RelativeTo(const string& path, const string& base, string* result) { back_slash_pos = pos; } - ostringstream buffer; + wostringstream buffer; // Create the ..\\ prefix // eg. path = C:\foo\bar1, base = C:\foo\bar2, we need ..\ prefix @@ -249,11 +262,11 @@ bool RelativeTo(const string& path, const string& base, string* result) { // back_slash_pos + 1 == base.length() is not possible because the last // character of a normalized path won't be back slash. if (back_slash_pos + 1 < base.length()) { - buffer << "..\\"; + buffer << L"..\\"; } for (int i = back_slash_pos + 1; i < base.length(); i++) { - if (base[i] == '\\') { - buffer << "..\\"; + if (base[i] == L'\\') { + buffer << L"..\\"; } } diff --git a/src/tools/launcher/util/launcher_util.h b/src/tools/launcher/util/launcher_util.h index 760eb7266e..deb4065ab7 100644 --- a/src/tools/launcher/util/launcher_util.h +++ b/src/tools/launcher/util/launcher_util.h @@ -25,77 +25,78 @@ namespace launcher { std::string GetLastErrorString(); // Prints the specified error message and exits nonzero. -__declspec(noreturn) void die(const char* format, ...) PRINTF_ATTRIBUTE(1, 2); +__declspec(noreturn) void die(const wchar_t* format, ...) + PRINTF_ATTRIBUTE(1, 2); // Prints the specified error message. -void PrintError(const char* format, ...) PRINTF_ATTRIBUTE(1, 2); +void PrintError(const wchar_t* format, ...) PRINTF_ATTRIBUTE(1, 2); // Strip the .exe extension from binary path. // // On Windows, if the binary path is foo/bar/bin.exe then return foo/bar/bin -std::string GetBinaryPathWithoutExtension(const std::string& binary); +std::wstring GetBinaryPathWithoutExtension(const std::wstring& binary); // Add exectuable extension to binary path // // On Windows, if the binary path is foo/bar/bin then return foo/bar/bin.exe -std::string GetBinaryPathWithExtension(const std::string& binary); +std::wstring GetBinaryPathWithExtension(const std::wstring& binary); // Escape a command line argument. // // If the argument has space, then we quote it. // Escape " to \" // Escape \ to \\ if escape_backslash is true -std::string GetEscapedArgument(const std::string& argument, - bool escape_backslash); +std::wstring GetEscapedArgument(const std::wstring& argument, + bool escape_backslash); // Convert a path to an absolute Windows path with \\?\ prefix. // This method will print an error and exit if it cannot convert the path. -std::wstring AsAbsoluteWindowsPath(const char* path); +std::wstring AsAbsoluteWindowsPath(const wchar_t* path); // Check if a file exists at a given path. -bool DoesFilePathExist(const char* path); +bool DoesFilePathExist(const wchar_t* path); // Check if a directory exists at a given path. -bool DoesDirectoryPathExist(const char* path); +bool DoesDirectoryPathExist(const wchar_t* path); // Delete a file at a given path. -bool DeleteFileByPath(const char* path); +bool DeleteFileByPath(const wchar_t* path); // Delete a directory at a given path,. // If it's a real directory, it must be empty // If it's a junction, the target directory it points to doesn't have to be // empty, the junction will be deleted regardless of the state of the target. -bool DeleteDirectoryByPath(const char* path); +bool DeleteDirectoryByPath(const wchar_t* 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); +bool GetEnv(const std::wstring& env_name, std::wstring* 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); +bool SetEnv(const std::wstring& env_name, const std::wstring& value); // Return a random string with a given length. // The string consists of a-zA-Z0-9 -std::string GetRandomStr(size_t len); +std::wstring GetRandomStr(size_t len); // Normalize a path to a Windows path in lower case -bool NormalizePath(const std::string& path, std::string* result); +bool NormalizePath(const std::wstring& path, std::wstring* result); // Get the base name from a normalized absoulute path -std::string GetBaseNameFromPath(const std::string& path); +std::wstring GetBaseNameFromPath(const std::wstring& path); // Get parent directory from a normalized absoulute path -std::string GetParentDirFromPath(const std::string& path); +std::wstring GetParentDirFromPath(const std::wstring& path); // Calculate a relative path from `path` to `base`. // This function expects normalized Windows path in lower case. // `path` and `base` should be both absolute or both relative. -bool RelativeTo(const std::string& path, const std::string& base, - std::string* result); +bool RelativeTo(const std::wstring& path, const std::wstring& base, + std::wstring* result); } // 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 f8ddf803f3..82b3f9898b 100644 --- a/src/tools/launcher/util/launcher_util_test.cc +++ b/src/tools/launcher/util/launcher_util_test.cc @@ -18,6 +18,7 @@ #include <iostream> #include <string> +#include "src/main/cpp/util/strings.h" #include "src/tools/launcher/util/launcher_util.h" #include "gtest/gtest.h" @@ -28,6 +29,7 @@ using std::getenv; using std::ios; using std::ofstream; using std::string; +using std::wstring; class LaunchUtilTest : public ::testing::Test { protected: @@ -38,141 +40,142 @@ class LaunchUtilTest : public ::testing::Test { void SetUp() override { char* tmpdir = getenv("TEST_TMPDIR"); if (tmpdir != NULL) { - test_tmpdir = string(tmpdir); + test_tmpdir = blaze_util::CstringToWstring(string(tmpdir)); } else { tmpdir = getenv("TEMP"); ASSERT_FALSE(tmpdir == NULL); - test_tmpdir = string(tmpdir); + test_tmpdir = blaze_util::CstringToWstring(string(tmpdir)); } } void TearDown() override {} - string GetTmpDir() { return this->test_tmpdir; } + wstring GetTmpDir() { return this->test_tmpdir; } // Create an empty file at path - static void CreateEmptyFile(const string& path) { + static void CreateEmptyFile(const wstring& path) { ofstream file_stream(path.c_str(), ios::out | ios::binary); file_stream.put('\0'); } private: - string test_tmpdir; + wstring test_tmpdir; }; TEST_F(LaunchUtilTest, GetBinaryPathWithoutExtensionTest) { - ASSERT_EQ("foo", GetBinaryPathWithoutExtension("foo.exe")); - ASSERT_EQ("foo.sh", GetBinaryPathWithoutExtension("foo.sh.exe")); - ASSERT_EQ("foo.sh", GetBinaryPathWithoutExtension("foo.sh")); + ASSERT_EQ(L"foo", GetBinaryPathWithoutExtension(L"foo.exe")); + ASSERT_EQ(L"foo.sh", GetBinaryPathWithoutExtension(L"foo.sh.exe")); + ASSERT_EQ(L"foo.sh", GetBinaryPathWithoutExtension(L"foo.sh")); } TEST_F(LaunchUtilTest, GetBinaryPathWithExtensionTest) { - ASSERT_EQ("foo.exe", GetBinaryPathWithExtension("foo")); - ASSERT_EQ("foo.sh.exe", GetBinaryPathWithExtension("foo.sh.exe")); - ASSERT_EQ("foo.sh.exe", GetBinaryPathWithExtension("foo.sh")); + ASSERT_EQ(L"foo.exe", GetBinaryPathWithExtension(L"foo")); + ASSERT_EQ(L"foo.sh.exe", GetBinaryPathWithExtension(L"foo.sh.exe")); + ASSERT_EQ(L"foo.sh.exe", GetBinaryPathWithExtension(L"foo.sh")); } TEST_F(LaunchUtilTest, GetEscapedArgumentTest) { - ASSERT_EQ("foo", GetEscapedArgument("foo", true)); - ASSERT_EQ("\"foo bar\"", GetEscapedArgument("foo bar", true)); - ASSERT_EQ("\"\\\"foo bar\\\"\"", GetEscapedArgument("\"foo bar\"", true)); - ASSERT_EQ("foo\\\\bar", GetEscapedArgument("foo\\bar", true)); - ASSERT_EQ("foo\\\"bar", GetEscapedArgument("foo\"bar", true)); - ASSERT_EQ("C:\\\\foo\\\\bar\\\\", GetEscapedArgument("C:\\foo\\bar\\", true)); - ASSERT_EQ("\"C:\\\\foo foo\\\\bar\\\\\"", - GetEscapedArgument("C:\\foo foo\\bar\\", true)); - - ASSERT_EQ("foo\\bar", GetEscapedArgument("foo\\bar", false)); - ASSERT_EQ("C:\\foo\\bar\\", GetEscapedArgument("C:\\foo\\bar\\", false)); - ASSERT_EQ("\"C:\\foo foo\\bar\\\"", - GetEscapedArgument("C:\\foo foo\\bar\\", false)); + ASSERT_EQ(L"foo", GetEscapedArgument(L"foo", true)); + ASSERT_EQ(L"\"foo bar\"", GetEscapedArgument(L"foo bar", true)); + ASSERT_EQ(L"\"\\\"foo bar\\\"\"", GetEscapedArgument(L"\"foo bar\"", true)); + ASSERT_EQ(L"foo\\\\bar", GetEscapedArgument(L"foo\\bar", true)); + ASSERT_EQ(L"foo\\\"bar", GetEscapedArgument(L"foo\"bar", true)); + ASSERT_EQ(L"C:\\\\foo\\\\bar\\\\", + GetEscapedArgument(L"C:\\foo\\bar\\", true)); + ASSERT_EQ(L"\"C:\\\\foo foo\\\\bar\\\\\"", + GetEscapedArgument(L"C:\\foo foo\\bar\\", true)); + + ASSERT_EQ(L"foo\\bar", GetEscapedArgument(L"foo\\bar", false)); + ASSERT_EQ(L"C:\\foo\\bar\\", GetEscapedArgument(L"C:\\foo\\bar\\", false)); + ASSERT_EQ(L"\"C:\\foo foo\\bar\\\"", + GetEscapedArgument(L"C:\\foo foo\\bar\\", false)); } TEST_F(LaunchUtilTest, DoesFilePathExistTest) { - string file1 = GetTmpDir() + "/foo"; - string file2 = GetTmpDir() + "/bar"; + wstring file1 = GetTmpDir() + L"/foo"; + wstring file2 = GetTmpDir() + L"/bar"; CreateEmptyFile(file1); ASSERT_TRUE(DoesFilePathExist(file1.c_str())); ASSERT_FALSE(DoesFilePathExist(file2.c_str())); } TEST_F(LaunchUtilTest, DoesDirectoryPathExistTest) { - string dir1 = GetTmpDir() + "/dir1"; - string dir2 = GetTmpDir() + "/dir2"; - CreateDirectory(dir1.c_str(), NULL); + wstring dir1 = GetTmpDir() + L"/dir1"; + wstring dir2 = GetTmpDir() + L"/dir2"; + CreateDirectoryW(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)); + ASSERT_TRUE(SetEnv(L"foo", L"bar")); + wstring value; + ASSERT_TRUE(GetEnv(L"foo", &value)); + ASSERT_EQ(value, L"bar"); + SetEnv(L"FOO", L""); + ASSERT_FALSE(GetEnv(L"FOO", &value)); } TEST_F(LaunchUtilTest, NormalizePathTest) { - string value; - ASSERT_TRUE(NormalizePath("C:\\foo\\bar\\", &value)); - ASSERT_EQ("c:\\foo\\bar", value); - ASSERT_TRUE(NormalizePath("c:/foo/bar/", &value)); - ASSERT_EQ("c:\\foo\\bar", value); - ASSERT_TRUE(NormalizePath("FoO\\\\bAr\\", &value)); - ASSERT_EQ("foo\\bar", value); - ASSERT_TRUE(NormalizePath("X\\Y/Z\\", &value)); - ASSERT_EQ("x\\y\\z", value); - ASSERT_TRUE(NormalizePath("c://foo//bar", &value)); - ASSERT_EQ("c:\\foo\\bar", value); - ASSERT_FALSE(NormalizePath("c:foo\\bar", &value)); + wstring value; + ASSERT_TRUE(NormalizePath(L"C:\\foo\\bar\\", &value)); + ASSERT_EQ(L"c:\\foo\\bar", value); + ASSERT_TRUE(NormalizePath(L"c:/foo/bar/", &value)); + ASSERT_EQ(L"c:\\foo\\bar", value); + ASSERT_TRUE(NormalizePath(L"FoO\\\\bAr\\", &value)); + ASSERT_EQ(L"foo\\bar", value); + ASSERT_TRUE(NormalizePath(L"X\\Y/Z\\", &value)); + ASSERT_EQ(L"x\\y\\z", value); + ASSERT_TRUE(NormalizePath(L"c://foo//bar", &value)); + ASSERT_EQ(L"c:\\foo\\bar", value); + ASSERT_FALSE(NormalizePath(L"c:foo\\bar", &value)); } TEST_F(LaunchUtilTest, RelativeToTest) { - string value; - ASSERT_TRUE(RelativeTo("c:\\foo\\bar1", "c:\\foo\\bar2", &value)); - ASSERT_EQ("..\\bar1", value); - ASSERT_TRUE(RelativeTo("c:\\foo\\bar", "c:\\", &value)); - ASSERT_EQ("foo\\bar", value); - ASSERT_TRUE(RelativeTo("c:\\foo\\bar", "c:\\foo\\bar", &value)); - ASSERT_EQ("", value); - ASSERT_TRUE(RelativeTo("c:\\foo\\bar", "c:\\foo", &value)); - ASSERT_EQ("bar", value); - ASSERT_TRUE(RelativeTo("c:\\foo\\bar", "c:\\foo\\ba", &value)); - ASSERT_EQ("..\\bar", value); - ASSERT_TRUE(RelativeTo("c:\\", "c:\\foo", &value)); - ASSERT_EQ("..\\", value); - ASSERT_TRUE(RelativeTo("c:\\", "c:\\a\\b\\c", &value)); - ASSERT_EQ("..\\..\\..\\", value); - ASSERT_TRUE(RelativeTo("c:\\aa\\bb\\cc", "c:\\a\\b", &value)); - ASSERT_EQ("..\\..\\aa\\bb\\cc", value); - - ASSERT_TRUE(RelativeTo("foo\\bar", "foo\\bar", &value)); - ASSERT_EQ("", value); - ASSERT_TRUE(RelativeTo("foo\\bar1", "foo\\bar2", &value)); - ASSERT_EQ("..\\bar1", value); - ASSERT_TRUE(RelativeTo("foo\\bar1", "foo\\bar", &value)); - ASSERT_EQ("..\\bar1", value); - ASSERT_TRUE(RelativeTo("foo\\bar1", "foo", &value)); - ASSERT_EQ("bar1", value); - ASSERT_TRUE(RelativeTo("foo\\bar1", "fo", &value)); - ASSERT_EQ("..\\foo\\bar1", value); - ASSERT_TRUE(RelativeTo("foo\\ba", "foo\\bar", &value)); - ASSERT_EQ("..\\ba", value); - ASSERT_TRUE(RelativeTo("foo", "foo\\bar", &value)); - ASSERT_EQ("..\\", value); - ASSERT_TRUE(RelativeTo("fo", "foo\\bar", &value)); - ASSERT_EQ("..\\..\\fo", value); - ASSERT_TRUE(RelativeTo("", "foo\\bar", &value)); - ASSERT_EQ("..\\..\\", value); - ASSERT_TRUE(RelativeTo("foo\\bar", "", &value)); - ASSERT_EQ("foo\\bar", value); - ASSERT_TRUE(RelativeTo("a\\b\\c", "x\\y", &value)); - ASSERT_EQ("..\\..\\a\\b\\c", value); - - ASSERT_FALSE(RelativeTo("c:\\foo\\bar1", "foo\\bar2", &value)); - ASSERT_FALSE(RelativeTo("c:foo\\bar1", "c:\\foo\\bar2", &value)); - ASSERT_FALSE(RelativeTo("c:\\foo\\bar1", "d:\\foo\\bar2", &value)); + wstring value; + ASSERT_TRUE(RelativeTo(L"c:\\foo\\bar1", L"c:\\foo\\bar2", &value)); + ASSERT_EQ(L"..\\bar1", value); + ASSERT_TRUE(RelativeTo(L"c:\\foo\\bar", L"c:\\", &value)); + ASSERT_EQ(L"foo\\bar", value); + ASSERT_TRUE(RelativeTo(L"c:\\foo\\bar", L"c:\\foo\\bar", &value)); + ASSERT_EQ(L"", value); + ASSERT_TRUE(RelativeTo(L"c:\\foo\\bar", L"c:\\foo", &value)); + ASSERT_EQ(L"bar", value); + ASSERT_TRUE(RelativeTo(L"c:\\foo\\bar", L"c:\\foo\\ba", &value)); + ASSERT_EQ(L"..\\bar", value); + ASSERT_TRUE(RelativeTo(L"c:\\", L"c:\\foo", &value)); + ASSERT_EQ(L"..\\", value); + ASSERT_TRUE(RelativeTo(L"c:\\", L"c:\\a\\b\\c", &value)); + ASSERT_EQ(L"..\\..\\..\\", value); + ASSERT_TRUE(RelativeTo(L"c:\\aa\\bb\\cc", L"c:\\a\\b", &value)); + ASSERT_EQ(L"..\\..\\aa\\bb\\cc", value); + + ASSERT_TRUE(RelativeTo(L"foo\\bar", L"foo\\bar", &value)); + ASSERT_EQ(L"", value); + ASSERT_TRUE(RelativeTo(L"foo\\bar1", L"foo\\bar2", &value)); + ASSERT_EQ(L"..\\bar1", value); + ASSERT_TRUE(RelativeTo(L"foo\\bar1", L"foo\\bar", &value)); + ASSERT_EQ(L"..\\bar1", value); + ASSERT_TRUE(RelativeTo(L"foo\\bar1", L"foo", &value)); + ASSERT_EQ(L"bar1", value); + ASSERT_TRUE(RelativeTo(L"foo\\bar1", L"fo", &value)); + ASSERT_EQ(L"..\\foo\\bar1", value); + ASSERT_TRUE(RelativeTo(L"foo\\ba", L"foo\\bar", &value)); + ASSERT_EQ(L"..\\ba", value); + ASSERT_TRUE(RelativeTo(L"foo", L"foo\\bar", &value)); + ASSERT_EQ(L"..\\", value); + ASSERT_TRUE(RelativeTo(L"fo", L"foo\\bar", &value)); + ASSERT_EQ(L"..\\..\\fo", value); + ASSERT_TRUE(RelativeTo(L"", L"foo\\bar", &value)); + ASSERT_EQ(L"..\\..\\", value); + ASSERT_TRUE(RelativeTo(L"foo\\bar", L"", &value)); + ASSERT_EQ(L"foo\\bar", value); + ASSERT_TRUE(RelativeTo(L"a\\b\\c", L"x\\y", &value)); + ASSERT_EQ(L"..\\..\\a\\b\\c", value); + + ASSERT_FALSE(RelativeTo(L"c:\\foo\\bar1", L"foo\\bar2", &value)); + ASSERT_FALSE(RelativeTo(L"c:foo\\bar1", L"c:\\foo\\bar2", &value)); + ASSERT_FALSE(RelativeTo(L"c:\\foo\\bar1", L"d:\\foo\\bar2", &value)); } } // namespace launcher |