@@ -7,9 +7,33 @@ import (
7
7
"bufio"
8
8
"bytes"
9
9
"io"
10
- "strings"
11
10
)
12
11
12
+ const (
13
+ commitHeaderGpgsig = "gpgsig"
14
+ commitHeaderGpgsigSha256 = "gpgsig-sha256"
15
+ )
16
+
17
+ func assignCommitFields (gitRepo * Repository , commit * Commit , headerKey string , headerValue []byte ) {
18
+ if len (headerValue ) > 0 && headerValue [len (headerValue )- 1 ] == '\n' {
19
+ headerValue = headerValue [:len (headerValue )- 1 ] // remove trailing newline
20
+ }
21
+ switch headerKey {
22
+ case "tree" :
23
+ commit .Tree = * NewTree (gitRepo , MustIDFromString (string (headerValue )))
24
+ case "parent" :
25
+ commit .Parents = append (commit .Parents , MustIDFromString (string (headerValue )))
26
+ case "author" :
27
+ commit .Author .Decode (headerValue )
28
+ case "committer" :
29
+ commit .Committer .Decode (headerValue )
30
+ case commitHeaderGpgsig , commitHeaderGpgsigSha256 :
31
+ // if there are duplicate "gpgsig" and "gpgsig-sha256" headers, then the signature must have already been invalid
32
+ // so we don't need to handle duplicate headers here
33
+ commit .Signature = & CommitSignature {Signature : string (headerValue )}
34
+ }
35
+ }
36
+
13
37
// CommitFromReader will generate a Commit from a provided reader
14
38
// We need this to interpret commits from cat-file or cat-file --batch
15
39
//
@@ -21,90 +45,44 @@ func CommitFromReader(gitRepo *Repository, objectID ObjectID, reader io.Reader)
21
45
Committer : & Signature {},
22
46
}
23
47
24
- payloadSB := new (strings.Builder )
25
- signatureSB := new (strings.Builder )
26
- messageSB := new (strings.Builder )
27
- message := false
28
- pgpsig := false
29
-
30
- bufReader , ok := reader .(* bufio.Reader )
31
- if ! ok {
32
- bufReader = bufio .NewReader (reader )
33
- }
34
-
35
- readLoop:
48
+ bufReader := bufio .NewReader (reader )
49
+ inHeader := true
50
+ var payloadSB , messageSB bytes.Buffer
51
+ var headerKey string
52
+ var headerValue []byte
36
53
for {
37
54
line , err := bufReader .ReadBytes ('\n' )
38
- if err != nil {
39
- if err == io .EOF {
40
- if message {
41
- _ , _ = messageSB .Write (line )
42
- }
43
- _ , _ = payloadSB .Write (line )
44
- break readLoop
45
- }
46
- return nil , err
55
+ if len (line ) == 0 {
56
+ break
47
57
}
48
- if pgpsig {
49
- if len (line ) > 0 && line [0 ] == ' ' {
50
- _ , _ = signatureSB .Write (line [1 :])
51
- continue
52
- }
53
- pgpsig = false
58
+ if err != nil && err != io .EOF {
59
+ return nil , err
54
60
}
55
61
56
- if ! message {
57
- // This is probably not correct but is copied from go-gits interpretation...
58
- trimmed := bytes .TrimSpace (line )
59
- if len (trimmed ) == 0 {
60
- message = true
61
- _ , _ = payloadSB .Write (line )
62
- continue
63
- }
64
-
65
- split := bytes .SplitN (trimmed , []byte {' ' }, 2 )
66
- var data []byte
67
- if len (split ) > 1 {
68
- data = split [1 ]
62
+ if inHeader {
63
+ inHeader = ! (len (line ) == 1 && line [0 ] == '\n' ) // still in header if line is not just a newline
64
+ k , v , _ := bytes .Cut (line , []byte {' ' })
65
+ if len (k ) != 0 || ! inHeader {
66
+ if headerKey != "" {
67
+ assignCommitFields (gitRepo , commit , headerKey , headerValue )
68
+ }
69
+ headerKey = string (k ) // it also resets the headerValue to empty string if not inHeader
70
+ headerValue = v
71
+ } else {
72
+ headerValue = append (headerValue , v ... )
69
73
}
70
-
71
- switch string (split [0 ]) {
72
- case "tree" :
73
- commit .Tree = * NewTree (gitRepo , MustIDFromString (string (data )))
74
- _ , _ = payloadSB .Write (line )
75
- case "parent" :
76
- commit .Parents = append (commit .Parents , MustIDFromString (string (data )))
74
+ if headerKey != commitHeaderGpgsig && headerKey != commitHeaderGpgsigSha256 {
77
75
_ , _ = payloadSB .Write (line )
78
- case "author" :
79
- commit .Author = & Signature {}
80
- commit .Author .Decode (data )
81
- _ , _ = payloadSB .Write (line )
82
- case "committer" :
83
- commit .Committer = & Signature {}
84
- commit .Committer .Decode (data )
85
- _ , _ = payloadSB .Write (line )
86
- case "encoding" :
87
- _ , _ = payloadSB .Write (line )
88
- case "gpgsig" :
89
- fallthrough
90
- case "gpgsig-sha256" : // FIXME: no intertop, so only 1 exists at present.
91
- _ , _ = signatureSB .Write (data )
92
- _ = signatureSB .WriteByte ('\n' )
93
- pgpsig = true
94
76
}
95
77
} else {
96
78
_ , _ = messageSB .Write (line )
97
79
_ , _ = payloadSB .Write (line )
98
80
}
99
81
}
82
+
100
83
commit .CommitMessage = messageSB .String ()
101
- commit .Signature = & CommitSignature {
102
- Signature : signatureSB .String (),
103
- Payload : payloadSB .String (),
104
- }
105
- if len (commit .Signature .Signature ) == 0 {
106
- commit .Signature = nil
84
+ if commit .Signature != nil {
85
+ commit .Signature .Payload = payloadSB .String ()
107
86
}
108
-
109
87
return commit , nil
110
88
}
0 commit comments