Skip to content

Commit

Permalink
runfiles library: py_binary can run java_binary
Browse files Browse the repository at this point in the history
Add "JAVA_RUNFILES" (and "RUNFILES_DIR") to the
dict that Runfiles.EnvVars() returns in the Python
runfiles library, so Python programs that use the
Python runfiles library in @bazel_tools can now
run java_binary data-dependencies as subprocesses
and the latter will find the runfiles.

See #4460

Change-Id: I0566f6d3c68631a1d99e67964fbe8019ee82324b
PiperOrigin-RevId: 185812948
  • Loading branch information
laszlocsomor authored and Copybara-Service committed Feb 15, 2018
1 parent 3edf41b commit bb1d085
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 25 deletions.
16 changes: 15 additions & 1 deletion src/test/py/bazel/runfiles_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ def testPythonRunfilesLibraryInBazelToolsRepo(self):
("bar/BUILD.mock", "bar/BUILD"),
("bar/bar.py", "bar/bar.py"),
("bar/bar-py-data.txt", "bar/bar-py-data.txt"),
("bar/Bar.java", "bar/Bar.java"),
("bar/bar-java-data.txt", "bar/bar-java-data.txt"),
]:
self.CopyFile(
self.Rlocation(
Expand All @@ -101,15 +103,21 @@ def testPythonRunfilesLibraryInBazelToolsRepo(self):
exit_code, stdout, stderr = self.RunProgram(
[bin_path], env_add={"TEST_SRCDIR": "__ignore_me__"})
self.AssertExitCode(exit_code, 0, stderr)
if len(stdout) < 4:
if len(stdout) != 6:
self.fail("stdout: %s" % stdout)

self.assertEqual(stdout[0], "Hello Python Foo!")
six.assertRegex(self, stdout[1], "^rloc=.*/foo/datadep/hello.txt")
self.assertNotIn("__ignore_me__", stdout[1])

self.assertEqual(stdout[2], "Hello Python Bar!")
six.assertRegex(self, stdout[3], "^rloc=.*/bar/bar-py-data.txt")
self.assertNotIn("__ignore_me__", stdout[3])

self.assertEqual(stdout[4], "Hello Java Bar!")
six.assertRegex(self, stdout[5], "^rloc=.*/bar/bar-java-data.txt")
self.assertNotIn("__ignore_me__", stdout[5])

with open(stdout[1].split("=", 1)[1], "r") as f:
lines = [l.strip() for l in f.readlines()]
if len(lines) != 1:
Expand All @@ -122,6 +130,12 @@ def testPythonRunfilesLibraryInBazelToolsRepo(self):
self.fail("lines: %s" % lines)
self.assertEqual(lines[0], "data for bar.py")

with open(stdout[5].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], "data for Bar.java")

def testRunfilesLibrariesFindRunfilesWithoutEnvvars(self):
for s, t in [
("WORKSPACE.mock", "WORKSPACE"),
Expand Down
1 change: 1 addition & 0 deletions src/test/py/bazel/testdata/runfiles_test/foo/BUILD.mock
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ py_binary(
data = [
"datadep/hello.txt",
"//bar:bar-py",
"//bar:bar-java",
],
main = "runfiles.py",
deps = ["@bazel_tools//tools/runfiles:py-runfiles"],
Expand Down
26 changes: 14 additions & 12 deletions src/test/py/bazel/testdata/runfiles_test/foo/runfiles.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,18 +53,20 @@ def main():
else:
env = {}
env.update(r.EnvVars())
p = subprocess.Popen(
[r.Rlocation(ChildBinaryName("py"))],
env=env,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
out, err = p.communicate()
out = SplitToLines(out)
if len(out) >= 2:
print(out[0]) # e.g. "Hello Python Bar!"
print(out[1]) # e.g. "rloc=/tmp/foo_ws/bar/bar-py-data.txt"
else:
raise Exception("ERROR: error running bar-py: %s" % SplitToLines(err))
for lang in ["py", "java"]:
p = subprocess.Popen(
[r.Rlocation(ChildBinaryName(lang))],
env=env,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
out, err = p.communicate()
out = SplitToLines(out)
if len(out) >= 2:
print(out[0]) # e.g. "Hello Python Bar!"
print(out[1]) # e.g. "rloc=/tmp/foo_ws/bar/bar-py-data.txt"
else:
raise Exception("ERROR: error running bar-%s: %s" % (lang,
SplitToLines(err)))


if __name__ == "__main__":
Expand Down
24 changes: 22 additions & 2 deletions src/tools/runfiles/runfiles.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,8 +175,23 @@ def _LoadRunfiles(path):
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):
return {"RUNFILES_MANIFEST_FILE": self._path}
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):
Expand All @@ -196,4 +211,9 @@ def RlocationChecked(self, path):
return posixpath.join(self._runfiles_root, path)

def EnvVars(self):
return {"RUNFILES_DIR": self._runfiles_root}
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,
}
67 changes: 57 additions & 10 deletions src/tools/runfiles/runfiles_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,54 @@ def testRlocationArgumentValidation(self):
lambda: r.Rlocation("/foo"))

def testCreatesManifestBasedRunfiles(self):
with _MockFile(["a/b c/d"]) as mf:
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"))
self.assertDictEqual(r.EnvVars(), {"RUNFILES_MANIFEST_FILE": mf.Path()})

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({
Expand All @@ -59,7 +98,16 @@ def testCreatesDirectoryBasedRunfiles(self):
})
self.assertEqual(r.Rlocation("a/b"), "runfiles/dir/a/b")
self.assertEqual(r.Rlocation("foo"), "runfiles/dir/foo")
self.assertDictEqual(r.EnvVars(), {"RUNFILES_DIR": "runfiles/dir"})

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):

Expand All @@ -69,7 +117,7 @@ def _Run():
self.assertRaisesRegexp(IOError, "non-existing path", _Run)

def testFailsToCreateAnyRunfilesBecauseEnvvarsAreNotDefined(self):
with _MockFile(["a b"]) as mf:
with _MockFile(contents=["a b"]) as mf:
runfiles.Create({
"RUNFILES_MANIFEST_FILE": mf.Path(),
"RUNFILES_DIR": "whatever",
Expand All @@ -83,7 +131,7 @@ def testFailsToCreateAnyRunfilesBecauseEnvvarsAreNotDefined(self):
self.assertIsNone(runfiles.Create({"FOO": "bar"}))

def testManifestBasedRlocation(self):
with _MockFile([
with _MockFile(contents=[
"Foo/runfile1", "Foo/runfile2 C:/Actual Path\\runfile2",
"Foo/Bar/runfile3 D:\\the path\\run file 3.txt"
]) as mf:
Expand All @@ -93,15 +141,13 @@ def testManifestBasedRlocation(self):
self.assertEqual(
r.Rlocation("Foo/Bar/runfile3"), "D:\\the path\\run file 3.txt")
self.assertIsNone(r.Rlocation("unknown"))
self.assertDictEqual(r.EnvVars(), {"RUNFILES_MANIFEST_FILE": mf.Path()})

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")
self.assertDictEqual(r.EnvVars(), {"RUNFILES_DIR": "foo/bar baz//qux/"})

@staticmethod
def IsWindows():
Expand All @@ -110,13 +156,14 @@ def IsWindows():

class _MockFile(object):

def __init__(self, contents):
self._contents = contents
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), "x")
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
Expand Down

0 comments on commit bb1d085

Please sign in to comment.