diff --git a/tools/python/gen_runfiles_constants.bzl b/tools/python/gen_runfiles_constants.bzl deleted file mode 100644 index 973a8f0c98a975..00000000000000 --- a/tools/python/gen_runfiles_constants.bzl +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2022 The Bazel Authors. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""A rule to generate a Python source file containing the main repo's -runfiles directory name.""" - -_RUNFILES_CONSTANTS_TEMPLATE = """# Generated by gen_runfiles_constants.bzl -# Internal-only; do no use. -# The name of the runfiles directory corresponding to the main repository. -MAIN_REPOSITORY_RUNFILES_DIRECTORY = '%s' -""" - -def _gen_runfiles_constants_impl(ctx): - out = ctx.actions.declare_file(ctx.attr.name + ".py") - ctx.actions.write(out, _RUNFILES_CONSTANTS_TEMPLATE % ctx.workspace_name) - - return DefaultInfo( - files = depset([out]), - runfiles = ctx.runfiles([out]), - ) - -gen_runfiles_constants = rule( - implementation = _gen_runfiles_constants_impl, -) diff --git a/tools/python/runfiles/BUILD b/tools/python/runfiles/BUILD index 49d3964d0692c0..0e787c5d94f0b3 100644 --- a/tools/python/runfiles/BUILD +++ b/tools/python/runfiles/BUILD @@ -1,6 +1,3 @@ -load("@rules_python//python:defs.bzl", "py_library", "py_test") -load("//tools/python:gen_runfiles_constants.bzl", "gen_runfiles_constants") - package(default_visibility = ["//visibility:private"]) filegroup( @@ -17,23 +14,3 @@ filegroup( ], visibility = ["//tools/python:__pkg__"], ) - -py_library( - name = "runfiles", - testonly = 1, - srcs = [ - "runfiles.py", - ":_runfiles_constants", - ], -) - -gen_runfiles_constants( - name = "_runfiles_constants", -) - -py_test( - name = "runfiles_test", - srcs = ["runfiles_test.py"], - visibility = ["//visibility:public"], - deps = [":runfiles"], -) diff --git a/tools/python/runfiles/BUILD.tools b/tools/python/runfiles/BUILD.tools index e7110ba72ad927..986b6e89a2b3de 100644 --- a/tools/python/runfiles/BUILD.tools +++ b/tools/python/runfiles/BUILD.tools @@ -1,15 +1,12 @@ -load("//tools/python:gen_runfiles_constants.bzl", "gen_runfiles_constants") load("@rules_python//python:defs.bzl", "py_library") py_library( name = "runfiles", srcs = [ "runfiles.py", - ":_runfiles_constants", + ], + deps = [ + "@rules_python//python/runfiles", ], visibility = ["//visibility:public"], ) - -gen_runfiles_constants( - name = "_runfiles_constants", -) diff --git a/tools/python/runfiles/runfiles.py b/tools/python/runfiles/runfiles.py index 72de4da8f5174a..48128a255d8925 100644 --- a/tools/python/runfiles/runfiles.py +++ b/tools/python/runfiles/runfiles.py @@ -11,363 +11,15 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -"""Runfiles lookup library for Bazel-built Python binaries and tests. +"""Deprecated forwarder for the rules_python runfiles library. -USAGE: - -1. Depend on this runfiles library from your build rule: - - py_binary( - name = "my_binary", - ... - deps = ["@rules_python//python/runfiles"], - ) - -2. Import the runfiles library. - - from rules_python.python.runfiles import runfiles - -3. Create a Runfiles object and use rlocation to look up runfile paths: - - r = runfiles.Create() - ... - with open(r.Rlocation("my_workspace/path/to/my/data.txt"), "r") as f: - contents = f.readlines() - ... - - The code above creates a manifest- or directory-based implementations based - on the environment variables in os.environ. See `Create()` for more info. - - If you want to explicitly create a manifest- or directory-based - implementations, you can do so as follows: - - r1 = runfiles.CreateManifestBased("path/to/foo.runfiles_manifest") - - r2 = runfiles.CreateDirectoryBased("path/to/foo.runfiles/") - - If you want to start subprocesses that also need runfiles, you need to set - the right environment variables for them: - - import subprocess - from rules_python.python.runfiles import runfiles - - r = runfiles.Create() - env = {} - ... - env.update(r.EnvVars()) - p = subprocess.Popen([r.Rlocation("path/to/binary")], env, ...) +Depend on @rules_python//python/runfiles instead and refer to its documentation: +https://github.com/bazelbuild/rules_python/blob/main/python/runfiles/README.md """ +from python.runfiles import Create as _Create +from python.runfiles import CreateDirectoryBased as _CreateDirectoryBased +from python.runfiles import CreateManifestBased as _CreateManifestBased -import inspect -import os -import posixpath -import sys - -from ._runfiles_constants import MAIN_REPOSITORY_RUNFILES_DIRECTORY - - -def CreateManifestBased(manifest_path): - return _Runfiles(_ManifestBased(manifest_path)) - - -def CreateDirectoryBased(runfiles_dir_path): - return _Runfiles(_DirectoryBased(runfiles_dir_path)) - - -def Create(env=None): - """Returns a new `Runfiles` instance. - - The returned object is either: - - manifest-based, meaning it looks up runfile paths from a manifest file, or - - directory-based, meaning it looks up runfile paths under a given directory - path - - If `env` contains "RUNFILES_MANIFEST_FILE" with non-empty value, this method - returns a manifest-based implementation. The object eagerly reads and caches - the whole manifest file upon instantiation; this may be relevant for - performance consideration. - - Otherwise, if `env` contains "RUNFILES_DIR" with non-empty value (checked in - this priority order), this method returns a directory-based implementation. - - If neither cases apply, this method returns null. - - Args: - env: {string: string}; optional; the map of environment variables. If None, - this function uses the environment variable map of this process. - Raises: - IOError: if some IO error occurs. - """ - env_map = os.environ if env is None else env - manifest = env_map.get("RUNFILES_MANIFEST_FILE") - if manifest: - return CreateManifestBased(manifest) - - directory = env_map.get("RUNFILES_DIR") - if not directory: - directory = env_map.get("PYTHON_RUNFILES") - if directory: - return CreateDirectoryBased(directory) - - return None - - -class _Runfiles(object): - """Returns the runtime location of runfiles. - - Runfiles are data-dependencies of Bazel-built binaries and tests. - """ - - def __init__(self, strategy): - self._strategy = strategy - self._python_runfiles_root = _FindPythonRunfilesRoot() - - def Rlocation(self, path): - """Returns the runtime path of a runfile. - - Runfiles are data-dependencies of Bazel-built binaries and tests. - - The returned path may not be valid. The caller should check the path's - validity and that the path exists. - - The function may return None. In that case the caller can be sure that the - rule does not know about this data-dependency. - - Args: - path: string; runfiles-root-relative path of the runfile - Returns: - the path to the runfile, which the caller should check for existence, or - None if the method doesn't know about this runfile - Raises: - TypeError: if `path` is not a string - ValueError: if `path` is None or empty, or it's absolute or not normalized - """ - if not path: - raise ValueError() - if not isinstance(path, str): - raise TypeError() - if (path.startswith("../") or "/.." in path or path.startswith("./") or - "/./" in path or path.endswith("/.") or "//" in path): - raise ValueError("path is not normalized: \"%s\"" % path) - if path[0] == "\\": - raise ValueError("path is absolute without a drive letter: \"%s\"" % path) - if os.path.isabs(path): - return path - return self._strategy.RlocationChecked(path) - - def EnvVars(self): - """Returns environment variables for subprocesses. - - The caller should set the returned key-value pairs in the environment of - subprocesses in case those subprocesses are also Bazel-built binaries that - need to use runfiles. - - Returns: - {string: string}; a dict; keys are environment variable names, values are - the values for these environment variables - """ - return self._strategy.EnvVars() - - def CurrentRepository(self, frame=1): - """Returns the canonical name of the caller's Bazel repository. - - For example, this function returns '' (the empty string) when called from - the main repository and a string of the form 'rules_python+0.13.0` when - called from code in the repository corresponding to the rules_python Bazel - module. - - More information about the difference between canonical repository names and - the `@repo` part of labels is available at: - https://bazel.build/build/bzlmod#repository-names - - NOTE: This function inspects the callstack to determine where in the - runfiles the caller is located to determine which repository it came from. - This may fail or produce incorrect results depending on who the caller is, - for example if it is not represented by a Python source file. Use the - `frame` argument to control the stack lookup. - - Args: - frame: int; the stack frame to return the repository name for. Defaults to - 1, the caller of the CurrentRepository function. - - Returns: - The canonical name of the Bazel repository containing the file containing - the frame-th caller of this function - Raises: - ValueError: if the caller cannot be determined or the caller's file path - is not contained in the Python runfiles tree - """ - # pylint:disable=protected-access # for sys._getframe - # pylint:disable=raise-missing-from # we're still supporting Python 2... - try: - caller_path = inspect.getfile(sys._getframe(frame)) - except (TypeError, ValueError): - raise ValueError("failed to determine caller's file path") - caller_runfiles_path = os.path.relpath(caller_path, - self._python_runfiles_root) - if caller_runfiles_path.startswith(".." + os.path.sep): - raise ValueError("{} does not lie under the runfiles root {}".format( - caller_path, self._python_runfiles_root)) - - caller_runfiles_directory = caller_runfiles_path[:caller_runfiles_path - .find(os.path.sep)] - if caller_runfiles_directory == MAIN_REPOSITORY_RUNFILES_DIRECTORY: - # The canonical name of the main repository (also known as the workspace) - # is the empty string. - return "" - # For all other repositories, the name of the runfiles directory is the - # canonical name. - return caller_runfiles_directory - - -def _FindPythonRunfilesRoot(): - """Finds the root of the Python runfiles tree.""" - root = __file__ - # Walk up our own runfiles path to the root of the runfiles tree from which - # the current file is being run. This path coincides with what the Bazel - # Python stub sets up as sys.path[0]. Since that entry can be changed at - # runtime, we rederive it here. - for _ in range( - "bazel_tools/tools/python/runfiles/runfiles.py".count("/") + - 1): - root = os.path.dirname(root) - return root - - -class _ManifestBased(object): - """`Runfiles` strategy that parses a runfiles-manifest to look up runfiles.""" - - def __init__(self, path): - if not path: - raise ValueError() - if not isinstance(path, str): - raise TypeError() - self._path = path - self._runfiles = _ManifestBased._LoadRunfiles(path) - - def RlocationChecked(self, path): - """Returns the runtime path of a runfile.""" - exact_match = self._runfiles.get(path) - if exact_match: - return exact_match - # If path references a runfile that lies under a directory that itself is a - # runfile, then only the directory is listed in the manifest. Look up all - # prefixes of path in the manifest and append the relative path from the - # prefix to the looked up path. - prefix_end = len(path) - while True: - prefix_end = path.rfind("/", 0, prefix_end - 1) - if prefix_end == -1: - return None - prefix_match = self._runfiles.get(path[0:prefix_end]) - if prefix_match: - return prefix_match + "/" + path[prefix_end + 1:] - - @staticmethod - def _LoadRunfiles(path): - """Loads the runfiles manifest.""" - result = {} - with open(path, "r") as f: - for line in f: - line = line.strip() - if line: - tokens = line.split(" ", 1) - if len(tokens) == 1: - result[line] = line - else: - result[tokens[0]] = tokens[1] - return result - - def _GetRunfilesDir(self): - if self._path.endswith("/MANIFEST") or self._path.endswith("\\MANIFEST"): - return self._path[:-len("/MANIFEST")] - elif self._path.endswith(".runfiles_manifest"): - return self._path[:-len("_manifest")] - else: - return "" - - def EnvVars(self): - directory = self._GetRunfilesDir() - return { - "RUNFILES_MANIFEST_FILE": self._path, - "RUNFILES_DIR": directory, - # TODO(laszlocsomor): remove JAVA_RUNFILES once the Java launcher can - # pick up RUNFILES_DIR. - "JAVA_RUNFILES": directory, - } - - -class _DirectoryBased(object): - """`Runfiles` strategy that appends runfiles paths to the runfiles root.""" - - def __init__(self, path): - if not path: - raise ValueError() - if not isinstance(path, str): - raise TypeError() - self._runfiles_root = path - - def RlocationChecked(self, path): - # Use posixpath instead of os.path, because Bazel only creates a runfiles - # tree on Unix platforms, so `Create()` will only create a directory-based - # runfiles strategy on those platforms. - return posixpath.join(self._runfiles_root, path) - - def EnvVars(self): - return { - "RUNFILES_DIR": self._runfiles_root, - # TODO(laszlocsomor): remove JAVA_RUNFILES once the Java launcher can - # 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 "") +Create = _Create +CreateDirectoryBased = _CreateDirectoryBased +CreateManifestBased = _CreateManifestBased diff --git a/tools/python/runfiles/runfiles_test.py b/tools/python/runfiles/runfiles_test.py deleted file mode 100644 index 266e0332c7d9e6..00000000000000 --- a/tools/python/runfiles/runfiles_test.py +++ /dev/null @@ -1,297 +0,0 @@ -# pylint: disable=g-bad-file-header -# Copyright 2018 The Bazel Authors. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import os -import tempfile -import unittest - -from tools.python.runfiles import runfiles - - -class RunfilesTest(unittest.TestCase): - # """Unit tests for `runfiles.Runfiles`.""" - - def testRlocationArgumentValidation(self): - r = runfiles.Create({"RUNFILES_DIR": "whatever"}) - self.assertRaises(ValueError, lambda: r.Rlocation(None)) - self.assertRaises(ValueError, lambda: r.Rlocation("")) - self.assertRaises(TypeError, lambda: r.Rlocation(1)) - self.assertRaisesRegex(ValueError, "is not normalized", - lambda: r.Rlocation("../foo")) - self.assertRaisesRegex(ValueError, "is not normalized", - lambda: r.Rlocation("foo/..")) - self.assertRaisesRegex(ValueError, "is not normalized", - lambda: r.Rlocation("foo/../bar")) - self.assertRaisesRegex(ValueError, "is not normalized", - lambda: r.Rlocation("./foo")) - self.assertRaisesRegex(ValueError, "is not normalized", - lambda: r.Rlocation("foo/.")) - self.assertRaisesRegex(ValueError, "is not normalized", - lambda: r.Rlocation("foo/./bar")) - self.assertRaisesRegex(ValueError, "is not normalized", - lambda: r.Rlocation("//foobar")) - self.assertRaisesRegex(ValueError, "is not normalized", - lambda: r.Rlocation("foo//")) - self.assertRaisesRegex(ValueError, "is not normalized", - lambda: r.Rlocation("foo//bar")) - self.assertRaisesRegex(ValueError, "is absolute without a drive letter", - lambda: r.Rlocation("\\foo")) - - def testCreatesManifestBasedRunfiles(self): - with _MockFile(contents=["a/b c/d"]) as mf: - r = runfiles.Create({ - "RUNFILES_MANIFEST_FILE": mf.Path(), - "RUNFILES_DIR": "ignored when RUNFILES_MANIFEST_FILE has a value", - "TEST_SRCDIR": "always ignored", - }) - self.assertEqual(r.Rlocation("a/b"), "c/d") - self.assertIsNone(r.Rlocation("foo")) - - def testManifestBasedRunfilesEnvVars(self): - with _MockFile(name="MANIFEST") as mf: - r = runfiles.Create({ - "RUNFILES_MANIFEST_FILE": mf.Path(), - "TEST_SRCDIR": "always ignored", - }) - self.assertDictEqual( - r.EnvVars(), { - "RUNFILES_MANIFEST_FILE": mf.Path(), - "RUNFILES_DIR": mf.Path()[:-len("/MANIFEST")], - "JAVA_RUNFILES": mf.Path()[:-len("/MANIFEST")], - }) - - with _MockFile(name="foo.runfiles_manifest") as mf: - r = runfiles.Create({ - "RUNFILES_MANIFEST_FILE": mf.Path(), - "TEST_SRCDIR": "always ignored", - }) - self.assertDictEqual( - r.EnvVars(), { - "RUNFILES_MANIFEST_FILE": - mf.Path(), - "RUNFILES_DIR": ( - mf.Path()[:-len("foo.runfiles_manifest")] + "foo.runfiles"), - "JAVA_RUNFILES": ( - mf.Path()[:-len("foo.runfiles_manifest")] + "foo.runfiles"), - }) - - with _MockFile(name="x_manifest") as mf: - r = runfiles.Create({ - "RUNFILES_MANIFEST_FILE": mf.Path(), - "TEST_SRCDIR": "always ignored", - }) - self.assertDictEqual( - r.EnvVars(), { - "RUNFILES_MANIFEST_FILE": mf.Path(), - "RUNFILES_DIR": "", - "JAVA_RUNFILES": "", - }) - - def testCreatesDirectoryBasedRunfiles(self): - r = runfiles.Create({ - "RUNFILES_DIR": "runfiles/dir", - "TEST_SRCDIR": "always ignored", - }) - self.assertEqual(r.Rlocation("a/b"), "runfiles/dir/a/b") - self.assertEqual(r.Rlocation("foo"), "runfiles/dir/foo") - - def testDirectoryBasedRunfilesEnvVars(self): - r = runfiles.Create({ - "RUNFILES_DIR": "runfiles/dir", - "TEST_SRCDIR": "always ignored", - }) - self.assertDictEqual(r.EnvVars(), { - "RUNFILES_DIR": "runfiles/dir", - "JAVA_RUNFILES": "runfiles/dir", - }) - - def testFailsToCreateManifestBasedBecauseManifestDoesNotExist(self): - - def _Run(): - runfiles.Create({"RUNFILES_MANIFEST_FILE": "non-existing path"}) - - self.assertRaisesRegex(IOError, "non-existing path", _Run) - - def testFailsToCreateAnyRunfilesBecauseEnvvarsAreNotDefined(self): - with _MockFile(contents=["a b"]) as mf: - runfiles.Create({ - "RUNFILES_MANIFEST_FILE": mf.Path(), - "RUNFILES_DIR": "whatever", - "TEST_SRCDIR": "always ignored", - }) - runfiles.Create({ - "RUNFILES_DIR": "whatever", - "TEST_SRCDIR": "always ignored", - }) - self.assertIsNone(runfiles.Create({"TEST_SRCDIR": "always ignored"})) - self.assertIsNone(runfiles.Create({"FOO": "bar"})) - - def testManifestBasedRlocation(self): - with _MockFile(contents=[ - "Foo/runfile1", - "Foo/runfile2 C:/Actual Path\\runfile2", - "Foo/Bar/runfile3 D:\\the path\\run file 3.txt", - "Foo/Bar/Dir E:\\Actual Path\\Directory", - ]) as mf: - r = runfiles.CreateManifestBased(mf.Path()) - self.assertEqual(r.Rlocation("Foo/runfile1"), "Foo/runfile1") - self.assertEqual(r.Rlocation("Foo/runfile2"), "C:/Actual Path\\runfile2") - self.assertEqual( - r.Rlocation("Foo/Bar/runfile3"), "D:\\the path\\run file 3.txt") - self.assertEqual( - r.Rlocation("Foo/Bar/Dir/runfile4"), - "E:\\Actual Path\\Directory/runfile4") - self.assertEqual( - r.Rlocation("Foo/Bar/Dir/Deeply/Nested/runfile4"), - "E:\\Actual Path\\Directory/Deeply/Nested/runfile4") - self.assertIsNone(r.Rlocation("unknown")) - if RunfilesTest.IsWindows(): - self.assertEqual(r.Rlocation("c:/foo"), "c:/foo") - self.assertEqual(r.Rlocation("c:\\foo"), "c:\\foo") - else: - self.assertEqual(r.Rlocation("/foo"), "/foo") - - def testDirectoryBasedRlocation(self): - # The _DirectoryBased strategy simply joins the runfiles directory and the - # runfile's path on a "/". This strategy does not perform any normalization, - # nor does it check that the path exists. - r = runfiles.CreateDirectoryBased("foo/bar baz//qux/") - self.assertEqual(r.Rlocation("arg"), "foo/bar baz//qux/arg") - if RunfilesTest.IsWindows(): - self.assertEqual(r.Rlocation("c:/foo"), "c:/foo") - self.assertEqual(r.Rlocation("c:\\foo"), "c:\\foo") - 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, "") - - def testCurrentRepository(self): - self.assertEqual( - runfiles.Create({"RUNFILES_DIR": "whatever"}).CurrentRepository(), "") - - @staticmethod - def IsWindows(): - return os.name == "nt" - - -class _MockFile(object): - - def __init__(self, name=None, contents=None): - self._contents = contents or [] - self._name = name or "x" - self._path = None - - def __enter__(self): - tmpdir = os.environ.get("TEST_TMPDIR") - self._path = os.path.join(tempfile.mkdtemp(dir=tmpdir), self._name) - with open(self._path, "wt") as f: - f.writelines(l + "\n" for l in self._contents) - return self - - def __exit__(self, exc_type, exc_value, traceback): - os.remove(self._path) - os.rmdir(os.path.dirname(self._path)) - - def Path(self): - return self._path - - -if __name__ == "__main__": - unittest.main()