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 "codeberg.org/lindenii/furgit/objecttype"
10)
11
12// ParseTag decodes a tag object body.
13func ParseTag(body []byte, algo objectid.Algorithm) (*Tag, error) {
14 t := new(Tag)
15 i := 0
16
17 var haveTarget, haveType bool
18
19 for i < len(body) {
20 rel := bytes.IndexByte(body[i:], '\n')
21 if rel < 0 {
22 return nil, errors.New("object: tag: missing newline")
23 }
24
25 line := body[i : i+rel]
26 i += rel + 1
27
28 if len(line) == 0 {
29 break
30 }
31
32 key, value, found := bytes.Cut(line, []byte{' '})
33 if !found {
34 return nil, errors.New("object: tag: malformed header")
35 }
36
37 switch string(key) {
38 case "object":
39 id, err := objectid.ParseHex(algo, string(value))
40 if err != nil {
41 return nil, fmt.Errorf("object: tag: object: %w", err)
42 }
43
44 t.Target = id
45 haveTarget = true
46 case "type":
47 ty, ok := objecttype.ParseName(string(value))
48 if !ok {
49 return nil, errors.New("object: tag: unknown target type")
50 }
51
52 t.TargetType = ty
53 haveType = true
54 case "tag":
55 t.Name = append([]byte(nil), value...)
56 case "tagger":
57 idt, err := ParseSignature(value)
58 if err != nil {
59 return nil, fmt.Errorf("object: tag: tagger: %w", err)
60 }
61
62 t.Tagger = idt
63 case "gpgsig", "gpgsig-sha256":
64 for i < len(body) {
65 nextRel := bytes.IndexByte(body[i:], '\n')
66 if nextRel < 0 {
67 return nil, errors.New("object: tag: unterminated gpgsig")
68 }
69
70 if body[i] != ' ' {
71 break
72 }
73
74 i += nextRel + 1
75 }
76 default:
77 // Ignore unknown headers for now.
78 }
79 }
80
81 if !haveTarget || !haveType {
82 return nil, errors.New("object: tag: missing required headers")
83 }
84
85 t.Message = append([]byte(nil), body[i:]...)
86
87 return t, nil
88}