Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use _repo_mapping in C++ runfiles library #16701

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions src/test/py/bazel/bzlmod/bazel_module_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -694,5 +694,56 @@ def testRunfilesRepoMappingManifest(self):
self.Path('bazel-bin/external/bar~2.0/bar.runfiles_manifest')) as f:
self.assertIn('_repo_mapping ', f.read())

def testCppRunfilesLibraryRepoMapping(self):
self.main_registry.setModuleBasePath('projects')
projects_dir = self.main_registry.projects

self.main_registry.createLocalPathModule('data', '1.0', 'data')
projects_dir.joinpath('data').mkdir(exist_ok=True)
scratchFile(projects_dir.joinpath('data', 'WORKSPACE'))
scratchFile(projects_dir.joinpath('data', 'foo.txt'), ['hello'])
scratchFile(projects_dir.joinpath('data', 'BUILD'),
['exports_files(["foo.txt"])'])

self.main_registry.createLocalPathModule('test', '1.0', 'test',
{'data': '1.0'})
projects_dir.joinpath('test').mkdir(exist_ok=True)
scratchFile(projects_dir.joinpath('test', 'WORKSPACE'))
scratchFile(projects_dir.joinpath('test', 'BUILD'), [
'cc_test(',
' name = "test",'
' srcs = ["test.cpp"],',
' data = ["@data//:foo.txt"],',
' args = ["$(rlocationpath @data//:foo.txt)"],',
' deps = ["@bazel_tools//tools/cpp/runfiles"],',
')'
])
scratchFile(projects_dir.joinpath('test', 'test.cpp'), [
'#include <cstdlib>',
'#include <fstream>',
'#include "tools/cpp/runfiles/runfiles.h"',
'using bazel::tools::cpp::runfiles::Runfiles;',
'int main(int argc, char** argv) {',
' Runfiles* runfiles = Runfiles::Create(argv[0], BAZEL_CURRENT_REPOSITORY);',
' std::ifstream f1(runfiles->Rlocation(argv[1]));',
' if (!f1.good()) std::exit(1);',
' std::ifstream f2(runfiles->Rlocation("data/foo.txt"));',
' if (!f2.good()) std::exit(2);',
'}',
])

self.ScratchFile('MODULE.bazel', ['bazel_dep(name="test",version="1.0")'])
self.ScratchFile('WORKSPACE')

# Run sandboxed on Linux and macOS.
exit_code, stderr, stdout = self.RunBazel(
['test', '@test//:test', '--test_output=errors'], allow_failure=True)
self.AssertExitCode(exit_code, 0, stderr, stdout)
# Run unsandboxed on all platforms.
exit_code, stderr, stdout = self.RunBazel(
['run', '@test//:test'], allow_failure=True)
self.AssertExitCode(exit_code, 0, stderr, stdout)


if __name__ == '__main__':
unittest.main()
93 changes: 30 additions & 63 deletions tools/cpp/runfiles/runfiles_src.cc
Original file line number Diff line number Diff line change
Expand Up @@ -96,15 +96,13 @@ bool IsDirectory(const string& path) {

bool PathsFrom(const std::string& argv0, std::string runfiles_manifest_file,
std::string runfiles_dir, std::string* out_manifest,
std::string* out_directory, std::string* out_repo_mapping);
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::function<bool(const std::string&)> is_repo_mapping,
std::string* out_manifest, std::string* out_directory,
std::string* out_repo_mapping);
std::string* out_manifest, std::string* out_directory);

bool ParseManifest(const string& path, map<string, string>* result,
string* error);
Expand All @@ -117,9 +115,9 @@ Runfiles* Runfiles::Create(const string& argv0,
const string& runfiles_manifest_file,
const string& runfiles_dir,
const string& source_repository, string* error) {
string manifest, directory, repo_mapping;
string manifest, directory;
if (!PathsFrom(argv0, runfiles_manifest_file, runfiles_dir, &manifest,
&directory, &repo_mapping)) {
&directory)) {
if (error) {
std::ostringstream err;
err << "ERROR: " << __FILE__ << "(" << __LINE__
Expand All @@ -144,10 +142,10 @@ Runfiles* Runfiles::Create(const string& argv0,
}

map<pair<string, string>, string> mapping;
if (!repo_mapping.empty()) {
if (!ParseRepoMapping(repo_mapping, &mapping, error)) {
return nullptr;
}
if (!ParseRepoMapping(
RlocationUnchecked("_repo_mapping", runfiles, directory),
&mapping, error)) {
return nullptr;
}

return new Runfiles(std::move(runfiles), std::move(directory),
Expand Down Expand Up @@ -196,28 +194,29 @@ string Runfiles::Rlocation(const string& path,
return path;
}

if (repo_mapping_.empty()) {
return RlocationUnchecked(path);
}
string::size_type first_slash = path.find_first_of('/');
if (first_slash == string::npos) {
return RlocationUnchecked(path);
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);
return RlocationUnchecked(path, runfiles_map_, directory_);
}
return RlocationUnchecked(target->second + path.substr(first_slash));
return RlocationUnchecked(
target->second + path.substr(first_slash), runfiles_map_, directory_);
}

string Runfiles::RlocationUnchecked(const string& path) const {
const auto exact_match = runfiles_map_.find(path);
if (exact_match != runfiles_map_.end()) {
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 (!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
Expand All @@ -226,14 +225,14 @@ string Runfiles::RlocationUnchecked(const string& path) const {
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()) {
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;
if (!directory.empty()) {
return directory + "/" + path;
}
return "";
}
Expand Down Expand Up @@ -279,13 +278,7 @@ bool ParseRepoMapping(const string& path,
string* error) {
std::ifstream stm(path);
if (!stm.is_open()) {
if (error) {
std::ostringstream err;
err << "ERROR: " << __FILE__ << "(" << __LINE__
<< "): cannot open repository mapping \"" << path << "\"";
*error = err.str();
}
return false;
return true;
}
string line;
std::getline(stm, line);
Expand Down Expand Up @@ -333,12 +326,9 @@ 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,
function<bool(const string&)> is_repo_mapping,
string* out_manifest, string* out_directory,
string* out_repo_mapping) {
string* out_manifest, string* out_directory ) {
return PathsFrom(argv0, mf, dir, is_runfiles_manifest, is_runfiles_directory,
is_repo_mapping, out_manifest, out_directory,
out_repo_mapping);
out_manifest, out_directory);
}

bool TestOnly_IsAbsolute(const string& path) { return IsAbsolute(path); }
Expand Down Expand Up @@ -376,23 +366,19 @@ Runfiles* Runfiles::CreateForTest(std::string* error) {
namespace {

bool PathsFrom(const string& argv0, string mf, string dir, string* out_manifest,
string* out_directory, string* out_repo_mapping) {
string* out_directory) {
return PathsFrom(
argv0, mf, dir, [](const string& path) { return IsReadableFile(path); },
[](const string& path) { return IsDirectory(path); },
[](const string& path) { return IsReadableFile(path); }, out_manifest,
out_directory, out_repo_mapping);
[](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,
function<bool(const string&)> is_repo_mapping,
string* out_manifest, string* out_directory,
string* out_repo_mapping) {
string* out_manifest, string* out_directory) {
out_manifest->clear();
out_directory->clear();
out_repo_mapping->clear();

bool mfValid = is_runfiles_manifest(mf);
bool dirValid = is_runfiles_directory(dir);
Expand Down Expand Up @@ -428,21 +414,6 @@ bool PathsFrom(const string& argv0, string mf, string dir,
dirValid = is_runfiles_directory(dir);
}

string rm;
bool rmValid = false;

if (dirValid && ends_with(dir, ".runfiles")) {
rm = dir.substr(0, dir.size() - 9) + ".repo_mapping";
rmValid = is_repo_mapping(rm);
}

if (!rmValid && mfValid &&
(ends_with(mf, ".runfiles_manifest") ||
ends_with(mf, ".runfiles/MANIFEST"))) {
rm = mf.substr(0, mf.size() - 18) + ".repo_mapping";
rmValid = is_repo_mapping(rm);
}

if (mfValid) {
*out_manifest = mf;
}
Expand All @@ -451,10 +422,6 @@ bool PathsFrom(const string& argv0, string mf, string dir,
*out_directory = dir;
}

if (rmValid) {
*out_repo_mapping = rm;
}

return true;
}

Expand Down
11 changes: 6 additions & 5 deletions tools/cpp/runfiles/runfiles_src.h
Original file line number Diff line number Diff line change
Expand Up @@ -206,14 +206,17 @@ class Runfiles {
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_;

std::string RlocationUnchecked(const std::string& path) const;
};

// The "testing" namespace contains functions that allow unit testing the code.
Expand Down Expand Up @@ -243,9 +246,7 @@ bool TestOnly_PathsFrom(
std::string runfiles_dir,
std::function<bool(const std::string&)> is_runfiles_manifest,
std::function<bool(const std::string&)> is_runfiles_directory,
std::function<bool(const std::string&)> is_repo_mapping,
std::string* out_manifest, std::string* out_directory,
std::string* out_repo_mapping);
std::string* out_manifest, std::string* out_directory);

// For testing only.
// Returns true if `path` is an absolute Unix or Windows path.
Expand Down
Loading