2016-11-14 18:56:06 +00:00
|
|
|
package lfs
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
2017-03-22 21:15:54 +00:00
|
|
|
"crypto/sha256"
|
2016-11-14 18:56:06 +00:00
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
|
2017-04-04 20:14:19 +00:00
|
|
|
"github.com/git-lfs/git-lfs/git"
|
2016-11-14 18:56:06 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// runCatFileBatch uses 'git cat-file --batch' to get the object contents of a
|
|
|
|
// git object, given its sha1. The contents will be decoded into a Git LFS
|
|
|
|
// pointer. Git Blob SHA1s are read from the sha1Ch channel and fed to STDIN.
|
2017-02-16 23:52:40 +00:00
|
|
|
// Results are parsed from STDOUT, and any eligible LFS pointers are sent to
|
|
|
|
// pointerCh. If a Git Blob is not an LFS pointer, check the lockableSet to see
|
|
|
|
// if that blob is for a locked file. Any errors are sent to errCh. An error is
|
|
|
|
// returned if the 'git cat-file' command fails to start.
|
|
|
|
func runCatFileBatch(pointerCh chan *WrappedPointer, lockableCh chan string, lockableSet *lockableNameSet, revs *StringChannelWrapper, errCh chan error) error {
|
2017-04-04 20:35:03 +00:00
|
|
|
scanner, err := NewPointerScanner()
|
2016-11-14 18:56:06 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2016-11-18 22:35:51 +00:00
|
|
|
go func() {
|
2019-01-03 20:10:04 +00:00
|
|
|
canScan := true
|
2016-11-18 22:35:51 +00:00
|
|
|
for r := range revs.Results {
|
2019-01-03 20:10:04 +00:00
|
|
|
canScan = scanner.Scan(r)
|
2016-11-18 22:35:51 +00:00
|
|
|
|
2016-11-19 00:00:57 +00:00
|
|
|
if err := scanner.Err(); err != nil {
|
2016-11-18 22:35:51 +00:00
|
|
|
errCh <- err
|
2017-02-16 23:52:40 +00:00
|
|
|
} else if p := scanner.Pointer(); p != nil {
|
|
|
|
pointerCh <- p
|
|
|
|
} else if b := scanner.BlobSHA(); len(b) == 40 {
|
|
|
|
if name, ok := lockableSet.Check(b); ok {
|
|
|
|
lockableCh <- name
|
|
|
|
}
|
2016-11-18 22:35:51 +00:00
|
|
|
}
|
2016-11-14 18:56:06 +00:00
|
|
|
|
2016-11-21 16:20:18 +00:00
|
|
|
if !canScan {
|
2016-11-18 22:35:51 +00:00
|
|
|
break
|
|
|
|
}
|
2016-11-18 22:26:29 +00:00
|
|
|
}
|
|
|
|
|
2019-01-03 20:10:04 +00:00
|
|
|
if canScan {
|
|
|
|
if err := revs.Wait(); err != nil {
|
|
|
|
errCh <- err
|
|
|
|
}
|
2016-11-18 22:26:29 +00:00
|
|
|
}
|
|
|
|
|
2017-03-22 21:15:02 +00:00
|
|
|
if err := scanner.Close(); err != nil {
|
|
|
|
errCh <- err
|
2016-11-18 22:35:51 +00:00
|
|
|
}
|
2016-11-15 22:15:37 +00:00
|
|
|
|
2016-11-18 22:35:51 +00:00
|
|
|
close(pointerCh)
|
|
|
|
close(errCh)
|
2017-02-16 23:52:40 +00:00
|
|
|
close(lockableCh)
|
2016-11-18 22:35:51 +00:00
|
|
|
}()
|
2016-11-15 22:15:37 +00:00
|
|
|
|
2016-11-18 22:35:51 +00:00
|
|
|
return nil
|
2016-11-15 22:15:37 +00:00
|
|
|
}
|
|
|
|
|
2017-04-04 20:35:03 +00:00
|
|
|
type PointerScanner struct {
|
2017-04-04 20:14:19 +00:00
|
|
|
scanner *git.ObjectScanner
|
2017-03-22 21:15:02 +00:00
|
|
|
|
2017-03-22 21:15:54 +00:00
|
|
|
blobSha string
|
|
|
|
contentsSha string
|
|
|
|
pointer *WrappedPointer
|
|
|
|
err error
|
2016-11-15 22:14:52 +00:00
|
|
|
}
|
|
|
|
|
2017-04-04 20:35:03 +00:00
|
|
|
func NewPointerScanner() (*PointerScanner, error) {
|
2017-04-04 20:14:19 +00:00
|
|
|
scanner, err := git.NewObjectScanner()
|
2017-03-22 21:15:02 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2017-04-04 20:35:03 +00:00
|
|
|
return &PointerScanner{scanner: scanner}, nil
|
2017-03-22 21:15:02 +00:00
|
|
|
}
|
|
|
|
|
2017-04-04 20:35:03 +00:00
|
|
|
func (s *PointerScanner) BlobSHA() string {
|
2017-02-16 23:52:40 +00:00
|
|
|
return s.blobSha
|
|
|
|
}
|
|
|
|
|
2017-04-04 20:35:03 +00:00
|
|
|
func (s *PointerScanner) ContentsSha() string {
|
2017-03-22 21:15:54 +00:00
|
|
|
return s.contentsSha
|
|
|
|
}
|
|
|
|
|
2017-04-04 20:35:03 +00:00
|
|
|
func (s *PointerScanner) Pointer() *WrappedPointer {
|
2016-11-19 00:00:57 +00:00
|
|
|
return s.pointer
|
|
|
|
}
|
|
|
|
|
2017-04-04 20:35:03 +00:00
|
|
|
func (s *PointerScanner) Err() error {
|
2016-11-19 00:00:57 +00:00
|
|
|
return s.err
|
|
|
|
}
|
|
|
|
|
2017-04-04 20:35:03 +00:00
|
|
|
func (s *PointerScanner) Scan(sha string) bool {
|
2016-11-19 00:00:57 +00:00
|
|
|
s.pointer, s.err = nil, nil
|
2017-03-22 21:15:54 +00:00
|
|
|
s.blobSha, s.contentsSha = "", ""
|
2017-03-22 21:15:02 +00:00
|
|
|
|
2017-04-04 20:14:19 +00:00
|
|
|
b, c, p, err := s.next(sha)
|
2017-02-16 23:52:40 +00:00
|
|
|
s.blobSha = b
|
2017-03-22 21:15:54 +00:00
|
|
|
s.contentsSha = c
|
2016-11-19 00:00:57 +00:00
|
|
|
s.pointer = p
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
if err != io.EOF {
|
|
|
|
s.err = err
|
|
|
|
}
|
|
|
|
return false
|
2016-11-15 22:14:52 +00:00
|
|
|
}
|
2016-11-19 00:00:57 +00:00
|
|
|
|
|
|
|
return true
|
2016-11-15 22:14:52 +00:00
|
|
|
}
|
|
|
|
|
2017-04-04 20:35:03 +00:00
|
|
|
func (s *PointerScanner) Close() error {
|
2017-04-04 20:14:19 +00:00
|
|
|
return s.scanner.Close()
|
2017-03-22 21:15:02 +00:00
|
|
|
}
|
|
|
|
|
2017-04-04 20:35:03 +00:00
|
|
|
func (s *PointerScanner) next(blob string) (string, string, *WrappedPointer, error) {
|
2017-04-04 20:14:19 +00:00
|
|
|
if !s.scanner.Scan(blob) {
|
|
|
|
if err := s.scanner.Err(); err != nil {
|
|
|
|
return "", "", nil, err
|
|
|
|
}
|
|
|
|
return "", "", nil, io.EOF
|
2016-11-18 21:20:51 +00:00
|
|
|
}
|
2016-11-15 22:14:52 +00:00
|
|
|
|
2017-04-04 20:14:19 +00:00
|
|
|
blobSha := s.scanner.Sha1()
|
|
|
|
size := s.scanner.Size()
|
2016-11-14 18:56:06 +00:00
|
|
|
|
2017-03-22 21:15:54 +00:00
|
|
|
sha := sha256.New()
|
2017-03-23 17:55:40 +00:00
|
|
|
|
|
|
|
var buf *bytes.Buffer
|
|
|
|
var to io.Writer = sha
|
|
|
|
if size <= blobSizeCutoff {
|
|
|
|
buf = bytes.NewBuffer(make([]byte, 0, size))
|
|
|
|
to = io.MultiWriter(to, buf)
|
|
|
|
}
|
|
|
|
|
2017-04-04 20:14:19 +00:00
|
|
|
read, err := io.CopyN(to, s.scanner.Contents(), int64(size))
|
2016-11-18 21:20:51 +00:00
|
|
|
if err != nil {
|
2017-03-22 21:15:54 +00:00
|
|
|
return blobSha, "", nil, err
|
2016-11-18 21:20:51 +00:00
|
|
|
}
|
2016-11-14 18:56:06 +00:00
|
|
|
|
2017-03-23 17:55:40 +00:00
|
|
|
if int64(size) != read {
|
2017-03-22 21:15:54 +00:00
|
|
|
return blobSha, "", nil, fmt.Errorf("expected %d bytes, read %d bytes", size, read)
|
2016-11-18 21:20:51 +00:00
|
|
|
}
|
2016-11-18 16:09:52 +00:00
|
|
|
|
2016-11-18 21:20:51 +00:00
|
|
|
var pointer *WrappedPointer
|
2017-03-22 21:15:54 +00:00
|
|
|
var contentsSha string
|
2017-03-23 17:55:40 +00:00
|
|
|
|
|
|
|
if size <= blobSizeCutoff {
|
|
|
|
if p, err := DecodePointer(bytes.NewReader(buf.Bytes())); err != nil {
|
|
|
|
contentsSha = fmt.Sprintf("%x", sha.Sum(nil))
|
|
|
|
} else {
|
|
|
|
pointer = &WrappedPointer{
|
|
|
|
Sha1: blobSha,
|
|
|
|
Pointer: p,
|
|
|
|
}
|
|
|
|
contentsSha = p.Oid
|
2016-11-18 16:09:52 +00:00
|
|
|
}
|
2017-03-22 21:15:54 +00:00
|
|
|
} else {
|
|
|
|
contentsSha = fmt.Sprintf("%x", sha.Sum(nil))
|
2016-11-18 21:20:51 +00:00
|
|
|
}
|
2016-11-18 16:09:52 +00:00
|
|
|
|
2017-03-22 21:15:54 +00:00
|
|
|
return blobSha, contentsSha, pointer, err
|
2016-11-18 21:20:51 +00:00
|
|
|
}
|