Skip to content

Commit

Permalink
improved git commit object parsing - missing timezone parsing for aut…
Browse files Browse the repository at this point in the history
…hored and committed time
  • Loading branch information
richardjennings committed Jan 11, 2024
1 parent 36916d3 commit bce1292
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 37 deletions.
6 changes: 3 additions & 3 deletions internal/mygit/mygit.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,12 @@ func Log() error {
}
limit := 3
count := 0
for c, err := objects.ReadCommit(commitSha); c != nil && err == nil && len(c.Parents) > 0; c, err = objects.ReadCommit(c.Parents[0]) {
for c, err := objects.ReadCommit(commitSha); c != nil && err == nil; c, err = objects.ReadCommit(c.Parents[0]) {
fmt.Println(c)
count++
if count >= limit {
if count >= limit || len(c.Parents) == 0 {
break
}
count++
}

return nil
Expand Down
21 changes: 13 additions & 8 deletions internal/mygit/objects/object.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,16 @@ type (
}
objectType int
Commit struct {
Sha []byte
Tree []byte
Parents [][]byte
Author string
AuthoredTime time.Time
Committer string
CommittedTime time.Time
Message []byte
Sha []byte
Tree []byte
Parents [][]byte
Author string
AuthorEmail string
AuthoredTime time.Time
Committer string
CommitterEmail string
CommittedTime time.Time
Message []byte
}
Tree struct {
Sha []byte
Expand All @@ -49,9 +51,12 @@ const (
)

func (c Commit) String() string {
fmt.Printf("commit: %s\n", string(c.Sha))
fmt.Printf("tree: %s\n", string(c.Tree))
for _, v := range c.Parents {
fmt.Printf("parent: %s\n", string(v))
}
fmt.Printf("%s <%s> %s\n", c.Author, c.AuthorEmail, c.AuthoredTime.String())
fmt.Printf("%s <%s> %s\n", c.Committer, c.CommitterEmail, c.CommittedTime.String())
return fmt.Sprintf("message: \n%s\n", c.Message)
}
99 changes: 73 additions & 26 deletions internal/mygit/objects/reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"os"
"path/filepath"
"strconv"
"time"
)

// FlattenTree turns a TreeObject structure into a flat list of file paths
Expand Down Expand Up @@ -202,38 +203,84 @@ func readCommit(obj *Object) (*Commit, error) {
c := &Commit{Sha: obj.Sha}

s := bufio.NewScanner(r)
var parts [][]byte
parts = lineParts(s)
c.Tree = parts[1]
for {
parts = lineParts(s)
if string(parts[0]) == "parent" {
c.Parents = append(c.Parents, parts[1])
} else {
break
}
}
if string(parts[0]) != "author" {
return nil, fmt.Errorf("expected author got %s", string(parts[0]))
}
parts = lineParts(s)
if string(parts[0]) != "committer" {
return nil, fmt.Errorf("expected committer got %s", string(parts[0]))
}
s.Scan()
if s.Text() != "" {
return nil, fmt.Errorf("expected newline got %s", s.Text())
}

for {
if !s.Scan() {
break
}
c.Message = append(c.Message, s.Bytes()...)
l := s.Bytes()
p := bytes.SplitN(l, []byte(" "), 2)
t := string(p[0])
if c.Tree == nil {
if t != "tree" {
return nil, fmt.Errorf("expected tree got %s", t)
}
c.Tree = p[1]
continue
}
// can be parent
if t == "parent" {
c.Parents = append(c.Parents, p[1])
continue
}
if c.Author == "" {
// should be author
if t != "author" {
return nil, fmt.Errorf("expected author got %s", t)
}
// decode author line
if err := readAuthor(p[1], c); err != nil {
return nil, err
}
continue
}
if c.Committer == "" {
// should be committer
if t != "committer" {
return nil, fmt.Errorf("expected committer got %s", t)
}
// decode committer line
if err := readCommitter(p[1], c); err != nil {
return nil, err
}
continue
}
// can be GPG Signature
if t == "gpgsig" {
// currently not implementing @todo implement signed commits
continue
}
// now we have the message body hopefully
c.Message = append(c.Message, l...)
}

return c, nil
}
func lineParts(s *bufio.Scanner) [][]byte {
s.Scan()
return bytes.Split(s.Bytes(), []byte(" "))

func readAuthor(b []byte, c *Commit) error {
s := bytes.Index(b, []byte("<"))
e := bytes.Index(b, []byte(">"))
c.Author = string(b[0 : s-1])
c.AuthorEmail = string(b[s+1 : e])
ut, err := strconv.ParseInt(string(b[e+2:e+2+10]), 10, 64)
if err != nil {
return err
}
// @todo timezone part
c.AuthoredTime = time.Unix(ut, 0)
return nil
}

func readCommitter(b []byte, c *Commit) error {
s := bytes.Index(b, []byte("<"))
e := bytes.Index(b, []byte(">"))
c.Committer = string(b[0 : s-1])
c.CommitterEmail = string(b[s+1 : e])
ut, err := strconv.ParseInt(string(b[e+2:e+2+10]), 10, 64)
if err != nil {
return err
}
// @todo timezone part
c.CommittedTime = time.Unix(ut, 0)
return nil
}

0 comments on commit bce1292

Please sign in to comment.