aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/tools/launcher
diff options
context:
space:
mode:
authorGravatar Yun Peng <pcloudy@google.com>2018-01-11 04:37:39 -0800
committerGravatar Copybara-Service <copybara-piper@google.com>2018-01-11 04:40:54 -0800
commit5fa8dbd9d536417cfe544114a2584dfef9785dd7 (patch)
treec17a48f80f89c7500fa1c0f309e202cb01d956f5 /src/tools/launcher
parent2e631c99495f75270d2639542cefb531ec262d67 (diff)
Windows, Java launcher: Use relativize paths in classpath jar
Fixed https://github.com/bazelbuild/bazel/issues/4408 Change-Id: Id62b25e675822bbed91a448e70bdcb76e722721e PiperOrigin-RevId: 181591585
Diffstat (limited to 'src/tools/launcher')
-rw-r--r--src/tools/launcher/java_launcher.cc53
-rw-r--r--src/tools/launcher/util/launcher_util.cc83
-rw-r--r--src/tools/launcher/util/launcher_util.h9
-rw-r--r--src/tools/launcher/util/launcher_util_test.cc62
4 files changed, 197 insertions, 10 deletions
diff --git a/src/tools/launcher/java_launcher.cc b/src/tools/launcher/java_launcher.cc
index 8a91fef871..15a3354fb3 100644
--- a/src/tools/launcher/java_launcher.cc
+++ b/src/tools/launcher/java_launcher.cc
@@ -16,6 +16,7 @@
#include <string>
#include <vector>
+#include "src/main/cpp/util/file_platform.h"
#include "src/tools/launcher/java_launcher.h"
#include "src/tools/launcher/util/launcher_util.h"
@@ -115,26 +116,58 @@ vector<string> JavaBinaryLauncher::ProcessesCommandLine() {
return args;
}
+// 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 = "";
+ } 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;
+ }
+ string result;
+ if (!NormalizePath(abs_manifest_jar_dir, &result)) {
+ die("GetManifestJarDir Failed");
+ }
+ return result;
+}
+
string JavaBinaryLauncher::CreateClasspathJar(const string& classpath) {
- static constexpr const char* URI_PREFIX = "file:/";
+ string binary_base_path =
+ GetBinaryPathWithoutExtension(this->GetCommandlineArguments()[0]);
+ string abs_manifest_jar_dir_norm = GetManifestJarDir(binary_base_path);
+
ostringstream manifest_classpath;
manifest_classpath << "Class-Path:";
stringstream classpath_ss(classpath);
- string path;
+ string path, path_norm;
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;
+ if (blaze_util::IsAbsolute(path)) {
+ if (!NormalizePath(path, &path_norm) ||
+ !RelativeTo(path_norm, abs_manifest_jar_dir_norm, &path)) {
+ die("CreateClasspathJar failed");
}
}
+ if (path.find_first_of(" \\") != string::npos) {
+ for (const auto& x : path) {
+ if (x == ' ') {
+ manifest_classpath << "%20";
+ }
+ if (x == '\\') {
+ manifest_classpath << "/";
+ } else {
+ manifest_classpath << x;
+ }
+ }
+ } else {
+ manifest_classpath << path;
+ }
}
- string binary_base_path =
- GetBinaryPathWithoutExtension(this->GetCommandlineArguments()[0]);
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);
diff --git a/src/tools/launcher/util/launcher_util.cc b/src/tools/launcher/util/launcher_util.cc
index b4513559e4..83aa3f8988 100644
--- a/src/tools/launcher/util/launcher_util.cc
+++ b/src/tools/launcher/util/launcher_util.cc
@@ -19,6 +19,7 @@
#include <stdlib.h>
#include <string.h>
#include <windows.h>
+#include <algorithm>
#include <sstream>
#include <string>
@@ -170,5 +171,87 @@ string GetRandomStr(size_t len) {
return rand_str.str();
}
+bool NormalizePath(const string& path, string* result) {
+ if (!blaze_util::AsWindowsPath(path, result)) {
+ PrintError("Failed to normalize %s", path.c_str());
+ return false;
+ }
+ std::transform(result->begin(), result->end(), result->begin(), ::tolower);
+ return true;
+}
+
+bool RelativeTo(const string& path, const string& base, string* result) {
+ if (blaze_util::IsAbsolute(path) != blaze_util::IsAbsolute(base)) {
+ PrintError(
+ "Cannot calculate relative path from an absolute and a non-absolute"
+ " path.\npath = %s\nbase = %s",
+ path.c_str(), base.c_str());
+ return false;
+ }
+
+ if (blaze_util::IsAbsolute(path) && blaze_util::IsAbsolute(base) &&
+ path[0] != base[0]) {
+ PrintError(
+ "Cannot calculate relative path from absolute path under different "
+ "drives."
+ "\npath = %s\nbase = %s",
+ path.c_str(), base.c_str());
+ return false;
+ }
+
+ // 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] == '\\') {
+ back_slash_pos = pos;
+ }
+ pos++;
+ }
+
+ if (base[pos] == '\0' && path[pos] == '\0') {
+ // base == path in this case
+ result->assign("");
+ return true;
+ }
+
+ if ((base[pos] == '\0' && path[pos] == '\\') ||
+ (base[pos] == '\\' && path[pos] == '\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
+ // or path = c:\foo, base = c:\foo\bar => back_slash_pos = 6
+ back_slash_pos = pos;
+ }
+
+ ostringstream buffer;
+
+ // Create the ..\\ prefix
+ // eg. path = C:\foo\bar1, base = C:\foo\bar2, we need ..\ prefix
+ // In case "base" is a parent of "path", we set back_slash_pos to the end
+ // of "base", so we need no prefix when back_slash_pos + 1 > base.length().
+ // 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 << "..\\";
+ }
+ for (int i = back_slash_pos + 1; i < base.length(); i++) {
+ if (base[i] == '\\') {
+ buffer << "..\\";
+ }
+ }
+
+ // Add the result of not matched path fragments into result
+ // eg. path = C:\foo\bar1, base = C:\foo\bar2, adding `bar1`
+ // In case "path" is a parent of "base", we set back_slash_pos to the end
+ // of "path", so we need no suffix when back_slash_pos == path.length().
+ if (back_slash_pos != path.length()) {
+ buffer << path.substr(back_slash_pos + 1);
+ }
+
+ result->assign(buffer.str());
+ return true;
+}
+
} // namespace launcher
} // namespace bazel
diff --git a/src/tools/launcher/util/launcher_util.h b/src/tools/launcher/util/launcher_util.h
index 3877b7c5af..ae254bd09a 100644
--- a/src/tools/launcher/util/launcher_util.h
+++ b/src/tools/launcher/util/launcher_util.h
@@ -76,6 +76,15 @@ bool SetEnv(const std::string& env_name, const std::string& value);
// The string consists of a-zA-Z0-9
std::string GetRandomStr(size_t len);
+// Normalize a path to a Windows path in lower case
+bool NormalizePath(const std::string& path, std::string* result);
+
+// 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);
+
} // 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 9024d1d11e..f8ddf803f3 100644
--- a/src/tools/launcher/util/launcher_util_test.cc
+++ b/src/tools/launcher/util/launcher_util_test.cc
@@ -113,5 +113,67 @@ TEST_F(LaunchUtilTest, SetAndGetEnvTest) {
ASSERT_FALSE(GetEnv("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));
+}
+
+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));
+}
+
} // namespace launcher
} // namespace bazel