mirror of https://github.com/bazelbuild/rules_cc
Copy over runfiles library from Bazel
The runfiles library can be maintained independently of Bazel releases and bazel_tools can refer to it via an alias.
This commit is contained in:
parent
a5827bf372
commit
82e44f3c47
|
@ -1,2 +1,4 @@
|
||||||
bazel-*
|
bazel-*
|
||||||
MODULE.bazel.lock
|
MODULE.bazel.lock
|
||||||
|
/.ijwb/
|
||||||
|
/.clwb/
|
||||||
|
|
|
@ -13,5 +13,6 @@ use_repo(cc_configure, "local_config_cc", "local_config_cc_toolchains")
|
||||||
|
|
||||||
register_toolchains("@local_config_cc_toolchains//:all")
|
register_toolchains("@local_config_cc_toolchains//:all")
|
||||||
|
|
||||||
|
bazel_dep(name = "googletest", version = "1.15.2", dev_dependency = True)
|
||||||
bazel_dep(name = "rules_testing", version = "0.6.0", dev_dependency = True)
|
bazel_dep(name = "rules_testing", version = "0.6.0", dev_dependency = True)
|
||||||
bazel_dep(name = "stardoc", version = "0.7.0", dev_dependency = True)
|
bazel_dep(name = "stardoc", version = "0.7.0", dev_dependency = True)
|
||||||
|
|
|
@ -30,3 +30,10 @@ http_archive(
|
||||||
strip_prefix = "rules_testing-0.6.0",
|
strip_prefix = "rules_testing-0.6.0",
|
||||||
url = "https://github.com/bazelbuild/rules_testing/releases/download/v0.6.0/rules_testing-v0.6.0.tar.gz",
|
url = "https://github.com/bazelbuild/rules_testing/releases/download/v0.6.0/rules_testing-v0.6.0.tar.gz",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
http_archive(
|
||||||
|
name = "googletest",
|
||||||
|
integrity = "sha256-e0K01u1IgQxTYsJloX+uvpDcI3PIheUhZDnTeSfwKSY=",
|
||||||
|
strip_prefix = "googletest-1.15.2",
|
||||||
|
url = "https://github.com/google/googletest/releases/download/v1.15.2/googletest-1.15.2.tar.gz",
|
||||||
|
)
|
||||||
|
|
|
@ -1,7 +1,14 @@
|
||||||
|
load("@rules_cc//cc:cc_library.bzl", "cc_library")
|
||||||
|
|
||||||
licenses(["notice"])
|
licenses(["notice"])
|
||||||
|
|
||||||
alias(
|
cc_library(
|
||||||
name = "runfiles",
|
name = "runfiles",
|
||||||
actual = "@bazel_tools//tools/cpp/runfiles",
|
srcs = ["runfiles.cc"],
|
||||||
|
hdrs = ["runfiles.h"],
|
||||||
|
# Ensure that this header can be included from the same directory as the
|
||||||
|
# legacy @bazel_tools//tools/cpp/runfiles library.
|
||||||
|
include_prefix = "tools/cpp/runfiles",
|
||||||
|
strip_include_prefix = ".",
|
||||||
visibility = ["//visibility:public"],
|
visibility = ["//visibility:public"],
|
||||||
)
|
)
|
||||||
|
|
|
@ -0,0 +1,484 @@
|
||||||
|
// 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/cpp/runfiles/runfiles.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 <algorithm>
|
||||||
|
#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);
|
||||||
|
bool ParseRepoMapping(const string& path,
|
||||||
|
map<pair<string, string>, string>* result, string* error);
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
Runfiles* Runfiles::Create(const string& argv0,
|
||||||
|
const string& runfiles_manifest_file,
|
||||||
|
const string& runfiles_dir,
|
||||||
|
const string& source_repository, 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
map<pair<string, string>, string> mapping;
|
||||||
|
if (!ParseRepoMapping(
|
||||||
|
RlocationUnchecked("_repo_mapping", runfiles, directory), &mapping,
|
||||||
|
error)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Runfiles(std::move(runfiles), std::move(directory),
|
||||||
|
std::move(mapping), std::move(envvars),
|
||||||
|
string(source_repository));
|
||||||
|
}
|
||||||
|
|
||||||
|
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(), nullptr, 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 == nullptr) ? string() : string(result);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replaces \s, \n, and \b with their respective characters.
|
||||||
|
string Unescape(const string& path) {
|
||||||
|
string result;
|
||||||
|
result.reserve(path.size());
|
||||||
|
for (size_t i = 0; i < path.size(); ++i) {
|
||||||
|
if (path[i] == '\\' && i + 1 < path.size()) {
|
||||||
|
switch (path[i + 1]) {
|
||||||
|
case 's': {
|
||||||
|
result.push_back(' ');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'n': {
|
||||||
|
result.push_back('\n');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'b': {
|
||||||
|
result.push_back('\\');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
result.push_back(path[i]);
|
||||||
|
result.push_back(path[i + 1]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
++i;
|
||||||
|
} else {
|
||||||
|
result.push_back(path[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
string Runfiles::Rlocation(const string& path) const {
|
||||||
|
return Rlocation(path, source_repository_);
|
||||||
|
}
|
||||||
|
|
||||||
|
string Runfiles::Rlocation(const string& path,
|
||||||
|
const string& source_repo) 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
string::size_type first_slash = path.find_first_of('/');
|
||||||
|
if (first_slash == string::npos) {
|
||||||
|
return RlocationUnchecked(path, runfiles_map_, directory_);
|
||||||
|
}
|
||||||
|
string target_apparent = path.substr(0, first_slash);
|
||||||
|
auto target =
|
||||||
|
repo_mapping_.find(std::make_pair(source_repo, target_apparent));
|
||||||
|
if (target == repo_mapping_.cend()) {
|
||||||
|
return RlocationUnchecked(path, runfiles_map_, directory_);
|
||||||
|
}
|
||||||
|
return RlocationUnchecked(target->second + path.substr(first_slash),
|
||||||
|
runfiles_map_, directory_);
|
||||||
|
}
|
||||||
|
|
||||||
|
string Runfiles::RlocationUnchecked(const string& path,
|
||||||
|
const map<string, string>& runfiles_map,
|
||||||
|
const string& directory) {
|
||||||
|
const auto exact_match = runfiles_map.find(path);
|
||||||
|
if (exact_match != runfiles_map.end()) {
|
||||||
|
return exact_match->second;
|
||||||
|
}
|
||||||
|
if (!runfiles_map.empty()) {
|
||||||
|
// If path references a runfile that lies under a directory that itself is a
|
||||||
|
// runfile, then only the directory is listed in the manifest. Look up all
|
||||||
|
// prefixes of path in the manifest and append the relative path from the
|
||||||
|
// prefix to the looked up path.
|
||||||
|
std::size_t prefix_end = path.size();
|
||||||
|
while ((prefix_end = path.find_last_of('/', prefix_end - 1)) !=
|
||||||
|
string::npos) {
|
||||||
|
const string prefix = path.substr(0, prefix_end);
|
||||||
|
const auto prefix_match = runfiles_map.find(prefix);
|
||||||
|
if (prefix_match != runfiles_map.end()) {
|
||||||
|
return prefix_match->second + "/" + path.substr(prefix_end + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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()) {
|
||||||
|
std::string source;
|
||||||
|
std::string target;
|
||||||
|
if (line[0] == ' ') {
|
||||||
|
// The link path contains escape sequences for spaces and backslashes.
|
||||||
|
string::size_type idx = line.find(' ', 1);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
source = Unescape(line.substr(1, idx - 1));
|
||||||
|
target = Unescape(line.substr(idx + 1));
|
||||||
|
} else {
|
||||||
|
string::size_type idx = line.find(' ');
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
source = line.substr(0, idx);
|
||||||
|
target = line.substr(idx + 1);
|
||||||
|
}
|
||||||
|
(*result)[source] = target;
|
||||||
|
std::getline(stm, line);
|
||||||
|
++line_count;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ParseRepoMapping(const string& path,
|
||||||
|
map<pair<string, string>, string>* result,
|
||||||
|
string* error) {
|
||||||
|
std::ifstream stm(path);
|
||||||
|
if (!stm.is_open()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
string line;
|
||||||
|
std::getline(stm, line);
|
||||||
|
size_t line_count = 1;
|
||||||
|
while (!line.empty()) {
|
||||||
|
string::size_type first_comma = line.find_first_of(',');
|
||||||
|
if (first_comma == string::npos) {
|
||||||
|
if (error) {
|
||||||
|
std::ostringstream err;
|
||||||
|
err << "ERROR: " << __FILE__ << "(" << __LINE__
|
||||||
|
<< "): bad repository mapping entry in \"" << path << "\" line #"
|
||||||
|
<< line_count << ": \"" << line << "\"";
|
||||||
|
*error = err.str();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
string::size_type second_comma = line.find_first_of(',', first_comma + 1);
|
||||||
|
if (second_comma == string::npos) {
|
||||||
|
if (error) {
|
||||||
|
std::ostringstream err;
|
||||||
|
err << "ERROR: " << __FILE__ << "(" << __LINE__
|
||||||
|
<< "): bad repository mapping entry in \"" << path << "\" line #"
|
||||||
|
<< line_count << ": \"" << line << "\"";
|
||||||
|
*error = err.str();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
string source = line.substr(0, first_comma);
|
||||||
|
string target_apparent =
|
||||||
|
line.substr(first_comma + 1, second_comma - (first_comma + 1));
|
||||||
|
string target = line.substr(second_comma + 1);
|
||||||
|
|
||||||
|
(*result)[std::make_pair(source, target_apparent)] = target;
|
||||||
|
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 std::string& argv0,
|
||||||
|
const std::string& runfiles_manifest_file,
|
||||||
|
const std::string& runfiles_dir,
|
||||||
|
std::string* error) {
|
||||||
|
return Runfiles::Create(argv0, runfiles_manifest_file, runfiles_dir, "",
|
||||||
|
error);
|
||||||
|
}
|
||||||
|
|
||||||
|
Runfiles* Runfiles::Create(const string& argv0, const string& source_repository,
|
||||||
|
string* error) {
|
||||||
|
return Runfiles::Create(argv0, GetEnv("RUNFILES_MANIFEST_FILE"),
|
||||||
|
GetEnv("RUNFILES_DIR"), source_repository, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
Runfiles* Runfiles::Create(const string& argv0, string* error) {
|
||||||
|
return Runfiles::Create(argv0, "", error);
|
||||||
|
}
|
||||||
|
|
||||||
|
Runfiles* Runfiles::CreateForTest(const string& source_repository,
|
||||||
|
std::string* error) {
|
||||||
|
return Runfiles::Create(std::string(), GetEnv("RUNFILES_MANIFEST_FILE"),
|
||||||
|
GetEnv("TEST_SRCDIR"), source_repository, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
Runfiles* Runfiles::CreateForTest(std::string* error) {
|
||||||
|
return Runfiles::CreateForTest("", 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
|
|
@ -0,0 +1,266 @@
|
||||||
|
// 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/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], BAZEL_CURRENT_REPOSITORY, &error));
|
||||||
|
//
|
||||||
|
// // Important:
|
||||||
|
// // If this is a test, use
|
||||||
|
// // Runfiles::CreateForTest(BAZEL_CURRENT_REPOSITORY, &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 BAZEL_CURRENT_REPOSITORY macro is available in every target that
|
||||||
|
// depends on the runfiles library.
|
||||||
|
//
|
||||||
|
// 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], BAZEL_CURRENT_REPOSITORY, &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.
|
||||||
|
//
|
||||||
|
// If source_repository is not provided, it defaults to the main repository
|
||||||
|
// (also known as the workspace).
|
||||||
|
static Runfiles* CreateForTest(std::string* error = nullptr);
|
||||||
|
static Runfiles* CreateForTest(const std::string& source_repository,
|
||||||
|
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).
|
||||||
|
//
|
||||||
|
// If source_repository is not provided, it defaults to the main repository
|
||||||
|
// (also known as the workspace).
|
||||||
|
static Runfiles* Create(const std::string& argv0,
|
||||||
|
std::string* error = nullptr);
|
||||||
|
static Runfiles* Create(const std::string& argv0,
|
||||||
|
const std::string& source_repository,
|
||||||
|
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);
|
||||||
|
static Runfiles* Create(const std::string& argv0,
|
||||||
|
const std::string& runfiles_manifest_file,
|
||||||
|
const std::string& runfiles_dir,
|
||||||
|
const std::string& source_repository,
|
||||||
|
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.
|
||||||
|
// source_repository: if provided, overrides the source repository set when
|
||||||
|
// this Runfiles instance was created.
|
||||||
|
// 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;
|
||||||
|
std::string Rlocation(const std::string& path,
|
||||||
|
const std::string& source_repository) 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_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a new Runfiles instance that by default uses the provided source
|
||||||
|
// repository as a default for all calls to Rlocation.
|
||||||
|
//
|
||||||
|
// The current instance remains valid.
|
||||||
|
std::unique_ptr<Runfiles> WithSourceRepository(
|
||||||
|
const std::string& source_repository) const {
|
||||||
|
return std::unique_ptr<Runfiles>(new Runfiles(
|
||||||
|
runfiles_map_, directory_, repo_mapping_, envvars_, source_repository));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Runfiles(
|
||||||
|
std::map<std::string, std::string> runfiles_map, std::string directory,
|
||||||
|
std::map<std::pair<std::string, std::string>, std::string> repo_mapping,
|
||||||
|
std::vector<std::pair<std::string, std::string> > envvars,
|
||||||
|
std::string source_repository)
|
||||||
|
: runfiles_map_(std::move(runfiles_map)),
|
||||||
|
directory_(std::move(directory)),
|
||||||
|
repo_mapping_(std::move(repo_mapping)),
|
||||||
|
envvars_(std::move(envvars)),
|
||||||
|
source_repository_(std::move(source_repository)) {}
|
||||||
|
Runfiles(const Runfiles&) = delete;
|
||||||
|
Runfiles(Runfiles&&) = delete;
|
||||||
|
Runfiles& operator=(const Runfiles&) = delete;
|
||||||
|
Runfiles& operator=(Runfiles&&) = delete;
|
||||||
|
|
||||||
|
static std::string RlocationUnchecked(
|
||||||
|
const std::string& path,
|
||||||
|
const std::map<std::string, std::string>& runfiles_map,
|
||||||
|
const std::string& directory);
|
||||||
|
|
||||||
|
const std::map<std::string, std::string> runfiles_map_;
|
||||||
|
const std::string directory_;
|
||||||
|
const std::map<std::pair<std::string, std::string>, std::string>
|
||||||
|
repo_mapping_;
|
||||||
|
const std::vector<std::pair<std::string, std::string> > envvars_;
|
||||||
|
const std::string source_repository_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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_
|
|
@ -0,0 +1,10 @@
|
||||||
|
load("@rules_cc//cc:cc_test.bzl", "cc_test")
|
||||||
|
|
||||||
|
cc_test(
|
||||||
|
name = "runfiles_test",
|
||||||
|
srcs = ["runfiles_test.cc"],
|
||||||
|
deps = [
|
||||||
|
"//cc/runfiles",
|
||||||
|
"@googletest//:gtest_main",
|
||||||
|
],
|
||||||
|
)
|
|
@ -0,0 +1,882 @@
|
||||||
|
// 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/cpp/runfiles/runfiles.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", nullptr, 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 != nullptr ? 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(), nullptr)) {
|
||||||
|
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
|
||||||
|
|
||||||
|
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_AS_STRING() ".runfiles_manifest", {"a/b c/d"}));
|
||||||
|
ASSERT_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, /*runfiles_manifest_file=*/"",
|
||||||
|
/*runfiles_dir=*/"", &error));
|
||||||
|
ASSERT_TRUE(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"}));
|
||||||
|
ASSERT_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, /*runfiles_manifest_file=*/"",
|
||||||
|
/*runfiles_dir=*/"", &error));
|
||||||
|
ASSERT_TRUE(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"}));
|
||||||
|
ASSERT_TRUE(mf != nullptr);
|
||||||
|
|
||||||
|
string error;
|
||||||
|
unique_ptr<Runfiles> r(Runfiles::Create("ignore-argv0", mf->Path(),
|
||||||
|
"non-existent-runfiles_dir", &error));
|
||||||
|
ASSERT_TRUE(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"}));
|
||||||
|
ASSERT_TRUE(mf != nullptr);
|
||||||
|
|
||||||
|
string error;
|
||||||
|
unique_ptr<Runfiles> r(
|
||||||
|
Runfiles::Create("ignore-argv0", mf->Path(), "", &error));
|
||||||
|
EXPECT_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",
|
||||||
|
"e/f target path with spaces",
|
||||||
|
" h/\\si j k",
|
||||||
|
" dir\\swith\\sspaces l/m",
|
||||||
|
" h/\\n\\s\\bi j k \\n\\b",
|
||||||
|
"not_escaped with\\backslash and spaces",
|
||||||
|
}));
|
||||||
|
ASSERT_TRUE(mf != nullptr);
|
||||||
|
|
||||||
|
string error;
|
||||||
|
unique_ptr<Runfiles> r(
|
||||||
|
Runfiles::Create("ignore-argv0", mf->Path(), "", &error));
|
||||||
|
|
||||||
|
ASSERT_TRUE(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");
|
||||||
|
EXPECT_EQ(r->Rlocation("a/b/file"), "c/d/file");
|
||||||
|
EXPECT_EQ(r->Rlocation("a/b/deeply/nested/file"), "c/d/deeply/nested/file");
|
||||||
|
EXPECT_EQ(r->Rlocation("a/b/deeply/nested/file with spaces"),
|
||||||
|
"c/d/deeply/nested/file with spaces");
|
||||||
|
EXPECT_EQ(r->Rlocation("e/f"), "target path with spaces");
|
||||||
|
EXPECT_EQ(r->Rlocation("e/f/file"), "target path with spaces/file");
|
||||||
|
EXPECT_EQ(r->Rlocation("h/ i"), "j k");
|
||||||
|
EXPECT_EQ(r->Rlocation("h/\n \\i"), "j k \n\\");
|
||||||
|
EXPECT_EQ(r->Rlocation("dir with spaces"), "l/m");
|
||||||
|
EXPECT_EQ(r->Rlocation("dir with spaces/file"), "l/m/file");
|
||||||
|
EXPECT_EQ(r->Rlocation("not_escaped"), "with\\backslash and spaces");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(RunfilesTest, DirectoryBasedRunfilesRlocationAndEnvVars) {
|
||||||
|
unique_ptr<MockFile> dummy(
|
||||||
|
MockFile::Create("foo" LINE_AS_STRING() ".runfiles/dummy", {"a/b c/d"}));
|
||||||
|
ASSERT_TRUE(dummy != nullptr);
|
||||||
|
string dir = dummy->DirName();
|
||||||
|
|
||||||
|
string error;
|
||||||
|
unique_ptr<Runfiles> r(Runfiles::Create("ignore-argv0", "", dir, &error));
|
||||||
|
ASSERT_TRUE(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"}));
|
||||||
|
ASSERT_TRUE(mf != nullptr);
|
||||||
|
string dir = mf->DirName();
|
||||||
|
|
||||||
|
string error;
|
||||||
|
unique_ptr<Runfiles> r(
|
||||||
|
Runfiles::Create("ignore-argv0", mf->Path(), "", &error));
|
||||||
|
|
||||||
|
ASSERT_TRUE(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");
|
||||||
|
EXPECT_EQ(r->Rlocation("a/b/file"), "c/d/file");
|
||||||
|
EXPECT_EQ(r->Rlocation("a/b/deeply/nested/file"), "c/d/deeply/nested/file");
|
||||||
|
AssertEnvvars(*r, mf->Path(), dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(RunfilesTest, ManifestBasedRunfilesEnvVars) {
|
||||||
|
unique_ptr<MockFile> mf(
|
||||||
|
MockFile::Create(string("foo" LINE_AS_STRING() ".runfiles_manifest")));
|
||||||
|
ASSERT_TRUE(mf != nullptr);
|
||||||
|
|
||||||
|
string error;
|
||||||
|
unique_ptr<Runfiles> r(
|
||||||
|
Runfiles::Create("ignore-argv0", mf->Path(), "", &error));
|
||||||
|
ASSERT_TRUE(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, /*runfiles_manifest_file=*/"",
|
||||||
|
/*runfiles_dir=*/"", &error));
|
||||||
|
ASSERT_TRUE(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_TRUE(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")));
|
||||||
|
ASSERT_TRUE(mf != nullptr);
|
||||||
|
|
||||||
|
string error;
|
||||||
|
unique_ptr<Runfiles> r(
|
||||||
|
Runfiles::Create("ignore-argv0", mf->Path(), "whatever", &error));
|
||||||
|
ASSERT_TRUE(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_TRUE(r != nullptr);
|
||||||
|
EXPECT_TRUE(error.empty());
|
||||||
|
|
||||||
|
r.reset(Runfiles::Create("ignore-argv0", /*runfiles_manifest_file=*/"",
|
||||||
|
/*runfiles_dir=*/"", &error));
|
||||||
|
EXPECT_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")));
|
||||||
|
ASSERT_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>()));
|
||||||
|
ASSERT_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"}));
|
||||||
|
ASSERT_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, rm;
|
||||||
|
|
||||||
|
// Both envvars have a valid value.
|
||||||
|
EXPECT_TRUE(TestOnly_PathsFrom(
|
||||||
|
"argv0", "mock1.runfiles/MANIFEST", "mock2.runfiles",
|
||||||
|
[](const string& path) { return path == "mock1.runfiles/MANIFEST"; },
|
||||||
|
[](const string& path) { return path == "mock2.runfiles"; }, &mf, &dir));
|
||||||
|
EXPECT_EQ(mf, "mock1.runfiles/MANIFEST");
|
||||||
|
EXPECT_EQ(dir, "mock2.runfiles");
|
||||||
|
|
||||||
|
// 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.runfiles/MANIFEST", "mock2.runfiles",
|
||||||
|
[](const string& path) { return path == "mock2.runfiles/MANIFEST"; },
|
||||||
|
[](const string& path) { return path == "mock2.runfiles"; }, &mf, &dir));
|
||||||
|
EXPECT_EQ(mf, "mock2.runfiles/MANIFEST");
|
||||||
|
EXPECT_EQ(dir, "mock2.runfiles");
|
||||||
|
|
||||||
|
// 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.runfiles/MANIFEST", "mock2.runfiles",
|
||||||
|
[](const string& path) { return false; },
|
||||||
|
[](const string& path) { return path == "mock2.runfiles"; }, &mf, &dir));
|
||||||
|
EXPECT_EQ(mf, "");
|
||||||
|
EXPECT_EQ(dir, "mock2.runfiles");
|
||||||
|
|
||||||
|
// 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.runfiles/MANIFEST", "mock2",
|
||||||
|
[](const string& path) { return path == "mock1.runfiles/MANIFEST"; },
|
||||||
|
[](const string& path) { return path == "mock1.runfiles"; }, &mf, &dir));
|
||||||
|
EXPECT_EQ(mf, "mock1.runfiles/MANIFEST");
|
||||||
|
EXPECT_EQ(dir, "mock1.runfiles");
|
||||||
|
|
||||||
|
// 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");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(RunfilesTest, ManifestBasedRlocationWithRepoMapping_fromMain) {
|
||||||
|
string uid = LINE_AS_STRING();
|
||||||
|
unique_ptr<MockFile> rm(
|
||||||
|
MockFile::Create("foo" + uid + ".repo_mapping",
|
||||||
|
{",config.json,config.json+1.2.3", ",my_module,_main",
|
||||||
|
",my_protobuf,protobuf+3.19.2", ",my_workspace,_main",
|
||||||
|
"protobuf+3.19.2,config.json,config.json+1.2.3",
|
||||||
|
"protobuf+3.19.2,protobuf,protobuf+3.19.2"}));
|
||||||
|
ASSERT_TRUE(rm != nullptr);
|
||||||
|
unique_ptr<MockFile> mf(MockFile::Create(
|
||||||
|
"foo" + uid + ".runfiles_manifest",
|
||||||
|
{"_repo_mapping " + rm->Path(), "config.json /etc/config.json",
|
||||||
|
"protobuf+3.19.2/foo/runfile C:/Actual Path\\protobuf\\runfile",
|
||||||
|
"_main/bar/runfile /the/path/./to/other//other runfile.txt",
|
||||||
|
"protobuf+3.19.2/bar/dir E:\\Actual Path\\Directory"}));
|
||||||
|
ASSERT_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, /*runfiles_manifest_file=*/"",
|
||||||
|
/*runfiles_dir=*/"",
|
||||||
|
/*source_repository=*/"", &error));
|
||||||
|
ASSERT_TRUE(r != nullptr);
|
||||||
|
EXPECT_TRUE(error.empty());
|
||||||
|
|
||||||
|
EXPECT_EQ(r->Rlocation("my_module/bar/runfile"),
|
||||||
|
"/the/path/./to/other//other runfile.txt");
|
||||||
|
EXPECT_EQ(r->Rlocation("my_workspace/bar/runfile"),
|
||||||
|
"/the/path/./to/other//other runfile.txt");
|
||||||
|
EXPECT_EQ(r->Rlocation("my_protobuf/foo/runfile"),
|
||||||
|
"C:/Actual Path\\protobuf\\runfile");
|
||||||
|
EXPECT_EQ(r->Rlocation("my_protobuf/bar/dir"), "E:\\Actual Path\\Directory");
|
||||||
|
EXPECT_EQ(r->Rlocation("my_protobuf/bar/dir/file"),
|
||||||
|
"E:\\Actual Path\\Directory/file");
|
||||||
|
EXPECT_EQ(r->Rlocation("my_protobuf/bar/dir/de eply/nes ted/fi+le"),
|
||||||
|
"E:\\Actual Path\\Directory/de eply/nes ted/fi+le");
|
||||||
|
|
||||||
|
EXPECT_EQ(r->Rlocation("protobuf/foo/runfile"), "");
|
||||||
|
EXPECT_EQ(r->Rlocation("protobuf/bar/dir"), "");
|
||||||
|
EXPECT_EQ(r->Rlocation("protobuf/bar/dir/file"), "");
|
||||||
|
EXPECT_EQ(r->Rlocation("protobuf/bar/dir/dir/de eply/nes ted/fi+le"), "");
|
||||||
|
|
||||||
|
EXPECT_EQ(r->Rlocation("_main/bar/runfile"),
|
||||||
|
"/the/path/./to/other//other runfile.txt");
|
||||||
|
EXPECT_EQ(r->Rlocation("protobuf+3.19.2/foo/runfile"),
|
||||||
|
"C:/Actual Path\\protobuf\\runfile");
|
||||||
|
EXPECT_EQ(r->Rlocation("protobuf+3.19.2/bar/dir"),
|
||||||
|
"E:\\Actual Path\\Directory");
|
||||||
|
EXPECT_EQ(r->Rlocation("protobuf+3.19.2/bar/dir/file"),
|
||||||
|
"E:\\Actual Path\\Directory/file");
|
||||||
|
EXPECT_EQ(r->Rlocation("protobuf+3.19.2/bar/dir/de eply/nes ted/fi+le"),
|
||||||
|
"E:\\Actual Path\\Directory/de eply/nes ted/fi+le");
|
||||||
|
|
||||||
|
EXPECT_EQ(r->Rlocation("config.json"), "/etc/config.json");
|
||||||
|
EXPECT_EQ(r->Rlocation("_main"), "");
|
||||||
|
EXPECT_EQ(r->Rlocation("my_module"), "");
|
||||||
|
EXPECT_EQ(r->Rlocation("protobuf"), "");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(RunfilesTest, ManifestBasedRlocationWithRepoMapping_fromOtherRepo) {
|
||||||
|
string uid = LINE_AS_STRING();
|
||||||
|
unique_ptr<MockFile> rm(
|
||||||
|
MockFile::Create("foo" + uid + ".repo_mapping",
|
||||||
|
{",config.json,config.json+1.2.3", ",my_module,_main",
|
||||||
|
",my_protobuf,protobuf+3.19.2", ",my_workspace,_main",
|
||||||
|
"protobuf+3.19.2,config.json,config.json+1.2.3",
|
||||||
|
"protobuf+3.19.2,protobuf,protobuf+3.19.2"}));
|
||||||
|
ASSERT_TRUE(rm != nullptr);
|
||||||
|
unique_ptr<MockFile> mf(MockFile::Create(
|
||||||
|
"foo" + uid + ".runfiles_manifest",
|
||||||
|
{"_repo_mapping " + rm->Path(), "config.json /etc/config.json",
|
||||||
|
"protobuf+3.19.2/foo/runfile C:/Actual Path\\protobuf\\runfile",
|
||||||
|
"_main/bar/runfile /the/path/./to/other//other runfile.txt",
|
||||||
|
"protobuf+3.19.2/bar/dir E:\\Actual Path\\Directory"}));
|
||||||
|
ASSERT_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, /*runfiles_manifest_file=*/"",
|
||||||
|
/*runfiles_dir=*/"",
|
||||||
|
"protobuf+3.19.2", &error));
|
||||||
|
ASSERT_TRUE(r != nullptr);
|
||||||
|
EXPECT_TRUE(error.empty());
|
||||||
|
|
||||||
|
EXPECT_EQ(r->Rlocation("protobuf/foo/runfile"),
|
||||||
|
"C:/Actual Path\\protobuf\\runfile");
|
||||||
|
EXPECT_EQ(r->Rlocation("protobuf/bar/dir"), "E:\\Actual Path\\Directory");
|
||||||
|
EXPECT_EQ(r->Rlocation("protobuf/bar/dir/file"),
|
||||||
|
"E:\\Actual Path\\Directory/file");
|
||||||
|
EXPECT_EQ(r->Rlocation("protobuf/bar/dir/de eply/nes ted/fi+le"),
|
||||||
|
"E:\\Actual Path\\Directory/de eply/nes ted/fi+le");
|
||||||
|
|
||||||
|
EXPECT_EQ(r->Rlocation("my_module/bar/runfile"), "");
|
||||||
|
EXPECT_EQ(r->Rlocation("my_protobuf/foo/runfile"), "");
|
||||||
|
EXPECT_EQ(r->Rlocation("my_protobuf/bar/dir"), "");
|
||||||
|
EXPECT_EQ(r->Rlocation("my_protobuf/bar/dir/file"), "");
|
||||||
|
EXPECT_EQ(r->Rlocation("my_protobuf/bar/dir/de eply/nes ted/fi+le"), "");
|
||||||
|
|
||||||
|
EXPECT_EQ(r->Rlocation("_main/bar/runfile"),
|
||||||
|
"/the/path/./to/other//other runfile.txt");
|
||||||
|
EXPECT_EQ(r->Rlocation("protobuf+3.19.2/foo/runfile"),
|
||||||
|
"C:/Actual Path\\protobuf\\runfile");
|
||||||
|
EXPECT_EQ(r->Rlocation("protobuf+3.19.2/bar/dir"),
|
||||||
|
"E:\\Actual Path\\Directory");
|
||||||
|
EXPECT_EQ(r->Rlocation("protobuf+3.19.2/bar/dir/file"),
|
||||||
|
"E:\\Actual Path\\Directory/file");
|
||||||
|
EXPECT_EQ(r->Rlocation("protobuf+3.19.2/bar/dir/de eply/nes ted/fi+le"),
|
||||||
|
"E:\\Actual Path\\Directory/de eply/nes ted/fi+le");
|
||||||
|
|
||||||
|
EXPECT_EQ(r->Rlocation("config.json"), "/etc/config.json");
|
||||||
|
EXPECT_EQ(r->Rlocation("_main"), "");
|
||||||
|
EXPECT_EQ(r->Rlocation("my_module"), "");
|
||||||
|
EXPECT_EQ(r->Rlocation("protobuf"), "");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(RunfilesTest, DirectoryBasedRlocationWithRepoMapping_fromMain) {
|
||||||
|
string uid = LINE_AS_STRING();
|
||||||
|
unique_ptr<MockFile> rm(
|
||||||
|
MockFile::Create("foo" + uid + ".runfiles/_repo_mapping",
|
||||||
|
{",config.json,config.json+1.2.3", ",my_module,_main",
|
||||||
|
",my_protobuf,protobuf+3.19.2", ",my_workspace,_main",
|
||||||
|
"protobuf+3.19.2,config.json,config.json+1.2.3",
|
||||||
|
"protobuf+3.19.2,protobuf,protobuf+3.19.2"}));
|
||||||
|
ASSERT_TRUE(rm != nullptr);
|
||||||
|
string dir = rm->DirName();
|
||||||
|
string argv0(dir.substr(0, dir.size() - string(".runfiles").size()));
|
||||||
|
|
||||||
|
string error;
|
||||||
|
unique_ptr<Runfiles> r(Runfiles::Create(argv0, /*runfiles_manifest_file=*/"",
|
||||||
|
/*runfiles_dir=*/"",
|
||||||
|
/*source_repository=*/"", &error));
|
||||||
|
ASSERT_TRUE(r != nullptr);
|
||||||
|
EXPECT_TRUE(error.empty());
|
||||||
|
|
||||||
|
EXPECT_EQ(r->Rlocation("my_module/bar/runfile"), dir + "/_main/bar/runfile");
|
||||||
|
EXPECT_EQ(r->Rlocation("my_workspace/bar/runfile"),
|
||||||
|
dir + "/_main/bar/runfile");
|
||||||
|
EXPECT_EQ(r->Rlocation("my_protobuf/foo/runfile"),
|
||||||
|
dir + "/protobuf+3.19.2/foo/runfile");
|
||||||
|
EXPECT_EQ(r->Rlocation("my_protobuf/bar/dir"),
|
||||||
|
dir + "/protobuf+3.19.2/bar/dir");
|
||||||
|
EXPECT_EQ(r->Rlocation("my_protobuf/bar/dir/file"),
|
||||||
|
dir + "/protobuf+3.19.2/bar/dir/file");
|
||||||
|
EXPECT_EQ(r->Rlocation("my_protobuf/bar/dir/de eply/nes ted/fi+le"),
|
||||||
|
dir + "/protobuf+3.19.2/bar/dir/de eply/nes ted/fi+le");
|
||||||
|
|
||||||
|
EXPECT_EQ(r->Rlocation("protobuf/foo/runfile"),
|
||||||
|
dir + "/protobuf/foo/runfile");
|
||||||
|
EXPECT_EQ(r->Rlocation("protobuf/bar/dir/dir/de eply/nes ted/fi+le"),
|
||||||
|
dir + "/protobuf/bar/dir/dir/de eply/nes ted/fi+le");
|
||||||
|
|
||||||
|
EXPECT_EQ(r->Rlocation("_main/bar/runfile"), dir + "/_main/bar/runfile");
|
||||||
|
EXPECT_EQ(r->Rlocation("protobuf+3.19.2/foo/runfile"),
|
||||||
|
dir + "/protobuf+3.19.2/foo/runfile");
|
||||||
|
EXPECT_EQ(r->Rlocation("protobuf+3.19.2/bar/dir"),
|
||||||
|
dir + "/protobuf+3.19.2/bar/dir");
|
||||||
|
EXPECT_EQ(r->Rlocation("protobuf+3.19.2/bar/dir/file"),
|
||||||
|
dir + "/protobuf+3.19.2/bar/dir/file");
|
||||||
|
EXPECT_EQ(r->Rlocation("protobuf+3.19.2/bar/dir/de eply/nes ted/fi+le"),
|
||||||
|
dir + "/protobuf+3.19.2/bar/dir/de eply/nes ted/fi+le");
|
||||||
|
|
||||||
|
EXPECT_EQ(r->Rlocation("config.json"), dir + "/config.json");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(RunfilesTest, DirectoryBasedRlocationWithRepoMapping_fromOtherRepo) {
|
||||||
|
string uid = LINE_AS_STRING();
|
||||||
|
unique_ptr<MockFile> rm(
|
||||||
|
MockFile::Create("foo" + uid + ".runfiles/_repo_mapping",
|
||||||
|
{",config.json,config.json+1.2.3", ",my_module,_main",
|
||||||
|
",my_protobuf,protobuf+3.19.2", ",my_workspace,_main",
|
||||||
|
"protobuf+3.19.2,config.json,config.json+1.2.3",
|
||||||
|
"protobuf+3.19.2,protobuf,protobuf+3.19.2"}));
|
||||||
|
ASSERT_TRUE(rm != nullptr);
|
||||||
|
string dir = rm->DirName();
|
||||||
|
string argv0(dir.substr(0, dir.size() - string(".runfiles").size()));
|
||||||
|
|
||||||
|
string error;
|
||||||
|
unique_ptr<Runfiles> r(Runfiles::Create(argv0, /*runfiles_manifest_file=*/"",
|
||||||
|
/*runfiles_dir=*/"",
|
||||||
|
"protobuf+3.19.2", &error));
|
||||||
|
ASSERT_TRUE(r != nullptr);
|
||||||
|
EXPECT_TRUE(error.empty());
|
||||||
|
|
||||||
|
EXPECT_EQ(r->Rlocation("protobuf/foo/runfile"),
|
||||||
|
dir + "/protobuf+3.19.2/foo/runfile");
|
||||||
|
EXPECT_EQ(r->Rlocation("protobuf/bar/dir"), dir + "/protobuf+3.19.2/bar/dir");
|
||||||
|
EXPECT_EQ(r->Rlocation("protobuf/bar/dir/file"),
|
||||||
|
dir + "/protobuf+3.19.2/bar/dir/file");
|
||||||
|
EXPECT_EQ(r->Rlocation("protobuf/bar/dir/de eply/nes ted/fi+le"),
|
||||||
|
dir + "/protobuf+3.19.2/bar/dir/de eply/nes ted/fi+le");
|
||||||
|
|
||||||
|
EXPECT_EQ(r->Rlocation("my_module/bar/runfile"),
|
||||||
|
dir + "/my_module/bar/runfile");
|
||||||
|
EXPECT_EQ(r->Rlocation("my_protobuf/bar/dir/de eply/nes ted/fi+le"),
|
||||||
|
dir + "/my_protobuf/bar/dir/de eply/nes ted/fi+le");
|
||||||
|
|
||||||
|
EXPECT_EQ(r->Rlocation("_main/bar/runfile"), dir + "/_main/bar/runfile");
|
||||||
|
EXPECT_EQ(r->Rlocation("protobuf+3.19.2/foo/runfile"),
|
||||||
|
dir + "/protobuf+3.19.2/foo/runfile");
|
||||||
|
EXPECT_EQ(r->Rlocation("protobuf+3.19.2/bar/dir"),
|
||||||
|
dir + "/protobuf+3.19.2/bar/dir");
|
||||||
|
EXPECT_EQ(r->Rlocation("protobuf+3.19.2/bar/dir/file"),
|
||||||
|
dir + "/protobuf+3.19.2/bar/dir/file");
|
||||||
|
EXPECT_EQ(r->Rlocation("protobuf+3.19.2/bar/dir/de eply/nes ted/fi+le"),
|
||||||
|
dir + "/protobuf+3.19.2/bar/dir/de eply/nes ted/fi+le");
|
||||||
|
|
||||||
|
EXPECT_EQ(r->Rlocation("config.json"), dir + "/config.json");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(RunfilesTest,
|
||||||
|
DirectoryBasedRlocationWithRepoMapping_fromOtherRepo_withSourceRepo) {
|
||||||
|
string uid = LINE_AS_STRING();
|
||||||
|
unique_ptr<MockFile> rm(
|
||||||
|
MockFile::Create("foo" + uid + ".runfiles/_repo_mapping",
|
||||||
|
{",config.json,config.json+1.2.3", ",my_module,_main",
|
||||||
|
",my_protobuf,protobuf+3.19.2", ",my_workspace,_main",
|
||||||
|
"protobuf+3.19.2,config.json,config.json+1.2.3",
|
||||||
|
"protobuf+3.19.2,protobuf,protobuf+3.19.2"}));
|
||||||
|
ASSERT_TRUE(rm != nullptr);
|
||||||
|
string dir = rm->DirName();
|
||||||
|
string argv0(dir.substr(0, dir.size() - string(".runfiles").size()));
|
||||||
|
|
||||||
|
string error;
|
||||||
|
unique_ptr<Runfiles> r(Runfiles::Create(argv0, /*runfiles_manifest_file=*/"",
|
||||||
|
/*runfiles_dir=*/"",
|
||||||
|
/*source_repository=*/"", &error));
|
||||||
|
r = r->WithSourceRepository("protobuf+3.19.2");
|
||||||
|
ASSERT_TRUE(r != nullptr);
|
||||||
|
EXPECT_TRUE(error.empty());
|
||||||
|
|
||||||
|
EXPECT_EQ(r->Rlocation("protobuf/foo/runfile"),
|
||||||
|
dir + "/protobuf+3.19.2/foo/runfile");
|
||||||
|
EXPECT_EQ(r->Rlocation("protobuf/bar/dir"), dir + "/protobuf+3.19.2/bar/dir");
|
||||||
|
EXPECT_EQ(r->Rlocation("protobuf/bar/dir/file"),
|
||||||
|
dir + "/protobuf+3.19.2/bar/dir/file");
|
||||||
|
EXPECT_EQ(r->Rlocation("protobuf/bar/dir/de eply/nes ted/fi+le"),
|
||||||
|
dir + "/protobuf+3.19.2/bar/dir/de eply/nes ted/fi+le");
|
||||||
|
|
||||||
|
EXPECT_EQ(r->Rlocation("my_module/bar/runfile"),
|
||||||
|
dir + "/my_module/bar/runfile");
|
||||||
|
EXPECT_EQ(r->Rlocation("my_protobuf/bar/dir/de eply/nes ted/fi+le"),
|
||||||
|
dir + "/my_protobuf/bar/dir/de eply/nes ted/fi+le");
|
||||||
|
|
||||||
|
EXPECT_EQ(r->Rlocation("_main/bar/runfile"), dir + "/_main/bar/runfile");
|
||||||
|
EXPECT_EQ(r->Rlocation("protobuf+3.19.2/foo/runfile"),
|
||||||
|
dir + "/protobuf+3.19.2/foo/runfile");
|
||||||
|
EXPECT_EQ(r->Rlocation("protobuf+3.19.2/bar/dir"),
|
||||||
|
dir + "/protobuf+3.19.2/bar/dir");
|
||||||
|
EXPECT_EQ(r->Rlocation("protobuf+3.19.2/bar/dir/file"),
|
||||||
|
dir + "/protobuf+3.19.2/bar/dir/file");
|
||||||
|
EXPECT_EQ(r->Rlocation("protobuf+3.19.2/bar/dir/de eply/nes ted/fi+le"),
|
||||||
|
dir + "/protobuf+3.19.2/bar/dir/de eply/nes ted/fi+le");
|
||||||
|
|
||||||
|
EXPECT_EQ(r->Rlocation("config.json"), dir + "/config.json");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(RunfilesTest, InvalidRepoMapping) {
|
||||||
|
string uid = LINE_AS_STRING();
|
||||||
|
unique_ptr<MockFile> rm(
|
||||||
|
MockFile::Create("foo" + uid + ".runfiles/_repo_mapping", {"a,b"}));
|
||||||
|
ASSERT_TRUE(rm != nullptr);
|
||||||
|
string dir = rm->DirName();
|
||||||
|
string argv0(dir.substr(0, dir.size() - string(".runfiles").size()));
|
||||||
|
|
||||||
|
string error;
|
||||||
|
unique_ptr<Runfiles> r(Runfiles::Create(argv0, /*runfiles_manifest_file=*/"",
|
||||||
|
/*runfiles_dir=*/"",
|
||||||
|
/*source_repository=*/"", &error));
|
||||||
|
EXPECT_EQ(r, nullptr);
|
||||||
|
EXPECT_TRUE(error.find("bad repository mapping") != string::npos);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace runfiles
|
||||||
|
} // namespace cpp
|
||||||
|
} // namespace tools
|
||||||
|
} // namespace bazel
|
Loading…
Reference in New Issue