From 7d6c5a56c0b63705378f125523876de1a97fd1ce Mon Sep 17 00:00:00 2001 From: Máximo Cuadros Date: Tue, 27 Oct 2015 01:49:58 +0100 Subject: tree and commit --- tree.go | 122 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 tree.go (limited to 'tree.go') diff --git a/tree.go b/tree.go new file mode 100644 index 0000000..192c6a0 --- /dev/null +++ b/tree.go @@ -0,0 +1,122 @@ +package git + +import ( + "bufio" + "io" + "os" + "path/filepath" + "strconv" + + "gopkg.in/src-d/go-git.v2/internal" +) + +// Tree is basically like a directory - it references a bunch of other trees +// and/or blobs (i.e. files and sub-directories) +type Tree struct { + Entries []TreeEntry + Hash internal.Hash + + r *Repository +} + +// TreeEntry represents a file +type TreeEntry struct { + Name string + Mode os.FileMode + Hash internal.Hash +} + +func (t *Tree) Files() chan *File { + ch := make(chan *File, 1) + + go func() { + defer func() { close(ch) }() + t.walkEntries("", ch) + }() + + return ch +} + +func (t *Tree) walkEntries(base string, ch chan *File) { + for _, entry := range t.Entries { + obj, _ := t.r.Storage.Get(entry.Hash) + if obj.Type() == internal.TreeObject { + tree := &Tree{r: t.r} + tree.Decode(obj) + tree.walkEntries(filepath.Join(base, entry.Name), ch) + continue + } + + blob := &Blob{} + blob.Decode(obj) + + ch <- &File{Name: filepath.Join(base, entry.Name), Reader: blob.Reader()} + } +} + +// Decode transform an internal.Object into a Tree struct +func (t *Tree) Decode(o internal.Object) error { + t.Hash = o.Hash() + if o.Size() == 0 { + return nil + } + + r := bufio.NewReader(o.Reader()) + for { + mode, err := r.ReadString(' ') + if err != nil { + if err == io.EOF { + break + } + + return err + } + + fm, err := strconv.ParseInt(mode[:len(mode)-1], 8, 32) + if err != nil && err != io.EOF { + return err + } + + name, err := r.ReadString(0) + if err != nil && err != io.EOF { + return err + } + + var hash internal.Hash + _, err = r.Read(hash[:]) + if err != nil && err != io.EOF { + return err + } + + t.Entries = append(t.Entries, TreeEntry{ + Hash: hash, + Mode: os.FileMode(fm), + Name: name[:len(name)-1], + }) + } + + return nil +} + +type TreeIter struct { + iter +} + +func NewTreeIter(r *Repository) *TreeIter { + return &TreeIter{newIter(r)} +} + +func (i *TreeIter) Next() (*Tree, error) { + obj := <-i.ch + if obj == nil { + return nil, io.EOF + } + + tree := &Tree{r: i.r} + return tree, tree.Decode(obj) +} + +type File struct { + Name string + io.Reader +} -- cgit