aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Laszlo Csomor <laszlocsomor@google.com>2018-05-22 05:01:41 -0700
committerGravatar Copybara-Service <copybara-piper@google.com>2018-05-22 05:02:42 -0700
commitc29f34fa81a16abdfc1b5aad03f76d36ce8793ba (patch)
tree10dc1e3270e93e4e3af667735164cd91f9606194
parenta1ae44a71a6a43aa9d27888d9cf53d4baa0816e3 (diff)
runfiles,python: add a method to discover runfiles
The new method discovers the runfiles manifest and runfiles directory using the values of the RUNFILES_MANIFEST_FILE and RUNFILES_DIR envvars (if specified), and if needed, also looks for them next to sys.argv[0]. This commit is a copy of https://github.com/bazelbuild/bazel/commit/9f2b052d93bfd188687f28fe6771f390d3626936 ported from C++ to Python. See https://github.com/bazelbuild/bazel/issues/4460 Change-Id: I6916366ca73575703fe39ce69020eec3b54457bf Closes #5233. Change-Id: I6916366ca73575703fe39ce69020eec3b54457bf PiperOrigin-RevId: 197544480
-rw-r--r--tools/python/runfiles/runfiles.py51
-rw-r--r--tools/python/runfiles/runfiles_test.py87
2 files changed, 138 insertions, 0 deletions
diff --git a/tools/python/runfiles/runfiles.py b/tools/python/runfiles/runfiles.py
index 1053319eca..e80a7d19a9 100644
--- a/tools/python/runfiles/runfiles.py
+++ b/tools/python/runfiles/runfiles.py
@@ -219,3 +219,54 @@ class _DirectoryBased(object):
# pick up RUNFILES_DIR.
"JAVA_RUNFILES": self._runfiles_root,
}
+
+
+def _PathsFrom(argv0, runfiles_mf, runfiles_dir, is_runfiles_manifest,
+ is_runfiles_directory):
+ """Discover runfiles manifest and runfiles directory paths.
+
+ Args:
+ argv0: string; the value of sys.argv[0]
+ runfiles_mf: string; the value of the RUNFILES_MANIFEST_FILE environment
+ variable
+ runfiles_dir: string; the value of the RUNFILES_DIR environment variable
+ is_runfiles_manifest: lambda(string):bool; returns true if the argument is
+ the path of a runfiles manifest file
+ is_runfiles_directory: lambda(string):bool; returns true if the argument is
+ the path of a runfiles directory
+
+ Returns:
+ (string, string) pair, first element is the path to the runfiles manifest,
+ second element is the path to the runfiles directory. If the first element
+ is non-empty, then is_runfiles_manifest returns true for it. Same goes for
+ the second element and is_runfiles_directory respectively. If both elements
+ are empty, then this function could not find a manifest or directory for
+ which is_runfiles_manifest or is_runfiles_directory returns true.
+ """
+ mf_alid = is_runfiles_manifest(runfiles_mf)
+ dir_valid = is_runfiles_directory(runfiles_dir)
+
+ if not mf_alid and not dir_valid:
+ runfiles_mf = argv0 + ".runfiles/MANIFEST"
+ runfiles_dir = argv0 + ".runfiles"
+ mf_alid = is_runfiles_manifest(runfiles_mf)
+ dir_valid = is_runfiles_directory(runfiles_dir)
+ if not mf_alid:
+ runfiles_mf = argv0 + ".runfiles_manifest"
+ mf_alid = is_runfiles_manifest(runfiles_mf)
+
+ if not mf_alid and not dir_valid:
+ return ("", "")
+
+ if not mf_alid:
+ runfiles_mf = runfiles_dir + "/MANIFEST"
+ mf_alid = is_runfiles_manifest(runfiles_mf)
+ if not mf_alid:
+ runfiles_mf = runfiles_dir + "_manifest"
+ mf_alid = is_runfiles_manifest(runfiles_mf)
+
+ if not dir_valid:
+ runfiles_dir = runfiles_mf[:-9] # "_manifest" or "/MANIFEST"
+ dir_valid = is_runfiles_directory(runfiles_dir)
+
+ return (runfiles_mf if mf_alid else "", runfiles_dir if dir_valid else "")
diff --git a/tools/python/runfiles/runfiles_test.py b/tools/python/runfiles/runfiles_test.py
index f8373054c8..1212bbaad8 100644
--- a/tools/python/runfiles/runfiles_test.py
+++ b/tools/python/runfiles/runfiles_test.py
@@ -167,6 +167,93 @@ class RunfilesTest(unittest.TestCase):
else:
self.assertEqual(r.Rlocation("/foo"), "/foo")
+ def testPathsFromEnvvars(self):
+ # Both envvars have a valid value.
+ mf, dr = runfiles._PathsFrom("argv0", "mock1/MANIFEST", "mock2",
+ lambda path: path == "mock1/MANIFEST",
+ lambda path: path == "mock2")
+ self.assertEqual(mf, "mock1/MANIFEST")
+ self.assertEqual(dr, "mock2")
+
+ # RUNFILES_MANIFEST_FILE is invalid but RUNFILES_DIR is good and there's a
+ # runfiles manifest in the runfiles directory.
+ mf, dr = runfiles._PathsFrom("argv0", "mock1/MANIFEST", "mock2",
+ lambda path: path == "mock2/MANIFEST",
+ lambda path: path == "mock2")
+ self.assertEqual(mf, "mock2/MANIFEST")
+ self.assertEqual(dr, "mock2")
+
+ # RUNFILES_MANIFEST_FILE is invalid but RUNFILES_DIR is good, but there's no
+ # runfiles manifest in the runfiles directory.
+ mf, dr = runfiles._PathsFrom("argv0", "mock1/MANIFEST", "mock2",
+ lambda path: False,
+ lambda path: path == "mock2")
+ self.assertEqual(mf, "")
+ self.assertEqual(dr, "mock2")
+
+ # RUNFILES_DIR is invalid but RUNFILES_MANIFEST_FILE is good, and it is in
+ # a valid-looking runfiles directory.
+ mf, dr = runfiles._PathsFrom("argv0", "mock1/MANIFEST", "mock2",
+ lambda path: path == "mock1/MANIFEST",
+ lambda path: path == "mock1")
+ self.assertEqual(mf, "mock1/MANIFEST")
+ self.assertEqual(dr, "mock1")
+
+ # RUNFILES_DIR is invalid but RUNFILES_MANIFEST_FILE is good, but it is not
+ # in any valid-looking runfiles directory.
+ mf, dr = runfiles._PathsFrom("argv0", "mock1/MANIFEST", "mock2",
+ lambda path: path == "mock1/MANIFEST",
+ lambda path: False)
+ self.assertEqual(mf, "mock1/MANIFEST")
+ self.assertEqual(dr, "")
+
+ # Both envvars are invalid, but there's a manifest in a runfiles directory
+ # next to argv0, however there's no other content in the runfiles directory.
+ mf, dr = runfiles._PathsFrom("argv0", "mock1/MANIFEST", "mock2",
+ lambda path: path == "argv0.runfiles/MANIFEST",
+ lambda path: False)
+ self.assertEqual(mf, "argv0.runfiles/MANIFEST")
+ self.assertEqual(dr, "")
+
+ # Both envvars are invalid, but there's a manifest next to argv0. There's
+ # no runfiles tree anywhere.
+ mf, dr = runfiles._PathsFrom("argv0", "mock1/MANIFEST", "mock2",
+ lambda path: path == "argv0.runfiles_manifest",
+ lambda path: False)
+ self.assertEqual(mf, "argv0.runfiles_manifest")
+ self.assertEqual(dr, "")
+
+ # Both envvars are invalid, but there's a valid manifest next to argv0, and
+ # a valid runfiles directory (without a manifest in it).
+ mf, dr = runfiles._PathsFrom("argv0", "mock1/MANIFEST", "mock2",
+ lambda path: path == "argv0.runfiles_manifest",
+ lambda path: path == "argv0.runfiles")
+ self.assertEqual(mf, "argv0.runfiles_manifest")
+ self.assertEqual(dr, "argv0.runfiles")
+
+ # Both envvars are invalid, but there's a valid runfiles directory next to
+ # argv0, though no manifest in it.
+ mf, dr = runfiles._PathsFrom("argv0", "mock1/MANIFEST", "mock2",
+ lambda path: False,
+ lambda path: path == "argv0.runfiles")
+ self.assertEqual(mf, "")
+ self.assertEqual(dr, "argv0.runfiles")
+
+ # Both envvars are invalid, but there's a valid runfiles directory next to
+ # argv0 with a valid manifest in it.
+ mf, dr = runfiles._PathsFrom("argv0", "mock1/MANIFEST", "mock2",
+ lambda path: path == "argv0.runfiles/MANIFEST",
+ lambda path: path == "argv0.runfiles")
+ self.assertEqual(mf, "argv0.runfiles/MANIFEST")
+ self.assertEqual(dr, "argv0.runfiles")
+
+ # Both envvars are invalid and there's no runfiles directory or manifest
+ # next to the argv0.
+ mf, dr = runfiles._PathsFrom("argv0", "mock1/MANIFEST", "mock2",
+ lambda path: False, lambda path: False)
+ self.assertEqual(mf, "")
+ self.assertEqual(dr, "")
+
@staticmethod
def IsWindows():
return os.name == "nt"