@@ -96,25 +96,30 @@ bool IsDirectory(const string& path) {
9696
9797bool PathsFrom (const std::string& argv0, std::string runfiles_manifest_file,
9898 std::string runfiles_dir, std::string* out_manifest,
99- std::string* out_directory);
99+ std::string* out_directory, std::string* out_repo_mapping );
100100
101101bool PathsFrom (const std::string& argv0, std::string runfiles_manifest_file,
102102 std::string runfiles_dir,
103103 std::function<bool (const std::string&)> is_runfiles_manifest,
104104 std::function<bool(const std::string&)> is_runfiles_directory,
105- std::string* out_manifest, std::string* out_directory);
105+ std::function<bool(const std::string&)> is_repo_mapping,
106+ std::string* out_manifest, std::string* out_directory,
107+ std::string* out_repo_mapping);
106108
107109bool ParseManifest (const string& path, map<string, string>* result,
108110 string* error);
111+ bool ParseRepoMapping (const string& path,
112+ map<pair<string, string>, string>* result, string* error);
109113
110114} // namespace
111115
112116Runfiles* Runfiles::Create (const string& argv0,
113117 const string& runfiles_manifest_file,
114- const string& runfiles_dir, string* error) {
115- string manifest, directory;
118+ const string& runfiles_dir,
119+ const string& source_repository, string* error) {
120+ string manifest, directory, repo_mapping;
116121 if (!PathsFrom (argv0, runfiles_manifest_file, runfiles_dir, &manifest,
117- &directory)) {
122+ &directory, &repo_mapping )) {
118123 if (error) {
119124 std::ostringstream err;
120125 err << " ERROR: " << __FILE__ << " (" << __LINE__
@@ -124,7 +129,7 @@ Runfiles* Runfiles::Create(const string& argv0,
124129 return nullptr ;
125130 }
126131
127- const vector<pair<string, string> > envvars = {
132+ vector<pair<string, string> > envvars = {
128133 {" RUNFILES_MANIFEST_FILE" , manifest},
129134 {" RUNFILES_DIR" , directory},
130135 // TODO(laszlocsomor): remove JAVA_RUNFILES once the Java launcher can
@@ -138,8 +143,16 @@ Runfiles* Runfiles::Create(const string& argv0,
138143 }
139144 }
140145
146+ map<pair<string, string>, string> mapping;
147+ if (!repo_mapping.empty ()) {
148+ if (!ParseRepoMapping (repo_mapping, &mapping, error)) {
149+ return nullptr ;
150+ }
151+ }
152+
141153 return new Runfiles (std::move (runfiles), std::move (directory),
142- std::move (envvars));
154+ std::move (mapping), std::move (envvars),
155+ string (source_repository));
143156}
144157
145158bool IsAbsolute (const string& path) {
@@ -169,6 +182,11 @@ string GetEnv(const string& key) {
169182}
170183
171184string Runfiles::Rlocation (const string& path) const {
185+ return Rlocation (path, source_repository_);
186+ }
187+
188+ string Runfiles::Rlocation (const string& path,
189+ const string& source_repo) const {
172190 if (path.empty () || starts_with (path, " ../" ) || contains (path, " /.." ) ||
173191 starts_with (path, " ./" ) || contains (path, " /./" ) ||
174192 ends_with (path, " /." ) || contains (path, " //" )) {
@@ -177,6 +195,24 @@ string Runfiles::Rlocation(const string& path) const {
177195 if (IsAbsolute (path)) {
178196 return path;
179197 }
198+
199+ if (repo_mapping_.empty ()) {
200+ return RlocationUnchecked (path);
201+ }
202+ string::size_type first_slash = path.find_first_of (' /' );
203+ if (first_slash == string::npos) {
204+ return RlocationUnchecked (path);
205+ }
206+ string target_apparent = path.substr (0 , first_slash);
207+ auto target =
208+ repo_mapping_.find (std::make_pair (source_repo, target_apparent));
209+ if (target == repo_mapping_.cend ()) {
210+ return RlocationUnchecked (path);
211+ }
212+ return RlocationUnchecked (target->second + path.substr (first_slash));
213+ }
214+
215+ string Runfiles::RlocationUnchecked (const string& path) const {
180216 const auto exact_match = runfiles_map_.find (path);
181217 if (exact_match != runfiles_map_.end ()) {
182218 return exact_match->second ;
@@ -238,48 +274,125 @@ bool ParseManifest(const string& path, map<string, string>* result,
238274 return true ;
239275}
240276
277+ bool ParseRepoMapping (const string& path,
278+ map<pair<string, string>, string>* result,
279+ string* error) {
280+ std::ifstream stm (path);
281+ if (!stm.is_open ()) {
282+ if (error) {
283+ std::ostringstream err;
284+ err << " ERROR: " << __FILE__ << " (" << __LINE__
285+ << " ): cannot open repository mapping \" " << path << " \" " ;
286+ *error = err.str ();
287+ }
288+ return false ;
289+ }
290+ string line;
291+ std::getline (stm, line);
292+ size_t line_count = 1 ;
293+ while (!line.empty ()) {
294+ string::size_type first_comma = line.find_first_of (' ,' );
295+ if (first_comma == string::npos) {
296+ if (error) {
297+ std::ostringstream err;
298+ err << " ERROR: " << __FILE__ << " (" << __LINE__
299+ << " ): bad repository mapping entry in \" " << path << " \" line #"
300+ << line_count << " : \" " << line << " \" " ;
301+ *error = err.str ();
302+ }
303+ return false ;
304+ }
305+ string::size_type second_comma = line.find_first_of (' ,' , first_comma + 1 );
306+ if (second_comma == string::npos) {
307+ if (error) {
308+ std::ostringstream err;
309+ err << " ERROR: " << __FILE__ << " (" << __LINE__
310+ << " ): bad repository mapping entry in \" " << path << " \" line #"
311+ << line_count << " : \" " << line << " \" " ;
312+ *error = err.str ();
313+ }
314+ return false ;
315+ }
316+
317+ string source = line.substr (0 , first_comma);
318+ string target_apparent =
319+ line.substr (first_comma + 1 , second_comma - (first_comma + 1 ));
320+ string target = line.substr (second_comma + 1 );
321+
322+ (*result)[std::make_pair (source, target_apparent)] = target;
323+ std::getline (stm, line);
324+ ++line_count;
325+ }
326+ return true ;
327+ }
328+
241329} // namespace
242330
243331namespace testing {
244332
245333bool TestOnly_PathsFrom (const string& argv0, string mf, string dir,
246334 function<bool (const string&)> is_runfiles_manifest,
247335 function<bool(const string&)> is_runfiles_directory,
248- string* out_manifest, string* out_directory) {
336+ function<bool(const string&)> is_repo_mapping,
337+ string* out_manifest, string* out_directory,
338+ string* out_repo_mapping) {
249339 return PathsFrom (argv0, mf, dir, is_runfiles_manifest, is_runfiles_directory,
250- out_manifest, out_directory);
340+ is_repo_mapping, out_manifest, out_directory,
341+ out_repo_mapping);
251342}
252343
253344bool TestOnly_IsAbsolute (const string& path) { return IsAbsolute (path); }
254345
255346} // namespace testing
256347
257- Runfiles* Runfiles::Create (const string& argv0, string* error) {
348+ Runfiles* Runfiles::Create (const std::string& argv0,
349+ const std::string& runfiles_manifest_file,
350+ const std::string& runfiles_dir,
351+ std::string* error) {
352+ return Runfiles::Create (argv0, runfiles_manifest_file, runfiles_dir, " " ,
353+ error);
354+ }
355+
356+ Runfiles* Runfiles::Create (const string& argv0, const string& source_repository,
357+ string* error) {
258358 return Runfiles::Create (argv0, GetEnv (" RUNFILES_MANIFEST_FILE" ),
259- GetEnv (" RUNFILES_DIR" ), error);
359+ GetEnv (" RUNFILES_DIR" ), source_repository, error);
260360}
261361
262- Runfiles* Runfiles::CreateForTest (std::string* error) {
362+ Runfiles* Runfiles::Create (const string& argv0, string* error) {
363+ return Runfiles::Create (argv0, " " , error);
364+ }
365+
366+ Runfiles* Runfiles::CreateForTest (const string& source_repository,
367+ std::string* error) {
263368 return Runfiles::Create (std::string (), GetEnv (" RUNFILES_MANIFEST_FILE" ),
264- GetEnv (" TEST_SRCDIR" ), error);
369+ GetEnv (" TEST_SRCDIR" ), source_repository, error);
370+ }
371+
372+ Runfiles* Runfiles::CreateForTest (std::string* error) {
373+ return Runfiles::CreateForTest (" " , error);
265374}
266375
267376namespace {
268377
269378bool PathsFrom (const string& argv0, string mf, string dir, string* out_manifest,
270- string* out_directory) {
271- return PathsFrom (argv0, mf, dir,
272- [](const string& path) { return IsReadableFile (path); },
273- [](const string& path) { return IsDirectory (path); },
274- out_manifest, out_directory);
379+ string* out_directory, string* out_repo_mapping) {
380+ return PathsFrom (
381+ argv0, mf, dir, [](const string& path) { return IsReadableFile (path); },
382+ [](const string& path) { return IsDirectory (path); },
383+ [](const string& path) { return IsReadableFile (path); }, out_manifest,
384+ out_directory, out_repo_mapping);
275385}
276386
277387bool PathsFrom (const string& argv0, string mf, string dir,
278388 function<bool (const string&)> is_runfiles_manifest,
279389 function<bool(const string&)> is_runfiles_directory,
280- string* out_manifest, string* out_directory) {
390+ function<bool(const string&)> is_repo_mapping,
391+ string* out_manifest, string* out_directory,
392+ string* out_repo_mapping) {
281393 out_manifest->clear ();
282394 out_directory->clear ();
395+ out_repo_mapping->clear ();
283396
284397 bool mfValid = is_runfiles_manifest (mf);
285398 bool dirValid = is_runfiles_directory (dir);
@@ -315,6 +428,21 @@ bool PathsFrom(const string& argv0, string mf, string dir,
315428 dirValid = is_runfiles_directory (dir);
316429 }
317430
431+ string rm;
432+ bool rmValid = false ;
433+
434+ if (dirValid && ends_with (dir, " .runfiles" )) {
435+ rm = dir.substr (0 , dir.size () - 9 ) + " .repo_mapping" ;
436+ rmValid = is_repo_mapping (rm);
437+ }
438+
439+ if (!rmValid && mfValid &&
440+ (ends_with (mf, " .runfiles_manifest" ) ||
441+ ends_with (mf, " .runfiles/MANIFEST" ))) {
442+ rm = mf.substr (0 , mf.size () - 18 ) + " .repo_mapping" ;
443+ rmValid = is_repo_mapping (rm);
444+ }
445+
318446 if (mfValid) {
319447 *out_manifest = mf;
320448 }
@@ -323,6 +451,10 @@ bool PathsFrom(const string& argv0, string mf, string dir,
323451 *out_directory = dir;
324452 }
325453
454+ if (rmValid) {
455+ *out_repo_mapping = rm;
456+ }
457+
326458 return true ;
327459}
328460
0 commit comments