From 465fc29db9b716ec2ac11b1125939d383c143845 Mon Sep 17 00:00:00 2001 From: Andrew Bates Date: Thu, 16 Apr 2015 09:38:06 -0400 Subject: [PATCH] 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 --- convert.go | 24 ++++++- convert_test.go | 64 ++++++++++++++++++- testdata/symlinkFile/file1 | 1 + testdata/symlinkParent/symlinkTarget | 1 + testdata/symlinkRecursiveParent/file1 | 1 + testdata/symlinkRecursiveParent/symlinkTarget | 1 + testdata/symlinkSrc/file1 | 1 + testdata/symlinkSrc/file2 | 1 + testdata/symlinkSrc/file3 | 1 + testdata/symlinkSrc/file4 | 1 + 10 files changed, 92 insertions(+), 4 deletions(-) create mode 120000 testdata/symlinkFile/file1 create mode 120000 testdata/symlinkParent/symlinkTarget create mode 100644 testdata/symlinkRecursiveParent/file1 create mode 120000 testdata/symlinkRecursiveParent/symlinkTarget create mode 100644 testdata/symlinkSrc/file1 create mode 100644 testdata/symlinkSrc/file2 create mode 100644 testdata/symlinkSrc/file3 create mode 100644 testdata/symlinkSrc/file4 diff --git a/convert.go b/convert.go index 8489f62..bcccbcc 100644 --- a/convert.go +++ b/convert.go @@ -28,9 +28,10 @@ func Translate(c *Config) error { } var knownFuncs = make(map[string]int) + var visitedPaths = make(map[string]bool) // Locate all the assets. 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 { 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. // 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. -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 { dir, _ = filepath.Abs(dir) prefix, _ = filepath.Abs(prefix) @@ -114,6 +115,7 @@ func findFiles(dir, prefix string, recursive bool, toc *[]Asset, ignore []*regex dir = "" list = []os.FileInfo{fi} } else { + visitedPaths[dir] = true fd, err := os.Open(dir) if err != nil { return err @@ -148,7 +150,23 @@ func findFiles(dir, prefix string, recursive bool, toc *[]Asset, ignore []*regex if file.IsDir() { 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 } diff --git a/convert_test.go b/convert_test.go index 4bfa9db..5908adc 100644 --- a/convert_test.go +++ b/convert_test.go @@ -2,6 +2,7 @@ package bindata import ( "regexp" + "strings" "testing" ) @@ -17,7 +18,8 @@ func TestSafeFunctionName(t *testing.T) { func TestFindFiles(t *testing.T) { var toc []Asset 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 { t.Errorf("expected to be no error: %+v", err) } @@ -25,3 +27,63 @@ func TestFindFiles(t *testing.T) { 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) + } +} diff --git a/testdata/symlinkFile/file1 b/testdata/symlinkFile/file1 new file mode 120000 index 0000000..6e09272 --- /dev/null +++ b/testdata/symlinkFile/file1 @@ -0,0 +1 @@ +../symlinkSrc/file1 \ No newline at end of file diff --git a/testdata/symlinkParent/symlinkTarget b/testdata/symlinkParent/symlinkTarget new file mode 120000 index 0000000..ccb1f73 --- /dev/null +++ b/testdata/symlinkParent/symlinkTarget @@ -0,0 +1 @@ +../symlinkSrc/ \ No newline at end of file diff --git a/testdata/symlinkRecursiveParent/file1 b/testdata/symlinkRecursiveParent/file1 new file mode 100644 index 0000000..91ea38d --- /dev/null +++ b/testdata/symlinkRecursiveParent/file1 @@ -0,0 +1 @@ +// test file 1 diff --git a/testdata/symlinkRecursiveParent/symlinkTarget b/testdata/symlinkRecursiveParent/symlinkTarget new file mode 120000 index 0000000..2ee9371 --- /dev/null +++ b/testdata/symlinkRecursiveParent/symlinkTarget @@ -0,0 +1 @@ +../symlinkRecursiveParent/ \ No newline at end of file diff --git a/testdata/symlinkSrc/file1 b/testdata/symlinkSrc/file1 new file mode 100644 index 0000000..5161fce --- /dev/null +++ b/testdata/symlinkSrc/file1 @@ -0,0 +1 @@ +// symlink file 1 diff --git a/testdata/symlinkSrc/file2 b/testdata/symlinkSrc/file2 new file mode 100644 index 0000000..dfa589a --- /dev/null +++ b/testdata/symlinkSrc/file2 @@ -0,0 +1 @@ +// symlink file 2 diff --git a/testdata/symlinkSrc/file3 b/testdata/symlinkSrc/file3 new file mode 100644 index 0000000..9096fe8 --- /dev/null +++ b/testdata/symlinkSrc/file3 @@ -0,0 +1 @@ +// symlink file 3 diff --git a/testdata/symlinkSrc/file4 b/testdata/symlinkSrc/file4 new file mode 100644 index 0000000..49e0302 --- /dev/null +++ b/testdata/symlinkSrc/file4 @@ -0,0 +1 @@ +// symlink file 4