120 lines
2.2 KiB
Go
120 lines
2.2 KiB
Go
package git
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"runtime"
|
|
"strconv"
|
|
)
|
|
|
|
// An equivalent of the Tree struct except this one is parsed in Go. There is no
|
|
// corresponding libgit2 object so you cannot do everything that you can with a
|
|
// Tree.
|
|
type ManagedTree struct {
|
|
m map[string]*TreeEntry
|
|
l []*TreeEntry
|
|
}
|
|
|
|
func (t *ManagedTree) EntryById(id *Oid) *TreeEntry {
|
|
for _, entry := range t.l {
|
|
if entry.Id.Equal(id) {
|
|
return entry
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (t *ManagedTree) EntryByName(filename string) *TreeEntry {
|
|
return t.m[filename]
|
|
}
|
|
|
|
func (t *ManagedTree) EntryByIndex(index uint64) *TreeEntry {
|
|
return t.l[index]
|
|
}
|
|
|
|
func (t *ManagedTree) EntryCount() uint64 {
|
|
return uint64(len(t.l))
|
|
}
|
|
|
|
// NewManagedTree retrieves the tree with the given id and parses it.
|
|
func NewManagedTree(r *Repository, id *Oid) (*ManagedTree, error) {
|
|
odb, err := r.Odb()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
obj, err := odb.Read(id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if obj.Type() != ObjectTree {
|
|
return nil, errors.New("object is not a tree")
|
|
}
|
|
|
|
data := obj.Data()
|
|
l := make([]*TreeEntry, 0, 8)
|
|
m := make(map[string]*TreeEntry)
|
|
|
|
var done bool
|
|
for !done {
|
|
spAt := bytes.IndexByte(data, ' ')
|
|
if spAt < 0 {
|
|
return nil, errors.New("failed to find SP after mode")
|
|
}
|
|
mode, err := strconv.ParseInt(string(data[:spAt]), 8, 32)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
data = data[spAt+1:]
|
|
nulAt := bytes.IndexByte(data, 0)
|
|
if nulAt < 0 {
|
|
return nil, errors.New("failed to find NUL after filename")
|
|
}
|
|
|
|
var name bytes.Buffer
|
|
name.Grow(nulAt)
|
|
name.Write(data[:nulAt])
|
|
|
|
data = data[nulAt+1:]
|
|
oid := NewOidFromBytes(data)
|
|
if len(data) > 20 {
|
|
data = data[20:]
|
|
} else {
|
|
done = true
|
|
}
|
|
|
|
entry := &TreeEntry{
|
|
Name: name.String(),
|
|
Id: oid,
|
|
Type: typeFromMode(mode),
|
|
Filemode: Filemode(mode),
|
|
}
|
|
|
|
l = append(l, entry)
|
|
m[entry.Name] = entry
|
|
}
|
|
|
|
// This avoids the runtime from garbage-collecting 'obj' and freeing the
|
|
// memory we're borrowing from libgit2.
|
|
runtime.KeepAlive(obj)
|
|
|
|
return &ManagedTree{
|
|
l: l,
|
|
m: m,
|
|
}, nil
|
|
}
|
|
|
|
func typeFromMode(mode int64) ObjectType {
|
|
switch Filemode(mode) {
|
|
case FilemodeTree:
|
|
return ObjectTree
|
|
case FilemodeCommit:
|
|
return ObjectCommit
|
|
default:
|
|
return ObjectBlob
|
|
}
|
|
}
|