forked from speedata/gogit
-
Notifications
You must be signed in to change notification settings - Fork 32
/
Copy pathtree_utils.go
132 lines (110 loc) · 2.37 KB
/
tree_utils.go
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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package git
import (
"bufio"
"bytes"
"fmt"
"io"
"regexp"
)
type TreeScanner struct {
parent *Tree
*bufio.Scanner
closer io.Closer
treeEntry *TreeEntry
err error
}
func NewTreeScanner(parent *Tree, rc io.ReadCloser) *TreeScanner {
ts := &TreeScanner{
parent: parent,
Scanner: bufio.NewScanner(rc),
closer: rc,
}
ts.Split(ScanTreeEntry)
return ts
}
var TreeEntryRe = regexp.MustCompile("^([0-9]+) ([^\x00]+)\x00")
func (t *TreeScanner) parse() error {
t.treeEntry = nil
data := t.Bytes()
match := TreeEntryRe.FindSubmatch(data)
if match == nil {
return fmt.Errorf("failed to parse tree entry: %q", data)
}
modeString, name := string(match[1]), string(match[2])
id, err := NewId(data[len(match[0]):])
if err != nil {
return err
}
entryMode, objectType, err := ParseModeType(modeString)
if err != nil {
return err
}
t.treeEntry = &TreeEntry{
name: name,
mode: entryMode,
Id: id,
Type: objectType,
ptree: t.parent,
}
return nil
}
func (t *TreeScanner) Scan() bool {
if !t.Scanner.Scan() {
if t.closer != nil {
// Upon hitting any error, close the input.
t.closer.Close()
t.closer = nil
}
return false
}
t.err = t.parse()
return t.err == nil
}
func (t *TreeScanner) Err() error {
// Underlying IO errs take priority
if err := t.Scanner.Err(); err != nil {
return err
}
return t.err
}
func ScanTreeEntry(
data []byte,
atEOF bool,
) (
advance int, token []byte, err error,
) {
if atEOF && len(data) == 0 {
return 0, nil, nil
}
const shaLen = 20
nullIndex := bytes.IndexByte(data, '\x00')
recordLength := nullIndex + 1 + shaLen
if recordLength <= len(data) {
// We found 20 bytes after a null, we're done.
return recordLength, data[:recordLength], nil
}
if atEOF {
// atEOF but don't have a complete record
return 0, nil, fmt.Errorf("malformed record %q", data)
}
return 0, nil, nil // Request more data.
}
func (t *TreeScanner) TreeEntry() *TreeEntry {
return t.treeEntry
}
func ParseModeType(modeString string) (EntryMode, ObjectType, error) {
switch modeString {
case "100644":
return ModeBlob, ObjectBlob, nil
case "100755":
return ModeExec, ObjectBlob, nil
case "120000":
return ModeSymlink, ObjectBlob, nil
case "160000":
return ModeCommit, ObjectCommit, nil
case "40000":
return ModeTree, ObjectTree, nil
default:
}
return 0, 0, fmt.Errorf("unknown type: %q", modeString)
}