Windows: native launcher can run from a long path
This change fixed a bug in `src/tools/launcher/util/data_parser.cc` when running the native launcher at a long path.
Closes #7222.
Change-Id: I2ed2c6cb32592d6a178df9a69fe31d6df0974f0c
PiperOrigin-RevId: 230705416
diff --git a/src/test/py/bazel/launcher_test.py b/src/test/py/bazel/launcher_test.py
index 8284a1a..dfab59f 100644
--- a/src/test/py/bazel/launcher_test.py
+++ b/src/test/py/bazel/launcher_test.py
@@ -15,6 +15,7 @@
import os
import stat
+import string
import unittest
from src.test.py.bazel import test_base
@@ -548,8 +549,11 @@
self.AssertExitCode(exit_code, 0, stderr)
for f in [
- 'bin_java.exe', 'bin_java.exe.runfiles_manifest', 'bin_sh.exe',
- 'bin_sh', 'bin_sh.exe.runfiles_manifest'
+ 'bin_java.exe',
+ 'bin_java.exe.runfiles_manifest',
+ 'bin_sh.exe',
+ 'bin_sh',
+ 'bin_sh.exe.runfiles_manifest',
]:
self.CopyFile(os.path.join(bazel_bin, 'bin', f),
os.path.join(u'./\u6d4b\u8bd5', f))
@@ -564,6 +568,81 @@
self.AssertExitCode(exit_code, 0, stderr)
self.assertEqual('helloworld', ''.join(stdout))
+ def testWindowsNativeLauncherInLongPath(self):
+ if not self.IsWindows():
+ return
+ self.ScratchFile('WORKSPACE')
+ self.ScratchFile('bin/BUILD', [
+ 'java_binary(',
+ ' name = "bin_java",',
+ ' srcs = ["Main.java"],',
+ ' main_class = "Main",',
+ ')',
+ 'sh_binary(',
+ ' name = "bin_sh",',
+ ' srcs = ["main.sh"],',
+ ')',
+ 'py_binary(',
+ ' name = "bin_py",',
+ ' srcs = ["bin_py.py"],',
+ ')',
+ ])
+ self.ScratchFile('bin/Main.java', [
+ 'public class Main {',
+ ' public static void main(String[] args) {'
+ ' System.out.println("helloworld");',
+ ' }',
+ '}',
+ ])
+ self.ScratchFile('bin/main.sh', [
+ 'echo "helloworld"',
+ ])
+ self.ScratchFile('bin/bin_py.py', [
+ 'print("helloworld")',
+ ])
+
+ exit_code, stdout, stderr = self.RunBazel(['info', 'bazel-bin'])
+ self.AssertExitCode(exit_code, 0, stderr)
+ bazel_bin = stdout[0]
+
+ exit_code, _, stderr = self.RunBazel(['build', '//bin/...'])
+ self.AssertExitCode(exit_code, 0, stderr)
+
+ # Create a directory with a path longer than 260
+ long_dir_path = './' + '/'.join(
+ [(c * 8 + '.' + c * 3) for c in string.ascii_lowercase])
+
+ for f in [
+ 'bin_java.exe',
+ 'bin_java.exe.runfiles_manifest',
+ 'bin_sh.exe',
+ 'bin_sh',
+ 'bin_sh.exe.runfiles_manifest',
+ 'bin_py.exe',
+ 'bin_py.zip',
+ 'bin_py.exe.runfiles_manifest',
+ ]:
+ self.CopyFile(
+ os.path.join(bazel_bin, 'bin', f), os.path.join(long_dir_path, f))
+
+ long_binary_path = os.path.abspath(long_dir_path + '/bin_java.exe')
+ # subprocess doesn't support long path without shell=True
+ exit_code, stdout, stderr = self.RunProgram([long_binary_path], shell=True)
+ self.AssertExitCode(exit_code, 0, stderr)
+ self.assertEqual('helloworld', ''.join(stdout))
+
+ long_binary_path = os.path.abspath(long_dir_path + '/bin_sh.exe')
+ # subprocess doesn't support long path without shell=True
+ exit_code, stdout, stderr = self.RunProgram([long_binary_path], shell=True)
+ self.AssertExitCode(exit_code, 0, stderr)
+ self.assertEqual('helloworld', ''.join(stdout))
+
+ long_binary_path = os.path.abspath(long_dir_path + '/bin_py.exe')
+ # subprocess doesn't support long path without shell=True
+ exit_code, stdout, stderr = self.RunProgram([long_binary_path], shell=True)
+ self.AssertExitCode(exit_code, 0, stderr)
+ self.assertEqual('helloworld', ''.join(stdout))
+
def AssertRunfilesManifestContains(self, manifest, entry):
with open(manifest, 'r') as f:
for l in f:
diff --git a/src/test/py/bazel/test_base.py b/src/test/py/bazel/test_base.py
index 6455ae2..01f694f 100644
--- a/src/test/py/bazel/test_base.py
+++ b/src/test/py/bazel/test_base.py
@@ -310,7 +310,7 @@
print('--------------------------')
print('\n'.join(stderr_lines))
- def RunProgram(self, args, env_remove=None, env_add=None):
+ def RunProgram(self, args, env_remove=None, env_add=None, shell=False):
"""Runs a program (args[0]), waits for it to exit.
Args:
@@ -319,6 +319,8 @@
to the program
env_add: {string: string}; optional; environment variables to pass to
the program, won't be removed by env_remove.
+ shell: {bool: bool}; optional; whether to use the shell as the program
+ to execute
Returns:
(int, [string], [string]) tuple: exit code, stdout lines, stderr lines
"""
@@ -329,7 +331,8 @@
stdout=stdout,
stderr=stderr,
cwd=self._test_cwd,
- env=self._EnvMap(env_remove, env_add))
+ env=self._EnvMap(env_remove, env_add),
+ shell=shell)
exit_code = proc.wait()
stdout.seek(0)
diff --git a/src/tools/launcher/util/data_parser.cc b/src/tools/launcher/util/data_parser.cc
index cb77abe..aeff52c 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/path_platform.h"
#include "src/main/cpp/util/strings.h"
#include "src/tools/launcher/util/data_parser.h"
#include "src/tools/launcher/util/launcher_util.h"
@@ -89,7 +90,8 @@
bool LaunchDataParser::GetLaunchInfo(const wstring& binary_path,
LaunchInfo* launch_info) {
unique_ptr<ifstream> binary =
- make_unique<ifstream>(binary_path, ios::binary | ios::in);
+ make_unique<ifstream>(AsAbsoluteWindowsPath(binary_path.c_str()).c_str(),
+ ios::binary | ios::in);
int64_t data_size = ReadDataSize(binary.get());
if (data_size == 0) {
PrintError(L"No data appended, cannot launch anything!");