aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/test/py/bazel/runfiles_test.py88
-rwxr-xr-xsrc/test/shell/bazel/bazel_windows_example_test.sh3
-rw-r--r--src/tools/launcher/launcher.cc51
3 files changed, 127 insertions, 15 deletions
diff --git a/src/test/py/bazel/runfiles_test.py b/src/test/py/bazel/runfiles_test.py
index cda4bf11be..e3f697cc55 100644
--- a/src/test/py/bazel/runfiles_test.py
+++ b/src/test/py/bazel/runfiles_test.py
@@ -172,6 +172,94 @@ class RunfilesTest(test_base.TestBase):
self.fail("lines(%s): %s" % (lang[0], lines))
self.assertEqual(lines[0], "data for " + lang[2])
+ def testRunfilesLibrariesFindRunfilesWithRunfilesManifestEnvvar(self):
+ for s, t in [
+ ("WORKSPACE.mock", "WORKSPACE"),
+ ("bar/BUILD.mock", "bar/BUILD"),
+ # Note: do not test Python here, because py_binary always needs a
+ # runfiles tree, even on Windows, because it needs __init__.py files in
+ # every directory where there may be importable modules, so Bazel always
+ # needs to create a runfiles tree for py_binary.
+ ("bar/Bar.java", "bar/Bar.java"),
+ ("bar/bar-java-data.txt", "bar/bar-java-data.txt"),
+ ]:
+ self.CopyFile(
+ self.Rlocation(
+ "io_bazel/src/test/py/bazel/testdata/runfiles_test/" + s), t)
+
+ 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", "--experimental_enable_runfiles=no", "//bar:bar-java"])
+ self.AssertExitCode(exit_code, 0, stderr)
+
+ if test_base.TestBase.IsWindows():
+ bin_path = os.path.join(bazel_bin, "bar/bar-java.exe")
+ else:
+ bin_path = os.path.join(bazel_bin, "bar/bar-java")
+
+ manifest_path = bin_path + ".runfiles_manifest"
+ self.assertTrue(os.path.exists(bin_path))
+ self.assertTrue(os.path.exists(manifest_path))
+
+ # Create a copy of the runfiles manifest, replacing
+ # "bar/bar-java-data.txt" with a custom file.
+ mock_bar_dep = self.ScratchFile("bar-java-mockdata.txt", ["mock java data"])
+ if test_base.TestBase.IsWindows():
+ # Runfiles manifests use forward slashes as path separators, even on
+ # Windows.
+ mock_bar_dep = mock_bar_dep.replace("\\", "/")
+ manifest_key = "foo_ws/bar/bar-java-data.txt"
+ mock_manifest_line = manifest_key + " " + mock_bar_dep
+ with open(manifest_path, "rt") as f:
+ # Only rstrip newlines. Do not rstrip() completely, because that would
+ # remove spaces too. This is necessary in order to have at least one
+ # space in every manifest line.
+ # Some manifest entries don't have any path after this space, namely the
+ # "__init__.py" entries. (Bazel writes such manifests on every
+ # platform). The reason is that these files are never symlinks in the
+ # runfiles tree, Bazel actually creates empty __init__.py files (again
+ # on every platform). However to keep these manifest entries correct,
+ # they need to have a space character.
+ # We could probably strip thses lines completely, but this test doesn't
+ # aim to exercise what would happen in that case.
+ mock_manifest_data = [
+ mock_manifest_line
+ if line.split(" ", 1)[0] == manifest_key else line.rstrip("\n\r")
+ for line in f
+ ]
+
+ substitute_manifest = self.ScratchFile("mock-java.runfiles/MANIFEST",
+ mock_manifest_data)
+
+ exit_code, stdout, stderr = self.RunProgram(
+ [bin_path],
+ env_remove=set(["RUNFILES_DIR"]),
+ env_add={
+ # On Linux/macOS, the Java launcher picks up JAVA_RUNFILES and
+ # ignores RUNFILES_MANIFEST_FILE.
+ "JAVA_RUNFILES": substitute_manifest[:-len("/MANIFEST")],
+ # On Windows, the Java launcher picks up RUNFILES_MANIFEST_FILE.
+ "RUNFILES_MANIFEST_FILE": substitute_manifest,
+ "RUNFILES_MANIFEST_ONLY": "1",
+ "TEST_SRCDIR": "__ignore_me__",
+ })
+
+ self.AssertExitCode(exit_code, 0, stderr)
+ if len(stdout) < 2:
+ self.fail("stdout: %s" % stdout)
+ self.assertEqual(stdout[0], "Hello Java Bar!")
+ six.assertRegex(self, stdout[1], "^rloc=" + mock_bar_dep)
+ self.assertNotIn("__ignore_me__", stdout[1])
+
+ with open(stdout[1].split("=", 1)[1], "r") as f:
+ lines = [l.strip() for l in f.readlines()]
+ if len(lines) != 1:
+ self.fail("lines: %s" % lines)
+ self.assertEqual(lines[0], "mock java data")
+
if __name__ == "__main__":
unittest.main()
diff --git a/src/test/shell/bazel/bazel_windows_example_test.sh b/src/test/shell/bazel/bazel_windows_example_test.sh
index 53070e0e94..97de66108d 100755
--- a/src/test/shell/bazel/bazel_windows_example_test.sh
+++ b/src/test/shell/bazel/bazel_windows_example_test.sh
@@ -53,6 +53,9 @@ function assert_binary_run_from_subdir() {
cd x &&
unset JAVA_RUNFILES &&
unset TEST_SRCDIR &&
+ unset RUNFILES_MANIFEST_FILE &&
+ unset RUNFILES_MANIFEST_ONLY &&
+ unset RUNFILES_DIR &&
assert_binary_run "../$1" "$2" )
}
diff --git a/src/tools/launcher/launcher.cc b/src/tools/launcher/launcher.cc
index 11bf86b57a..a657fa41e7 100644
--- a/src/tools/launcher/launcher.cc
+++ b/src/tools/launcher/launcher.cc
@@ -44,27 +44,48 @@ BinaryLauncherBase::BinaryLauncherBase(
ParseManifestFile(&this->manifest_file_map, this->manifest_file);
}
-string BinaryLauncherBase::FindManifestFile(const char* argv0) {
- // Get the name of the binary
- string binary = GetBinaryPathWithExtension(argv0);
+static bool FindManifestFileImpl(const char* argv0, string* 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) &&
+ DoesFilePathExist(result->c_str())) {
+ return true;
+ }
- // 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.
- std::replace(binary.begin(), binary.end(), '\\', '/');
+ string directory;
+ if (GetEnv("RUNFILES_DIR", &directory)) {
+ *result = directory + "/MANIFEST";
+ if (DoesFilePathExist(result->c_str())) {
+ return true;
+ }
+ }
- // Try to find <path to binary>.runfiles/MANIFEST
- string manifest_file = binary + ".runfiles/MANIFEST";
- if (DoesFilePathExist(manifest_file.c_str())) {
- return manifest_file;
+ // 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";
+ if (DoesFilePathExist(result->c_str())) {
+ return true;
}
- // Also try to check if <path to binary>.runfiles_manifest exists
- manifest_file = binary + ".runfiles_manifest";
- if (DoesFilePathExist(manifest_file.c_str())) {
- return manifest_file;
+ *result = directory + "_manifest";
+ if (DoesFilePathExist(result->c_str())) {
+ return true;
}
- die("Couldn't find MANIFEST file under %s.runfiles\\", binary.c_str());
+ return false;
+}
+
+string BinaryLauncherBase::FindManifestFile(const char* argv0) {
+ string manifest_file;
+ if (!FindManifestFileImpl(argv0, &manifest_file)) {
+ die("Couldn't find runfiles manifest file.");
+ }
+ // 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.
+ std::replace(manifest_file.begin(), manifest_file.end(), '\\', '/');
+ return manifest_file;
}
string BinaryLauncherBase::GetRunfilesPath() const {