@@ -232,10 +232,27 @@ impl Runfiles {
232232 let path_mapping = manifest_content
233233 . lines ( )
234234 . flat_map ( |line| {
235- let pair = line
235+ let raw_pair = line
236+ . strip_prefix ( ' ' )
237+ . unwrap_or ( line)
236238 . split_once ( ' ' )
237239 . ok_or ( RunfilesError :: RunfilesManifestInvalidFormat ) ?;
238- Ok :: < ( PathBuf , PathBuf ) , RunfilesError > ( ( pair. 0 . into ( ) , pair. 1 . into ( ) ) )
240+ let pair = if line. starts_with ( ' ' ) {
241+ // Unescape according to SourceManifestAction.java.
242+ // https://github.com/bazelbuild/bazel/blob/3cb75e7bb181e3fb2b33707c172bf80431dc4712/src/main/java/com/google/devtools/build/lib/analysis/SourceManifestAction.java#L77-L84
243+ (
244+ raw_pair
245+ . 0
246+ . replace ( "\\ s" , " " )
247+ . replace ( "\\ n" , "\n " )
248+ . replace ( "\\ b" , "\\ " )
249+ . into ( ) ,
250+ raw_pair. 1 . replace ( "\\ n" , "\n " ) . replace ( "\\ b" , "\\ " ) . into ( ) ,
251+ )
252+ } else {
253+ ( raw_pair. 0 . into ( ) , raw_pair. 1 . into ( ) )
254+ } ;
255+ Ok :: < ( PathBuf , PathBuf ) , RunfilesError > ( pair)
239256 } )
240257 . collect :: < HashMap < _ , _ > > ( ) ;
241258 Ok ( Mode :: ManifestBased ( path_mapping) )
@@ -633,6 +650,43 @@ mod test {
633650 ) ;
634651 }
635652
653+ #[ test]
654+ fn test_manifest_parsing ( ) {
655+ let temp_dir = PathBuf :: from ( std:: env:: var ( "TEST_TMPDIR" ) . unwrap ( ) ) ;
656+ std:: fs:: create_dir_all ( & temp_dir) . unwrap ( ) ;
657+
658+ let manifest_file = temp_dir. join ( "test_manifest_parsing.manifest" ) ;
659+ std:: fs:: write (
660+ & manifest_file,
661+ [
662+ "a/b c/d\n " ,
663+ " a\\ sb/c\\ nd\\ be f g/h\\ ni\\ bj\n " ,
664+ "empty-file \n " ,
665+ ]
666+ . join ( "\n " ) ,
667+ )
668+ . unwrap ( ) ;
669+
670+ with_mock_env (
671+ [
672+ ( MANIFEST_FILE_ENV_VAR , Some ( manifest_file. to_str ( ) . unwrap ( ) ) ) ,
673+ ( RUNFILES_DIR_ENV_VAR , None :: < & str > ) ,
674+ ( TEST_SRCDIR_ENV_VAR , None :: < & str > ) ,
675+ ] ,
676+ || {
677+ let r = Runfiles :: create ( ) . unwrap ( ) ;
678+ assert_eq ! ( r. rlocation( "a/b" ) , Some ( PathBuf :: from( "c/d" ) ) ) ;
679+ // Note that the `\s` is not escaped in the link, so not testing for it.
680+ assert_eq ! (
681+ r. rlocation( "a b/c\n d\\ e" ) ,
682+ Some ( PathBuf :: from( "f g/h\n i\\ j" ) )
683+ ) ;
684+ assert_eq ! ( r. rlocation( "empty-file" ) , Some ( PathBuf :: from( "" ) ) ) ;
685+ assert_eq ! ( r. rlocation( "does/not/exist" ) , None ) ;
686+ } ,
687+ ) ;
688+ }
689+
636690 #[ test]
637691 fn test_manifest_based_can_read_data_from_runfiles ( ) {
638692 let mut path_mapping = HashMap :: new ( ) ;
0 commit comments