Fast implementation of Git in pure Go
1package object
2
3import (
4 "bytes"
5 "errors"
6 "fmt"
7
8 "codeberg.org/lindenii/furgit/objectid"
9)
10
11// ParseCommit decodes a commit object body.
12func ParseCommit(body []byte, algo objectid.Algorithm) (*Commit, error) {
13 c := new(Commit)
14
15 i := 0
16 for i < len(body) {
17 rel := bytes.IndexByte(body[i:], '\n')
18 if rel < 0 {
19 return nil, errors.New("object: commit: missing newline")
20 }
21
22 line := body[i : i+rel]
23 i += rel + 1
24
25 if len(line) == 0 {
26 break
27 }
28
29 key, value, found := bytes.Cut(line, []byte{' '})
30 if !found {
31 return nil, errors.New("object: commit: malformed header")
32 }
33
34 switch string(key) {
35 case "tree":
36 id, err := objectid.ParseHex(algo, string(value))
37 if err != nil {
38 return nil, fmt.Errorf("object: commit: tree: %w", err)
39 }
40
41 c.Tree = id
42 case "parent":
43 id, err := objectid.ParseHex(algo, string(value))
44 if err != nil {
45 return nil, fmt.Errorf("object: commit: parent: %w", err)
46 }
47
48 c.Parents = append(c.Parents, id)
49 case "author":
50 idt, err := ParseSignature(value)
51 if err != nil {
52 return nil, fmt.Errorf("object: commit: author: %w", err)
53 }
54
55 c.Author = *idt
56 case "committer":
57 idt, err := ParseSignature(value)
58 if err != nil {
59 return nil, fmt.Errorf("object: commit: committer: %w", err)
60 }
61
62 c.Committer = *idt
63 case "change-id":
64 c.ChangeID = string(value)
65 case "gpgsig", "gpgsig-sha256":
66 for i < len(body) {
67 nextRel := bytes.IndexByte(body[i:], '\n')
68 if nextRel < 0 {
69 return nil, errors.New("object: commit: unterminated gpgsig")
70 }
71
72 if body[i] != ' ' {
73 break
74 }
75
76 i += nextRel + 1
77 }
78 default:
79 c.ExtraHeaders = append(c.ExtraHeaders, ExtraHeader{
80 Key: string(key),
81 Value: append([]byte(nil), value...),
82 })
83 }
84 }
85
86 if i > len(body) {
87 return nil, errors.New("object: commit: parser position out of bounds")
88 }
89
90 c.Message = append([]byte(nil), body[i:]...)
91
92 return c, nil
93}