This repository has been archived by the owner on May 29, 2018. It is now read-only.
/
tree.go
139 lines (116 loc) · 2.48 KB
/
tree.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
133
134
135
136
137
138
139
package git
import (
"errors"
"path"
"strings"
)
var (
SkipDir = errors.New("skip this directory")
)
// TreeWalkFunc is similar to path/filepath.WalkFunc, it will continue as long
// as the returned error is nil. If SkipDir is returned, then that subtree will
// be skipped.
type TreeWalkFunc func(path string, te *TreeEntry, err error) error
// A tree is a flat directory listing.
type Tree struct {
Id sha1
repo *Repository
// parent tree
ptree *Tree
entries Entries
entriesParsed bool
}
// The tree's directory heirarchy will be traversed recursively in breadth-first
// order, walkFn will be called once for each entry.
func (t *Tree) Walk(walkFn TreeWalkFunc) error {
return t.walk("", walkFn)
}
func (t *Tree) walkSubtree(te *TreeEntry) (*Tree, error) {
commit, err := t.repo.getCommit(te.Id)
if err != nil {
return nil, err
}
return t.repo.getTree(commit.Id)
}
func (t *Tree) walk(dir string, walkFn TreeWalkFunc) error {
entries, err := t.ListEntries()
if err != nil {
return err
}
for _, te := range entries {
var subErr error
var subTree *Tree
if te.Type == ObjectTree {
subTree, subErr = t.walkSubtree(te)
}
d := path.Join(dir, te.name)
if err := walkFn(d, te, subErr); err != nil {
if err == SkipDir {
continue
}
return err
}
if subTree != nil {
// Descend
if err := subTree.walk(d, walkFn); err != nil {
return err
}
}
}
return nil
}
func (t *Tree) SubTree(rpath string) (*Tree, error) {
if len(rpath) == 0 {
return t, nil
}
paths := strings.Split(rpath, "/")
var err error
var g = t
var p = t
var te *TreeEntry
for _, name := range paths {
te, err = p.GetTreeEntryByPath(name)
if err != nil {
return nil, err
}
g, err = t.repo.getTree(te.Id)
if err != nil {
return nil, err
}
g.ptree = p
p = g
}
return g, nil
}
func (t *Tree) ListEntries() (Entries, error) {
if t.entriesParsed {
return t.entries, nil
}
t.entriesParsed = true
var entries Entries
scanner, err := t.Scanner()
if err != nil {
return nil, err
}
for scanner.Scan() {
entries = append(entries, scanner.TreeEntry())
}
if err := scanner.Err(); err != nil {
return nil, err
}
t.entries = entries
return t.entries, nil
}
func NewTree(repo *Repository, id sha1) *Tree {
tree := new(Tree)
tree.Id = id
tree.repo = repo
return tree
}
func (t *Tree) Scanner() (*TreeScanner, error) {
_, _, r, err := t.repo.getRawObject(t.Id, false)
if err != nil {
return nil, err
}
return NewTreeScanner(t, r), nil
}