update runCatFileBatchCheck() too

This commit is contained in:
risk danger olson 2016-11-18 15:56:29 -07:00
parent 5dc3c9c70e
commit 558da776d9
4 changed files with 92 additions and 97 deletions

@ -27,7 +27,6 @@ func runCatFileBatch(pointerCh chan *WrappedPointer, revs *StringChannelWrapper,
scanner := &catFileBatchScanner{r: cmd.Stdout}
for r := range revs.Results {
cmd.Stdin.Write([]byte(r + "\n"))
p, hasNext, err := scanner.Next()
if p != nil {
pointerCh <- p
@ -68,7 +67,7 @@ type catFileBatchScanner struct {
}
func (s *catFileBatchScanner) Next() (*WrappedPointer, bool, error) {
p, err := s.scanChunk()
p, err := s.next()
switch err {
case nil:
return p, true, nil
@ -79,7 +78,7 @@ func (s *catFileBatchScanner) Next() (*WrappedPointer, bool, error) {
}
}
func (s *catFileBatchScanner) scanChunk() (*WrappedPointer, error) {
func (s *catFileBatchScanner) next() (*WrappedPointer, error) {
l, err := s.r.ReadBytes('\n')
if err != nil {
return nil, err

@ -3,7 +3,6 @@ package lfs
import (
"bufio"
"fmt"
"io"
"io/ioutil"
"strconv"
)
@ -19,43 +18,41 @@ func runCatFileBatchCheck(smallRevCh chan string, revs *StringChannelWrapper, er
return err
}
go catFileBatchCheckOutput(smallRevCh, cmd, errCh)
go catFileBatchCheckInput(cmd, revs, errCh)
go func() {
scanner := &catFileBatchCheckScanner{s: bufio.NewScanner(cmd.Stdout), limit: blobSizeCutoff}
for r := range revs.Results {
cmd.Stdin.Write([]byte(r + "\n"))
blobOid, hasNext, err := scanner.Next()
if len(blobOid) > 0 {
smallRevCh <- blobOid
}
if err != nil {
errCh <- err
}
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
}
func catFileBatchCheckOutput(smallRevCh chan string, cmd *wrappedCmd, errCh chan error) {
scanner := &catFileBatchCheckScanner{s: bufio.NewScanner(cmd.Stdout), limit: blobSizeCutoff}
for scanner.Scan() {
smallRevCh <- scanner.BlobOID()
}
if err := scanner.Err(); err != nil {
errCh <- err
}
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)
}
func catFileBatchCheckInput(cmd *wrappedCmd, revs *StringChannelWrapper, errCh chan error) {
for r := range revs.Results {
cmd.Stdin.Write([]byte(r + "\n"))
}
err := revs.Wait()
if err != nil {
// We can share errchan with other goroutine since that won't close it
// until we close the stdin below
errCh <- err
}
cmd.Stdin.Close()
}
type catFileBatchCheckScanner struct {
s *bufio.Scanner
limit int
@ -63,56 +60,31 @@ type catFileBatchCheckScanner struct {
err error
}
func (s *catFileBatchCheckScanner) BlobOID() string {
return s.blobOID
}
func (s *catFileBatchCheckScanner) Next() (string, bool, error) {
hasNext := s.s.Scan()
line := s.s.Text()
lineLen := len(line)
func (s *catFileBatchCheckScanner) Err() error {
return s.err
}
// 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, nil
}
func (s *catFileBatchCheckScanner) Scan() bool {
s.blobOID, s.err = "", nil
b, err := scanBlobOID(s.s, s.limit)
if line[41:45] != "blob" {
return "", hasNext, nil
}
size, err := strconv.Atoi(line[46:lineLen])
if err != nil {
// EOF halts scanning, but isn't a reportable error
if err != io.EOF {
s.err = err
}
return false
return "", hasNext, nil
}
s.blobOID = b
return true
}
func scanBlobOID(s *bufio.Scanner, limit int) (string, error) {
objType := "blob"
for s.Scan() {
line := 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 {
continue
}
if line[41:45] != objType {
continue
}
size, err := strconv.Atoi(line[46:lineLen])
if err != nil {
continue
}
if size < limit {
return line[0:40], nil
}
if size >= s.limit {
return "", hasNext, nil
}
return "", io.EOF
return line[0:40], hasNext, nil
}

@ -23,12 +23,36 @@ func TestCatFileBatchCheckScannerWithValidOutput(t *testing.T) {
limit: 1024,
}
var found []string
for s.Scan() {
found = append(found, s.BlobOID())
}
assert.Nil(t, s.Err())
assert.Equal(t, 1, len(found))
assert.Equal(t, "0000000000000000000000000000000000000002", found[0])
assertNextEmptyString(t, s)
assertNextEmptyString(t, s)
assertNextEmptyString(t, s)
assertNextOID(t, s, "0000000000000000000000000000000000000002")
assertNextEmptyString(t, s)
assertNextEmptyString(t, s)
assertStringScannerDone(t, s)
}
type stringScanner interface {
Next() (string, bool, error)
}
func assertNextOID(t *testing.T, scanner stringScanner, oid string) {
actual, hasNext, err := scanner.Next()
assert.Equal(t, oid, actual)
assert.Nil(t, err)
assert.True(t, hasNext)
}
func assertNextEmptyString(t *testing.T, scanner stringScanner) {
actual, hasNext, err := scanner.Next()
assert.Equal(t, "", actual)
assert.Nil(t, err)
assert.True(t, hasNext)
}
func assertStringScannerDone(t *testing.T, scanner stringScanner) {
actual, hasNext, err := scanner.Next()
assert.Equal(t, "", actual)
assert.Nil(t, err)
assert.False(t, hasNext)
}

@ -35,22 +35,22 @@ func TestCatFileBatchScannerWithValidOutput(t *testing.T) {
scanner := &catFileBatchScanner{r: bufio.NewReader(reader)}
for i := 0; i < 5; i++ {
assertNextEmpty(t, scanner)
assertNextEmptyPointer(t, scanner)
}
assertNextPointer(t, scanner, "e71eefd918ea175b8f362611f981f648dbf9888ff74865077cb4c9077728f350")
for i := 0; i < 5; i++ {
assertNextEmpty(t, scanner)
assertNextEmptyPointer(t, scanner)
}
assertNextPointer(t, scanner, "0eb69b651be65d5a61d6bebf2c53c811a5bf8031951111000e2077f4d7fe43b1")
for i := 0; i < 5; i++ {
assertNextEmpty(t, scanner)
assertNextEmptyPointer(t, scanner)
}
assertScannerDone(t, scanner)
assertPointerScannerDone(t, scanner)
}
type pointerScanner interface {
@ -65,14 +65,14 @@ func assertNextPointer(t *testing.T, scanner pointerScanner, oid string) {
assert.True(t, hasNext)
}
func assertNextEmpty(t *testing.T, scanner pointerScanner) {
func assertNextEmptyPointer(t *testing.T, scanner pointerScanner) {
p, hasNext, err := scanner.Next()
assert.Nil(t, err)
assert.Nil(t, p)
assert.True(t, hasNext)
}
func assertScannerDone(t *testing.T, scanner pointerScanner) {
func assertPointerScannerDone(t *testing.T, scanner pointerScanner) {
p, hasNext, err := scanner.Next()
assert.Nil(t, err)
assert.Nil(t, p)