Skip to content

Commit

Permalink
runfiles libraries: fix tests and comments
Browse files Browse the repository at this point in the history
- 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 bazelbuild#4460

Change-Id: I17e18308506ab9f5c9f410ef6bc6b9df912d42a9
  • Loading branch information
laszlocsomor committed Jun 27, 2018
1 parent 1030323 commit 3f70169
Show file tree
Hide file tree
Showing 5 changed files with 161 additions and 112 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,30 @@
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
Expand Down
83 changes: 44 additions & 39 deletions tools/bash/runfiles/runfiles.bash
Original file line number Diff line number Diff line change
Expand Up @@ -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.
#
# 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)"
#
# 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 ---

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

Expand All @@ -73,7 +78,7 @@ function rlocation() {
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
Expand Down
51 changes: 30 additions & 21 deletions tools/cpp/runfiles/runfiles.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
//
// 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.
// #include "tools/cpp/runfiles/runfiles.h"
//
// using bazel::tools::cpp::runfiles::Runfiles;
//
// 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:
Expand Down
60 changes: 32 additions & 28 deletions tools/cpp/runfiles/runfiles_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -145,8 +146,8 @@ RunfilesTest::MockFile* RunfilesTest::MockFile::Create(
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()));
Expand All @@ -164,8 +165,8 @@ TEST_F(RunfilesTest, CreatesManifestBasedRunfilesFromManifestNextToBinary) {

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()));
Expand All @@ -180,8 +181,8 @@ TEST_F(RunfilesTest,
}

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;
Expand All @@ -197,8 +198,8 @@ TEST_F(RunfilesTest, CreatesManifestBasedRunfilesFromEnvvar) {
}

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;
Expand All @@ -210,8 +211,8 @@ TEST_F(RunfilesTest, CannotCreateManifestBasedRunfilesDueToBadManifest) {
}

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;
Expand Down Expand Up @@ -242,7 +243,7 @@ TEST_F(RunfilesTest, ManifestBasedRunfilesRlocationAndEnvVars) {

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();

Expand Down Expand Up @@ -273,8 +274,8 @@ TEST_F(RunfilesTest, DirectoryBasedRunfilesRlocationAndEnvVars) {
}

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();

Expand Down Expand Up @@ -311,7 +312,7 @@ TEST_F(RunfilesTest, ManifestBasedRunfilesEnvVars) {
".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;
Expand All @@ -334,7 +335,7 @@ TEST_F(RunfilesTest, ManifestBasedRunfilesEnvVars) {
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()));

Expand All @@ -353,7 +354,7 @@ TEST_F(RunfilesTest, CreatesDirectoryBasedRunfilesFromDirectoryNextToBinary) {
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;
Expand All @@ -371,7 +372,7 @@ TEST_F(RunfilesTest, CreatesDirectoryBasedRunfilesFromEnvvar) {

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;
Expand All @@ -381,7 +382,7 @@ TEST_F(RunfilesTest, FailsToCreateAnyRunfilesBecauseEnvvarsAreNotDefined) {
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());
Expand All @@ -393,23 +394,26 @@ TEST_F(RunfilesTest, FailsToCreateAnyRunfilesBecauseEnvvarsAreNotDefined) {

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();

Expand All @@ -425,8 +429,8 @@ TEST_F(RunfilesTest, MockFileTest) {
}

{
unique_ptr<MockFile> mf(
MockFile::Create(string("foo" LINE() "/bar2/qux"), vector<string>()));
unique_ptr<MockFile> mf(MockFile::Create(
string("foo" LINE_AS_STRING() "/bar2/qux"), vector<string>()));
EXPECT_TRUE(mf != nullptr);
path = mf->Path();

Expand All @@ -443,7 +447,7 @@ TEST_F(RunfilesTest, MockFileTest) {

{
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();
Expand Down
Loading

0 comments on commit 3f70169

Please sign in to comment.