diff options
author | Laszlo Csomor <laszlocsomor@google.com> | 2018-02-28 06:48:18 -0800 |
---|---|---|
committer | Copybara-Service <copybara-piper@google.com> | 2018-02-28 06:49:53 -0800 |
commit | e7d9e1f8aae459ec71cdb31f988661f4c3975ca8 (patch) | |
tree | b9e4f36d4ad55fe8a45aba0667db010fae9e8e95 /src/tools/runfiles/runfiles.cc | |
parent | 51275462a5f63d34e176e76ef372e91b25ecee56 (diff) |
runfiles,C++: implement manifest-based runfiles
Implement a manifest-based Runfiles object, add
tests and test utils (MockFile).
Subsequent commits will add more feataures:
- creating list of envvars to pass to child
processes
- automatic Runfiles creation based on argv[0] and
the envvars of this process
See https://github.com/bazelbuild/bazel/issues/4460
Change-Id: I4376ede3ac00241688ff16a36ed596fb08f13a72
PiperOrigin-RevId: 187318502
Diffstat (limited to 'src/tools/runfiles/runfiles.cc')
-rw-r--r-- | src/tools/runfiles/runfiles.cc | 83 |
1 files changed, 82 insertions, 1 deletions
diff --git a/src/tools/runfiles/runfiles.cc b/src/tools/runfiles/runfiles.cc index 9ff1f3f4c5..1de2f1a1f4 100644 --- a/src/tools/runfiles/runfiles.cc +++ b/src/tools/runfiles/runfiles.cc @@ -13,9 +13,14 @@ // limitations under the License. #include "tools/runfiles/runfiles.h" +#include <fstream> +#include <map> +#include <sstream> + namespace bazel { namespace runfiles { +using std::map; using std::string; namespace { @@ -39,7 +44,31 @@ class RunfilesImpl : public Runfiles { virtual ~RunfilesImpl() {} }; -// TODO(laszlocsomor): derive a ManifestBased class from RunfilesImpl. +// Runfiles implementation that parses a runfiles-manifest to look up runfiles. +class ManifestBased : public RunfilesImpl { + public: + // Returns a new `ManifestBased` instance. + // Reads the file at `manifest_path` to build a map of the runfiles. + // Returns nullptr upon failure. + static ManifestBased* Create(const string& manifest_path, string* error); + + string RlocationChecked(const string& path) const override; + + private: + ManifestBased(const string& manifest_path, map<string, string>&& runfiles_map) + : manifest_path_(manifest_path), runfiles_map_(runfiles_map) {} + + ManifestBased(const ManifestBased&) = delete; + ManifestBased(ManifestBased&&) = delete; + ManifestBased& operator=(const ManifestBased&) = delete; + ManifestBased& operator=(ManifestBased&&) = delete; + + static bool ParseManifest(const string& path, map<string, string>* result, + string* error); + + const string manifest_path_; + const map<string, string> runfiles_map_; +}; // Runfiles implementation that appends runfiles paths to the runfiles root. class DirectoryBased : public RunfilesImpl { @@ -77,6 +106,53 @@ string RunfilesImpl::Rlocation(const string& path) const { return RlocationChecked(path); } +ManifestBased* ManifestBased::Create(const string& manifest_path, + string* error) { + map<string, string> runfiles; + return ParseManifest(manifest_path, &runfiles, error) + ? new ManifestBased(manifest_path, std::move(runfiles)) + : nullptr; +} + +string ManifestBased::RlocationChecked(const string& path) const { + const auto value = runfiles_map_.find(path); + return std::move(value == runfiles_map_.end() ? string() : value->second); +} + +bool ManifestBased::ParseManifest(const string& path, + map<string, string>* result, string* error) { + std::ifstream stm(path); + if (!stm.is_open()) { + if (error) { + std::ostringstream err; + err << "ERROR: " << __FILE__ << "(" << __LINE__ + << "): cannot open runfiles manifest \"" << path << "\""; + *error = err.str(); + } + return false; + } + string line; + std::getline(stm, line); + size_t line_count = 1; + while (!line.empty()) { + string::size_type idx = line.find_first_of(' '); + if (idx == string::npos) { + if (error) { + std::ostringstream err; + err << "ERROR: " << __FILE__ << "(" << __LINE__ + << "): bad runfiles manifest entry in \"" << path << "\" line #" + << line_count << ": \"" << line << "\""; + *error = err.str(); + } + return false; + } + (*result)[line.substr(0, idx)] = line.substr(idx + 1); + std::getline(stm, line); + ++line_count; + } + return true; +} + string DirectoryBased::RlocationChecked(const string& path) const { return std::move(runfiles_path_ + "/" + path); } @@ -89,6 +165,11 @@ bool TestOnly_IsAbsolute(const string& path) { return IsAbsolute(path); } } // namespace testing +Runfiles* Runfiles::CreateManifestBased(const string& manifest_path, + string* error) { + return ManifestBased::Create(manifest_path, error); +} + Runfiles* Runfiles::CreateDirectoryBased(const string& directory_path, string* error) { // Note: `error` is intentionally unused because we don't expect any errors |