Skip to content

Commit

Permalink
Bash,runfiles: add tests
Browse files Browse the repository at this point in the history
The runfiles library can now discover where the
runfiles are.

Also remove the shebang line from the runfiles
library. This script should never by executed on
its own but be sourced by other Bash scripts.

See bazelbuild#4460

RELNOTES[NEW]: Bash,runfiles: use the new platform-independent library in `@bazel_tools//tools/bash/runfiles` to access runfiles (data-dependencies). See https://github.com/bazelbuild/bazel/blob/master/tools/bash/runfiles/runfiles.bash for usage information.

Closes bazelbuild#5071.

Change-Id: I94557133e76ecc927646d109e2611d711c363cdc
PiperOrigin-RevId: 193923870
  • Loading branch information
laszlocsomor authored and Copybara-Service committed Apr 23, 2018
1 parent 27b0bcf commit 8762165
Show file tree
Hide file tree
Showing 11 changed files with 238 additions and 42 deletions.
82 changes: 47 additions & 35 deletions src/test/py/bazel/runfiles_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,21 +32,23 @@ def testAttemptToBuildRunfilesOnWindows(self):
"\n".join(stderr))

def _AssertRunfilesLibraryInBazelToolsRepo(self, family, lang_name):
for s, t in [
("WORKSPACE.mock", "WORKSPACE"),
("foo/BUILD.mock", "foo/BUILD"),
("foo/foo.py", "foo/foo.py"),
("foo/Foo.java", "foo/Foo.java"),
("foo/datadep/hello.txt", "foo/datadep/hello.txt"),
("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"),
]:
for s, t, exe in [
("WORKSPACE.mock", "WORKSPACE", False),
("foo/BUILD.mock", "foo/BUILD", False),
("foo/foo.py", "foo/foo.py", True),
("foo/Foo.java", "foo/Foo.java", False),
("foo/foo.sh", "foo/foo.sh", True),
("foo/datadep/hello.txt", "foo/datadep/hello.txt", False),
("bar/BUILD.mock", "bar/BUILD", False),
("bar/bar.py", "bar/bar.py", True),
("bar/bar-py-data.txt", "bar/bar-py-data.txt", False),
("bar/Bar.java", "bar/Bar.java", False),
("bar/bar-java-data.txt", "bar/bar-java-data.txt", False),
("bar/bar.sh", "bar/bar.sh", True),
("bar/bar-sh-data.txt", "bar/bar-sh-data.txt", False)]:
self.CopyFile(
self.Rlocation(
"io_bazel/src/test/py/bazel/testdata/runfiles_test/" + s), t)
self.Rlocation("io_bazel/src/test/py/bazel/testdata/runfiles_test/" +
s), t, exe)

exit_code, stdout, stderr = self.RunBazel(["info", "bazel-bin"])
self.AssertExitCode(exit_code, 0, stderr)
Expand All @@ -65,7 +67,7 @@ def _AssertRunfilesLibraryInBazelToolsRepo(self, family, lang_name):
exit_code, stdout, stderr = self.RunProgram(
[bin_path], env_add={"TEST_SRCDIR": "__ignore_me__"})
self.AssertExitCode(exit_code, 0, stderr)
if len(stdout) != 6:
if len(stdout) != 8:
self.fail("stdout: %s" % stdout)

self.assertEqual(stdout[0], "Hello %s Foo!" % lang_name)
Expand All @@ -79,7 +81,8 @@ def _AssertRunfilesLibraryInBazelToolsRepo(self, family, lang_name):
self.assertEqual(lines[0], "world")

i = 2
for lang in [("py", "Python", "bar.py"), ("java", "Java", "Bar.java")]:
for lang in [("py", "Python", "bar.py"), ("java", "Java", "Bar.java"),
("sh", "Bash", "bar.sh")]:
self.assertEqual(stdout[i], "Hello %s Bar!" % lang[1])
six.assertRegex(self, stdout[i + 1],
"^rloc=.*/bar/bar-%s-data.txt" % lang[0])
Expand All @@ -99,28 +102,34 @@ def testPythonRunfilesLibraryInBazelToolsRepo(self):
def testJavaRunfilesLibraryInBazelToolsRepo(self):
self._AssertRunfilesLibraryInBazelToolsRepo("java", "Java")

def testBashRunfilesLibraryInBazelToolsRepo(self):
self._AssertRunfilesLibraryInBazelToolsRepo("sh", "Bash")

def testRunfilesLibrariesFindRunfilesWithoutEnvvars(self):
for s, t in [
("WORKSPACE.mock", "WORKSPACE"),
("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"),
for s, t, exe in [
("WORKSPACE.mock", "WORKSPACE", False),
("bar/BUILD.mock", "bar/BUILD", False),
("bar/bar.py", "bar/bar.py", True),
("bar/bar-py-data.txt", "bar/bar-py-data.txt", False),
("bar/Bar.java", "bar/Bar.java", False),
("bar/bar-java-data.txt", "bar/bar-java-data.txt", False),
("bar/bar.sh", "bar/bar.sh", True),
("bar/bar-sh-data.txt", "bar/bar-sh-data.txt", False),
]:
self.CopyFile(
self.Rlocation(
"io_bazel/src/test/py/bazel/testdata/runfiles_test/" + s), t)
self.Rlocation("io_bazel/src/test/py/bazel/testdata/runfiles_test/" +
s), t, exe)

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", "//bar:bar-py", "//bar:bar-java"])
["build", "//bar:bar-py", "//bar:bar-java", "//bar:bar-sh"])
self.AssertExitCode(exit_code, 0, stderr)

for lang in [("py", "Python", "bar.py"), ("java", "Java", "Bar.java")]:
for lang in [("py", "Python", "bar.py"), ("java", "Java", "Bar.java"),
("sh", "Bash", "bar.sh")]:
if test_base.TestBase.IsWindows():
bin_path = os.path.join(bazel_bin, "bar/bar-%s.exe" % lang[0])
else:
Expand Down Expand Up @@ -151,25 +160,28 @@ def testRunfilesLibrariesFindRunfilesWithoutEnvvars(self):
self.assertEqual(lines[0], "data for " + lang[2])

def testRunfilesLibrariesFindRunfilesWithRunfilesManifestEnvvar(self):
for s, t in [
("WORKSPACE.mock", "WORKSPACE"),
("bar/BUILD.mock", "bar/BUILD"),
for s, t, exe in [
("WORKSPACE.mock", "WORKSPACE", False),
("bar/BUILD.mock", "bar/BUILD", False),
# 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"),
("bar/Bar.java", "bar/Bar.java", False),
("bar/bar-java-data.txt", "bar/bar-java-data.txt", False),
("bar/bar.sh", "bar/bar.sh", True),
("bar/bar-sh-data.txt", "bar/bar-sh-data.txt", False),
]:
self.CopyFile(
self.Rlocation(
"io_bazel/src/test/py/bazel/testdata/runfiles_test/" + s), t)
self.Rlocation("io_bazel/src/test/py/bazel/testdata/runfiles_test/" +
s), t, exe)

exit_code, stdout, stderr = self.RunBazel(["info", "bazel-bin"])
self.AssertExitCode(exit_code, 0, stderr)
bazel_bin = stdout[0]

for lang in [("java", "Java")]: # TODO(laszlocsomor): add "cc" when ready.
for lang in [("java", "Java"),
("sh", "Bash")]: # TODO(laszlocsomor): add "cc" when ready.
exit_code, _, stderr = self.RunBazel([
"build", "--experimental_enable_runfiles=no", "//bar:bar-" + lang[0]
])
Expand Down
7 changes: 7 additions & 0 deletions src/test/py/bazel/testdata/runfiles_test/bar/BUILD.mock
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,10 @@ java_binary(
main_class = "Bar",
deps = ["@bazel_tools//tools/runfiles:java-runfiles"],
)

sh_binary(
name = "bar-sh",
srcs = ["bar.sh"],
data = ["bar-sh-data.txt"],
deps = ["@bazel_tools//tools/bash/runfiles"],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
data for bar.sh
41 changes: 41 additions & 0 deletions src/test/py/bazel/testdata/runfiles_test/bar/bar.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#!/bin/bash
# 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.

set -euo pipefail
# --- begin runfiles.bash initialization ---
if [[ "${RUNFILES_MANIFEST_ONLY:-}" != 1 && -z "${RUNFILES_DIR:-}" ]]; then
if [[ -f "$0.runfiles_manifest" ]]; then
export RUNFILES_MANIFEST_ONLY=1
export RUNFILES_MANIFEST_FILE="$0.runfiles_manifest"
elif [[ -f "$0.runfiles/MANIFEST" ]]; then
export RUNFILES_MANIFEST_ONLY=1
export RUNFILES_MANIFEST_FILE="$0.runfiles/MANIFEST"
elif [[ -d "$0.runfiles" ]]; then
export RUNFILES_DIR="$0.runfiles"
fi
fi
if [[ "${RUNFILES_MANIFEST_ONLY:-}" == 1 && -f "${RUNFILES_MANIFEST_FILE:-}" ]]; then
source "$(grep -m1 "^bazel_tools/tools/bash/runfiles/runfiles.bash " \
"$RUNFILES_MANIFEST_FILE" | cut -d ' ' -f 2-)"
elif [[ -n "${RUNFILES_DIR:-}" && -d "${RUNFILES_DIR}" ]]; then
source "${RUNFILES_DIR}/bazel_tools/tools/bash/runfiles/runfiles.bash"
else
echo >&2 "ERROR: cannot find @bazel_tools//tools/bash/runfiles:runfiles.bash"
exit 1
fi
# --- end runfiles.bash initialization ---

echo "Hello Bash Bar!"
echo "rloc=$(rlocation "foo_ws/bar/bar-sh-data.txt")"
16 changes: 15 additions & 1 deletion src/test/py/bazel/testdata/runfiles_test/foo/BUILD.mock
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ py_binary(
srcs = ["foo.py"],
data = [
"datadep/hello.txt",
"//bar:bar-py",
"//bar:bar-java",
"//bar:bar-py",
"//bar:bar-sh",
],
main = "foo.py",
deps = ["@bazel_tools//tools/python/runfiles"],
Expand All @@ -17,7 +18,20 @@ java_binary(
"datadep/hello.txt",
"//bar:bar-py",
"//bar:bar-java",
"//bar:bar-sh",
],
main_class = "Foo",
deps = ["@bazel_tools//tools/runfiles:java-runfiles"],
)

sh_binary(
name = "runfiles-sh",
srcs = ["foo.sh"],
data = [
"datadep/hello.txt",
"//bar:bar-java",
"//bar:bar-py",
"//bar:bar-sh",
],
deps = ["@bazel_tools//tools/bash/runfiles"],
)
2 changes: 1 addition & 1 deletion src/test/py/bazel/testdata/runfiles_test/foo/Foo.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public static void main(String[] args) throws IOException, InterruptedException
Runfiles r = Runfiles.create();
System.out.println("rloc=" + r.rlocation("foo_ws/foo/datadep/hello.txt"));

for (String lang : new String[] {"py", "java"}) {
for (String lang : new String[] {"py", "java", "sh"}) {
String path = r.rlocation(childBinaryName(lang));
if (path == null || path.isEmpty()) {
throw new IOException("cannot find child binary for " + lang);
Expand Down
2 changes: 1 addition & 1 deletion src/test/py/bazel/testdata/runfiles_test/foo/foo.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def main():
else:
env = {}
env.update(r.EnvVars())
for lang in ["py", "java"]:
for lang in ["py", "java", "sh"]:
p = subprocess.Popen(
[r.Rlocation(ChildBinaryName(lang))],
env=env,
Expand Down
82 changes: 82 additions & 0 deletions src/test/py/bazel/testdata/runfiles_test/foo/foo.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#!/bin/bash
# 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.

set -euo pipefail
# --- begin runfiles.bash initialization ---
if [[ "${RUNFILES_MANIFEST_ONLY:-}" != 1 && -z "${RUNFILES_DIR:-}" ]]; then
if [[ -f "$0.runfiles_manifest" ]]; then
export RUNFILES_MANIFEST_ONLY=1
export RUNFILES_MANIFEST_FILE="$0.runfiles_manifest"
elif [[ -f "$0.runfiles/MANIFEST" ]]; then
export RUNFILES_MANIFEST_ONLY=1
export RUNFILES_MANIFEST_FILE="$0.runfiles/MANIFEST"
elif [[ -d "$0.runfiles" ]]; then
export RUNFILES_DIR="$0.runfiles"
fi
fi
if [[ "${RUNFILES_MANIFEST_ONLY:-}" == 1 && -f "${RUNFILES_MANIFEST_FILE:-}" ]]; then
source "$(grep -m1 "^bazel_tools/tools/bash/runfiles/runfiles.bash " \
"$RUNFILES_MANIFEST_FILE" | cut -d ' ' -f 2-)"
elif [[ -n "${RUNFILES_DIR:-}" && -d "${RUNFILES_DIR}" ]]; then
source "${RUNFILES_DIR}/bazel_tools/tools/bash/runfiles/runfiles.bash"
else
echo >&2 "ERROR: cannot find @bazel_tools//tools/bash/runfiles:runfiles.bash"
exit 1
fi
# --- end runfiles.bash initialization ---

if ! type rlocation >&/dev/null; then
echo >&2 "ERROR: rlocation is undefined"
exit 1
fi

case "$(uname -s | tr [:upper:] [:lower:])" in
msys*|mingw*|cygwin*)
function is_windows() { true ; }
;;
*)
function is_windows() { false ; }
;;
esac

function child_binary_name() {
local lang=$1
if is_windows; then
echo "foo_ws/bar/bar-${lang}.exe"
else
echo "foo_ws/bar/bar-${lang}"
fi
}

function main() {
echo "Hello Bash Foo!"
echo "rloc=$(rlocation "foo_ws/foo/datadep/hello.txt")"

# Run a subprocess, propagate the runfiles envvar to it. The subprocess will
# use this process's runfiles manifest or runfiles directory.
runfiles_export_envvars
if is_windows; then
export SYSTEMROOT="${SYSTEMROOT:-}"
fi
for lang in py java sh; do
child_bin="$(rlocation "$(child_binary_name $lang)")"
if ! "$child_bin"; then
echo >&2 "ERROR: error running bar-$lang"
exit 1
fi
done
}

main
7 changes: 5 additions & 2 deletions tools/bash/runfiles/BUILD.tools
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
# This package will host the Bash runfiles library.
# See https://github.com/bazelbuild/bazel/issues/4460
sh_library(
name = "runfiles",
srcs = ["runfiles.bash"],
visibility = ["//visibility:public"],
)
40 changes: 38 additions & 2 deletions tools/bash/runfiles/runfiles.bash
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
#!/bin/bash
#
# Copyright 2018 The Bazel Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
Expand All @@ -24,6 +22,44 @@
# to the absolute path of the runfiles manifest. RUNFILES_DIR may be unset in
# this case.
# - If RUNFILES_LIB_DEBUG=1 is set, the script will print errors to stderr.
#
# USAGE:
# 1. Depend on this runfiles library from your build rule:
#
# sh_binary(
# name = "my_binary",
# ...
# deps = ["@bazel_tools//tools/bash/runfiles"],
# )
#
# 2. Source the runfiles library.
# The runfiles library itself defines rlocation which you would need to look
# up the library's runtime location, thus we have a chicken-and-egg problem.
# Insert the following code snippet to the top of your main script:
#
# set -euo pipefail
# # --- begin runfiles.bash initialization ---
# if [[ "${RUNFILES_MANIFEST_ONLY:-}" != 1 && -z "${RUNFILES_DIR:-}" ]]; then
# if [[ -f "$0.runfiles_manifest" ]]; then
# export RUNFILES_MANIFEST_ONLY=1
# export RUNFILES_MANIFEST_FILE="$0.runfiles_manifest"
# elif [[ -f "$0.runfiles/MANIFEST" ]]; then
# export RUNFILES_MANIFEST_ONLY=1
# export RUNFILES_MANIFEST_FILE="$0.runfiles/MANIFEST"
# elif [[ -d "$0.runfiles" ]]; then
# export RUNFILES_DIR="$0.runfiles"
# fi
# fi
# if [[ "${RUNFILES_MANIFEST_ONLY:-}" == 1 && -f "${RUNFILES_MANIFEST_FILE:-}" ]]; then
# source "$(grep -m1 "^bazel_tools/tools/bash/runfiles/runfiles.bash " \
# "$RUNFILES_MANIFEST_FILE" | cut -d ' ' -f 2-)"
# elif [[ -n "${RUNFILES_DIR:-}" && -d "${RUNFILES_DIR}" ]]; then
# source "${RUNFILES_DIR}/bazel_tools/tools/bash/runfiles/runfiles.bash"
# else
# echo >&2 "ERROR: cannot find @bazel_tools//tools/bash/runfiles:runfiles.bash"
# exit 1
# fi
# # --- end runfiles.bash initialization ---

case "$(uname -s | tr [:upper:] [:lower:])" in
msys*|mingw*|cygwin*)
Expand Down
Empty file modified tools/bash/runfiles/runfiles_test.bash
100644 → 100755
Empty file.

0 comments on commit 8762165

Please sign in to comment.