mirror of https://github.com/bazelbuild/rules_cc
The targets in the old package were either not publicly visible or testonly dependencies and had diverged heavily from @bazel_tools.
Instead, add an alias to the Bazel-provided runfiles library under //cc/runfiles, following https://bazel.build/rules/deploying. Closes #162 PiperOrigin-RevId: 500929486 Change-Id: I3290c2b836af2313fbf45459c81af24fbde877d0
This commit is contained in:
parent
15ed46df43
commit
06112c7d9e
|
@ -11,12 +11,12 @@ x_defaults:
|
|||
- "//cc:all"
|
||||
- "//cc/private/rules_impl:all"
|
||||
- "//cc/private/toolchain:all"
|
||||
- "//cc/runfiles:all"
|
||||
- "//examples:all"
|
||||
- "//examples/my_c_archive:all"
|
||||
- "//examples/my_c_compile:all"
|
||||
- "//examples/write_cc_toolchain_cpu:all"
|
||||
- "//tools/migration:all"
|
||||
- "//tools/runfiles:all"
|
||||
test_flags:
|
||||
- "--test_timeout=120"
|
||||
test_targets:
|
||||
|
@ -29,7 +29,6 @@ x_defaults:
|
|||
- "//examples/my_c_compile:all"
|
||||
- "//examples/write_cc_toolchain_cpu:all"
|
||||
- "//tools/migration:all"
|
||||
- "//tools/runfiles:all"
|
||||
|
||||
buildifier:
|
||||
version: latest
|
||||
|
|
|
@ -6,4 +6,3 @@ tasks:
|
|||
platform: ${{ platform }}
|
||||
build_targets:
|
||||
- "@rules_cc//cc/..."
|
||||
- "@rules_cc//tools/runfiles"
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
licenses(["notice"])
|
||||
|
||||
alias(
|
||||
name = "runfiles",
|
||||
actual = "@bazel_tools//tools/cpp/runfiles",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
|
@ -1,20 +0,0 @@
|
|||
load("//third_party/bazel_rules/rules_cc/cc:defs.bzl", "cc_library", "cc_test")
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
cc_library(
|
||||
name = "runfiles",
|
||||
testonly = 1,
|
||||
srcs = ["runfiles_src.cc"],
|
||||
hdrs = ["runfiles_src.h"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "runfiles_test",
|
||||
srcs = ["runfiles_test.cc"],
|
||||
deps = [
|
||||
":runfiles",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
|
@ -1,318 +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.
|
||||
|
||||
// The "srcs_for_embedded_tools" rule in the same package sets the line below to
|
||||
// include runfiles.h from the correct path. Do not modify the line below.
|
||||
#include "tools/runfiles/runfiles_src.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#else // not _WIN32
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#endif // _WIN32
|
||||
|
||||
#include <fstream>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <memory>
|
||||
#endif // _WIN32
|
||||
|
||||
namespace bazel {
|
||||
namespace tools {
|
||||
namespace cpp {
|
||||
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 char* prefix) {
|
||||
if (!prefix || !*prefix) {
|
||||
return true;
|
||||
}
|
||||
if (s.empty()) {
|
||||
return false;
|
||||
}
|
||||
return s.find(prefix) == 0;
|
||||
}
|
||||
|
||||
bool contains(const string& s, const char* substr) {
|
||||
if (!substr || !*substr) {
|
||||
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();
|
||||
}
|
||||
|
||||
bool IsReadableFile(const string& path) {
|
||||
return std::ifstream(path).is_open();
|
||||
}
|
||||
|
||||
bool IsDirectory(const string& path) {
|
||||
#ifdef _WIN32
|
||||
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
|
||||
}
|
||||
|
||||
bool PathsFrom(const std::string& argv0, std::string runfiles_manifest_file,
|
||||
std::string runfiles_dir, std::string* out_manifest,
|
||||
std::string* out_directory);
|
||||
|
||||
bool PathsFrom(const std::string& argv0, std::string runfiles_manifest_file,
|
||||
std::string runfiles_dir,
|
||||
std::function<bool(const std::string&)> is_runfiles_manifest,
|
||||
std::function<bool(const std::string&)> is_runfiles_directory,
|
||||
std::string* out_manifest, std::string* out_directory);
|
||||
|
||||
bool ParseManifest(const string& path, map<string, string>* result,
|
||||
string* error);
|
||||
|
||||
} // namespace
|
||||
|
||||
Runfiles* Runfiles::Create(const string& argv0,
|
||||
const string& runfiles_manifest_file,
|
||||
const string& runfiles_dir, string* error) {
|
||||
string manifest, directory;
|
||||
if (!PathsFrom(argv0, runfiles_manifest_file, runfiles_dir, &manifest,
|
||||
&directory)) {
|
||||
if (error) {
|
||||
std::ostringstream err;
|
||||
err << "ERROR: " << __FILE__ << "(" << __LINE__
|
||||
<< "): cannot find runfiles (argv0=\"" << argv0 << "\")";
|
||||
*error = err.str();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const vector<pair<string, string> > envvars = {
|
||||
{"RUNFILES_MANIFEST_FILE", manifest},
|
||||
{"RUNFILES_DIR", directory},
|
||||
// TODO(laszlocsomor): remove JAVA_RUNFILES once the Java launcher can
|
||||
// pick up RUNFILES_DIR.
|
||||
{"JAVA_RUNFILES", directory}};
|
||||
|
||||
map<string, string> runfiles;
|
||||
if (!manifest.empty()) {
|
||||
if (!ParseManifest(manifest, &runfiles, error)) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return new Runfiles(std::move(runfiles), std::move(directory),
|
||||
std::move(envvars));
|
||||
}
|
||||
|
||||
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 _WIN32
|
||||
DWORD size = ::GetEnvironmentVariableA(key.c_str(), NULL, 0);
|
||||
if (size == 0) {
|
||||
return string(); // unset or empty envvar
|
||||
}
|
||||
std::unique_ptr<char[]> value(new char[size]);
|
||||
::GetEnvironmentVariableA(key.c_str(), value.get(), size);
|
||||
return value.get();
|
||||
#else
|
||||
char* result = getenv(key.c_str());
|
||||
return (result == NULL) ? string() : string(result);
|
||||
#endif
|
||||
}
|
||||
|
||||
string Runfiles::Rlocation(const string& path) const {
|
||||
if (path.empty() || starts_with(path, "../") || contains(path, "/..") ||
|
||||
starts_with(path, "./") || contains(path, "/./") ||
|
||||
ends_with(path, "/.") || contains(path, "//")) {
|
||||
return string();
|
||||
}
|
||||
if (IsAbsolute(path)) {
|
||||
return path;
|
||||
}
|
||||
const auto value = runfiles_map_.find(path);
|
||||
if (value != runfiles_map_.end()) {
|
||||
return value->second;
|
||||
}
|
||||
if (!directory_.empty()) {
|
||||
return directory_ + "/" + path;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
bool 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;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace testing {
|
||||
|
||||
bool TestOnly_PathsFrom(const string& argv0, string mf, string dir,
|
||||
function<bool(const string&)> is_runfiles_manifest,
|
||||
function<bool(const string&)> is_runfiles_directory,
|
||||
string* out_manifest, string* out_directory) {
|
||||
return PathsFrom(argv0, mf, dir, is_runfiles_manifest, is_runfiles_directory,
|
||||
out_manifest, out_directory);
|
||||
}
|
||||
|
||||
bool TestOnly_IsAbsolute(const string& path) { return IsAbsolute(path); }
|
||||
|
||||
} // namespace testing
|
||||
|
||||
Runfiles* Runfiles::Create(const string& argv0, string* error) {
|
||||
return Runfiles::Create(argv0, GetEnv("RUNFILES_MANIFEST_FILE"),
|
||||
GetEnv("RUNFILES_DIR"), error);
|
||||
}
|
||||
|
||||
Runfiles* Runfiles::CreateForTest(std::string* error) {
|
||||
return Runfiles::Create(std::string(), GetEnv("RUNFILES_MANIFEST_FILE"),
|
||||
GetEnv("TEST_SRCDIR"), error);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
bool PathsFrom(const string& argv0, string mf, string dir, string* out_manifest,
|
||||
string* out_directory) {
|
||||
return PathsFrom(
|
||||
argv0, mf, dir, [](const string& path) { return IsReadableFile(path); },
|
||||
[](const string& path) { return IsDirectory(path); }, out_manifest,
|
||||
out_directory);
|
||||
}
|
||||
|
||||
bool PathsFrom(const string& argv0, string mf, string dir,
|
||||
function<bool(const string&)> is_runfiles_manifest,
|
||||
function<bool(const string&)> is_runfiles_directory,
|
||||
string* out_manifest, string* out_directory) {
|
||||
out_manifest->clear();
|
||||
out_directory->clear();
|
||||
|
||||
bool mfValid = is_runfiles_manifest(mf);
|
||||
bool dirValid = is_runfiles_directory(dir);
|
||||
|
||||
if (!argv0.empty() && !mfValid && !dirValid) {
|
||||
mf = argv0 + ".runfiles/MANIFEST";
|
||||
dir = argv0 + ".runfiles";
|
||||
mfValid = is_runfiles_manifest(mf);
|
||||
dirValid = is_runfiles_directory(dir);
|
||||
if (!mfValid) {
|
||||
mf = argv0 + ".runfiles_manifest";
|
||||
mfValid = is_runfiles_manifest(mf);
|
||||
}
|
||||
}
|
||||
|
||||
if (!mfValid && !dirValid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mfValid) {
|
||||
mf = dir + "/MANIFEST";
|
||||
mfValid = is_runfiles_manifest(mf);
|
||||
if (!mfValid) {
|
||||
mf = dir + "_manifest";
|
||||
mfValid = is_runfiles_manifest(mf);
|
||||
}
|
||||
}
|
||||
|
||||
if (!dirValid &&
|
||||
(ends_with(mf, ".runfiles_manifest") || ends_with(mf, "/MANIFEST"))) {
|
||||
static const size_t kSubstrLen = 9; // "_manifest" or "/MANIFEST"
|
||||
dir = mf.substr(0, mf.size() - kSubstrLen);
|
||||
dirValid = is_runfiles_directory(dir);
|
||||
}
|
||||
|
||||
if (mfValid) {
|
||||
*out_manifest = mf;
|
||||
}
|
||||
|
||||
if (dirValid) {
|
||||
*out_directory = dir;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
} // namespace runfiles
|
||||
} // namespace cpp
|
||||
} // namespace tools
|
||||
} // namespace bazel
|
|
@ -1,222 +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:
|
||||
// 1. Depend on this runfiles library from your build rule:
|
||||
//
|
||||
// cc_binary(
|
||||
// name = "my_binary",
|
||||
// ...
|
||||
// deps = ["@rules_cc//cc/private/toolchain/runfiles"],
|
||||
// )
|
||||
//
|
||||
// 2. Include the runfiles library.
|
||||
//
|
||||
// #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));
|
||||
//
|
||||
// // Important:
|
||||
// // If this is a test, use Runfiles::CreateForTest(&error).
|
||||
// // Otherwise, if you don't have the value for argv[0] for whatever
|
||||
// // reason, then use Runfiles::Create(&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:
|
||||
//
|
||||
// std::unique_ptr<Runfiles> runfiles(Runfiles::Create(argv[0], &error));
|
||||
//
|
||||
// std::string path = runfiles->Rlocation("path/to/binary"));
|
||||
// if (!path.empty()) {
|
||||
// ... // create "args" argument vector for execv
|
||||
// const auto envvars = runfiles->EnvVars();
|
||||
// pid_t child = fork();
|
||||
// if (child) {
|
||||
// int status;
|
||||
// waitpid(child, &status, 0);
|
||||
// } else {
|
||||
// for (const auto i : envvars) {
|
||||
// setenv(i.first.c_str(), i.second.c_str(), 1);
|
||||
// }
|
||||
// execv(args[0], args);
|
||||
// }
|
||||
|
||||
#ifndef TOOLS_CPP_RUNFILES_RUNFILES_H_
|
||||
#define TOOLS_CPP_RUNFILES_RUNFILES_H_ 1
|
||||
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace bazel {
|
||||
namespace tools {
|
||||
namespace cpp {
|
||||
namespace runfiles {
|
||||
|
||||
class Runfiles {
|
||||
public:
|
||||
virtual ~Runfiles() {}
|
||||
|
||||
// Returns a new `Runfiles` instance.
|
||||
//
|
||||
// Use this from within `cc_test` rules.
|
||||
//
|
||||
// Returns nullptr on error. If `error` is provided, the method prints an
|
||||
// error message into it.
|
||||
//
|
||||
// This method looks at the RUNFILES_MANIFEST_FILE and TEST_SRCDIR
|
||||
// environment variables.
|
||||
static Runfiles* CreateForTest(std::string* error = nullptr);
|
||||
|
||||
// Returns a new `Runfiles` instance.
|
||||
//
|
||||
// Use this from `cc_binary` or `cc_library` rules. You may pass an empty
|
||||
// `argv0` if `argv[0]` from the `main` method is unknown.
|
||||
//
|
||||
// Returns nullptr on error. If `error` is provided, the method prints an
|
||||
// error message into it.
|
||||
//
|
||||
// This method looks at the RUNFILES_MANIFEST_FILE and RUNFILES_DIR
|
||||
// environment variables. If either is empty, the method looks for the
|
||||
// manifest or directory using the other environment variable, or using argv0
|
||||
// (unless it's empty).
|
||||
static Runfiles* Create(const std::string& argv0,
|
||||
std::string* error = nullptr);
|
||||
|
||||
// Returns a new `Runfiles` instance.
|
||||
//
|
||||
// Use this from any `cc_*` rule if you want to manually specify the paths to
|
||||
// the runfiles manifest and/or runfiles directory. You may pass an empty
|
||||
// `argv0` if `argv[0]` from the `main` method is unknown.
|
||||
//
|
||||
// This method is the same as `Create(argv0, error)`, except it uses
|
||||
// `runfiles_manifest_file` and `runfiles_dir` as the corresponding
|
||||
// environment variable values, instead of looking up the actual environment
|
||||
// variables.
|
||||
static Runfiles* Create(const std::string& argv0,
|
||||
const std::string& runfiles_manifest_file,
|
||||
const std::string& runfiles_dir,
|
||||
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 exist. The caller should verify the path's
|
||||
// existence.
|
||||
//
|
||||
// The function may return an empty string if it cannot find a runfile.
|
||||
//
|
||||
// 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
|
||||
std::string Rlocation(const std::string& path) const;
|
||||
|
||||
// Returns environment variables for subprocesses.
|
||||
//
|
||||
// The caller should set the returned key-value pairs in the environment of
|
||||
// subprocesses, so that those subprocesses can also access runfiles (in case
|
||||
// they are also Bazel-built binaries).
|
||||
const std::vector<std::pair<std::string, std::string> >& EnvVars() const {
|
||||
return envvars_;
|
||||
}
|
||||
|
||||
private:
|
||||
Runfiles(const std::map<std::string, std::string>&& runfiles_map,
|
||||
const std::string&& directory,
|
||||
const std::vector<std::pair<std::string, std::string> >&& envvars)
|
||||
: runfiles_map_(std::move(runfiles_map)),
|
||||
directory_(std::move(directory)),
|
||||
envvars_(std::move(envvars)) {}
|
||||
Runfiles(const Runfiles&) = delete;
|
||||
Runfiles(Runfiles&&) = delete;
|
||||
Runfiles& operator=(const Runfiles&) = delete;
|
||||
Runfiles& operator=(Runfiles&&) = delete;
|
||||
|
||||
const std::map<std::string, std::string> runfiles_map_;
|
||||
const std::string directory_;
|
||||
const std::vector<std::pair<std::string, std::string> > envvars_;
|
||||
};
|
||||
|
||||
// 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.
|
||||
//
|
||||
// Computes the path of the runfiles manifest and the runfiles directory.
|
||||
//
|
||||
// If the method finds both a valid manifest and valid directory according to
|
||||
// `is_runfiles_manifest` and `is_runfiles_directory`, then the method sets
|
||||
// the corresponding values to `out_manifest` and `out_directory` and returns
|
||||
// true.
|
||||
//
|
||||
// If the method only finds a valid manifest or a valid directory, but not
|
||||
// both, then it sets the corresponding output variable (`out_manifest` or
|
||||
// `out_directory`) to the value while clearing the other output variable. The
|
||||
// method still returns true in this case.
|
||||
//
|
||||
// If the method cannot find either a valid manifest or valid directory, it
|
||||
// clears both output variables and returns false.
|
||||
bool TestOnly_PathsFrom(
|
||||
const std::string& argv0, std::string runfiles_manifest_file,
|
||||
std::string runfiles_dir,
|
||||
std::function<bool(const std::string&)> is_runfiles_manifest,
|
||||
std::function<bool(const std::string&)> is_runfiles_directory,
|
||||
std::string* out_manifest, std::string* out_directory);
|
||||
|
||||
// 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 cpp
|
||||
} // namespace tools
|
||||
} // namespace bazel
|
||||
|
||||
#endif // TOOLS_CPP_RUNFILES_RUNFILES_H_
|
|
@ -1,582 +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_src.h"
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif // _WIN32
|
||||
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#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 {
|
||||
namespace cpp {
|
||||
namespace runfiles {
|
||||
namespace {
|
||||
|
||||
using bazel::tools::cpp::runfiles::testing::TestOnly_IsAbsolute;
|
||||
using bazel::tools::cpp::runfiles::testing::TestOnly_PathsFrom;
|
||||
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_; }
|
||||
|
||||
string DirName() const {
|
||||
string::size_type pos = path_.find_last_of('/');
|
||||
return pos == string::npos ? "" : path_.substr(0, pos);
|
||||
}
|
||||
|
||||
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_;
|
||||
};
|
||||
|
||||
void AssertEnvvars(const Runfiles& runfiles,
|
||||
const string& expected_manifest_file,
|
||||
const string& expected_directory);
|
||||
|
||||
static string GetTemp();
|
||||
};
|
||||
|
||||
void RunfilesTest::AssertEnvvars(const Runfiles& runfiles,
|
||||
const string& expected_manifest_file,
|
||||
const string& expected_directory) {
|
||||
vector<pair<string, string> > expected = {
|
||||
{"RUNFILES_MANIFEST_FILE", expected_manifest_file},
|
||||
{"RUNFILES_DIR", expected_directory},
|
||||
{"JAVA_RUNFILES", expected_directory}};
|
||||
ASSERT_EQ(runfiles.EnvVars(), expected);
|
||||
}
|
||||
|
||||
string RunfilesTest::GetTemp() {
|
||||
#ifdef _WIN32
|
||||
DWORD size = ::GetEnvironmentVariableA("TEST_TMPDIR", NULL, 0);
|
||||
if (size == 0) {
|
||||
return string(); // unset or empty envvar
|
||||
}
|
||||
unique_ptr<char[]> value(new char[size]);
|
||||
::GetEnvironmentVariableA("TEST_TMPDIR", value.get(), size);
|
||||
return value.get();
|
||||
#else
|
||||
char* result = getenv("TEST_TMPDIR");
|
||||
return result != NULL ? string(result) : 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(RunfilesTest::GetTemp());
|
||||
if (tmp.empty()) {
|
||||
cerr << "WARNING: " << __FILE__ << "(" << __LINE__
|
||||
<< "): $TEST_TMPDIR is empty" << endl;
|
||||
return nullptr;
|
||||
}
|
||||
string path(tmp + "/" + name);
|
||||
|
||||
string::size_type i = 0;
|
||||
#ifdef _WIN32
|
||||
while ((i = name.find_first_of("/\\", i + 1)) != string::npos) {
|
||||
string d = tmp + "\\" + name.substr(0, i);
|
||||
if (!CreateDirectoryA(d.c_str(), NULL)) {
|
||||
cerr << "ERROR: " << __FILE__ << "(" << __LINE__
|
||||
<< "): failed to create directory \"" << d << "\"" << endl;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
#else
|
||||
while ((i = name.find_first_of('/', i + 1)) != string::npos) {
|
||||
string d = tmp + "/" + name.substr(0, i);
|
||||
if (mkdir(d.c_str(), 0777)) {
|
||||
cerr << "ERROR: " << __FILE__ << "(" << __LINE__
|
||||
<< "): failed to create directory \"" << d << "\"" << endl;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
std::ofstream stm(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_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()));
|
||||
|
||||
string error;
|
||||
unique_ptr<Runfiles> r(Runfiles::Create(argv0, "", "", &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"), "");
|
||||
AssertEnvvars(*r, mf->Path(), "");
|
||||
}
|
||||
|
||||
TEST_F(RunfilesTest,
|
||||
CreatesManifestBasedRunfilesFromManifestInRunfilesDirectory) {
|
||||
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()));
|
||||
|
||||
string error;
|
||||
unique_ptr<Runfiles> r(Runfiles::Create(argv0, "", "", &error));
|
||||
ASSERT_NE(r, nullptr);
|
||||
EXPECT_TRUE(error.empty());
|
||||
EXPECT_EQ(r->Rlocation("a/b"), "c/d");
|
||||
EXPECT_EQ(r->Rlocation("foo"), argv0 + ".runfiles/foo");
|
||||
AssertEnvvars(*r, mf->Path(), argv0 + ".runfiles");
|
||||
}
|
||||
|
||||
TEST_F(RunfilesTest, CreatesManifestBasedRunfilesFromEnvvar) {
|
||||
unique_ptr<MockFile> mf(MockFile::Create(
|
||||
"foo" LINE_AS_STRING() ".runfiles_manifest", {"a/b c/d"}));
|
||||
EXPECT_TRUE(mf != nullptr);
|
||||
|
||||
string error;
|
||||
unique_ptr<Runfiles> r(Runfiles::Create("ignore-argv0", mf->Path(),
|
||||
"non-existent-runfiles_dir", &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"), "");
|
||||
AssertEnvvars(*r, mf->Path(), "");
|
||||
}
|
||||
|
||||
TEST_F(RunfilesTest, CannotCreateManifestBasedRunfilesDueToBadManifest) {
|
||||
unique_ptr<MockFile> mf(MockFile::Create(
|
||||
"foo" LINE_AS_STRING() ".runfiles_manifest", {"a b", "nospace"}));
|
||||
EXPECT_TRUE(mf != nullptr);
|
||||
|
||||
string error;
|
||||
unique_ptr<Runfiles> r(
|
||||
Runfiles::Create("ignore-argv0", 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, ManifestBasedRunfilesRlocationAndEnvVars) {
|
||||
unique_ptr<MockFile> mf(MockFile::Create(
|
||||
"foo" LINE_AS_STRING() ".runfiles_manifest", {"a/b c/d"}));
|
||||
EXPECT_TRUE(mf != nullptr);
|
||||
|
||||
string error;
|
||||
unique_ptr<Runfiles> r(
|
||||
Runfiles::Create("ignore-argv0", 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, DirectoryBasedRunfilesRlocationAndEnvVars) {
|
||||
unique_ptr<MockFile> dummy(
|
||||
MockFile::Create("foo" LINE_AS_STRING() ".runfiles/dummy", {"a/b c/d"}));
|
||||
EXPECT_TRUE(dummy != nullptr);
|
||||
string dir = dummy->DirName();
|
||||
|
||||
string error;
|
||||
unique_ptr<Runfiles> r(Runfiles::Create("ignore-argv0", "", dir, &error));
|
||||
ASSERT_NE(r, nullptr);
|
||||
EXPECT_TRUE(error.empty());
|
||||
|
||||
EXPECT_EQ(r->Rlocation("a/b"), dir + "/a/b");
|
||||
EXPECT_EQ(r->Rlocation("c/d"), dir + "/c/d");
|
||||
EXPECT_EQ(r->Rlocation(""), "");
|
||||
EXPECT_EQ(r->Rlocation("foo"), dir + "/foo");
|
||||
EXPECT_EQ(r->Rlocation("foo/"), dir + "/foo/");
|
||||
EXPECT_EQ(r->Rlocation("foo/bar"), dir + "/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");
|
||||
AssertEnvvars(*r, "", dir);
|
||||
}
|
||||
|
||||
TEST_F(RunfilesTest, ManifestAndDirectoryBasedRunfilesRlocationAndEnvVars) {
|
||||
unique_ptr<MockFile> mf(MockFile::Create(
|
||||
"foo" LINE_AS_STRING() ".runfiles/MANIFEST", {"a/b c/d"}));
|
||||
EXPECT_TRUE(mf != nullptr);
|
||||
string dir = mf->DirName();
|
||||
|
||||
string error;
|
||||
unique_ptr<Runfiles> r(
|
||||
Runfiles::Create("ignore-argv0", 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"), dir + "/c/d");
|
||||
EXPECT_EQ(r->Rlocation(""), "");
|
||||
EXPECT_EQ(r->Rlocation("foo"), dir + "/foo");
|
||||
EXPECT_EQ(r->Rlocation("foo/"), dir + "/foo/");
|
||||
EXPECT_EQ(r->Rlocation("foo/bar"), dir + "/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");
|
||||
AssertEnvvars(*r, mf->Path(), dir);
|
||||
}
|
||||
|
||||
TEST_F(RunfilesTest, ManifestBasedRunfilesEnvVars) {
|
||||
unique_ptr<MockFile> mf(
|
||||
MockFile::Create(string("foo" LINE_AS_STRING() ".runfiles_manifest")));
|
||||
EXPECT_TRUE(mf != nullptr);
|
||||
|
||||
string error;
|
||||
unique_ptr<Runfiles> r(
|
||||
Runfiles::Create("ignore-argv0", mf->Path(), "", &error));
|
||||
ASSERT_NE(r, nullptr);
|
||||
EXPECT_TRUE(error.empty());
|
||||
|
||||
AssertEnvvars(*r, mf->Path(), "");
|
||||
}
|
||||
|
||||
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_AS_STRING() ".runfiles/dummy")));
|
||||
string argv0(mf->Path().substr(
|
||||
0, mf->Path().size() - string(".runfiles/dummy").size()));
|
||||
|
||||
string error;
|
||||
unique_ptr<Runfiles> r(Runfiles::Create(argv0, "", "", &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");
|
||||
AssertEnvvars(*r, "", argv0 + ".runfiles");
|
||||
}
|
||||
|
||||
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_AS_STRING() ".runfiles/dummy")));
|
||||
string dir = mf->DirName();
|
||||
|
||||
string error;
|
||||
unique_ptr<Runfiles> r(Runfiles::Create("ignore-argv0", "", dir, &error));
|
||||
ASSERT_NE(r, nullptr);
|
||||
EXPECT_TRUE(error.empty());
|
||||
|
||||
EXPECT_EQ(r->Rlocation("a/b"), dir + "/a/b");
|
||||
EXPECT_EQ(r->Rlocation("foo"), dir + "/foo");
|
||||
EXPECT_EQ(r->Rlocation("/Foo"), "/Foo");
|
||||
EXPECT_EQ(r->Rlocation("c:/Foo"), "c:/Foo");
|
||||
EXPECT_EQ(r->Rlocation("c:\\Foo"), "c:\\Foo");
|
||||
AssertEnvvars(*r, "", dir);
|
||||
}
|
||||
|
||||
TEST_F(RunfilesTest, FailsToCreateAnyRunfilesBecauseEnvvarsAreNotDefined) {
|
||||
unique_ptr<MockFile> mf(
|
||||
MockFile::Create(string("foo" LINE_AS_STRING() ".runfiles/MANIFEST")));
|
||||
EXPECT_TRUE(mf != nullptr);
|
||||
|
||||
string error;
|
||||
unique_ptr<Runfiles> r(
|
||||
Runfiles::Create("ignore-argv0", mf->Path(), "whatever", &error));
|
||||
ASSERT_NE(r, nullptr);
|
||||
EXPECT_TRUE(error.empty());
|
||||
|
||||
// We create a directory as a side-effect of creating a mock file.
|
||||
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());
|
||||
|
||||
r.reset(Runfiles::Create("ignore-argv0", "", "", &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_AS_STRING() "/..")));
|
||||
EXPECT_TRUE(mf == nullptr);
|
||||
}
|
||||
|
||||
{
|
||||
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_AS_STRING())));
|
||||
EXPECT_TRUE(mf == nullptr);
|
||||
}
|
||||
|
||||
string path;
|
||||
{
|
||||
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();
|
||||
|
||||
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() "/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:\\"));
|
||||
}
|
||||
|
||||
TEST_F(RunfilesTest, PathsFromEnvVars) {
|
||||
string mf, dir;
|
||||
|
||||
// Both envvars have a valid value.
|
||||
EXPECT_TRUE(TestOnly_PathsFrom(
|
||||
"argv0", "mock1/MANIFEST", "mock2",
|
||||
[](const string& path) { return path == "mock1/MANIFEST"; },
|
||||
[](const string& path) { return path == "mock2"; }, &mf, &dir));
|
||||
EXPECT_EQ(mf, "mock1/MANIFEST");
|
||||
EXPECT_EQ(dir, "mock2");
|
||||
|
||||
// RUNFILES_MANIFEST_FILE is invalid but RUNFILES_DIR is good and there's a
|
||||
// runfiles manifest in the runfiles directory.
|
||||
EXPECT_TRUE(TestOnly_PathsFrom(
|
||||
"argv0", "mock1/MANIFEST", "mock2",
|
||||
[](const string& path) { return path == "mock2/MANIFEST"; },
|
||||
[](const string& path) { return path == "mock2"; }, &mf, &dir));
|
||||
EXPECT_EQ(mf, "mock2/MANIFEST");
|
||||
EXPECT_EQ(dir, "mock2");
|
||||
|
||||
// RUNFILES_MANIFEST_FILE is invalid but RUNFILES_DIR is good, but there's no
|
||||
// runfiles manifest in the runfiles directory.
|
||||
EXPECT_TRUE(TestOnly_PathsFrom(
|
||||
"argv0", "mock1/MANIFEST", "mock2",
|
||||
[](const string& path) { return false; },
|
||||
[](const string& path) { return path == "mock2"; }, &mf, &dir));
|
||||
EXPECT_EQ(mf, "");
|
||||
EXPECT_EQ(dir, "mock2");
|
||||
|
||||
// RUNFILES_DIR is invalid but RUNFILES_MANIFEST_FILE is good, and it is in
|
||||
// a valid-looking runfiles directory.
|
||||
EXPECT_TRUE(TestOnly_PathsFrom(
|
||||
"argv0", "mock1/MANIFEST", "mock2",
|
||||
[](const string& path) { return path == "mock1/MANIFEST"; },
|
||||
[](const string& path) { return path == "mock1"; }, &mf, &dir));
|
||||
EXPECT_EQ(mf, "mock1/MANIFEST");
|
||||
EXPECT_EQ(dir, "mock1");
|
||||
|
||||
// RUNFILES_DIR is invalid but RUNFILES_MANIFEST_FILE is good, but it is not
|
||||
// in any valid-looking runfiles directory.
|
||||
EXPECT_TRUE(TestOnly_PathsFrom(
|
||||
"argv0", "mock1/MANIFEST", "mock2",
|
||||
[](const string& path) { return path == "mock1/MANIFEST"; },
|
||||
[](const string& path) { return false; }, &mf, &dir));
|
||||
EXPECT_EQ(mf, "mock1/MANIFEST");
|
||||
EXPECT_EQ(dir, "");
|
||||
|
||||
// Both envvars are invalid, but there's a manifest in a runfiles directory
|
||||
// next to argv0, however there's no other content in the runfiles directory.
|
||||
EXPECT_TRUE(TestOnly_PathsFrom(
|
||||
"argv0", "mock1/MANIFEST", "mock2",
|
||||
[](const string& path) { return path == "argv0.runfiles/MANIFEST"; },
|
||||
[](const string& path) { return false; }, &mf, &dir));
|
||||
EXPECT_EQ(mf, "argv0.runfiles/MANIFEST");
|
||||
EXPECT_EQ(dir, "");
|
||||
|
||||
// Both envvars are invalid, but there's a manifest next to argv0. There's
|
||||
// no runfiles tree anywhere.
|
||||
EXPECT_TRUE(TestOnly_PathsFrom(
|
||||
"argv0", "mock1/MANIFEST", "mock2",
|
||||
[](const string& path) { return path == "argv0.runfiles_manifest"; },
|
||||
[](const string& path) { return false; }, &mf, &dir));
|
||||
EXPECT_EQ(mf, "argv0.runfiles_manifest");
|
||||
EXPECT_EQ(dir, "");
|
||||
|
||||
// Both envvars are invalid, but there's a valid manifest next to argv0, and a
|
||||
// valid runfiles directory (without a manifest in it).
|
||||
EXPECT_TRUE(TestOnly_PathsFrom(
|
||||
"argv0", "mock1/MANIFEST", "mock2",
|
||||
[](const string& path) { return path == "argv0.runfiles_manifest"; },
|
||||
[](const string& path) { return path == "argv0.runfiles"; }, &mf, &dir));
|
||||
EXPECT_EQ(mf, "argv0.runfiles_manifest");
|
||||
EXPECT_EQ(dir, "argv0.runfiles");
|
||||
|
||||
// Both envvars are invalid, but there's a valid runfiles directory next to
|
||||
// argv0, though no manifest in it.
|
||||
EXPECT_TRUE(TestOnly_PathsFrom(
|
||||
"argv0", "mock1/MANIFEST", "mock2",
|
||||
[](const string& path) { return false; },
|
||||
[](const string& path) { return path == "argv0.runfiles"; }, &mf, &dir));
|
||||
EXPECT_EQ(mf, "");
|
||||
EXPECT_EQ(dir, "argv0.runfiles");
|
||||
|
||||
// Both envvars are invalid, but there's a valid runfiles directory next to
|
||||
// argv0 with a valid manifest in it.
|
||||
EXPECT_TRUE(TestOnly_PathsFrom(
|
||||
"argv0", "mock1/MANIFEST", "mock2",
|
||||
[](const string& path) { return path == "argv0.runfiles/MANIFEST"; },
|
||||
[](const string& path) { return path == "argv0.runfiles"; }, &mf, &dir));
|
||||
EXPECT_EQ(mf, "argv0.runfiles/MANIFEST");
|
||||
EXPECT_EQ(dir, "argv0.runfiles");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace runfiles
|
||||
} // namespace cpp
|
||||
} // namespace tools
|
||||
} // namespace bazel
|
Loading…
Reference in New Issue