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
|
2017-02-16 23:52:40 +00:00
|
|
|
// 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 {
|
2016-11-16 18:50:42 +00:00
|
|
|
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 err := scanner.Err(); err != nil {
|
2016-11-18 22:56:29 +00:00
|
|
|
errCh <- err
|
2017-02-16 23:52:40 +00:00
|
|
|
} 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
|
|
|
|
}
|
2016-11-18 22:56:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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 {
|
2017-02-16 23:52:40 +00:00
|
|
|
s *bufio.Scanner
|
|
|
|
limit int
|
|
|
|
lfsBlobOID string
|
|
|
|
gitBlobOID string
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *catFileBatchCheckScanner) LFSBlobOID() string {
|
|
|
|
return s.lfsBlobOID
|
2016-11-16 19:00:23 +00:00
|
|
|
}
|
|
|
|
|
2017-02-16 23:52:40 +00:00
|
|
|
func (s *catFileBatchCheckScanner) GitBlobOID() string {
|
|
|
|
return s.gitBlobOID
|
2016-11-19 00:00:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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 {
|
2017-02-16 23:52:40 +00:00
|
|
|
lfsBlobSha, gitBlobSha, hasNext := s.next()
|
|
|
|
s.lfsBlobOID = lfsBlobSha
|
|
|
|
s.gitBlobOID = gitBlobSha
|
2016-11-19 00:00:57 +00:00
|
|
|
return hasNext
|
|
|
|
}
|
|
|
|
|
2017-02-16 23:52:40 +00:00
|
|
|
func (s *catFileBatchCheckScanner) next() (string, 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 {
|
2017-02-16 23:52:40 +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" {
|
2017-02-16 23:52:40 +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 {
|
2017-02-16 23:52:40 +00:00
|
|
|
return "", "", hasNext
|
2016-11-16 19:00:23 +00:00
|
|
|
}
|
|
|
|
|
2017-02-16 23:52:40 +00:00
|
|
|
blobSha := line[0:40]
|
2016-11-18 22:56:29 +00:00
|
|
|
if size >= s.limit {
|
2017-02-16 23:52:40 +00:00
|
|
|
return "", blobSha, hasNext
|
2016-11-16 19:00:23 +00:00
|
|
|
}
|
|
|
|
|
2017-02-16 23:52:40 +00:00
|
|
|
return blobSha, "", hasNext
|
2016-11-16 19:00:23 +00:00
|
|
|
}
|