runfiles libraries: fix tests and comments - Update all runfiles libraries to have the same header comment format, including the build rule to depend on the namespace / header / module to import - Fix runfiles_test.cc to include the right files (recent refactoring commit has split src/main/cpp/util/path.cc from file_[platform].cc) - Change exported variable _rlocation_isabs_pattern in runfiles.bash to be upper-case, so it is visibly a variable and not a function. See https://github.com/bazelbuild/bazel/issues/4460 Change-Id: I17e18308506ab9f5c9f410ef6bc6b9df912d42a9 Closes #5481. Change-Id: I17e18308506ab9f5c9f410ef6bc6b9df912d42a9 PiperOrigin-RevId: 202291629
diff --git a/src/tools/runfiles/java/com/google/devtools/build/runfiles/Runfiles.java b/src/tools/runfiles/java/com/google/devtools/build/runfiles/Runfiles.java index 8b62773..3c9eef3 100644 --- a/src/tools/runfiles/java/com/google/devtools/build/runfiles/Runfiles.java +++ b/src/tools/runfiles/java/com/google/devtools/build/runfiles/Runfiles.java
@@ -25,13 +25,33 @@ import java.util.Map; /** - * Returns the runtime location of runfiles (data-dependencies of Bazel-built binaries and tests). + * Runfiles lookup library for Bazel-built Java binaries and tests. * - * <p>Usage: + * <p>USAGE: + * + * <p>1. Depend on this runfiles library from your build rule: * * <pre> - * Runfiles runfiles = Runfiles.create(); - * File p = new File(runfiles.rlocation("io_bazel/src/bazel")); + * java_binary( + * name = "my_binary", + * ... + * deps = ["@bazel_tools//tools/runfiles:java-runfiles"], + * ) + * </pre> + * + * <p>2. Import the runfiles library. + * + * <pre> + * import com.google.devtools.build.runfiles.Runfiles; + * </pre> + * + * <p>3. Create a Runfiles object and use rlocation to look up runfile paths: + * + * <pre> + * public void myFunction() { + * Runfiles runfiles = Runfiles.create(); + * String path = runfiles.rlocation("my_workspace/path/to/my/data.txt"); + * ... * </pre> * * <p>If you want to start subprocesses that also need runfiles, you need to set the right
diff --git a/tools/bash/runfiles/runfiles.bash b/tools/bash/runfiles/runfiles.bash index cba75ab..b8bb7b2 100644 --- a/tools/bash/runfiles/runfiles.bash +++ b/tools/bash/runfiles/runfiles.bash
@@ -12,59 +12,64 @@ # See the License for the specific language governing permissions and # limitations under the License. -# This Bash script defines functions to handle sh_binary/sh_test runfiles. +# Runfiles lookup library for Bazel-built Bash binaries and tests. # -# REQUIREMENTS: -# - At least one of RUNFILES_MANIFEST_FILE and RUNFILES_DIR environment -# variables must be set, to the absolute path of the runfiles manifest or the -# <rulename>.runfiles directory respectively. +# ENVIRONMENT: +# - Use the example code provided below. It initializes the environment +# variables required by this script. # - If RUNFILES_LIB_DEBUG=1 is set, the script will print diagnostic messages to # stderr. # # USAGE: -# 1. Depend on this runfiles library from your build rule: +# 1. Depend on this runfiles library from your build rule: # -# sh_binary( -# name = "my_binary", -# ... -# deps = ["@bazel_tools//tools/bash/runfiles"], -# ) +# 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: +# 2. Source the runfiles library. # -# set -euo pipefail -# # --- begin runfiles.bash initialization --- -# if [[ ! -d "${RUNFILES_DIR:-/dev/null}" && ! -f "${RUNFILES_MANIFEST_FILE:-/dev/null}" ]]; then -# if [[ -f "$0.runfiles_manifest" ]]; then -# export RUNFILES_MANIFEST_FILE="$0.runfiles_manifest" -# elif [[ -f "$0.runfiles/MANIFEST" ]]; then -# export RUNFILES_MANIFEST_FILE="$0.runfiles/MANIFEST" -# elif [[ -f "$0.runfiles/bazel_tools/tools/bash/runfiles/runfiles.bash" ]]; then -# export RUNFILES_DIR="$0.runfiles" -# fi -# fi -# if [[ -f "${RUNFILES_DIR:-/dev/null}/bazel_tools/tools/bash/runfiles/runfiles.bash" ]]; then -# source "${RUNFILES_DIR}/bazel_tools/tools/bash/runfiles/runfiles.bash" -# elif [[ -f "${RUNFILES_MANIFEST_FILE:-/dev/null}" ]]; then -# source "$(grep -m1 "^bazel_tools/tools/bash/runfiles/runfiles.bash " \ -# "$RUNFILES_MANIFEST_FILE" | cut -d ' ' -f 2-)" -# else -# echo >&2 "ERROR: cannot find @bazel_tools//tools/bash/runfiles:runfiles.bash" -# exit 1 -# fi -# # --- end runfiles.bash initialization --- +# 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 [[ ! -d "${RUNFILES_DIR:-/dev/null}" && ! -f "${RUNFILES_MANIFEST_FILE:-/dev/null}" ]]; then +# if [[ -f "$0.runfiles_manifest" ]]; then +# export RUNFILES_MANIFEST_FILE="$0.runfiles_manifest" +# elif [[ -f "$0.runfiles/MANIFEST" ]]; then +# export RUNFILES_MANIFEST_FILE="$0.runfiles/MANIFEST" +# elif [[ -f "$0.runfiles/bazel_tools/tools/bash/runfiles/runfiles.bash" ]]; then +# export RUNFILES_DIR="$0.runfiles" +# fi +# fi +# if [[ -f "${RUNFILES_DIR:-/dev/null}/bazel_tools/tools/bash/runfiles/runfiles.bash" ]]; then +# source "${RUNFILES_DIR}/bazel_tools/tools/bash/runfiles/runfiles.bash" +# elif [[ -f "${RUNFILES_MANIFEST_FILE:-/dev/null}" ]]; then +# source "$(grep -m1 "^bazel_tools/tools/bash/runfiles/runfiles.bash " \ +# "$RUNFILES_MANIFEST_FILE" | cut -d ' ' -f 2-)" +# else +# echo >&2 "ERROR: cannot find @bazel_tools//tools/bash/runfiles:runfiles.bash" +# exit 1 +# fi +# # --- end runfiles.bash initialization --- +# +# 3. Use rlocation to look up runfile paths: +# +# cat "$(rlocation my_workspace/path/to/my/data.txt)" +# case "$(uname -s | tr [:upper:] [:lower:])" in msys*|mingw*|cygwin*) # matches an absolute Windows path - export _rlocation_isabs_pattern="^[a-zA-Z]:[/\\]" + export _RLOCATION_ISABS_PATTERN="^[a-zA-Z]:[/\\]" ;; *) # matches an absolute Unix path - export _rlocation_isabs_pattern="^/[^/].*" + export _RLOCATION_ISABS_PATTERN="^/[^/].*" ;; esac @@ -73,7 +78,7 @@ if [[ "${RUNFILES_LIB_DEBUG:-}" == 1 ]]; then echo >&2 "INFO[runfiles.bash]: rlocation($1): start" fi - if [[ "$1" =~ $_rlocation_isabs_pattern ]]; then + if [[ "$1" =~ $_RLOCATION_ISABS_PATTERN ]]; then if [[ "${RUNFILES_LIB_DEBUG:-}" == 1 ]]; then echo >&2 "INFO[runfiles.bash]: rlocation($1): absolute path, return" fi
diff --git a/tools/cpp/runfiles/runfiles.h b/tools/cpp/runfiles/runfiles.h index b2bfe30..cfb1f30 100644 --- a/tools/cpp/runfiles/runfiles.h +++ b/tools/cpp/runfiles/runfiles.h
@@ -14,30 +14,39 @@ // Runfiles lookup library for Bazel-built C++ binaries and tests. // -// Usage: +// USAGE: +// 1. Depend on this runfiles library from your build rule: // -// #include "tools/cpp/runfiles/runfiles.h" +// cc_binary( +// name = "my_binary", +// ... +// deps = ["@bazel_tools//tools/cpp/runfiles"], +// ) // -// using bazel::tools::cpp::runfiles::Runfiles; +// 2. Include the runfiles library. // -// int main(int argc, char** argv) { -// std::string error; -// std::unique_ptr<Runfiles> runfiles(Runfiles::Create(argv[0], &error)); -// if (runfiles == nullptr) { -// ... // error handling -// } -// std::string path = runfiles->Rlocation("io_bazel/src/bazel"); -// if (!path.empty()) { -// std::ifstream data(path); -// if (data.is_open()) { -// ... // use the runfile +// #include "tools/cpp/runfiles/runfiles.h" // -// The code above creates a Runfiles object and retrieves a runfile path. +// using bazel::tools::cpp::runfiles::Runfiles; // -// The Runfiles::Create function uses the runfiles manifest and the runfiles -// directory from the RUNFILES_MANIFEST_FILE and RUNFILES_DIR environment -// variables. If not present, the function looks for the manifest and directory -// near argv[0], the path of the main program. +// 3. Create a Runfiles object and use rlocation to look up runfile paths: +// +// int main(int argc, char** argv) { +// std::string error; +// std::unique_ptr<Runfiles> runfiles(Runfiles::Create(argv[0], +// &error)); if (runfiles == nullptr) { +// ... // error handling +// } +// std::string path = +// runfiles->Rlocation("my_workspace/path/to/my/data.txt"); +// ... +// +// The code above creates a Runfiles object and retrieves a runfile path. +// +// The Runfiles::Create function uses the runfiles manifest and the +// runfiles directory from the RUNFILES_MANIFEST_FILE and RUNFILES_DIR +// environment variables. If not present, the function looks for the +// manifest and directory near argv[0], the path of the main program. // // To start child processes that also need runfiles, you need to set the right // environment variables for them:
diff --git a/tools/cpp/runfiles/runfiles_test.cc b/tools/cpp/runfiles/runfiles_test.cc index 17c1d42..d6ecac9 100644 --- a/tools/cpp/runfiles/runfiles_test.cc +++ b/tools/cpp/runfiles/runfiles_test.cc
@@ -25,10 +25,11 @@ #include "gtest/gtest.h" #include "src/main/cpp/util/file.h" +#include "src/main/cpp/util/path.h" -#define _T(x) #x -#define T(x) _T(x) -#define LINE() T(__LINE__) +#define RUNFILES_TEST_TOSTRING_HELPER(x) #x +#define RUNFILES_TEST_TOSTRING(x) RUNFILES_TEST_TOSTRING_HELPER(x) +#define LINE_AS_STRING() RUNFILES_TEST_TOSTRING(__LINE__) namespace bazel { namespace tools { @@ -145,8 +146,8 @@ RunfilesTest::MockFile::~MockFile() { std::remove(path_.c_str()); } TEST_F(RunfilesTest, CreatesManifestBasedRunfilesFromManifestNextToBinary) { - unique_ptr<MockFile> mf( - MockFile::Create("foo" LINE() ".runfiles_manifest", {"a/b c/d"})); + unique_ptr<MockFile> mf(MockFile::Create( + "foo" LINE_AS_STRING() ".runfiles_manifest", {"a/b c/d"})); EXPECT_TRUE(mf != nullptr); string argv0(mf->Path().substr( 0, mf->Path().size() - string(".runfiles_manifest").size())); @@ -164,8 +165,8 @@ TEST_F(RunfilesTest, CreatesManifestBasedRunfilesFromManifestInRunfilesDirectory) { - unique_ptr<MockFile> mf( - MockFile::Create("foo" LINE() ".runfiles/MANIFEST", {"a/b c/d"})); + unique_ptr<MockFile> mf(MockFile::Create( + "foo" LINE_AS_STRING() ".runfiles/MANIFEST", {"a/b c/d"})); EXPECT_TRUE(mf != nullptr); string argv0(mf->Path().substr( 0, mf->Path().size() - string(".runfiles/MANIFEST").size())); @@ -180,8 +181,8 @@ } TEST_F(RunfilesTest, CreatesManifestBasedRunfilesFromEnvvar) { - unique_ptr<MockFile> mf( - MockFile::Create("foo" LINE() ".runfiles_manifest", {"a/b c/d"})); + unique_ptr<MockFile> mf(MockFile::Create( + "foo" LINE_AS_STRING() ".runfiles_manifest", {"a/b c/d"})); EXPECT_TRUE(mf != nullptr); string error; @@ -197,8 +198,8 @@ } TEST_F(RunfilesTest, CannotCreateManifestBasedRunfilesDueToBadManifest) { - unique_ptr<MockFile> mf( - MockFile::Create("foo" LINE() ".runfiles_manifest", {"a b", "nospace"})); + unique_ptr<MockFile> mf(MockFile::Create( + "foo" LINE_AS_STRING() ".runfiles_manifest", {"a b", "nospace"})); EXPECT_TRUE(mf != nullptr); string error; @@ -210,8 +211,8 @@ } TEST_F(RunfilesTest, ManifestBasedRunfilesRlocationAndEnvVars) { - unique_ptr<MockFile> mf( - MockFile::Create("foo" LINE() ".runfiles_manifest", {"a/b c/d"})); + unique_ptr<MockFile> mf(MockFile::Create( + "foo" LINE_AS_STRING() ".runfiles_manifest", {"a/b c/d"})); EXPECT_TRUE(mf != nullptr); string error; @@ -242,7 +243,7 @@ TEST_F(RunfilesTest, DirectoryBasedRunfilesRlocationAndEnvVars) { unique_ptr<MockFile> dummy( - MockFile::Create("foo" LINE() ".runfiles/dummy", {"a/b c/d"})); + MockFile::Create("foo" LINE_AS_STRING() ".runfiles/dummy", {"a/b c/d"})); EXPECT_TRUE(dummy != nullptr); string dir = dummy->DirName(); @@ -273,8 +274,8 @@ } TEST_F(RunfilesTest, ManifestAndDirectoryBasedRunfilesRlocationAndEnvVars) { - unique_ptr<MockFile> mf( - MockFile::Create("foo" LINE() ".runfiles/MANIFEST", {"a/b c/d"})); + unique_ptr<MockFile> mf(MockFile::Create( + "foo" LINE_AS_STRING() ".runfiles/MANIFEST", {"a/b c/d"})); EXPECT_TRUE(mf != nullptr); string dir = mf->DirName(); @@ -311,7 +312,7 @@ ".txt"}); for (vector<string>::size_type i = 0; i < suffixes.size(); ++i) { unique_ptr<MockFile> mf( - MockFile::Create(string("foo" LINE()) + suffixes[i])); + MockFile::Create(string("foo" LINE_AS_STRING()) + suffixes[i])); EXPECT_TRUE(mf != nullptr) << " (suffix=\"" << suffixes[i] << "\")"; string error; @@ -334,7 +335,7 @@ TEST_F(RunfilesTest, CreatesDirectoryBasedRunfilesFromDirectoryNextToBinary) { // We create a directory as a side-effect of creating a mock file. unique_ptr<MockFile> mf( - MockFile::Create(string("foo" LINE() ".runfiles/dummy"))); + MockFile::Create(string("foo" LINE_AS_STRING() ".runfiles/dummy"))); string argv0(mf->Path().substr( 0, mf->Path().size() - string(".runfiles/dummy").size())); @@ -353,7 +354,7 @@ TEST_F(RunfilesTest, CreatesDirectoryBasedRunfilesFromEnvvar) { // We create a directory as a side-effect of creating a mock file. unique_ptr<MockFile> mf( - MockFile::Create(string("foo" LINE() ".runfiles/dummy"))); + MockFile::Create(string("foo" LINE_AS_STRING() ".runfiles/dummy"))); string dir = mf->DirName(); string error; @@ -371,7 +372,7 @@ TEST_F(RunfilesTest, FailsToCreateAnyRunfilesBecauseEnvvarsAreNotDefined) { unique_ptr<MockFile> mf( - MockFile::Create(string("foo" LINE() ".runfiles/MANIFEST"))); + MockFile::Create(string("foo" LINE_AS_STRING() ".runfiles/MANIFEST"))); EXPECT_TRUE(mf != nullptr); string error; @@ -381,7 +382,7 @@ EXPECT_TRUE(error.empty()); // We create a directory as a side-effect of creating a mock file. - mf.reset(MockFile::Create(string("foo" LINE() ".runfiles/dummy"))); + mf.reset(MockFile::Create(string("foo" LINE_AS_STRING() ".runfiles/dummy"))); r.reset(Runfiles::Create("ignore-argv0", "", mf->DirName(), &error)); ASSERT_NE(r, nullptr); EXPECT_TRUE(error.empty()); @@ -393,23 +394,43 @@ TEST_F(RunfilesTest, MockFileTest) { { - unique_ptr<MockFile> mf(MockFile::Create(string("foo" LINE() "/.."))); + unique_ptr<MockFile> mf( + MockFile::Create(string("foo" LINE_AS_STRING() "/.."))); EXPECT_TRUE(mf == nullptr); } { - unique_ptr<MockFile> mf(MockFile::Create(string("/Foo" LINE()))); + unique_ptr<MockFile> mf(MockFile::Create(string("/Foo" LINE_AS_STRING()))); EXPECT_TRUE(mf == nullptr); } { - unique_ptr<MockFile> mf(MockFile::Create(string("C:/Foo" LINE()))); + unique_ptr<MockFile> mf( + MockFile::Create(string("C:/Foo" LINE_AS_STRING()))); EXPECT_TRUE(mf == nullptr); } string path; { - unique_ptr<MockFile> mf(MockFile::Create(string("foo" LINE() "/bar1/qux"))); + unique_ptr<MockFile> mf( + MockFile::Create(string("foo" LINE_AS_STRING() "/bar1/qux"))); + EXPECT_TRUE(mf != nullptr); + path = mf->Path(); + + std::ifstream stm(path); + EXPECT_TRUE(stm.good()); + string actual; + stm >> actual; + EXPECT_TRUE(actual.empty()); + } + { + std::ifstream stm(path); + EXPECT_FALSE(stm.good()); + } + + { + unique_ptr<MockFile> mf(MockFile::Create( + string("foo" LINE_AS_STRING() "/bar2/qux"), vector<string>())); EXPECT_TRUE(mf != nullptr); path = mf->Path(); @@ -426,24 +447,7 @@ { unique_ptr<MockFile> mf( - MockFile::Create(string("foo" LINE() "/bar2/qux"), vector<string>())); - EXPECT_TRUE(mf != nullptr); - path = mf->Path(); - - std::ifstream stm(path); - EXPECT_TRUE(stm.good()); - string actual; - stm >> actual; - EXPECT_TRUE(actual.empty()); - } - { - std::ifstream stm(path); - EXPECT_FALSE(stm.good()); - } - - { - unique_ptr<MockFile> mf( - MockFile::Create(string("foo" LINE() "/bar3/qux"), + MockFile::Create(string("foo" LINE_AS_STRING() "/bar3/qux"), {"hello world", "you are beautiful"})); EXPECT_TRUE(mf != nullptr); path = mf->Path();
diff --git a/tools/python/runfiles/runfiles.py b/tools/python/runfiles/runfiles.py index e80a7d1..cdf62b6 100644 --- a/tools/python/runfiles/runfiles.py +++ b/tools/python/runfiles/runfiles.py
@@ -13,35 +13,49 @@ # limitations under the License. """Runfiles lookup library for Bazel-built Python binaries and tests. -Usage: +USAGE: -from bazel_tools.tools.python.runfiles import runfiles +1. Depend on this runfiles library from your build rule: -r = runfiles.Create() -with open(r.Rlocation("io_bazel/foo/bar.txt"), "r") as f: - contents = f.readlines() + py_binary( + name = "my_binary", + ... + deps = ["@bazel_tools//tools/python/runfiles"], + ) -The code above creates a manifest- or directory-based implementations based on -the environment variables in os.environ. See `Create()` for more info. +2. Import the runfiles library. -If you want to explicitly create a manifest- or directory-based -implementations, you can do so as follows: + from bazel_tools.tools.python.runfiles import runfiles - r1 = runfiles.CreateManifestBased("path/to/foo.runfiles_manifest") +3. Create a Runfiles object and use rlocation to look up runfile paths: - r2 = runfiles.CreateDirectoryBased("path/to/foo.runfiles/") + r = runfiles.Create() + ... + with open(r.Rlocation("my_workspace/path/to/my/data.txt"), "r") as f: + contents = f.readlines() + ... -If you want to start subprocesses that also need runfiles, you need to set the -right environment variables for them: + The code above creates a manifest- or directory-based implementations based + on the environment variables in os.environ. See `Create()` for more info. - import subprocess - from bazel_tools.tools.python.runfiles import runfiles + If you want to explicitly create a manifest- or directory-based + implementations, you can do so as follows: - r = runfiles.Create() - env = {} - ... - env.update(r.EnvVars()) - p = subprocess.Popen([r.Rlocation("path/to/binary")], env, ...) + 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 bazel_tools.tools.python.runfiles import runfiles + + r = runfiles.Create() + env = {} + ... + env.update(r.EnvVars()) + p = subprocess.Popen([r.Rlocation("path/to/binary")], env, ...) """ import os