Skip to content

Commit

Permalink
runfiles,python: add a method to discover runfiles
Browse files Browse the repository at this point in the history
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 9f2b052
ported from C++ to Python.

See #4460

Change-Id: I6916366ca73575703fe39ce69020eec3b54457bf

Closes #5233.

Change-Id: I6916366ca73575703fe39ce69020eec3b54457bf
PiperOrigin-RevId: 197544480
  • Loading branch information
laszlocsomor authored and Copybara-Service committed May 22, 2018
1 parent a1ae44a commit c29f34f
Show file tree
Hide file tree
Showing 2 changed files with 138 additions and 0 deletions.
51 changes: 51 additions & 0 deletions tools/python/runfiles/runfiles.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,3 +219,54 @@ def EnvVars(self):
# 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 "")
87 changes: 87 additions & 0 deletions tools/python/runfiles/runfiles_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,93 @@ def testDirectoryBasedRlocation(self):
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"
Expand Down

0 comments on commit c29f34f

Please sign in to comment.