Implementation for following symlinks

This is an implementation where findFiles will follow symlinks and keep
track of paths already followed.  No paths will be evaluated more than
once, therefore preventing recursive link evaluation.

Commit includes test cases and test data
This commit is contained in:
Andrew Bates 2015-04-16 09:38:06 -04:00
parent f449dcd26c
commit 465fc29db9
10 changed files with 92 additions and 4 deletions

View File

@ -28,9 +28,10 @@ func Translate(c *Config) error {
} }
var knownFuncs = make(map[string]int) var knownFuncs = make(map[string]int)
var visitedPaths = make(map[string]bool)
// Locate all the assets. // Locate all the assets.
for _, input := range c.Input { for _, input := range c.Input {
err = findFiles(input.Path, c.Prefix, input.Recursive, &toc, c.Ignore, knownFuncs) err = findFiles(input.Path, c.Prefix, input.Recursive, &toc, c.Ignore, knownFuncs, visitedPaths)
if err != nil { if err != nil {
return err return err
} }
@ -96,7 +97,7 @@ func (v ByName) Less(i, j int) bool { return v[i].Name() < v[j].Name() }
// findFiles recursively finds all the file paths in the given directory tree. // findFiles recursively finds all the file paths in the given directory tree.
// They are added to the given map as keys. Values will be safe function names // They are added to the given map as keys. Values will be safe function names
// for each file, which will be used when generating the output code. // for each file, which will be used when generating the output code.
func findFiles(dir, prefix string, recursive bool, toc *[]Asset, ignore []*regexp.Regexp, knownFuncs map[string]int) error { func findFiles(dir, prefix string, recursive bool, toc *[]Asset, ignore []*regexp.Regexp, knownFuncs map[string]int, visitedPaths map[string]bool) error {
if len(prefix) > 0 { if len(prefix) > 0 {
dir, _ = filepath.Abs(dir) dir, _ = filepath.Abs(dir)
prefix, _ = filepath.Abs(prefix) prefix, _ = filepath.Abs(prefix)
@ -114,6 +115,7 @@ func findFiles(dir, prefix string, recursive bool, toc *[]Asset, ignore []*regex
dir = "" dir = ""
list = []os.FileInfo{fi} list = []os.FileInfo{fi}
} else { } else {
visitedPaths[dir] = true
fd, err := os.Open(dir) fd, err := os.Open(dir)
if err != nil { if err != nil {
return err return err
@ -148,7 +150,23 @@ func findFiles(dir, prefix string, recursive bool, toc *[]Asset, ignore []*regex
if file.IsDir() { if file.IsDir() {
if recursive { if recursive {
findFiles(asset.Path, prefix, recursive, toc, ignore, knownFuncs) visitedPaths[asset.Path] = true
findFiles(asset.Path, prefix, recursive, toc, ignore, knownFuncs, visitedPaths)
}
continue
} else if file.Mode()&os.ModeSymlink == os.ModeSymlink {
var linkPath string
if linkPath, err = os.Readlink(asset.Path); err != nil {
return err
}
if !filepath.IsAbs(linkPath) {
if linkPath, err = filepath.Abs(dir + "/" + linkPath); err != nil {
return err
}
}
if _, ok := visitedPaths[linkPath]; !ok {
visitedPaths[linkPath] = true
findFiles(asset.Path, prefix, recursive, toc, ignore, knownFuncs, visitedPaths)
} }
continue continue
} }

View File

@ -2,6 +2,7 @@ package bindata
import ( import (
"regexp" "regexp"
"strings"
"testing" "testing"
) )
@ -17,7 +18,8 @@ func TestSafeFunctionName(t *testing.T) {
func TestFindFiles(t *testing.T) { func TestFindFiles(t *testing.T) {
var toc []Asset var toc []Asset
var knownFuncs = make(map[string]int) var knownFuncs = make(map[string]int)
err := findFiles("testdata/dupname", "testdata/dupname", true, &toc, []*regexp.Regexp{}, knownFuncs) var visitedPaths = make(map[string]bool)
err := findFiles("testdata/dupname", "testdata/dupname", true, &toc, []*regexp.Regexp{}, knownFuncs, visitedPaths)
if err != nil { if err != nil {
t.Errorf("expected to be no error: %+v", err) t.Errorf("expected to be no error: %+v", err)
} }
@ -25,3 +27,63 @@ func TestFindFiles(t *testing.T) {
t.Errorf("name collision") t.Errorf("name collision")
} }
} }
func TestFindFilesWithSymlinks(t *testing.T) {
var tocSrc []Asset
var tocTarget []Asset
var knownFuncs = make(map[string]int)
var visitedPaths = make(map[string]bool)
err := findFiles("testdata/symlinkSrc", "testdata/symlinkSrc", true, &tocSrc, []*regexp.Regexp{}, knownFuncs, visitedPaths)
if err != nil {
t.Errorf("expected to be no error: %+v", err)
}
knownFuncs = make(map[string]int)
visitedPaths = make(map[string]bool)
err = findFiles("testdata/symlinkParent", "testdata/symlinkParent", true, &tocTarget, []*regexp.Regexp{}, knownFuncs, visitedPaths)
if err != nil {
t.Errorf("expected to be no error: %+v", err)
}
if len(tocSrc) != len(tocTarget) {
t.Errorf("Symlink source and target should have the same number of assets. Expected %d got %d", len(tocTarget), len(tocSrc))
} else {
for i, _ := range tocSrc {
targetFunc := strings.TrimPrefix(tocTarget[i].Func, "symlinktarget_")
if tocSrc[i].Func != targetFunc {
t.Errorf("Symlink source and target produced different function lists. Expected %s to be %s", targetFunc, tocSrc[i].Func)
}
}
}
}
func TestFindFilesWithRecursiveSymlinks(t *testing.T) {
var toc []Asset
var knownFuncs = make(map[string]int)
var visitedPaths = make(map[string]bool)
err := findFiles("testdata/symlinkRecursiveParent", "testdata/symlinkRecursiveParent", true, &toc, []*regexp.Regexp{}, knownFuncs, visitedPaths)
if err != nil {
t.Errorf("expected to be no error: %+v", err)
}
if len(toc) != 1 {
t.Errorf("Only one asset should have been found. Got %d: %v", len(toc), toc)
}
}
func TestFindFilesWithSymlinkedFile(t *testing.T) {
var toc []Asset
var knownFuncs = make(map[string]int)
var visitedPaths = make(map[string]bool)
err := findFiles("testdata/symlinkFile", "testdata/symlinkFile", true, &toc, []*regexp.Regexp{}, knownFuncs, visitedPaths)
if err != nil {
t.Errorf("expected to be no error: %+v", err)
}
if len(toc) != 1 {
t.Errorf("Only one asset should have been found. Got %d: %v", len(toc), toc)
}
}

1
testdata/symlinkFile/file1 vendored Symbolic link
View File

@ -0,0 +1 @@
../symlinkSrc/file1

1
testdata/symlinkParent/symlinkTarget vendored Symbolic link
View File

@ -0,0 +1 @@
../symlinkSrc/

1
testdata/symlinkRecursiveParent/file1 vendored Normal file
View File

@ -0,0 +1 @@
// test file 1

View File

@ -0,0 +1 @@
../symlinkRecursiveParent/

1
testdata/symlinkSrc/file1 vendored Normal file
View File

@ -0,0 +1 @@
// symlink file 1

1
testdata/symlinkSrc/file2 vendored Normal file
View File

@ -0,0 +1 @@
// symlink file 2

1
testdata/symlinkSrc/file3 vendored Normal file
View File

@ -0,0 +1 @@
// symlink file 3

1
testdata/symlinkSrc/file4 vendored Normal file
View File

@ -0,0 +1 @@
// symlink file 4