-
Notifications
You must be signed in to change notification settings - Fork 0
/
gitscanner_refs.go
144 lines (116 loc) · 3.52 KB
/
gitscanner_refs.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
package lfs
import (
"encoding/hex"
"regexp"
"github.com/git-lfs/git-lfs/git"
)
var z40 = regexp.MustCompile(`\^?0{40}`)
type lockableNameSet struct {
opt *ScanRefsOptions
set GitScannerSet
}
// Determines if the given blob sha matches a locked file.
func (s *lockableNameSet) Check(blobSha string) (string, bool) {
if s == nil || s.opt == nil || s.set == nil {
return "", false
}
name, ok := s.opt.GetName(blobSha)
if !ok {
return name, ok
}
if s.set.Contains(name) {
return name, true
}
return name, false
}
func noopFoundLockable(name string) {}
// scanRefsToChan scans through all commits reachable by refs contained in
// "include" and not reachable by any refs included in "excluded" and returns
// a channel of WrappedPointer objects for all Git LFS pointers it finds.
// Reports unique oids once only, not multiple times if >1 file uses the same content
func scanRefsToChan(scanner *GitScanner, pointerCb GitScannerFoundPointer, include, exclude []string, opt *ScanRefsOptions) error {
if opt == nil {
panic("no scan ref options")
}
revs, err := revListShas(include, exclude, opt)
if err != nil {
return err
}
lockableSet := &lockableNameSet{opt: opt, set: scanner.PotentialLockables}
smallShas, batchLockableCh, err := catFileBatchCheck(revs, lockableSet)
if err != nil {
return err
}
lockableCb := scanner.FoundLockable
if lockableCb == nil {
lockableCb = noopFoundLockable
}
go func(cb GitScannerFoundLockable, ch chan string) {
for name := range ch {
cb(name)
}
}(lockableCb, batchLockableCh)
pointers, checkLockableCh, err := catFileBatch(smallShas, lockableSet)
if err != nil {
return err
}
for p := range pointers.Results {
if name, ok := opt.GetName(p.Sha1); ok {
p.Name = name
}
if scanner.Filter.Allows(p.Name) {
pointerCb(p, nil)
}
}
for lockableName := range checkLockableCh {
if scanner.Filter.Allows(lockableName) {
lockableCb(lockableName)
}
}
if err := pointers.Wait(); err != nil {
pointerCb(nil, err)
}
return nil
}
// scanLeftRightToChan takes a ref and returns a channel of WrappedPointer objects
// for all Git LFS pointers it finds for that ref.
// Reports unique oids once only, not multiple times if >1 file uses the same content
func scanLeftRightToChan(scanner *GitScanner, pointerCb GitScannerFoundPointer, refLeft, refRight string, opt *ScanRefsOptions) error {
return scanRefsToChan(scanner, pointerCb, []string{refLeft, refRight}, nil, opt)
}
// revListShas uses git rev-list to return the list of object sha1s
// for the given ref. If all is true, ref is ignored. It returns a
// channel from which sha1 strings can be read.
func revListShas(include, exclude []string, opt *ScanRefsOptions) (*StringChannelWrapper, error) {
scanner, err := git.NewRevListScanner(include, exclude, &git.ScanRefsOptions{
Mode: git.ScanningMode(opt.ScanMode),
Remote: opt.RemoteName,
SkipDeletedBlobs: opt.SkipDeletedBlobs,
SkippedRefs: opt.skippedRefs,
Mutex: opt.mutex,
Names: opt.nameMap,
})
if err != nil {
return nil, err
}
revs := make(chan string, chanBufSize)
errs := make(chan error, 5) // may be multiple errors
go func() {
for scanner.Scan() {
sha := hex.EncodeToString(scanner.OID())
if name := scanner.Name(); len(name) > 0 {
opt.SetName(sha, name)
}
revs <- sha
}
if err = scanner.Err(); err != nil {
errs <- err
}
if err = scanner.Close(); err != nil {
errs <- err
}
close(revs)
close(errs)
}()
return NewStringChannelWrapper(revs, errs), nil
}