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