aboutsummaryrefslogtreecommitdiffstats
path: root/objects.go
diff options
context:
space:
mode:
authorMáximo Cuadros <mcuadros@gmail.com>2015-10-25 20:30:36 +0100
committerMáximo Cuadros <mcuadros@gmail.com>2015-10-25 20:30:36 +0100
commit9a44cd8ccff143a112436c38bfe5581e74b68f07 (patch)
treef4d2f38cc61647bf159a7c870913e6f6b60828b2 /objects.go
parentbe69a505926451bf10450ac68d40265a6f43e150 (diff)
downloadgo-git-9a44cd8ccff143a112436c38bfe5581e74b68f07.tar.gz
formats/packfile: new reader API
Diffstat (limited to 'objects.go')
-rw-r--r--objects.go217
1 files changed, 217 insertions, 0 deletions
diff --git a/objects.go b/objects.go
new file mode 100644
index 0000000..77bdc2a
--- /dev/null
+++ b/objects.go
@@ -0,0 +1,217 @@
+package git
+
+import (
+ "bytes"
+ "encoding/hex"
+ "fmt"
+ "strconv"
+ "time"
+
+ "gopkg.in/src-d/go-git.v2/common"
+)
+
+// Object generic object interface
+type Object interface {
+ Type() common.ObjectType
+ Hash() common.Hash
+}
+
+// Commit points to a single tree, marking it as what the project looked like
+// at a certain point in time. It contains meta-information about that point
+// in time, such as a timestamp, the author of the changes since the last
+// commit, a pointer to the previous commit(s), etc.
+// http://schacon.github.io/gitbook/1_the_git_object_model.html
+type Commit struct {
+ Tree common.Hash
+ Parents []common.Hash
+ Author Signature
+ Committer Signature
+ Message string
+ hash common.Hash
+}
+
+// ParseCommit transform a byte slice into a Commit struct
+func ParseCommit(b []byte) (*Commit, error) {
+ o := &Commit{hash: common.ComputeHash(common.CommitObject, b)}
+
+ lines := bytes.Split(b, []byte{'\n'})
+ for i := range lines {
+ if len(lines[i]) > 0 {
+ var err error
+
+ split := bytes.SplitN(lines[i], []byte{' '}, 2)
+ switch string(split[0]) {
+ case "tree":
+ _, err = hex.Decode(o.Tree[:], split[1])
+ case "parent":
+ var h common.Hash
+ _, err = hex.Decode(h[:], split[1])
+ if err == nil {
+ o.Parents = append(o.Parents, h)
+ }
+ case "author":
+ o.Author = ParseSignature(split[1])
+ case "committer":
+ o.Committer = ParseSignature(split[1])
+ }
+
+ if err != nil {
+ return nil, err
+ }
+ } else {
+ o.Message = string(bytes.Join(append(lines[i+1:]), []byte{'\n'}))
+ break
+ }
+
+ }
+
+ return o, nil
+}
+
+// Type returns the object type
+func (o *Commit) Type() common.ObjectType {
+ return common.CommitObject
+}
+
+// Hash returns the computed hash of the commit
+func (o *Commit) Hash() common.Hash {
+ return o.hash
+}
+
+// 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 common.Hash
+}
+
+// TreeEntry represents a file
+type TreeEntry struct {
+ Name string
+ Hash common.Hash
+}
+
+// ParseTree transform a byte slice into a Tree struct
+func ParseTree(b []byte) (*Tree, error) {
+ o := &Tree{hash: common.ComputeHash(common.TreeObject, b)}
+
+ if len(b) == 0 {
+ return o, nil
+ }
+
+ for {
+ split := bytes.SplitN(b, []byte{0}, 2)
+ split1 := bytes.SplitN(split[0], []byte{' '}, 2)
+
+ entry := TreeEntry{}
+ entry.Name = string(split1[1])
+ copy(entry.Hash[:], split[1][0:20])
+
+ o.Entries = append(o.Entries, entry)
+
+ b = split[1][20:]
+ if len(split[1]) == 20 {
+ break
+ }
+ }
+
+ return o, nil
+}
+
+// Type returns the object type
+func (o *Tree) Type() common.ObjectType {
+ return common.TreeObject
+}
+
+// Hash returns the computed hash of the tree
+func (o *Tree) Hash() common.Hash {
+ return o.hash
+}
+
+// Blob is used to store file data - it is generally a file.
+type Blob struct {
+ Len int
+ hash common.Hash
+}
+
+// ParseBlob transform a byte slice into a Blob struct
+func ParseBlob(b []byte) (*Blob, error) {
+ return &Blob{
+ Len: len(b),
+ hash: common.ComputeHash(common.BlobObject, b),
+ }, nil
+}
+
+// Type returns the object type
+func (o *Blob) Type() common.ObjectType {
+ return common.BlobObject
+}
+
+// Hash returns the computed hash of the blob
+func (o *Blob) Hash() common.Hash {
+ return o.hash
+}
+
+// Signature represents an action signed by a person
+type Signature struct {
+ Name string
+ Email string
+ When time.Time
+}
+
+// ParseSignature parse a byte slice returning a new action signature.
+func ParseSignature(signature []byte) Signature {
+ ret := Signature{}
+ if len(signature) == 0 {
+ return ret
+ }
+
+ from := 0
+ state := 'n' // n: name, e: email, t: timestamp, z: timezone
+ for i := 0; ; i++ {
+ var c byte
+ var end bool
+ if i < len(signature) {
+ c = signature[i]
+ } else {
+ end = true
+ }
+
+ switch state {
+ case 'n':
+ if c == '<' || end {
+ if i == 0 {
+ break
+ }
+ ret.Name = string(signature[from : i-1])
+ state = 'e'
+ from = i + 1
+ }
+ case 'e':
+ if c == '>' || end {
+ ret.Email = string(signature[from:i])
+ i++
+ state = 't'
+ from = i + 1
+ }
+ case 't':
+ if c == ' ' || end {
+ t, err := strconv.ParseInt(string(signature[from:i]), 10, 64)
+ if err == nil {
+ ret.When = time.Unix(t, 0)
+ }
+ end = true
+ }
+ }
+
+ if end {
+ break
+ }
+ }
+
+ return ret
+}
+
+func (s *Signature) String() string {
+ return fmt.Sprintf("%q <%s> @ %s", s.Name, s.Email, s.When)
+}