aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/tools
diff options
context:
space:
mode:
authorGravatar Laszlo Csomor <laszlocsomor@google.com>2018-03-05 06:35:20 -0800
committerGravatar Copybara-Service <copybara-piper@google.com>2018-03-05 06:36:54 -0800
commit3bcad502164dd169e5bb0af88f406dea86e24109 (patch)
treef55bc72b869b085578af8e1be390cb00ec5be20b /src/tools
parentb2ba2079ccba96c60203c7f23fb75ab1a3586d60 (diff)
runfiles,C++: create envvar list for subprocesses
Implement Runfiles::EnvVars so it's now possible to propagate runfiles to subprocesses via environment variables (RUNFILES_MANIFEST_FILE and RUNFILES_DIR). Subsequent commits will add more feataures: - automatic Runfiles creation based on argv[0] and the envvars of this process See https://github.com/bazelbuild/bazel/issues/4460 Change-Id: If9a37b1be13b9cbacf21a496305d60444fd660b2 PiperOrigin-RevId: 187858830
Diffstat (limited to 'src/tools')
-rw-r--r--src/tools/runfiles/runfiles.cc34
-rw-r--r--src/tools/runfiles/runfiles.h19
-rw-r--r--src/tools/runfiles/runfiles_test.cc53
3 files changed, 99 insertions, 7 deletions
diff --git a/src/tools/runfiles/runfiles.cc b/src/tools/runfiles/runfiles.cc
index 1de2f1a1f4..60d1ec3124 100644
--- a/src/tools/runfiles/runfiles.cc
+++ b/src/tools/runfiles/runfiles.cc
@@ -16,12 +16,15 @@
#include <fstream>
#include <map>
#include <sstream>
+#include <vector>
namespace bazel {
namespace runfiles {
using std::map;
+using std::pair;
using std::string;
+using std::vector;
namespace {
@@ -52,6 +55,7 @@ class ManifestBased : public RunfilesImpl {
// Returns nullptr upon failure.
static ManifestBased* Create(const string& manifest_path, string* error);
+ vector<pair<string, string> > EnvVars() const override;
string RlocationChecked(const string& path) const override;
private:
@@ -63,6 +67,7 @@ class ManifestBased : public RunfilesImpl {
ManifestBased& operator=(const ManifestBased&) = delete;
ManifestBased& operator=(ManifestBased&&) = delete;
+ string RunfilesDir() const;
static bool ParseManifest(const string& path, map<string, string>* result,
string* error);
@@ -75,6 +80,7 @@ class DirectoryBased : public RunfilesImpl {
public:
DirectoryBased(string runfiles_path)
: runfiles_path_(std::move(runfiles_path)) {}
+ vector<pair<string, string> > EnvVars() const override;
string RlocationChecked(const string& path) const override;
private:
@@ -119,6 +125,26 @@ string ManifestBased::RlocationChecked(const string& path) const {
return std::move(value == runfiles_map_.end() ? string() : value->second);
}
+vector<pair<string, string> > ManifestBased::EnvVars() const {
+ return std::move(vector<pair<string, string> >(
+ {std::make_pair("RUNFILES_MANIFEST_FILE", manifest_path_),
+ // TODO(laszlocsomor): remove JAVA_RUNFILES once the Java launcher can
+ // pick up RUNFILES_DIR.
+ std::make_pair("JAVA_RUNFILES", RunfilesDir())}));
+}
+
+string ManifestBased::RunfilesDir() const {
+ const auto pos1 = manifest_path_.size() - 9; // "_MANIFEST"
+ const auto pos2 = manifest_path_.size() - 18; // ".runfiles_manifest"
+ if (manifest_path_.rfind("/MANIFEST") == pos1 ||
+ manifest_path_.rfind("\\MANIFEST") == pos1 ||
+ manifest_path_.rfind(".runfiles_manifest") == pos2) {
+ return std::move(manifest_path_.substr(0, pos1)); // remove ".MANIFEST"
+ } else {
+ return std::move(string());
+ }
+}
+
bool ManifestBased::ParseManifest(const string& path,
map<string, string>* result, string* error) {
std::ifstream stm(path);
@@ -157,6 +183,14 @@ string DirectoryBased::RlocationChecked(const string& path) const {
return std::move(runfiles_path_ + "/" + path);
}
+vector<pair<string, string> > DirectoryBased::EnvVars() const {
+ return std::move(vector<pair<string, string> >(
+ {std::make_pair("RUNFILES_DIR", runfiles_path_),
+ // TODO(laszlocsomor): remove JAVA_RUNFILES once the Java launcher can
+ // pick up RUNFILES_DIR.
+ std::make_pair("JAVA_RUNFILES", runfiles_path_)}));
+}
+
} // namespace
namespace testing {
diff --git a/src/tools/runfiles/runfiles.h b/src/tools/runfiles/runfiles.h
index 821cc1aa6f..b29981e7f6 100644
--- a/src/tools/runfiles/runfiles.h
+++ b/src/tools/runfiles/runfiles.h
@@ -19,7 +19,9 @@
#ifndef BAZEL_SRC_TOOLS_RUNFILES_RUNFILES_H_
#define BAZEL_SRC_TOOLS_RUNFILES_RUNFILES_H_ 1
+#include <memory>
#include <string>
+#include <vector>
namespace bazel {
namespace runfiles {
@@ -28,11 +30,6 @@ class Runfiles {
public:
virtual ~Runfiles() {}
- // TODO(laszlocsomor): implement:
- // Runfiles* Create(const string& argv0, string* error);
- // TODO(laszlocsomor): implement:
- // vector<pair<string, string>> EnvVars();
-
// Returns a new manifest-based `Runfiles` instance.
// Returns nullptr on error. If `error` is provided, the method prints an
// error message into it.
@@ -63,6 +60,13 @@ class Runfiles {
// an empty string if the method doesn't know about this runfile
virtual std::string Rlocation(const std::string& path) const = 0;
+ // 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.
+ virtual std::vector<std::pair<std::string, std::string> > EnvVars() const = 0;
+
protected:
Runfiles() {}
@@ -74,8 +78,9 @@ class Runfiles {
};
// The "testing" namespace contains functions that allow unit testing the code.
-// Do not use these outside of runfiles_test.cc, because they may change without
-// notice.
+// Do not use these outside of runfiles_test.cc, they are only part of the
+// public API for the benefit of the tests.
+// These functions and their interface may change without notice.
namespace testing {
// For testing only.
diff --git a/src/tools/runfiles/runfiles_test.cc b/src/tools/runfiles/runfiles_test.cc
index 408dfde2e1..71a9d1d413 100644
--- a/src/tools/runfiles/runfiles_test.cc
+++ b/src/tools/runfiles/runfiles_test.cc
@@ -172,6 +172,45 @@ TEST_F(RunfilesTest, DirectoryBasedRunfilesRlocation) {
EXPECT_EQ(r->Rlocation("c:\\Foo"), "c:\\Foo");
}
+TEST_F(RunfilesTest, ManifestBasedRunfilesEnvVars) {
+ const vector<string> suffixes({"/MANIFEST", ".runfiles_manifest",
+ "runfiles_manifest", ".runfiles", ".manifest",
+ ".txt"});
+ for (vector<string>::size_type i = 0; i < suffixes.size(); ++i) {
+ unique_ptr<MockFile> mf(
+ MockFile::Create(string("foo" LINE()) + suffixes[i]));
+ EXPECT_TRUE(mf != nullptr) << " (suffix=\"" << suffixes[i] << "\")";
+
+ string error;
+ unique_ptr<Runfiles> r(Runfiles::CreateManifestBased(mf->Path(), &error));
+ ASSERT_NE(r, nullptr) << " (suffix=\"" << suffixes[i] << "\")";
+ EXPECT_TRUE(error.empty());
+
+ // The object can compute the runfiles directory when i=0 and i=1, but not
+ // when i>1 because the manifest file's name doesn't end in a well-known
+ // way.
+ const string expected_runfiles_dir(
+ i < 2 ? mf->Path().substr(0, mf->Path().size() - 9 /* "_manifest" */)
+ : "");
+ vector<pair<string, string> > expected(
+ {{"RUNFILES_MANIFEST_FILE", mf->Path()},
+ {"JAVA_RUNFILES", expected_runfiles_dir}});
+ EXPECT_EQ(r->EnvVars(), expected) << " (suffix=\"" << suffixes[i] << "\")";
+ }
+}
+
+TEST_F(RunfilesTest, DirectoryBasedRunfilesEnvVars) {
+ string error;
+ unique_ptr<Runfiles> r(
+ Runfiles::CreateDirectoryBased("runfiles/dir", &error));
+ ASSERT_NE(r, nullptr);
+ EXPECT_TRUE(error.empty());
+
+ vector<pair<string, string> > expected(
+ {{"RUNFILES_DIR", "runfiles/dir"}, {"JAVA_RUNFILES", "runfiles/dir"}});
+ EXPECT_EQ(r->EnvVars(), expected);
+}
+
TEST_F(RunfilesTest, FailsToCreateManifestBasedBecauseManifestDoesNotExist) {
string error;
unique_ptr<Runfiles> r(
@@ -253,6 +292,20 @@ TEST_F(RunfilesTest, MockFileTest) {
}
}
+TEST_F(RunfilesTest, IsAbsolute) {
+ EXPECT_FALSE(TestOnly_IsAbsolute("foo"));
+ EXPECT_FALSE(TestOnly_IsAbsolute("foo/bar"));
+ EXPECT_FALSE(TestOnly_IsAbsolute("\\foo"));
+ EXPECT_TRUE(TestOnly_IsAbsolute("c:\\foo"));
+ EXPECT_TRUE(TestOnly_IsAbsolute("c:/foo"));
+ EXPECT_TRUE(TestOnly_IsAbsolute("/foo"));
+ EXPECT_TRUE(TestOnly_IsAbsolute("x:\\foo"));
+ EXPECT_FALSE(TestOnly_IsAbsolute("::\\foo"));
+ EXPECT_FALSE(TestOnly_IsAbsolute("x\\foo"));
+ EXPECT_FALSE(TestOnly_IsAbsolute("x:"));
+ EXPECT_TRUE(TestOnly_IsAbsolute("x:\\"));
+}
+
} // namespace
} // namespace runfiles
} // namespace bazel