diff --git a/go/runfiles/manifest.go b/go/runfiles/manifest.go index 52aa44190..64ef7309a 100644 --- a/go/runfiles/manifest.go +++ b/go/runfiles/manifest.go @@ -79,11 +79,25 @@ func (f ManifestFile) parse() (manifest, error) { s := bufio.NewScanner(r) m := manifest{make(map[string]string), nil} for s.Scan() { - fields := strings.SplitN(s.Text(), " ", 2) - if len(fields) != 2 || fields[0] == "" { - return manifest{}, fmt.Errorf("runfiles: bad manifest line %q in file %s", s.Text(), f) + line := s.Text() + var link, target string + if strings.HasPrefix(line, " ") { + // In lines that start with a space, spaces, newlines, and backslashes are escaped as \s, \n, and \b in + // link and newlines and backslashes are escaped in target. + fields := strings.SplitN(s.Text()[1:], " ", 2) + link = fields[0] + target = fields[1] + link = strings.ReplaceAll(link, `\s`, " ") + link = strings.ReplaceAll(link, `\n`, "\n") + link = strings.ReplaceAll(link, `\b`, `\`) + target = strings.ReplaceAll(target, `\n`, "\n") + target = strings.ReplaceAll(target, `\b`, `\`) + } else { + fields := strings.SplitN(line, " ", 2) + link = fields[0] + target = fields[1] } - m.index[fields[0]] = filepath.FromSlash(fields[1]) + m.index[link] = filepath.FromSlash(target) } if err := s.Err(); err != nil { diff --git a/tests/runfiles/runfiles_test.go b/tests/runfiles/runfiles_test.go index e86371f03..04434e2f3 100644 --- a/tests/runfiles/runfiles_test.go +++ b/tests/runfiles/runfiles_test.go @@ -124,7 +124,9 @@ func TestRunfiles_empty(t *testing.T) { func TestRunfiles_manifestWithDir(t *testing.T) { dir := t.TempDir() manifest := filepath.Join(dir, "manifest") - if err := os.WriteFile(manifest, []byte("foo/dir path/to/foo/dir\n"), 0o600); err != nil { + if err := os.WriteFile(manifest, []byte(`foo/dir path/to/foo/dir + dir\swith\sspac\be\ns F:\bj k\bdir with spa\nces +`), 0o600); err != nil { t.Fatal(err) } r, err := runfiles.New(runfiles.ManifestFile(manifest)) @@ -136,6 +138,12 @@ func TestRunfiles_manifestWithDir(t *testing.T) { "foo/dir": filepath.FromSlash("path/to/foo/dir"), "foo/dir/file": filepath.FromSlash("path/to/foo/dir/file"), "foo/dir/deeply/nested/file": filepath.FromSlash("path/to/foo/dir/deeply/nested/file"), + `dir with spac\e +s`: filepath.FromSlash(`F:\j k\dir with spa +ces`), + `dir with spac\e +s/file`: filepath.FromSlash(`F:\j k\dir with spa +ces/file`), } { t.Run(rlocation, func(t *testing.T) { got, err := r.Rlocation(rlocation)