summaryrefslogtreecommitdiffstats
path: root/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/object.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/gopkg.in/src-d/go-git.v4/plumbing/object/object.go')
-rw-r--r--vendor/gopkg.in/src-d/go-git.v4/plumbing/object/object.go237
1 files changed, 237 insertions, 0 deletions
diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/object.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/object.go
new file mode 100644
index 0000000000..e960e50c94
--- /dev/null
+++ b/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/object.go
@@ -0,0 +1,237 @@
+// Package object contains implementations of all Git objects and utility
+// functions to work with them.
+package object
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "io"
+ "strconv"
+ "time"
+
+ "gopkg.in/src-d/go-git.v4/plumbing"
+ "gopkg.in/src-d/go-git.v4/plumbing/storer"
+)
+
+// ErrUnsupportedObject trigger when a non-supported object is being decoded.
+var ErrUnsupportedObject = errors.New("unsupported object type")
+
+// Object is a generic representation of any git object. It is implemented by
+// Commit, Tree, Blob, and Tag, and includes the functions that are common to
+// them.
+//
+// Object is returned when an object can be of any type. It is frequently used
+// with a type cast to acquire the specific type of object:
+//
+// func process(obj Object) {
+// switch o := obj.(type) {
+// case *Commit:
+// // o is a Commit
+// case *Tree:
+// // o is a Tree
+// case *Blob:
+// // o is a Blob
+// case *Tag:
+// // o is a Tag
+// }
+// }
+//
+// This interface is intentionally different from plumbing.EncodedObject, which
+// is a lower level interface used by storage implementations to read and write
+// objects in its encoded form.
+type Object interface {
+ ID() plumbing.Hash
+ Type() plumbing.ObjectType
+ Decode(plumbing.EncodedObject) error
+ Encode(plumbing.EncodedObject) error
+}
+
+// GetObject gets an object from an object storer and decodes it.
+func GetObject(s storer.EncodedObjectStorer, h plumbing.Hash) (Object, error) {
+ o, err := s.EncodedObject(plumbing.AnyObject, h)
+ if err != nil {
+ return nil, err
+ }
+
+ return DecodeObject(s, o)
+}
+
+// DecodeObject decodes an encoded object into an Object and associates it to
+// the given object storer.
+func DecodeObject(s storer.EncodedObjectStorer, o plumbing.EncodedObject) (Object, error) {
+ switch o.Type() {
+ case plumbing.CommitObject:
+ return DecodeCommit(s, o)
+ case plumbing.TreeObject:
+ return DecodeTree(s, o)
+ case plumbing.BlobObject:
+ return DecodeBlob(o)
+ case plumbing.TagObject:
+ return DecodeTag(s, o)
+ default:
+ return nil, plumbing.ErrInvalidType
+ }
+}
+
+// DateFormat is the format being used in the original git implementation
+const DateFormat = "Mon Jan 02 15:04:05 2006 -0700"
+
+// Signature is used to identify who and when created a commit or tag.
+type Signature struct {
+ // Name represents a person name. It is an arbitrary string.
+ Name string
+ // Email is an email, but it cannot be assumed to be well-formed.
+ Email string
+ // When is the timestamp of the signature.
+ When time.Time
+}
+
+// Decode decodes a byte slice into a signature
+func (s *Signature) Decode(b []byte) {
+ open := bytes.LastIndexByte(b, '<')
+ close := bytes.LastIndexByte(b, '>')
+ if open == -1 || close == -1 {
+ return
+ }
+
+ if close < open {
+ return
+ }
+
+ s.Name = string(bytes.Trim(b[:open], " "))
+ s.Email = string(b[open+1 : close])
+
+ hasTime := close+2 < len(b)
+ if hasTime {
+ s.decodeTimeAndTimeZone(b[close+2:])
+ }
+}
+
+// Encode encodes a Signature into a writer.
+func (s *Signature) Encode(w io.Writer) error {
+ if _, err := fmt.Fprintf(w, "%s <%s> ", s.Name, s.Email); err != nil {
+ return err
+ }
+ if err := s.encodeTimeAndTimeZone(w); err != nil {
+ return err
+ }
+ return nil
+}
+
+var timeZoneLength = 5
+
+func (s *Signature) decodeTimeAndTimeZone(b []byte) {
+ space := bytes.IndexByte(b, ' ')
+ if space == -1 {
+ space = len(b)
+ }
+
+ ts, err := strconv.ParseInt(string(b[:space]), 10, 64)
+ if err != nil {
+ return
+ }
+
+ s.When = time.Unix(ts, 0).In(time.UTC)
+ var tzStart = space + 1
+ if tzStart >= len(b) || tzStart+timeZoneLength > len(b) {
+ return
+ }
+
+ // Include a dummy year in this time.Parse() call to avoid a bug in Go:
+ // https://github.com/golang/go/issues/19750
+ //
+ // Parsing the timezone with no other details causes the tl.Location() call
+ // below to return time.Local instead of the parsed zone in some cases
+ tl, err := time.Parse("2006 -0700", "1970 "+string(b[tzStart:tzStart+timeZoneLength]))
+ if err != nil {
+ return
+ }
+
+ s.When = s.When.In(tl.Location())
+}
+
+func (s *Signature) encodeTimeAndTimeZone(w io.Writer) error {
+ u := s.When.Unix()
+ if u < 0 {
+ u = 0
+ }
+ _, err := fmt.Fprintf(w, "%d %s", u, s.When.Format("-0700"))
+ return err
+}
+
+func (s *Signature) String() string {
+ return fmt.Sprintf("%s <%s>", s.Name, s.Email)
+}
+
+// ObjectIter provides an iterator for a set of objects.
+type ObjectIter struct {
+ storer.EncodedObjectIter
+ s storer.EncodedObjectStorer
+}
+
+// NewObjectIter takes a storer.EncodedObjectStorer and a
+// storer.EncodedObjectIter and returns an *ObjectIter that iterates over all
+// objects contained in the storer.EncodedObjectIter.
+func NewObjectIter(s storer.EncodedObjectStorer, iter storer.EncodedObjectIter) *ObjectIter {
+ return &ObjectIter{iter, s}
+}
+
+// Next moves the iterator to the next object and returns a pointer to it. If
+// there are no more objects, it returns io.EOF.
+func (iter *ObjectIter) Next() (Object, error) {
+ for {
+ obj, err := iter.EncodedObjectIter.Next()
+ if err != nil {
+ return nil, err
+ }
+
+ o, err := iter.toObject(obj)
+ if err == plumbing.ErrInvalidType {
+ continue
+ }
+
+ if err != nil {
+ return nil, err
+ }
+
+ return o, nil
+ }
+}
+
+// ForEach call the cb function for each object contained on this iter until
+// an error happens or the end of the iter is reached. If ErrStop is sent
+// the iteration is stop but no error is returned. The iterator is closed.
+func (iter *ObjectIter) ForEach(cb func(Object) error) error {
+ return iter.EncodedObjectIter.ForEach(func(obj plumbing.EncodedObject) error {
+ o, err := iter.toObject(obj)
+ if err == plumbing.ErrInvalidType {
+ return nil
+ }
+
+ if err != nil {
+ return err
+ }
+
+ return cb(o)
+ })
+}
+
+func (iter *ObjectIter) toObject(obj plumbing.EncodedObject) (Object, error) {
+ switch obj.Type() {
+ case plumbing.BlobObject:
+ blob := &Blob{}
+ return blob, blob.Decode(obj)
+ case plumbing.TreeObject:
+ tree := &Tree{s: iter.s}
+ return tree, tree.Decode(obj)
+ case plumbing.CommitObject:
+ commit := &Commit{}
+ return commit, commit.Decode(obj)
+ case plumbing.TagObject:
+ tag := &Tag{}
+ return tag, tag.Decode(obj)
+ default:
+ return nil, plumbing.ErrInvalidType
+ }
+}