diff options
author | Máximo Cuadros <mcuadros@gmail.com> | 2016-01-21 13:01:59 +0100 |
---|---|---|
committer | Máximo Cuadros <mcuadros@gmail.com> | 2016-01-21 13:01:59 +0100 |
commit | abe470a3c1b9fae99161ee5531d18d0e3168fdfa (patch) | |
tree | c1067a2175af73e8fba349128a860dfeb936abff /tree.go | |
parent | 37cc5cf842c3c0fb989bcf7525cc8f826d96b295 (diff) | |
parent | 5ec2de7f1a563bee521332568df591ef63623232 (diff) | |
download | go-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.go | 82 |
1 files changed, 82 insertions, 0 deletions
@@ -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) |