aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/tools/launcher
diff options
context:
space:
mode:
authorGravatar Yun Peng <pcloudy@google.com>2018-05-14 02:53:01 -0700
committerGravatar Copybara-Service <copybara-piper@google.com>2018-05-14 02:54:17 -0700
commitf96f037f8f77335dc444844abcc31a372a3e1849 (patch)
tree27e5f8adededa0817c2758dc965aa42dcb2db67a /src/tools/launcher
parent43181c9363473baed3de071a320e1da23ac45d26 (diff)
Windows, Java launcher: Support jar files under different drives
Create junctions to jar's directory when java launcher and its jar are under different drives Fixed https://github.com/bazelbuild/bazel/issues/5135 Change-Id: I21c5b28f5f36c1fe234f8b781fe40d526db846cc PiperOrigin-RevId: 196477704
Diffstat (limited to 'src/tools/launcher')
-rw-r--r--src/tools/launcher/java_launcher.cc108
-rw-r--r--src/tools/launcher/java_launcher.h7
-rw-r--r--src/tools/launcher/util/launcher_util.cc12
-rw-r--r--src/tools/launcher/util/launcher_util.h12
4 files changed, 125 insertions, 14 deletions
diff --git a/src/tools/launcher/java_launcher.cc b/src/tools/launcher/java_launcher.cc
index af60de2fed..5b5a498b71 100644
--- a/src/tools/launcher/java_launcher.cc
+++ b/src/tools/launcher/java_launcher.cc
@@ -12,11 +12,16 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include <memory>
#include <sstream>
#include <string>
+#include <unordered_map>
#include <vector>
+#include "src/main/cpp/util/file.h"
#include "src/main/cpp/util/file_platform.h"
+#include "src/main/cpp/util/strings.h"
+#include "src/main/native/windows/file.h"
#include "src/tools/launcher/java_launcher.h"
#include "src/tools/launcher/util/launcher_util.h"
@@ -29,6 +34,7 @@ using std::ostringstream;
using std::string;
using std::stringstream;
using std::vector;
+using std::wstring;
// The runfile path of java binary, eg. local_jdk/bin/java.exe
static constexpr const char* JAVA_BIN_PATH = "java_bin_path";
@@ -135,6 +141,52 @@ static string GetManifestJarDir(const string& binary_base_path) {
return result;
}
+static void WriteJarClasspath(const string& jar_path,
+ ostringstream* manifest_classpath) {
+ *manifest_classpath << ' ';
+ if (jar_path.find_first_of(" \\") != string::npos) {
+ for (const auto& x : jar_path) {
+ if (x == ' ') {
+ *manifest_classpath << "%20";
+ }
+ if (x == '\\') {
+ *manifest_classpath << "/";
+ } else {
+ *manifest_classpath << x;
+ }
+ }
+ } else {
+ *manifest_classpath << jar_path;
+ }
+}
+
+string JavaBinaryLauncher::GetJunctionBaseDir() {
+ string binary_base_path =
+ GetBinaryPathWithExtension(this->GetCommandlineArguments()[0]);
+ string result;
+ if (!NormalizePath(binary_base_path + ".j", &result)) {
+ die("Failed to get normalized junction base directory.");
+ }
+ return result;
+}
+
+void JavaBinaryLauncher::DeleteJunctionBaseDir() {
+ string 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);
+ for (const auto& junction : junctions) {
+ if (!DeleteDirectoryByPath(junction.c_str())) {
+ PrintError(GetLastErrorString().c_str());
+ }
+ }
+ if (!DeleteDirectoryByPath(junction_base_dir_norm.c_str())) {
+ PrintError(GetLastErrorString().c_str());
+ }
+}
+
string JavaBinaryLauncher::CreateClasspathJar(const string& classpath) {
string binary_base_path =
GetBinaryPathWithoutExtension(this->GetCommandlineArguments()[0]);
@@ -144,28 +196,55 @@ string JavaBinaryLauncher::CreateClasspathJar(const string& classpath) {
manifest_classpath << "Class-Path:";
stringstream classpath_ss(classpath);
string 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();
+ int junction_count = 0;
+ // Make sure the junction base directory doesn't exist already.
+ DeleteJunctionBaseDir();
+ blaze_util::MakeDirectories(junction_base_dir_norm, 0755);
+
while (getline(classpath_ss, path, ';')) {
- manifest_classpath << ' ';
if (blaze_util::IsAbsolute(path)) {
- if (!NormalizePath(path, &path_norm) ||
- !RelativeTo(path_norm, abs_manifest_jar_dir_norm, &path)) {
+ if (!NormalizePath(path, &path_norm)) {
die("CreateClasspathJar failed");
}
- }
- if (path.find_first_of(" \\") != string::npos) {
- for (const auto& x : path) {
- if (x == ' ') {
- manifest_classpath << "%20";
- }
- if (x == '\\') {
- manifest_classpath << "/";
+
+ // 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;
+ 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());
+ }
+
+ jar_dirs.insert(std::make_pair(jar_dir, junction));
} else {
- manifest_classpath << x;
+ junction = search->second;
}
+ path_norm = junction + "\\" + jar_base_name;
+ }
+
+ if (!RelativeTo(path_norm, abs_manifest_jar_dir_norm, &path)) {
+ die("CreateClasspathJar failed");
}
- } else {
- manifest_classpath << path;
}
+ WriteJarClasspath(path, &manifest_classpath);
}
string rand_id = "-" + GetRandomStr(10);
@@ -335,6 +414,7 @@ ExitCode JavaBinaryLauncher::Launch() {
// Delete classpath jar file after execution.
if (!classpath_jar.empty()) {
DeleteFileByPath(classpath_jar.c_str());
+ DeleteJunctionBaseDir();
}
return exit_code;
diff --git a/src/tools/launcher/java_launcher.h b/src/tools/launcher/java_launcher.h
index 896aacd74a..93366b3a8a 100644
--- a/src/tools/launcher/java_launcher.h
+++ b/src/tools/launcher/java_launcher.h
@@ -90,6 +90,13 @@ class JavaBinaryLauncher : public BinaryLauncherBase {
//
// Return the path of the classpath jar created.
std::string CreateClasspathJar(const std::string& classpath);
+
+ // Creat a directory based on the binary path, all the junctions will be
+ // generated under this directory.
+ std::string GetJunctionBaseDir();
+
+ // Delete all the junction directory and all the junctions under it.
+ void DeleteJunctionBaseDir();
};
} // namespace launcher
diff --git a/src/tools/launcher/util/launcher_util.cc b/src/tools/launcher/util/launcher_util.cc
index 573a99669a..2ef25a352f 100644
--- a/src/tools/launcher/util/launcher_util.cc
+++ b/src/tools/launcher/util/launcher_util.cc
@@ -100,6 +100,10 @@ bool DeleteFileByPath(const char* path) {
return DeleteFileW(AsAbsoluteWindowsPath(path).c_str());
}
+bool DeleteDirectoryByPath(const char* path) {
+ return RemoveDirectoryW(AsAbsoluteWindowsPath(path).c_str());
+}
+
string GetBinaryPathWithoutExtension(const string& binary) {
if (binary.find(".exe", binary.size() - 4) != string::npos) {
return binary.substr(0, binary.length() - 4);
@@ -184,6 +188,14 @@ bool NormalizePath(const string& path, string* result) {
return true;
}
+string GetBaseNameFromPath(const string& path) {
+ return path.substr(path.find_last_of("\\/") + 1);
+}
+
+string GetParentDirFromPath(const string& path) {
+ return path.substr(0, path.find_last_of("\\/"));
+}
+
bool RelativeTo(const string& path, const string& base, string* result) {
if (blaze_util::IsAbsolute(path) != blaze_util::IsAbsolute(base)) {
PrintError(
diff --git a/src/tools/launcher/util/launcher_util.h b/src/tools/launcher/util/launcher_util.h
index ae254bd09a..760eb7266e 100644
--- a/src/tools/launcher/util/launcher_util.h
+++ b/src/tools/launcher/util/launcher_util.h
@@ -61,6 +61,12 @@ bool DoesDirectoryPathExist(const char* path);
// Delete a file at a given path.
bool DeleteFileByPath(const char* 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);
+
// Get the value of a specific environment variable
//
// Return true if succeeded and the result is stored in buffer.
@@ -79,6 +85,12 @@ 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);
+// Get the base name from a normalized absoulute path
+std::string GetBaseNameFromPath(const std::string& path);
+
+// Get parent directory from a normalized absoulute path
+std::string GetParentDirFromPath(const std::string& 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.