forked from git-lfs/git-lfs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
gitscanner_catfilebatchcheck.go
114 lines (95 loc) · 2.54 KB
/
gitscanner_catfilebatchcheck.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
package lfs
import (
"bufio"
"fmt"
"io/ioutil"
"strconv"
"github.com/git-lfs/git-lfs/git"
)
// runCatFileBatchCheck uses 'git cat-file --batch-check' to get the type and
// size of a git object. Any object that isn't of type blob and under the
// blobSizeCutoff will be ignored, unless it's a locked file. revs is a channel
// over which strings containing git sha1s will be sent. It returns a channel
// from which sha1 strings can be read.
func runCatFileBatchCheck(smallRevCh chan string, lockableCh chan string, lockableSet *lockableNameSet, revs *StringChannelWrapper, errCh chan error) error {
cmd, err := git.CatFile()
if err != nil {
return err
}
go func() {
scanner := &catFileBatchCheckScanner{s: bufio.NewScanner(cmd.Stdout), limit: blobSizeCutoff}
for r := range revs.Results {
cmd.Stdin.Write([]byte(r + "\n"))
hasNext := scanner.Scan()
if err := scanner.Err(); err != nil {
errCh <- err
} else if b := scanner.LFSBlobOID(); len(b) > 0 {
smallRevCh <- b
} else if b := scanner.GitBlobOID(); len(b) > 0 {
if name, ok := lockableSet.Check(b); ok {
lockableCh <- name
}
}
if !hasNext {
break
}
}
if err := revs.Wait(); err != nil {
errCh <- err
}
cmd.Stdin.Close()
stderr, _ := ioutil.ReadAll(cmd.Stderr)
err := cmd.Wait()
if err != nil {
errCh <- fmt.Errorf("Error in git cat-file --batch-check: %v %v", err, string(stderr))
}
close(smallRevCh)
close(errCh)
}()
return nil
}
type catFileBatchCheckScanner struct {
s *bufio.Scanner
limit int
lfsBlobOID string
gitBlobOID string
}
func (s *catFileBatchCheckScanner) LFSBlobOID() string {
return s.lfsBlobOID
}
func (s *catFileBatchCheckScanner) GitBlobOID() string {
return s.gitBlobOID
}
func (s *catFileBatchCheckScanner) Err() error {
return s.s.Err()
}
func (s *catFileBatchCheckScanner) Scan() bool {
lfsBlobSha, gitBlobSha, hasNext := s.next()
s.lfsBlobOID = lfsBlobSha
s.gitBlobOID = gitBlobSha
return hasNext
}
func (s *catFileBatchCheckScanner) next() (string, string, bool) {
hasNext := s.s.Scan()
line := s.s.Text()
lineLen := len(line)
// Format is:
// <sha1> <type> <size>
// type is at a fixed spot, if we see that it's "blob", we can avoid
// splitting the line just to get the size.
if lineLen < 46 {
return "", "", hasNext
}
if line[41:45] != "blob" {
return "", "", hasNext
}
size, err := strconv.Atoi(line[46:lineLen])
if err != nil {
return "", "", hasNext
}
blobSha := line[0:40]
if size >= s.limit {
return "", blobSha, hasNext
}
return blobSha, "", hasNext
}