aboutsummaryrefslogtreecommitdiffstats
path: root/tree.go
diff options
context:
space:
mode:
authorMáximo Cuadros <mcuadros@gmail.com>2016-01-21 13:01:59 +0100
committerMáximo Cuadros <mcuadros@gmail.com>2016-01-21 13:01:59 +0100
commitabe470a3c1b9fae99161ee5531d18d0e3168fdfa (patch)
treec1067a2175af73e8fba349128a860dfeb936abff /tree.go
parent37cc5cf842c3c0fb989bcf7525cc8f826d96b295 (diff)
parent5ec2de7f1a563bee521332568df591ef63623232 (diff)
downloadgo-git-abe470a3c1b9fae99161ee5531d18d0e3168fdfa.tar.gz
Merge pull request #14 from alcortesm/fix-file-iterator-gorutine-leak
Fix commit.File() gorutine leak
Diffstat (limited to 'tree.go')
-rw-r--r--tree.go82
1 files changed, 82 insertions, 0 deletions
diff --git a/tree.go b/tree.go
index 7b988a1..523baac 100644
--- a/tree.go
+++ b/tree.go
@@ -2,10 +2,12 @@ package git
import (
"bufio"
+ "errors"
"io"
"os"
"path/filepath"
"strconv"
+ "strings"
"gopkg.in/src-d/go-git.v2/core"
)
@@ -26,6 +28,86 @@ type TreeEntry struct {
Hash core.Hash
}
+// New errors defined by this package.
+var ErrFileNotFound = errors.New("file not found")
+
+// File returns the hash of the file identified by the `path` argument.
+// The path is interpreted as relative to the tree receiver.
+func (t *Tree) File(path string) (*File, error) {
+ hash, err := t.findHash(path)
+ if err != nil {
+ return nil, ErrFileNotFound
+ }
+
+ obj, ok := t.r.Storage.Get(*hash)
+ if !ok {
+ return nil, ErrFileNotFound // a git submodule
+ }
+
+ if obj.Type() != core.BlobObject {
+ return nil, ErrFileNotFound // a directory
+ }
+
+ blob := &Blob{}
+ blob.Decode(obj)
+
+ return &File{Name: path, Reader: blob.Reader(), Hash: *hash}, nil
+}
+
+func (t *Tree) findHash(path string) (*core.Hash, error) {
+ pathParts := strings.Split(path, "/")
+
+ var tree *Tree
+ var err error
+ for tree = t; len(pathParts) > 1; pathParts = pathParts[1:] {
+ if tree, err = tree.dir(pathParts[0]); err != nil {
+ return nil, err
+ }
+ }
+
+ entry, err := tree.entry(pathParts[0])
+ if err != nil {
+ return nil, err
+ }
+
+ return &entry.Hash, nil
+}
+
+var errDirNotFound = errors.New("directory not found")
+
+func (t *Tree) dir(baseName string) (*Tree, error) {
+ entry, err := t.entry(baseName)
+ if err != nil {
+ return nil, errDirNotFound
+ }
+
+ obj, ok := t.r.Storage.Get(entry.Hash)
+ if !ok { // git submodule
+ return nil, errDirNotFound
+ }
+
+ if obj.Type() != core.TreeObject {
+ return nil, errDirNotFound // a file
+ }
+
+ tree := &Tree{r: t.r}
+ tree.Decode(obj)
+
+ return tree, nil
+}
+
+var errEntryNotFound = errors.New("entry not found")
+
+func (t *Tree) entry(baseName string) (*TreeEntry, error) {
+ for _, entry := range t.Entries {
+ if entry.Name == baseName {
+ return &entry, nil
+ }
+ }
+
+ return nil, errEntryNotFound
+}
+
func (t *Tree) Files() chan *File {
ch := make(chan *File, 1)