aboutsummaryrefslogtreecommitdiff
path: root/object/commit_parse.go
blob: 31e215de3462e3861c277e87513fd7f63c41217b (about) (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
package object

import (
	"bytes"
	"errors"
	"fmt"

	"codeberg.org/lindenii/furgit/objectid"
)

// ParseCommit decodes a commit object body.
func ParseCommit(body []byte, algo objectid.Algorithm) (*Commit, error) {
	c := new(Commit)

	i := 0
	for i < len(body) {
		rel := bytes.IndexByte(body[i:], '\n')
		if rel < 0 {
			return nil, errors.New("object: commit: missing newline")
		}

		line := body[i : i+rel]
		i += rel + 1

		if len(line) == 0 {
			break
		}

		key, value, found := bytes.Cut(line, []byte{' '})
		if !found {
			return nil, errors.New("object: commit: malformed header")
		}

		switch string(key) {
		case "tree":
			id, err := objectid.ParseHex(algo, string(value))
			if err != nil {
				return nil, fmt.Errorf("object: commit: tree: %w", err)
			}

			c.Tree = id
		case "parent":
			id, err := objectid.ParseHex(algo, string(value))
			if err != nil {
				return nil, fmt.Errorf("object: commit: parent: %w", err)
			}

			c.Parents = append(c.Parents, id)
		case "author":
			idt, err := ParseSignature(value)
			if err != nil {
				return nil, fmt.Errorf("object: commit: author: %w", err)
			}

			c.Author = *idt
		case "committer":
			idt, err := ParseSignature(value)
			if err != nil {
				return nil, fmt.Errorf("object: commit: committer: %w", err)
			}

			c.Committer = *idt
		case "change-id":
			c.ChangeID = string(value)
		case "gpgsig", "gpgsig-sha256":
			for i < len(body) {
				nextRel := bytes.IndexByte(body[i:], '\n')
				if nextRel < 0 {
					return nil, errors.New("object: commit: unterminated gpgsig")
				}

				if body[i] != ' ' {
					break
				}

				i += nextRel + 1
			}
		default:
			c.ExtraHeaders = append(c.ExtraHeaders, ExtraHeader{
				Key:   string(key),
				Value: append([]byte(nil), value...),
			})
		}
	}

	if i > len(body) {
		return nil, errors.New("object: commit: parser position out of bounds")
	}

	c.Message = append([]byte(nil), body[i:]...)

	return c, nil
}