-
Notifications
You must be signed in to change notification settings - Fork 1
/
git.go
157 lines (135 loc) · 3.88 KB
/
git.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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
package git
import (
"fmt"
"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/object"
"gitreefs/core/common"
"gitreefs/core/logger"
)
const (
MaxFileSizeMB int64 = 6
MaxFileSizeBytes = MaxFileSizeMB * 1024 * 1024
ShortShaLength = 7
RootEntryPath = ""
)
type RepositoryProvider struct {
repository *git.Repository
shortShaMapping map[string]string
}
func NewRepositoryProvider(clonePath string) (provider *RepositoryProvider, err error) {
validateErr := common.ValidateDirectory(clonePath, false)
if validateErr != nil {
logger.Info("clone at %v doesn't exist", clonePath)
return nil, nil
}
provider = &RepositoryProvider{
shortShaMapping: make(map[string]string),
}
provider.repository, err = git.PlainOpen(clonePath)
if err != nil {
return
}
// Manual implementation of short sha mapping, due to bug in go-git: https://github.com/go-git/go-git/issues/148
var iter object.CommitIter
iter, err = provider.repository.CommitObjects()
if err != nil {
return
}
err = iter.ForEach(func(commit *object.Commit) error {
sha := commit.Hash.String()
shortSha := sha[:ShortShaLength]
provider.shortShaMapping[shortSha] = sha
return nil
})
logger.Info("NewRepositoryProvider for %v with total of %v commits detected", clonePath, len(provider.shortShaMapping))
return
}
func (provider *RepositoryProvider) getCommit(commitish string) (commit *object.Commit, err error) {
if len(commitish) == ShortShaLength {
sha, found := provider.shortShaMapping[commitish]
if found {
commitish = sha
}
}
var hash *plumbing.Hash
hash, err = provider.repository.ResolveRevision(plumbing.Revision(commitish))
if err != nil {
logger.Info("commitish '%v' could not be resolved: %v", commitish, err)
return nil, nil
}
commit, err = provider.repository.CommitObject(*hash)
return
}
func (provider *RepositoryProvider) CanResolve(commitish string) (canResolve bool, err error) {
var commit *object.Commit
commit, err = provider.getCommit(commitish)
if err != nil {
return false, err
}
canResolve = commit != nil
return
}
func (provider *RepositoryProvider) ListTree(commitish string) (root *RootEntry, err error) {
var commit *object.Commit
commit, err = provider.getCommit(commitish)
if err != nil {
return
}
if commit == nil {
return nil, fmt.Errorf("%v not found", commitish)
}
var tree *object.Tree
tree, err = commit.Tree()
if err != nil {
return
}
root = &RootEntry{
Entry: Entry{
Size: 0,
IsDir: true,
EntriesByName: make(map[string]*Entry),
},
EntriesByPath: make(map[string]*Entry),
}
root.EntriesByPath[RootEntryPath] = &root.Entry
err = tree.Files().ForEach(func(file *object.File) (err error) {
mode := file.Mode
if !mode.IsFile() || mode.IsMalformed() || !mode.IsRegular() {
return
}
filePath := file.Name
fileName := ExtractBaseName(filePath)
parentPath := ExtractDirPath(filePath)
parent := root.ensurePath(parentPath)
fileEntry := FileEntry(parent, fileName, file.Size)
root.EntriesByPath[filePath] = fileEntry
return
})
logger.Info("ListTree for %v with total of %v paths detected", commitish, len(root.EntriesByPath))
return
}
func (provider *RepositoryProvider) FileContents(commitish string, filePath string) (contents string, err error) {
var commit *object.Commit
commit, err = provider.getCommit(commitish)
if err != nil {
return
}
if commit == nil {
return "", fmt.Errorf("%v not found", commitish)
}
var file *object.File
file, err = commit.File(filePath)
if err != nil {
return
}
if file.Size >= MaxFileSizeBytes {
err = fmt.Errorf("file size is too large to load to memory - %v at %v/%v", file.Size, commitish, filePath)
return
}
contents, err = file.Contents()
if err != nil {
logger.Info("FileContents for %v :: %v with content of size %v", commitish, filePath, len(contents))
}
return
}