@@ -96,25 +96,30 @@ bool IsDirectory(const string& path) {
96
96
97
97
bool PathsFrom (const std::string& argv0, std::string runfiles_manifest_file,
98
98
std::string runfiles_dir, std::string* out_manifest,
99
- std::string* out_directory);
99
+ std::string* out_directory, std::string* out_repo_mapping );
100
100
101
101
bool PathsFrom (const std::string& argv0, std::string runfiles_manifest_file,
102
102
std::string runfiles_dir,
103
103
std::function<bool (const std::string&)> is_runfiles_manifest,
104
104
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);
106
108
107
109
bool ParseManifest (const string& path, map<string, string>* result,
108
110
string* error);
111
+ bool ParseRepoMapping (const string& path,
112
+ map<pair<string, string>, string>* result, string* error);
109
113
110
114
} // namespace
111
115
112
116
Runfiles* Runfiles::Create (const string& argv0,
113
117
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;
116
121
if (!PathsFrom (argv0, runfiles_manifest_file, runfiles_dir, &manifest,
117
- &directory)) {
122
+ &directory, &repo_mapping )) {
118
123
if (error) {
119
124
std::ostringstream err;
120
125
err << " ERROR: " << __FILE__ << " (" << __LINE__
@@ -124,7 +129,7 @@ Runfiles* Runfiles::Create(const string& argv0,
124
129
return nullptr ;
125
130
}
126
131
127
- const vector<pair<string, string> > envvars = {
132
+ vector<pair<string, string> > envvars = {
128
133
{" RUNFILES_MANIFEST_FILE" , manifest},
129
134
{" RUNFILES_DIR" , directory},
130
135
// TODO(laszlocsomor): remove JAVA_RUNFILES once the Java launcher can
@@ -138,8 +143,16 @@ Runfiles* Runfiles::Create(const string& argv0,
138
143
}
139
144
}
140
145
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
+
141
153
return new Runfiles (std::move (runfiles), std::move (directory),
142
- std::move (envvars));
154
+ std::move (mapping), std::move (envvars),
155
+ string (source_repository));
143
156
}
144
157
145
158
bool IsAbsolute (const string& path) {
@@ -169,6 +182,11 @@ string GetEnv(const string& key) {
169
182
}
170
183
171
184
string 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 {
172
190
if (path.empty () || starts_with (path, " ../" ) || contains (path, " /.." ) ||
173
191
starts_with (path, " ./" ) || contains (path, " /./" ) ||
174
192
ends_with (path, " /." ) || contains (path, " //" )) {
@@ -177,6 +195,24 @@ string Runfiles::Rlocation(const string& path) const {
177
195
if (IsAbsolute (path)) {
178
196
return path;
179
197
}
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 {
180
216
const auto exact_match = runfiles_map_.find (path);
181
217
if (exact_match != runfiles_map_.end ()) {
182
218
return exact_match->second ;
@@ -238,48 +274,125 @@ bool ParseManifest(const string& path, map<string, string>* result,
238
274
return true ;
239
275
}
240
276
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
+
241
329
} // namespace
242
330
243
331
namespace testing {
244
332
245
333
bool TestOnly_PathsFrom (const string& argv0, string mf, string dir,
246
334
function<bool (const string&)> is_runfiles_manifest,
247
335
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) {
249
339
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);
251
342
}
252
343
253
344
bool TestOnly_IsAbsolute (const string& path) { return IsAbsolute (path); }
254
345
255
346
} // namespace testing
256
347
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) {
258
358
return Runfiles::Create (argv0, GetEnv (" RUNFILES_MANIFEST_FILE" ),
259
- GetEnv (" RUNFILES_DIR" ), error);
359
+ GetEnv (" RUNFILES_DIR" ), source_repository, error);
260
360
}
261
361
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) {
263
368
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);
265
374
}
266
375
267
376
namespace {
268
377
269
378
bool 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);
275
385
}
276
386
277
387
bool PathsFrom (const string& argv0, string mf, string dir,
278
388
function<bool (const string&)> is_runfiles_manifest,
279
389
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) {
281
393
out_manifest->clear ();
282
394
out_directory->clear ();
395
+ out_repo_mapping->clear ();
283
396
284
397
bool mfValid = is_runfiles_manifest (mf);
285
398
bool dirValid = is_runfiles_directory (dir);
@@ -315,6 +428,21 @@ bool PathsFrom(const string& argv0, string mf, string dir,
315
428
dirValid = is_runfiles_directory (dir);
316
429
}
317
430
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
+
318
446
if (mfValid) {
319
447
*out_manifest = mf;
320
448
}
@@ -323,6 +451,10 @@ bool PathsFrom(const string& argv0, string mf, string dir,
323
451
*out_directory = dir;
324
452
}
325
453
454
+ if (rmValid) {
455
+ *out_repo_mapping = rm;
456
+ }
457
+
326
458
return true ;
327
459
}
328
460
0 commit comments