From 7c1996d8950db8c13a0ba4fd8cf3d5d51760d488 Mon Sep 17 00:00:00 2001 From: Zachary Scott Date: Wed, 13 Jun 2018 19:03:03 +0900 Subject: [PATCH 1/4] Add a filetree package we'll need for collapsing folders --- filetree/tree.go | 54 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 filetree/tree.go diff --git a/filetree/tree.go b/filetree/tree.go new file mode 100644 index 000000000..9850005b3 --- /dev/null +++ b/filetree/tree.go @@ -0,0 +1,54 @@ +package filetree + +import ( + "fmt" + "os" + "path/filepath" +) + +type Node struct { + FullPath string + Info *os.FileInfo + Children []*Node + Parent *Node +} + +func NewTree(root string) (*Node, error) { + parents := make(map[string]*Node) + // need to pass this in as an array + exclude := []string{"path/to/skip"} + + err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + + // check if file is in exclude slice and skip it + name := info.Name() + _, exists := exclude[name] + if exists { + fmt.Printf("skipping a dir without errors: %+v \n", info.Name()) + return filepath.SkipDir + } + + parents[path] = &Node{ + FullPath: path, + Info: info, + Children: make([]*Node, 0), + } + return nil + }) + if err != nil { + return nil, err + } + for path, node := range parents { + parentPath := filepath.Dir(path) + parent, exists := parents[parentPath] + if exists { + node.Parent = parent + parent.Children = append(parent.Children, node) + } + + } + return node, err +} From 3cd4f3964243b0b618a39ccd784b2c615018da26 Mon Sep 17 00:00:00 2001 From: Zachary Scott Date: Thu, 14 Jun 2018 15:03:19 +0900 Subject: [PATCH 2/4] Implement excluded to skip certain paths Linter is also happy now --- filetree/tree.go | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/filetree/tree.go b/filetree/tree.go index 9850005b3..170addcef 100644 --- a/filetree/tree.go +++ b/filetree/tree.go @@ -6,6 +6,7 @@ import ( "path/filepath" ) +// Node represents a leaf in the filetree type Node struct { FullPath string Info *os.FileInfo @@ -13,10 +14,20 @@ type Node struct { Parent *Node } +// Helper function that returns true if a path exists in excludes array +func excluded(exclude []string, path string) bool { + for _, n := range exclude { + if path == n { + return true + } + } + return false +} + +// NewTree creates a new filetree starting at the root func NewTree(root string) (*Node, error) { parents := make(map[string]*Node) - // need to pass this in as an array - exclude := []string{"path/to/skip"} + var result *Node err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error { if err != nil { @@ -24,20 +35,21 @@ func NewTree(root string) (*Node, error) { } // check if file is in exclude slice and skip it - name := info.Name() - _, exists := exclude[name] - if exists { - fmt.Printf("skipping a dir without errors: %+v \n", info.Name()) + // need to pass this in as an array + exclude := []string{"path/to/skip"} + if excluded(exclude, path) { + fmt.Printf("skipping: %+v \n", info.Name()) return filepath.SkipDir } parents[path] = &Node{ FullPath: path, - Info: info, + Info: &info, Children: make([]*Node, 0), } return nil }) + if err != nil { return nil, err } @@ -47,8 +59,10 @@ func NewTree(root string) (*Node, error) { if exists { node.Parent = parent parent.Children = append(parent.Children, node) + } else { + result = node } } - return node, err + return result, err } From e43ef6b912231f961b630f35c764a78448c7b6aa Mon Sep 17 00:00:00 2001 From: Zachary Scott Date: Thu, 14 Jun 2018 16:06:29 +0900 Subject: [PATCH 3/4] (*Node).Info is now a full copy of os.FileInfo instead of a pointer Also moved tree.go to match package name This seems to break testing? Though not sure why.. Renaming was a 2 second change to fix :shrug: --- filetree/{tree.go => filetree.go} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename filetree/{tree.go => filetree.go} (96%) diff --git a/filetree/tree.go b/filetree/filetree.go similarity index 96% rename from filetree/tree.go rename to filetree/filetree.go index 170addcef..f257b75a5 100644 --- a/filetree/tree.go +++ b/filetree/filetree.go @@ -9,7 +9,7 @@ import ( // Node represents a leaf in the filetree type Node struct { FullPath string - Info *os.FileInfo + Info os.FileInfo Children []*Node Parent *Node } @@ -44,7 +44,7 @@ func NewTree(root string) (*Node, error) { parents[path] = &Node{ FullPath: path, - Info: &info, + Info: info, Children: make([]*Node, 0), } return nil From 3c52039977f7c66f5dc6c5fe5fdde181ede1933b Mon Sep 17 00:00:00 2001 From: Zachary Scott Date: Thu, 14 Jun 2018 16:07:54 +0900 Subject: [PATCH 4/4] Add some tests for filetree --- filetree/filetree_test.go | 58 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 filetree/filetree_test.go diff --git a/filetree/filetree_test.go b/filetree/filetree_test.go new file mode 100644 index 000000000..a2143f3a9 --- /dev/null +++ b/filetree/filetree_test.go @@ -0,0 +1,58 @@ +package filetree_test + +import ( + "io/ioutil" + "os" + "path/filepath" + "testing" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "github.com/circleci/circleci-cli/filetree" +) + +var _ = Describe("filetree", func() { + var ( + tempRoot string + ) + + BeforeEach(func() { + var err error + tempRoot, err = ioutil.TempDir("", "circleci-cli-test-") + Expect(err).ToNot(HaveOccurred()) + }) + + AfterEach(func() { + Expect(os.RemoveAll(tempRoot)).To(Succeed()) + }) + + Describe("NewTree", func() { + BeforeEach(func() { + var err error + _, err = os.OpenFile( + filepath.Join(tempRoot, "foo"), + os.O_RDWR|os.O_CREATE, + 0600, + ) + Expect(err).ToNot(HaveOccurred()) + }) + + It("Builds a tree of the nested file-structure", func() { + tree, err := filetree.NewTree(tempRoot) + + Expect(err).ToNot(HaveOccurred()) + Expect(tree.FullPath).To(Equal(tempRoot)) + Expect(tree.Info.Name()).To(Equal(filepath.Base(tempRoot))) + + fooPath := filepath.Join(tempRoot, "foo") + Expect(tree.Children[0].Info.Name()).To(Equal("foo")) + Expect(tree.Children[0].FullPath).To(Equal(fooPath)) + }) + }) +}) + +func TestCmd(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Filetree Suite") +}