github.com/psexton/git-lfs@v2.1.1-0.20170517224304-289a18b2bc53+incompatible/lfs/gitscanner_catfilebatchcheck.go (about) 1 package lfs 2 3 import ( 4 "bufio" 5 "fmt" 6 "io/ioutil" 7 "strconv" 8 ) 9 10 // runCatFileBatchCheck uses 'git cat-file --batch-check' to get the type and 11 // size of a git object. Any object that isn't of type blob and under the 12 // blobSizeCutoff will be ignored, unless it's a locked file. revs is a channel 13 // over which strings containing git sha1s will be sent. It returns a channel 14 // from which sha1 strings can be read. 15 func runCatFileBatchCheck(smallRevCh chan string, lockableCh chan string, lockableSet *lockableNameSet, revs *StringChannelWrapper, errCh chan error) error { 16 cmd, err := startCommand("git", "cat-file", "--batch-check") 17 if err != nil { 18 return err 19 } 20 21 go func() { 22 scanner := &catFileBatchCheckScanner{s: bufio.NewScanner(cmd.Stdout), limit: blobSizeCutoff} 23 for r := range revs.Results { 24 cmd.Stdin.Write([]byte(r + "\n")) 25 hasNext := scanner.Scan() 26 if err := scanner.Err(); err != nil { 27 errCh <- err 28 } else if b := scanner.LFSBlobOID(); len(b) > 0 { 29 smallRevCh <- b 30 } else if b := scanner.GitBlobOID(); len(b) > 0 { 31 if name, ok := lockableSet.Check(b); ok { 32 lockableCh <- name 33 } 34 } 35 36 if !hasNext { 37 break 38 } 39 } 40 41 if err := revs.Wait(); err != nil { 42 errCh <- err 43 } 44 cmd.Stdin.Close() 45 46 stderr, _ := ioutil.ReadAll(cmd.Stderr) 47 err := cmd.Wait() 48 if err != nil { 49 errCh <- fmt.Errorf("Error in git cat-file --batch-check: %v %v", err, string(stderr)) 50 } 51 close(smallRevCh) 52 close(errCh) 53 }() 54 55 return nil 56 } 57 58 type catFileBatchCheckScanner struct { 59 s *bufio.Scanner 60 limit int 61 lfsBlobOID string 62 gitBlobOID string 63 } 64 65 func (s *catFileBatchCheckScanner) LFSBlobOID() string { 66 return s.lfsBlobOID 67 } 68 69 func (s *catFileBatchCheckScanner) GitBlobOID() string { 70 return s.gitBlobOID 71 } 72 73 func (s *catFileBatchCheckScanner) Err() error { 74 return s.s.Err() 75 } 76 77 func (s *catFileBatchCheckScanner) Scan() bool { 78 lfsBlobSha, gitBlobSha, hasNext := s.next() 79 s.lfsBlobOID = lfsBlobSha 80 s.gitBlobOID = gitBlobSha 81 return hasNext 82 } 83 84 func (s *catFileBatchCheckScanner) next() (string, string, bool) { 85 hasNext := s.s.Scan() 86 line := s.s.Text() 87 lineLen := len(line) 88 89 // Format is: 90 // <sha1> <type> <size> 91 // type is at a fixed spot, if we see that it's "blob", we can avoid 92 // splitting the line just to get the size. 93 if lineLen < 46 { 94 return "", "", hasNext 95 } 96 97 if line[41:45] != "blob" { 98 return "", "", hasNext 99 } 100 101 size, err := strconv.Atoi(line[46:lineLen]) 102 if err != nil { 103 return "", "", hasNext 104 } 105 106 blobSha := line[0:40] 107 if size >= s.limit { 108 return "", blobSha, hasNext 109 } 110 111 return blobSha, "", hasNext 112 }