aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/tools
diff options
context:
space:
mode:
authorGravatar Laszlo Csomor <laszlocsomor@google.com>2018-04-30 03:29:21 -0700
committerGravatar Copybara-Service <copybara-piper@google.com>2018-04-30 03:30:49 -0700
commit819bf38d97e6eef3c823bdae3ffcdb013d6d83e3 (patch)
treef18d8d0cc5e34061c5c46514b18b9e5608f3d566 /src/tools
parenteb35e41242e1f9fb0ae1061623272c891237c8a8 (diff)
c++,runfiles: move runfiles library
Move the half-done C++ runfiles library to `//tools/cpp/runfiles`. (The Python and Bash runfiles libraries are already under `//tools/<language>/runfiles`.) See https://github.com/bazelbuild/bazel/issues/4460 Change-Id: I1006f7f81462ea0e4b1de1adcdba89e386d4f9e7 Closes #5107. Change-Id: I1006f7f81462ea0e4b1de1adcdba89e386d4f9e7 PiperOrigin-RevId: 194763392
Diffstat (limited to 'src/tools')
-rw-r--r--src/tools/runfiles/BUILD31
-rw-r--r--src/tools/runfiles/runfiles.cc350
-rw-r--r--src/tools/runfiles/runfiles.h184
-rw-r--r--src/tools/runfiles/runfiles_test.cc489
4 files changed, 0 insertions, 1054 deletions
diff --git a/src/tools/runfiles/BUILD b/src/tools/runfiles/BUILD
index 7222654d6b..9dd99e6b04 100644
--- a/src/tools/runfiles/BUILD
+++ b/src/tools/runfiles/BUILD
@@ -20,42 +20,11 @@ filegroup(
name = "embedded_tools",
srcs = [
"BUILD.tools",
- "runfiles.cc",
- "runfiles.h",
"//src/tools/runfiles/java/com/google/devtools/build/runfiles:embedded_tools",
],
visibility = ["//src:__pkg__"],
)
-cc_library(
- name = "cc-runfiles",
- srcs = ["runfiles.cc"],
- hdrs = ["runfiles.h"],
- # This library is available to clients under
- # @bazel_tools//tools/runfiles:cc-runfiles, with the same source files.
- # The include statement in runfiles.cc that includes runfiles.h must work
- # both here in the //src/tools/runfiles package, and in the
- # @bazel_tools//tools/runfiles package.
- # runfiles.cc includes "tools/runfiles/runfiles.h" so we need to tell the
- # compiler to prepend "src" to it so the include path is valid.
- # Alternatively we could omit this "copts" attribute here and add some
- # include path manipulating attributes to
- # @bazel_tools//tools/runfiles:cc-runfiles instead -- that would work too,
- # but I (laszlocsomor@) find this solution (i.e. the "copts" attribute on
- # this rule) to be simpler.
- copts = ["-Isrc"],
-)
-
-cc_test(
- name = "cc-runfiles-test",
- srcs = ["runfiles_test.cc"],
- deps = [
- ":cc-runfiles",
- "//src/main/cpp/util:file",
- "@com_google_googletest//:gtest_main",
- ],
-)
-
test_suite(
name = "windows_tests",
tags = [
diff --git a/src/tools/runfiles/runfiles.cc b/src/tools/runfiles/runfiles.cc
deleted file mode 100644
index 801e44e374..0000000000
--- a/src/tools/runfiles/runfiles.cc
+++ /dev/null
@@ -1,350 +0,0 @@
-// 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.
-#include "tools/runfiles/runfiles.h"
-
-#ifdef COMPILER_MSVC
-#include <windows.h>
-#else // not COMPILER_MSVC
-#include <stdlib.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-#endif // COMPILER_MSVC
-
-#include <fstream>
-#include <map>
-#include <sstream>
-#include <vector>
-
-#ifdef COMPILER_MSVC
-#include <memory>
-#endif // COMPILER_MSVC
-
-namespace bazel {
-namespace runfiles {
-
-using std::function;
-using std::map;
-using std::pair;
-using std::string;
-using std::vector;
-
-namespace {
-
-bool starts_with(const string& s, const string& prefix) {
- if (prefix.empty()) {
- return true;
- }
- if (s.empty()) {
- return false;
- }
- return s.find(prefix) == 0;
-}
-
-bool contains(const string& s, const string& substr) {
- if (substr.empty()) {
- return true;
- }
- if (s.empty()) {
- return false;
- }
- return s.find(substr) != string::npos;
-}
-
-bool ends_with(const string& s, const string& suffix) {
- if (suffix.empty()) {
- return true;
- }
- if (s.empty()) {
- return false;
- }
- return s.rfind(suffix) == s.size() - suffix.size();
-}
-
-class RunfilesImpl : public Runfiles {
- public:
- static Runfiles* Create(const string& argv0,
- function<string(const string&)> env_lookup,
- string* error);
-
- string Rlocation(const string& path) const override;
-
- // Returns the runtime-location of a given runfile.
- //
- // This method assumes that the caller already validated the `path`. See
- // Runfiles::Rlocation for requirements.
- virtual string RlocationChecked(const string& path) const = 0;
-
- protected:
- RunfilesImpl() {}
- virtual ~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);
-
- vector<pair<string, string> > EnvVars() const override;
- 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;
-
- string RunfilesDir() const;
- 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 {
- 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:
- DirectoryBased(const DirectoryBased&) = delete;
- DirectoryBased(DirectoryBased&&) = delete;
- DirectoryBased& operator=(const DirectoryBased&) = delete;
- DirectoryBased& operator=(DirectoryBased&&) = delete;
-
- const string runfiles_path_;
-};
-
-bool IsReadableFile(const string& path) {
- return std::ifstream(path).is_open();
-}
-
-bool IsDirectory(const string& path) {
-#ifdef COMPILER_MSVC
- DWORD attrs = GetFileAttributesA(path.c_str());
- return (attrs != INVALID_FILE_ATTRIBUTES) &&
- (attrs & FILE_ATTRIBUTE_DIRECTORY);
-#else
- struct stat buf;
- return stat(path.c_str(), &buf) == 0 && S_ISDIR(buf.st_mode);
-#endif
-}
-
-Runfiles* RunfilesImpl::Create(const string& argv0,
- function<string(const string&)> env_lookup,
- string* error) {
- string manifest(std::move(env_lookup("RUNFILES_MANIFEST_FILE")));
- if (!manifest.empty()) {
- return ManifestBased::Create(manifest, error);
- }
-
- string directory(std::move(env_lookup("RUNFILES_DIR")));
- if (!directory.empty()) {
- return new DirectoryBased(directory);
- }
-
- manifest = argv0 + ".runfiles_manifest";
- if (IsReadableFile(manifest)) {
- return CreateManifestBased(manifest, error);
- }
-
- manifest = argv0 + ".runfiles/MANIFEST";
- if (IsReadableFile(manifest)) {
- return CreateManifestBased(manifest, error);
- }
-
- directory = argv0 + ".runfiles";
- if (IsDirectory(directory)) {
- return CreateDirectoryBased(std::move(directory), error);
- }
-
- if (error) {
- std::ostringstream err;
- err << "ERROR: " << __FILE__ << "(" << __LINE__
- << "): cannot find runfiles (argv0=\"" << argv0 << "\")";
- *error = err.str();
- }
- return nullptr;
-}
-
-bool IsAbsolute(const string& path) {
- if (path.empty()) {
- return false;
- }
- char c = path.front();
- return (c == '/' && (path.size() < 2 || path[1] != '/')) ||
- (path.size() >= 3 &&
- ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) &&
- path[1] == ':' && (path[2] == '\\' || path[2] == '/'));
-}
-
-string GetEnv(const string& key) {
-#ifdef COMPILER_MSVC
- DWORD size = ::GetEnvironmentVariableA(key.c_str(), NULL, 0);
- if (size == 0) {
- return std::move(string()); // unset or empty envvar
- }
- std::unique_ptr<char[]> value(new char[size]);
- ::GetEnvironmentVariableA(key.c_str(), value.get(), size);
- return move(string(value.get()));
-#else
- char* result = getenv(key.c_str());
- return std::move((result == NULL) ? string() : string(result));
-#endif
-}
-
-string RunfilesImpl::Rlocation(const string& path) const {
- if (path.empty() || starts_with(path, "../") || contains(path, "/..") ||
- starts_with(path, "./") || contains(path, "/./") ||
- ends_with(path, "/.") || contains(path, "//")) {
- return std::move(string());
- }
- if (IsAbsolute(path)) {
- return path;
- }
- 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);
-}
-
-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);
- 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);
-}
-
-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 {
-
-Runfiles* TestOnly_CreateRunfiles(const std::string& argv0,
- function<string(const string&)> env_lookup,
- string* error) {
- return RunfilesImpl::Create(argv0, env_lookup, error);
-}
-
-bool TestOnly_IsAbsolute(const string& path) { return IsAbsolute(path); }
-
-} // namespace testing
-
-Runfiles* Runfiles::Create(const string& argv0, string* error) {
- return RunfilesImpl::Create(
- argv0,
- [](const string& key) {
- if (key == "RUNFILES_MANIFEST_FILE" || key == "RUNFILES_DIR") {
- string val(GetEnv(key));
- return std::move(val);
- } else {
- return std::move(string());
- }
- },
- error);
-}
-
-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
- // here. We expect an `error` pointer so that we may use it in the future if
- // need be, without having to change the API.
- return new DirectoryBased(directory_path);
-}
-
-} // namespace runfiles
-} // namespace bazel
diff --git a/src/tools/runfiles/runfiles.h b/src/tools/runfiles/runfiles.h
deleted file mode 100644
index 20e9dca1e1..0000000000
--- a/src/tools/runfiles/runfiles.h
+++ /dev/null
@@ -1,184 +0,0 @@
-// 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.
-
-// Runfiles lookup library for Bazel-built C++ binaries and tests.
-//
-// Usage:
-//
-// #include "tools/runfiles/runfiles.h"
-// ...
-//
-// int main(int argc, char** argv) {
-// std::string error;
-// std::unique_ptr<bazel::runfiles::Runfiles> runfiles(
-// bazel::runfiles::Runfiles::Create(argv[0], &error));
-// if (runfiles == nullptr) {
-// ... // error handling
-// }
-// std::string path(runfiles->Rlocation("io_bazel/src/bazel"));
-// std::ifstream data(path);
-// if (data.is_open()) {
-// ... // use the runfile
-//
-// The code above creates a manifest- or directory-based implementations
-// depending on it finding a runfiles manifest or -directory near argv[0] or
-// finding appropriate environment variables that tell it where to find the
-// manifest or directory. See `Runfiles::Create` for more info.
-//
-// If you want to explicitly create a manifest- or directory-based
-// implementation, you can do so as follows:
-//
-// std::unique_ptr<bazel::runfiles::Runfiles> runfiles1(
-// bazel::runfiles::Runfiles::CreateManifestBased(
-// "path/to/foo.runfiles/MANIFEST", &error));
-//
-// std::unique_ptr<bazel::runfiles::Runfiles> runfiles2(
-// bazel::runfiles::Runfiles::CreateDirectoryBased(
-// "path/to/foo.runfiles", &error));
-//
-// If you want to start child processes that also need runfiles, you need to set
-// the right environment variables for them:
-//
-// std::unique_ptr<bazel::runfiles::Runfiles> runfiles(
-// bazel::runfiles::Runfiles::Create(argv[0], &error));
-//
-// for (const auto i : runfiles->EnvVars()) {
-// setenv(i.first, i.second, 1);
-// }
-// std::string path(runfiles->Rlocation("path/to/binary"));
-// if (!path.empty()) {
-// pid_t child = fork();
-// ...
-
-#ifndef BAZEL_SRC_TOOLS_RUNFILES_RUNFILES_H_
-#define BAZEL_SRC_TOOLS_RUNFILES_RUNFILES_H_ 1
-
-#include <functional>
-#include <memory>
-#include <string>
-#include <vector>
-
-namespace bazel {
-namespace runfiles {
-
-class Runfiles {
- public:
- virtual ~Runfiles() {}
-
- // Returns a new `Runfiles` instance.
- //
- // The returned object is either:
- // - manifest-based, meaning it looks up runfile paths from a manifest file,
- // or
- // - directory-based, meaning it looks up runfile paths under a given
- // directory path
- //
- // This method:
- // 1. checks the RUNFILES_MANIFEST_FILE or RUNFILES_DIR environment variables;
- // if either is non-empty, returns a manifest- or directory-based Runfiles
- // object; otherwise
- // 2. checks if there's a runfiles manifest (argv0 + ".runfiles_manifest") or
- // runfiles directory (argv0 + ".runfiles") next to this binary; if so,
- // returns a manifest- or directory-based Runfiles object; otherwise
- // 3. returns nullptr.
- //
- // The manifest-based Runfiles object eagerly reads and caches the whole
- // manifest file upon instantiation; this may be relevant for performance
- // consideration.
- //
- // Returns nullptr on error. If `error` is provided, the method prints an
- // error message into it.
- static Runfiles* Create(const std::string& argv0,
- std::string* error = nullptr);
-
- // Returns a new manifest-based `Runfiles` instance.
- // Returns nullptr on error. If `error` is provided, the method prints an
- // error message into it.
- static Runfiles* CreateManifestBased(const std::string& manifest_path,
- std::string* error = nullptr);
-
- // Returns a new directory-based `Runfiles` instance.
- // Returns nullptr on error. If `error` is provided, the method prints an
- // error message into it.
- static Runfiles* CreateDirectoryBased(const std::string& directory_path,
- std::string* error = nullptr);
-
- // Returns the runtime path of a runfile.
- //
- // Runfiles are data-dependencies of Bazel-built binaries and tests.
- //
- // The returned path may not be valid. The caller should check the path's
- // validity and that the path exists.
- //
- // The function may return an empty string. In that case the caller can be
- // sure that the Runfiles object does not know about this data-dependency.
- //
- // Args:
- // path: runfiles-root-relative path of the runfile; must not be empty and
- // must not contain uplevel references.
- // Returns:
- // the path to the runfile, which the caller should check for existence, or
- // 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() {}
-
- private:
- Runfiles(const Runfiles&) = delete;
- Runfiles(Runfiles&&) = delete;
- Runfiles& operator=(const Runfiles&) = delete;
- Runfiles& operator=(Runfiles&&) = delete;
-};
-
-// The "testing" namespace contains functions that allow unit testing the code.
-// 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.
-//
-// Create a new Runfiles instance, looking up environment variables using
-// `env_lookup`.
-//
-// Args:
-// argv0: name of the binary; if this string is not empty, then the function
-// looks for a runfiles manifest or directory next to this
-// env_lookup: a function that returns envvar values if an envvar is known, or
-// empty string otherwise
-Runfiles* TestOnly_CreateRunfiles(
- const std::string& argv0,
- std::function<std::string(const std::string&)> env_lookup,
- std::string* error);
-
-// For testing only.
-// Returns true if `path` is an absolute Unix or Windows path.
-// For Windows paths, this function does not regard drive-less absolute paths
-// (i.e. absolute-on-current-drive, e.g. "\foo\bar") as absolute and returns
-// false for these.
-bool TestOnly_IsAbsolute(const std::string& path);
-
-} // namespace testing
-} // namespace runfiles
-} // namespace bazel
-
-#endif // BAZEL_SRC_TOOLS_RUNFILES_RUNFILES_H_
diff --git a/src/tools/runfiles/runfiles_test.cc b/src/tools/runfiles/runfiles_test.cc
deleted file mode 100644
index b15fc04a68..0000000000
--- a/src/tools/runfiles/runfiles_test.cc
+++ /dev/null
@@ -1,489 +0,0 @@
-// 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.
-
-#include "src/tools/runfiles/runfiles.h"
-
-#ifdef COMPILER_MSVC
-#include <windows.h>
-#endif // COMPILER_MSVC
-
-#include <fstream>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "gtest/gtest.h"
-#include "src/main/cpp/util/file.h"
-
-#define _T(x) #x
-#define T(x) _T(x)
-#define LINE() T(__LINE__)
-
-namespace bazel {
-namespace runfiles {
-namespace {
-
-using bazel::runfiles::testing::TestOnly_CreateRunfiles;
-using bazel::runfiles::testing::TestOnly_IsAbsolute;
-using std::cerr;
-using std::endl;
-using std::function;
-using std::pair;
-using std::string;
-using std::unique_ptr;
-using std::vector;
-
-class RunfilesTest : public ::testing::Test {
- protected:
- // Create a temporary file that is deleted with the destructor.
- class MockFile {
- public:
- // Create an empty file with the given name under $TEST_TMPDIR.
- static MockFile* Create(const string& name);
-
- // Create a file with the given name and contents under $TEST_TMPDIR.
- // The method ensures to create all parent directories, so `name` is allowed
- // to contain directory components.
- static MockFile* Create(const string& name, const vector<string>& lines);
-
- ~MockFile();
- const string& Path() const { return path_; }
-
- private:
- MockFile(const string& path) : path_(path) {}
- MockFile(const MockFile&) = delete;
- MockFile(MockFile&&) = delete;
- MockFile& operator=(const MockFile&) = delete;
- MockFile& operator=(MockFile&&) = delete;
-
- const string path_;
- };
-
- static string GetTemp();
-
- static function<string(const string&)> kEnvWithTestSrcdir;
-};
-
-function<string(const string&)> RunfilesTest::kEnvWithTestSrcdir =
- [](const string& key) {
- if (key == "TEST_SRCDIR") {
- return string("always ignored");
- } else {
- return string();
- }
- };
-
-string RunfilesTest::GetTemp() {
-#ifdef COMPILER_MSVC
- DWORD size = ::GetEnvironmentVariableA("TEST_TMPDIR", NULL, 0);
- if (size == 0) {
- return std::move(string()); // unset or empty envvar
- }
- unique_ptr<char[]> value(new char[size]);
- ::GetEnvironmentVariableA("TEST_TMPDIR", value.get(), size);
- return std::move(string(value.get()));
-#else
- char* result = getenv("TEST_TMPDIR");
- return result != NULL ? std::move(string(result)) : std::move(string());
-#endif
-}
-
-RunfilesTest::MockFile* RunfilesTest::MockFile::Create(const string& name) {
- return Create(name, vector<string>());
-}
-
-RunfilesTest::MockFile* RunfilesTest::MockFile::Create(
- const string& name, const vector<string>& lines) {
- if (name.find("..") != string::npos || TestOnly_IsAbsolute(name)) {
- cerr << "WARNING: " << __FILE__ << "(" << __LINE__ << "): bad name: \""
- << name << "\"" << endl;
- return nullptr;
- }
-
- string tmp(std::move(RunfilesTest::GetTemp()));
- if (tmp.empty()) {
- cerr << "WARNING: " << __FILE__ << "(" << __LINE__
- << "): $TEST_TMPDIR is empty" << endl;
- return nullptr;
- }
- string path(tmp + "/" + name);
- string dirname = blaze_util::Dirname(path);
- if (!blaze_util::MakeDirectories(dirname, 0777)) {
- cerr << "WARNING: " << __FILE__ << "(" << __LINE__ << "): MakeDirectories("
- << dirname << ") failed" << endl;
- return nullptr;
- }
-
- auto stm = std::ofstream(path);
- for (auto i : lines) {
- stm << i << std::endl;
- }
- return new MockFile(path);
-}
-
-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"}));
- EXPECT_TRUE(mf != nullptr);
- string argv0(mf->Path().substr(
- 0, mf->Path().size() - string(".runfiles_manifest").size()));
-
- string error;
- unique_ptr<Runfiles> r(
- TestOnly_CreateRunfiles(argv0, kEnvWithTestSrcdir, &error));
- ASSERT_NE(r, nullptr);
- EXPECT_TRUE(error.empty());
- EXPECT_EQ(r->Rlocation("a/b"), "c/d");
- // We know it's manifest-based because it returns empty string for unknown
- // paths.
- EXPECT_EQ(r->Rlocation("unknown"), "");
-}
-
-TEST_F(RunfilesTest,
- CreatesManifestBasedRunfilesFromManifestInRunfilesDirectory) {
- unique_ptr<MockFile> mf(
- MockFile::Create("foo" LINE() ".runfiles/MANIFEST", {"a/b c/d"}));
- EXPECT_TRUE(mf != nullptr);
- string argv0(mf->Path().substr(
- 0, mf->Path().size() - string(".runfiles/MANIFEST").size()));
-
- string error;
- unique_ptr<Runfiles> r(
- TestOnly_CreateRunfiles(argv0, kEnvWithTestSrcdir, &error));
- ASSERT_NE(r, nullptr);
- EXPECT_TRUE(error.empty());
- EXPECT_EQ(r->Rlocation("a/b"), "c/d");
- // We know it's manifest-based because it returns empty string for unknown
- // paths.
- EXPECT_EQ(r->Rlocation("unknown"), "");
-}
-
-TEST_F(RunfilesTest, CreatesManifestBasedRunfilesFromEnvvar) {
- unique_ptr<MockFile> mf(
- MockFile::Create("foo" LINE() ".runfiles_manifest", {"a/b c/d"}));
- EXPECT_TRUE(mf != nullptr);
-
- string error;
- unique_ptr<Runfiles> r(TestOnly_CreateRunfiles(
- "ignore-argv0",
- [&mf](const string& key) {
- if (key == "RUNFILES_MANIFEST_FILE") {
- return mf->Path();
- } else if (key == "RUNFILES_DIR") {
- return string("ignored when RUNFILES_MANIFEST_FILE has a value");
- } else if (key == "TEST_SRCDIR") {
- return string("always ignored");
- } else {
- return string();
- }
- },
- &error));
- ASSERT_NE(r, nullptr);
- EXPECT_TRUE(error.empty());
- EXPECT_EQ(r->Rlocation("a/b"), "c/d");
- // We know it's manifest-based because it returns empty string for unknown
- // paths.
- EXPECT_EQ(r->Rlocation("unknown"), "");
-}
-
-TEST_F(RunfilesTest, CannotCreateManifestBasedRunfilesDueToBadManifest) {
- unique_ptr<MockFile> mf(
- MockFile::Create("foo" LINE() ".runfiles_manifest", {"a b", "nospace"}));
- EXPECT_TRUE(mf != nullptr);
-
- string error;
- unique_ptr<Runfiles> r(Runfiles::CreateManifestBased(mf->Path(), &error));
- ASSERT_EQ(r, nullptr);
- EXPECT_NE(error.find("bad runfiles manifest entry"), string::npos);
- EXPECT_NE(error.find("line #2: \"nospace\""), string::npos);
-}
-
-TEST_F(RunfilesTest, ManifestBasedRunfilesRlocation) {
- unique_ptr<MockFile> mf(
- MockFile::Create("foo" LINE() ".runfiles_manifest", {"a/b c/d"}));
- EXPECT_TRUE(mf != nullptr);
-
- string error;
- unique_ptr<Runfiles> r(Runfiles::CreateManifestBased(mf->Path(), &error));
- ASSERT_NE(r, nullptr);
- EXPECT_TRUE(error.empty());
- EXPECT_EQ(r->Rlocation("a/b"), "c/d");
- EXPECT_EQ(r->Rlocation("c/d"), "");
- EXPECT_EQ(r->Rlocation(""), "");
- EXPECT_EQ(r->Rlocation("foo"), "");
- EXPECT_EQ(r->Rlocation("foo/"), "");
- EXPECT_EQ(r->Rlocation("foo/bar"), "");
- EXPECT_EQ(r->Rlocation("../foo"), "");
- EXPECT_EQ(r->Rlocation("foo/.."), "");
- EXPECT_EQ(r->Rlocation("foo/../bar"), "");
- EXPECT_EQ(r->Rlocation("./foo"), "");
- EXPECT_EQ(r->Rlocation("foo/."), "");
- EXPECT_EQ(r->Rlocation("foo/./bar"), "");
- EXPECT_EQ(r->Rlocation("//foo"), "");
- EXPECT_EQ(r->Rlocation("foo//"), "");
- EXPECT_EQ(r->Rlocation("foo//bar"), "");
- EXPECT_EQ(r->Rlocation("/Foo"), "/Foo");
- EXPECT_EQ(r->Rlocation("c:/Foo"), "c:/Foo");
- EXPECT_EQ(r->Rlocation("c:\\Foo"), "c:\\Foo");
-}
-
-TEST_F(RunfilesTest, DirectoryBasedRunfilesRlocation) {
- string error;
- unique_ptr<Runfiles> r(Runfiles::CreateDirectoryBased("whatever", &error));
- ASSERT_NE(r, nullptr);
- EXPECT_TRUE(error.empty());
-
- EXPECT_EQ(r->Rlocation("a/b"), "whatever/a/b");
- EXPECT_EQ(r->Rlocation("c/d"), "whatever/c/d");
- EXPECT_EQ(r->Rlocation(""), "");
- EXPECT_EQ(r->Rlocation("foo"), "whatever/foo");
- EXPECT_EQ(r->Rlocation("foo/"), "whatever/foo/");
- EXPECT_EQ(r->Rlocation("foo/bar"), "whatever/foo/bar");
- EXPECT_EQ(r->Rlocation("../foo"), "");
- EXPECT_EQ(r->Rlocation("foo/.."), "");
- EXPECT_EQ(r->Rlocation("foo/../bar"), "");
- EXPECT_EQ(r->Rlocation("./foo"), "");
- EXPECT_EQ(r->Rlocation("foo/."), "");
- EXPECT_EQ(r->Rlocation("foo/./bar"), "");
- EXPECT_EQ(r->Rlocation("//foo"), "");
- EXPECT_EQ(r->Rlocation("foo//"), "");
- EXPECT_EQ(r->Rlocation("foo//bar"), "");
- EXPECT_EQ(r->Rlocation("/Foo"), "/Foo");
- EXPECT_EQ(r->Rlocation("c:/Foo"), "c:/Foo");
- 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, 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")));
- string argv0(mf->Path().substr(
- 0, mf->Path().size() - string(".runfiles/dummy").size()));
-
- string error;
- unique_ptr<Runfiles> r(
- TestOnly_CreateRunfiles(argv0, kEnvWithTestSrcdir, &error));
- ASSERT_NE(r, nullptr);
- EXPECT_TRUE(error.empty());
-
- EXPECT_EQ(r->Rlocation("a/b"), argv0 + ".runfiles/a/b");
- // We know it's directory-based because it returns some result for unknown
- // paths.
- EXPECT_EQ(r->Rlocation("unknown"), argv0 + ".runfiles/unknown");
-}
-
-TEST_F(RunfilesTest, CreatesDirectoryBasedRunfilesFromEnvvar) {
- string error;
- unique_ptr<Runfiles> r(
- TestOnly_CreateRunfiles("ignore-argv0",
- [](const string& key) {
- if (key == "RUNFILES_DIR") {
- return string("runfiles/dir");
- } else if (key == "TEST_SRCDIR") {
- return string("always ignored");
- } else {
- return string();
- }
- },
- &error));
- ASSERT_NE(r, nullptr);
- EXPECT_TRUE(error.empty());
-
- EXPECT_EQ(r->Rlocation("a/b"), "runfiles/dir/a/b");
- EXPECT_EQ(r->Rlocation("foo"), "runfiles/dir/foo");
- EXPECT_EQ(r->Rlocation("/Foo"), "/Foo");
- EXPECT_EQ(r->Rlocation("c:/Foo"), "c:/Foo");
- EXPECT_EQ(r->Rlocation("c:\\Foo"), "c:\\Foo");
-}
-
-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(
- Runfiles::CreateManifestBased("non-existent-file", &error));
- ASSERT_EQ(r, nullptr);
- EXPECT_NE(error.find("cannot open runfiles manifest"), string::npos);
-}
-
-TEST_F(RunfilesTest, FailsToCreateAnyRunfilesBecauseEnvvarsAreNotDefined) {
- unique_ptr<MockFile> mf(MockFile::Create(string("foo" LINE())));
- EXPECT_TRUE(mf != nullptr);
-
- string error;
- unique_ptr<Runfiles> r(
- TestOnly_CreateRunfiles("ignore-argv0",
- [&mf](const string& key) {
- if (key == "RUNFILES_MANIFEST_FILE") {
- return mf->Path();
- } else if (key == "RUNFILES_DIR") {
- return string("whatever");
- } else if (key == "TEST_SRCDIR") {
- return string("always ignored");
- } else {
- return string();
- }
- },
- &error));
- ASSERT_NE(r, nullptr);
- EXPECT_TRUE(error.empty());
-
- r.reset(TestOnly_CreateRunfiles("ignore-argv0",
- [](const string& key) {
- if (key == "RUNFILES_DIR") {
- return string("whatever");
- } else if (key == "TEST_SRCDIR") {
- return string("always ignored");
- } else {
- return string();
- }
- },
- &error));
- ASSERT_NE(r, nullptr);
- EXPECT_TRUE(error.empty());
-
- r.reset(TestOnly_CreateRunfiles("ignore-argv0", kEnvWithTestSrcdir, &error));
- ASSERT_EQ(r, nullptr);
- EXPECT_NE(error.find("cannot find runfiles"), string::npos);
-}
-
-TEST_F(RunfilesTest, MockFileTest) {
- {
- unique_ptr<MockFile> mf(MockFile::Create(string("foo" LINE() "/..")));
- EXPECT_TRUE(mf == nullptr);
- }
-
- {
- unique_ptr<MockFile> mf(MockFile::Create(string("/Foo" LINE())));
- EXPECT_TRUE(mf == nullptr);
- }
-
- {
- unique_ptr<MockFile> mf(MockFile::Create(string("C:/Foo" LINE())));
- EXPECT_TRUE(mf == nullptr);
- }
-
- string path;
- {
- unique_ptr<MockFile> mf(MockFile::Create(string("foo" LINE() "/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() "/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"),
- {"hello world", "you are beautiful"}));
- EXPECT_TRUE(mf != nullptr);
- path = mf->Path();
-
- std::ifstream stm(path);
- EXPECT_TRUE(stm.good());
- string actual;
- std::getline(stm, actual);
- EXPECT_EQ("hello world", actual);
- std::getline(stm, actual);
- EXPECT_EQ("you are beautiful", actual);
- std::getline(stm, actual);
- EXPECT_EQ("", actual);
- }
- {
- std::ifstream stm(path);
- EXPECT_FALSE(stm.good());
- }
-}
-
-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