git-lfs/lfs/gitscanner_catfilebatchcheck.go

105 lines
2.1 KiB
Go
Raw Normal View History

2016-11-16 18:50:42 +00:00
package lfs
import (
"bufio"
"fmt"
"io/ioutil"
"strconv"
)
// 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. 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, revs *StringChannelWrapper, errCh chan error) error {
cmd, err := startCommand("git", "cat-file", "--batch-check")
if err != nil {
return err
}
2016-11-18 22:56:29 +00:00
go func() {
scanner := &catFileBatchCheckScanner{s: bufio.NewScanner(cmd.Stdout), limit: blobSizeCutoff}
for r := range revs.Results {
cmd.Stdin.Write([]byte(r + "\n"))
2016-11-19 00:00:57 +00:00
hasNext := scanner.Scan()
if b := scanner.BlobOID(); len(b) > 0 {
smallRevCh <- b
2016-11-18 22:56:29 +00:00
}
2016-11-19 00:00:57 +00:00
if err := scanner.Err(); err != nil {
2016-11-18 22:56:29 +00:00
errCh <- err
}
if !hasNext {
break
}
}
2016-11-16 18:50:42 +00:00
2016-11-18 22:56:29 +00:00
if err := revs.Wait(); err != nil {
errCh <- err
}
cmd.Stdin.Close()
2016-11-16 18:50:42 +00:00
2016-11-18 22:56:29 +00:00
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)
}()
2016-11-16 18:50:42 +00:00
2016-11-18 22:56:29 +00:00
return nil
2016-11-16 18:50:42 +00:00
}
2016-11-16 19:00:23 +00:00
type catFileBatchCheckScanner struct {
s *bufio.Scanner
limit int
2016-11-16 19:00:23 +00:00
blobOID string
}
2016-11-19 00:00:57 +00:00
func (s *catFileBatchCheckScanner) BlobOID() string {
return s.blobOID
}
func (s *catFileBatchCheckScanner) Err() error {
2016-11-19 00:53:49 +00:00
return s.s.Err()
2016-11-19 00:00:57 +00:00
}
func (s *catFileBatchCheckScanner) Scan() bool {
2016-11-19 00:53:49 +00:00
s.blobOID = ""
b, hasNext := s.next()
2016-11-19 00:00:57 +00:00
s.blobOID = b
return hasNext
}
2016-11-19 00:53:49 +00:00
func (s *catFileBatchCheckScanner) next() (string, bool) {
2016-11-18 22:56:29 +00:00
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 {
2016-11-19 00:53:49 +00:00
return "", hasNext
2016-11-18 22:56:29 +00:00
}
2016-11-16 19:00:23 +00:00
2016-11-18 22:56:29 +00:00
if line[41:45] != "blob" {
2016-11-19 00:53:49 +00:00
return "", hasNext
2016-11-18 22:56:29 +00:00
}
2016-11-16 19:00:23 +00:00
2016-11-18 22:56:29 +00:00
size, err := strconv.Atoi(line[46:lineLen])
2016-11-16 19:00:23 +00:00
if err != nil {
2016-11-19 00:53:49 +00:00
return "", hasNext
2016-11-16 19:00:23 +00:00
}
2016-11-18 22:56:29 +00:00
if size >= s.limit {
2016-11-19 00:53:49 +00:00
return "", hasNext
2016-11-16 19:00:23 +00:00
}
2016-11-19 00:53:49 +00:00
return line[0:40], hasNext
2016-11-16 19:00:23 +00:00
}