Skip to content

Commit

Permalink
Remove symlink walk functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
cpsauer committed Feb 13, 2023
1 parent 3dd09e6 commit e2140cc
Show file tree
Hide file tree
Showing 3 changed files with 3 additions and 237 deletions.
1 change: 0 additions & 1 deletion walk/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ go_library(
deps = [
"//config",
"//flag",
"//pathtools",
"//rule",
"@com_github_bmatcuk_doublestar_v4//:doublestar",
],
Expand Down
74 changes: 3 additions & 71 deletions walk/walk.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import (
"strings"

"github.com/bazelbuild/bazel-gazelle/config"
"github.com/bazelbuild/bazel-gazelle/pathtools"
"github.com/bazelbuild/bazel-gazelle/rule"
)

Expand Down Expand Up @@ -75,7 +74,7 @@ const (
// including excluded files.
//
// regularFiles is a list of base names of regular files within dir, not
// including excluded files.
// including excluded files or symlinks.
//
// genFiles is a list of names of generated files, found by reading
// "out" and "outs" attributes of rules in f.
Expand Down Expand Up @@ -116,8 +115,6 @@ func Walk(c *config.Config, cexts []config.Configurer, dirs []string, mode Mode,
}
}

symlinks := symlinkResolver{visited: []string{c.RepoRoot}}

updateRels := buildUpdateRelMap(c.RepoRoot, dirs)

var visit func(*config.Config, string, string, bool)
Expand Down Expand Up @@ -155,10 +152,10 @@ func Walk(c *config.Config, cexts []config.Configurer, dirs []string, mode Mode,
for _, fi := range files {
base := fi.Name()
switch {
case base == "" || wc.isExcluded(rel, base):
case base == "" || wc.isExcluded(rel, base) || fi.Mode()&os.ModeSymlink != 0:
continue

case fi.IsDir() || fi.Mode()&os.ModeSymlink != 0 && symlinks.follow(c, dir, rel, base):
case fi.IsDir():
subdirs = append(subdirs, base)

default:
Expand Down Expand Up @@ -317,68 +314,3 @@ func findGenFiles(wc *walkConfig, f *rule.File) []string {
}
return genFiles
}

type symlinkResolver struct {
visited []string
}

// Decide if symlink dir/base should be followed.
func (r *symlinkResolver) follow(c *config.Config, dir, rel, base string) bool {
// See if the user has explicitly directed us to follow the link.
wc := getWalkConfig(c)
linkRel := path.Join(rel, base)
for _, follow := range wc.follow {
if linkRel == follow {
return true
}
}

// Get canonical path as dest
fullpath := filepath.Join(dir, base)
dest, err := filepath.EvalSymlinks(fullpath)
if err != nil {
return false
}
if !filepath.IsAbs(dest) {
dest, err = filepath.Abs(filepath.Join(dir, dest))
if err != nil {
return false
}
}

// Ignore symlinks into Bazel's output.
// This includes the bazel-* convenience symlinks and any created for IDEs.
// Start by getting a canonical path to Bazel's output base.
// Note that we expect the bazel-out symlink in the workspace root directory to point to
// <output-base>/execroot/<workspace-name>/bazel-out
// See https://docs.bazel.build/versions/master/output_directories.html
// for documentation on Bazel directory layout.
bazelOut, err := filepath.EvalSymlinks(filepath.Join(c.RepoRoot, "bazel-out"))
if err == nil {
if !filepath.IsAbs(bazelOut) {
absBazelOut, err := filepath.Abs(bazelOut)
if err == nil {
bazelOut = absBazelOut
}
}
if err == nil {
outputBase := filepath.Dir(filepath.Dir(filepath.Dir(bazelOut)))
if pathtools.HasPrefix(dest, outputBase) {
return false
}
}
}

// See if the symlink points to a tree that has been already visited.
for _, p := range r.visited {
if pathtools.HasPrefix(dest, p) || pathtools.HasPrefix(p, dest) {
return false
}
}
r.visited = append(r.visited, dest)
stat, err := os.Stat(fullpath)
if err != nil {
return false
}
return stat.IsDir()
}
165 changes: 0 additions & 165 deletions walk/walk_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -317,171 +317,6 @@ unknown_rule(
}
}

func TestSymlinksBasic(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("symlinks not supported on windows")
}
files := []testtools.FileSpec{
{Path: "root/a.go", Content: "package a"},
{Path: "root/b", Symlink: "../b"}, // symlink outside repo is followed
{Path: "root/c", Symlink: "c"}, // symlink inside repo is not followed.
{Path: "root/d", Symlink: "../b/d"}, // symlink under root/b not followed
{Path: "root/e", Symlink: "../e"},
{Path: "c/c.go", Symlink: "package c"},
{Path: "b/b.go", Content: "package b"},
{Path: "b/d/d.go", Content: "package d"},
{Path: "e/loop", Symlink: "loop2"}, // symlink loop
{Path: "e/loop2", Symlink: "loop"},
}
dir, cleanup := testtools.CreateFiles(t, files)
defer cleanup()

root := filepath.Join(dir, "root")
c, cexts := testConfig(t, root)
var rels []string
Walk(c, cexts, []string{root}, VisitAllUpdateSubdirsMode, func(_ string, rel string, _ *config.Config, _ bool, _ *rule.File, _, _, _ []string) {
rels = append(rels, rel)
})
want := []string{"b/d", "b", "e", ""}
if diff := cmp.Diff(want, rels); diff != "" {
t.Errorf("Walk relative paths (-want +got):\n%s", diff)
}
}

func TestSymlinksIgnore(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("symlinks not supported on windows")
}
files := []testtools.FileSpec{
{
Path: "root/BUILD",
Content: "# gazelle:exclude b",
},
{Path: "root/b", Symlink: "../b"},
{Path: "b/b.go", Content: "package b"},
}
dir, cleanup := testtools.CreateFiles(t, files)
defer cleanup()

root := filepath.Join(dir, "root")
c, cexts := testConfig(t, root)
var rels []string
Walk(c, cexts, []string{root}, VisitAllUpdateSubdirsMode, func(_ string, rel string, _ *config.Config, _ bool, _ *rule.File, _, _, _ []string) {
rels = append(rels, rel)
})
want := []string{""}
if diff := cmp.Diff(want, rels); diff != "" {
t.Errorf("Walk relative paths (-want +got):\n%s", diff)
}
}

func TestSymlinksMixIgnoredAndNonIgnored(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("symlinks not supported on windows")
}
files := []testtools.FileSpec{
{
Path: "root/BUILD",
Content: "# gazelle:exclude b",
},
{Path: "root/b", Symlink: "../b"}, // ignored
{Path: "root/b2", Symlink: "../b"}, // not ignored
{Path: "b/b.go", Content: "package b"},
}
dir, cleanup := testtools.CreateFiles(t, files)
defer cleanup()

root := filepath.Join(dir, "root")
c, cexts := testConfig(t, root)
var rels []string
Walk(c, cexts, []string{root}, VisitAllUpdateSubdirsMode, func(_ string, rel string, _ *config.Config, _ bool, _ *rule.File, _, _, _ []string) {
rels = append(rels, rel)
})
want := []string{"b2", ""}
if diff := cmp.Diff(want, rels); diff != "" {
t.Errorf("Walk relative paths (-want +got):\n%s", diff)
}
}

func TestSymlinksChained(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("symlinks not supported on windows")
}
files := []testtools.FileSpec{
{Path: "root/b", Symlink: "../link0"},
{Path: "link0", Symlink: "b"},
{Path: "root/b2", Symlink: "../b"},
{Path: "b/b.go", Content: "package b"},
}
dir, cleanup := testtools.CreateFiles(t, files)
defer cleanup()

root := filepath.Join(dir, "root")
c, cexts := testConfig(t, root)
var rels []string
Walk(c, cexts, []string{root}, VisitAllUpdateSubdirsMode, func(_ string, rel string, _ *config.Config, _ bool, _ *rule.File, _, _, _ []string) {
rels = append(rels, rel)
})
want := []string{"b", ""}
if diff := cmp.Diff(want, rels); diff != "" {
t.Errorf("Walk relative paths (-want +got):\n%s", diff)
}
}

func TestSymlinksDangling(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("symlinks not supported on windows")
}
files := []testtools.FileSpec{
{Path: "root/b", Symlink: "../b"},
}
dir, cleanup := testtools.CreateFiles(t, files)
defer cleanup()

root := filepath.Join(dir, "root")
c, cexts := testConfig(t, root)
var rels []string
Walk(c, cexts, []string{root}, VisitAllUpdateSubdirsMode, func(_ string, rel string, _ *config.Config, _ bool, _ *rule.File, _, _, _ []string) {
rels = append(rels, rel)
})
want := []string{""}
if diff := cmp.Diff(want, rels); diff != "" {
t.Errorf("Walk relative paths (-want +got):\n%s", diff)
}
}

func TestSymlinksFollow(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("symlinks not supported on windows")
}
files := []testtools.FileSpec{
{Path: "staging/src/k8s.io/api/"},
{Path: "staging/src/k8s.io/BUILD.bazel", Content: "# gazelle:exclude api"},
{Path: "vendor/k8s.io/api", Symlink: "../../staging/src/k8s.io/api"},
{Path: "vendor/BUILD.bazel", Content: "# gazelle:follow k8s.io/api"},
}
dir, cleanup := testtools.CreateFiles(t, files)
defer cleanup()

c, cexts := testConfig(t, dir)
var rels []string
Walk(c, cexts, []string{dir}, VisitAllUpdateSubdirsMode, func(_ string, rel string, _ *config.Config, _ bool, _ *rule.File, _, _, _ []string) {
rels = append(rels, rel)
})
want := []string{
"staging/src/k8s.io",
"staging/src",
"staging",
"vendor/k8s.io/api",
"vendor/k8s.io",
"vendor",
"",
}
if diff := cmp.Diff(want, rels); diff != "" {
t.Errorf("Walk relative paths (-want +got):\n%s", diff)
}
}

func testConfig(t *testing.T, dir string) (*config.Config, []config.Configurer) {
args := []string{"-repo_root", dir}
cexts := []config.Configurer{&config.CommonConfigurer{}, &Configurer{}}
Expand Down

0 comments on commit e2140cc

Please sign in to comment.