Skip to content

Commit

Permalink
Find runfiles in directories that are themselves runfiles
Browse files Browse the repository at this point in the history
When a target has a runfile that is contained in a directory that is
itself one of its runfiles, the runfile will be shadowed by the
SymlinkEntry for the directory. While this still allows to resolve the
file in the runfiles symlink tree, a manifest-based lookup will fail.

This PR extends the lookup logic to also find runfiles contained within
directories that are themselves runfiles. It does so by searching the
manifest not only for the exact provided rlocation path, but also for
all path prefixes. If a prefix is looked up successfully, the
corresponding suffix is resolved relative to the looked up path.

See bazelbuild/bazel#14336 for more context.
  • Loading branch information
fmeum committed Mar 24, 2022
1 parent 388095b commit ceecf5a
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 5 deletions.
20 changes: 15 additions & 5 deletions manifest.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"bufio"
"fmt"
"os"
"path"
"path/filepath"
"strings"
)
Expand Down Expand Up @@ -60,13 +61,22 @@ func (f ManifestFile) parse() (manifest, error) {

func (m manifest) path(s string) (string, error) {
r, ok := m[s]
if !ok {
return "", os.ErrNotExist
}
if r == "" {
if ok && r == "" {
return "", ErrEmpty
}
return r, nil
if ok {
return r, nil
}
// 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.
for prefix := s; prefix != ""; prefix, _ = path.Split(prefix) {
prefix = strings.TrimSuffix(prefix, "/")
if prefixMatch, ok := m[prefix]; ok {
return prefixMatch + strings.TrimPrefix(s, prefix), nil
}
}
return "", os.ErrNotExist
}

const manifestFileVar = "RUNFILES_MANIFEST_FILE"
27 changes: 27 additions & 0 deletions runfiles_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,30 @@ func TestRunfiles_empty(t *testing.T) {
t.Errorf("Path for empty file: got error %q, want something that wraps %q", got, want)
}
}

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"), 0600); err != nil {
t.Fatal(err)
}
r, err := runfiles.New(runfiles.ManifestFile(manifest))
if err != nil {
t.Fatal(err)
}
for rlocation, want := range map[string]string{
"foo/dir": "path/to/foo/dir",
"foo/dir/file": "path/to/foo/dir/file",
"foo/dir/deeply/nested/file": "path/to/foo/dir/deeply/nested/file",
} {
t.Run(rlocation, func(t *testing.T) {
got, err := r.Path(rlocation)
if err != nil {
t.Fatalf("Path failed: got unexpected error %q", err)
}
if got != want {
t.Errorf("Path failed: got %q, want %q", got, want)
}
})
}
}

0 comments on commit ceecf5a

Please sign in to comment.