2015-04-23 16:20:36 +00:00
|
|
|
package lfs
|
2014-10-03 16:08:00 +00:00
|
|
|
|
2016-11-18 19:02:38 +00:00
|
|
|
import "github.com/git-lfs/git-lfs/tools"
|
2014-10-03 16:08:00 +00:00
|
|
|
|
2014-10-11 14:28:46 +00:00
|
|
|
const (
|
2015-03-19 19:30:55 +00:00
|
|
|
// blobSizeCutoff is used to determine which files to scan for Git LFS
|
|
|
|
// pointers. Any file with a size below this cutoff will be scanned.
|
2015-07-24 04:53:36 +00:00
|
|
|
blobSizeCutoff = 1024
|
2014-10-13 15:07:46 +00:00
|
|
|
|
|
|
|
// stdoutBufSize is the size of the buffers given to a sub-process stdout
|
|
|
|
stdoutBufSize = 16384
|
|
|
|
|
2015-03-19 19:30:55 +00:00
|
|
|
// chanBufSize is the size of the channels used to pass data from one
|
|
|
|
// sub-process to another.
|
2014-10-13 15:07:46 +00:00
|
|
|
chanBufSize = 100
|
2014-10-07 16:33:00 +00:00
|
|
|
)
|
2014-10-07 15:59:59 +00:00
|
|
|
|
2015-05-27 19:45:18 +00:00
|
|
|
// WrappedPointer wraps a pointer.Pointer and provides the git sha1
|
2014-10-11 14:28:46 +00:00
|
|
|
// and the file name associated with the object, taken from the
|
|
|
|
// rev-list output.
|
2015-05-27 19:45:18 +00:00
|
|
|
type WrappedPointer struct {
|
2014-10-27 20:40:21 +00:00
|
|
|
Sha1 string
|
|
|
|
Name string
|
|
|
|
SrcName string
|
|
|
|
Status string
|
2015-04-23 16:20:36 +00:00
|
|
|
*Pointer
|
2014-10-07 17:05:09 +00:00
|
|
|
}
|
|
|
|
|
2014-10-07 16:44:28 +00:00
|
|
|
// catFileBatchCheck 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 blobSizeCutoff will be ignored. revs is a channel over
|
|
|
|
// which strings containing git sha1s will be sent. It returns a channel
|
|
|
|
// from which sha1 strings can be read.
|
2017-02-16 23:52:40 +00:00
|
|
|
func catFileBatchCheck(revs *StringChannelWrapper, lockableSet *lockableNameSet) (*StringChannelWrapper, chan string, error) {
|
2016-11-16 18:50:42 +00:00
|
|
|
smallRevCh := make(chan string, chanBufSize)
|
2017-02-16 23:52:40 +00:00
|
|
|
lockableCh := make(chan string, chanBufSize)
|
2016-11-16 18:50:42 +00:00
|
|
|
errCh := make(chan error, 2) // up to 2 errors, one from each goroutine
|
2017-02-16 23:52:40 +00:00
|
|
|
if err := runCatFileBatchCheck(smallRevCh, lockableCh, lockableSet, revs, errCh); err != nil {
|
|
|
|
return nil, nil, err
|
2014-10-03 16:08:00 +00:00
|
|
|
}
|
2017-02-16 23:52:40 +00:00
|
|
|
return NewStringChannelWrapper(smallRevCh, errCh), lockableCh, nil
|
2014-10-07 15:16:54 +00:00
|
|
|
}
|
|
|
|
|
2014-10-07 16:44:28 +00:00
|
|
|
// catFileBatch uses git cat-file --batch to get the object contents
|
|
|
|
// of a git object, given its sha1. The contents will be decoded into
|
2015-03-19 19:30:55 +00:00
|
|
|
// a Git LFS pointer. revs is a channel over which strings containing Git SHA1s
|
|
|
|
// will be sent. It returns a channel from which point.Pointers can be read.
|
2017-02-16 23:52:40 +00:00
|
|
|
func catFileBatch(revs *StringChannelWrapper, lockableSet *lockableNameSet) (*PointerChannelWrapper, chan string, error) {
|
2016-11-16 18:50:42 +00:00
|
|
|
pointerCh := make(chan *WrappedPointer, chanBufSize)
|
2017-02-16 23:52:40 +00:00
|
|
|
lockableCh := make(chan string, chanBufSize)
|
2016-11-16 18:50:42 +00:00
|
|
|
errCh := make(chan error, 5) // shared by 2 goroutines & may add more detail errors?
|
2017-02-16 23:52:40 +00:00
|
|
|
if err := runCatFileBatch(pointerCh, lockableCh, lockableSet, revs, errCh); err != nil {
|
|
|
|
return nil, nil, err
|
2016-11-14 18:56:06 +00:00
|
|
|
}
|
2017-02-16 23:52:40 +00:00
|
|
|
return NewPointerChannelWrapper(pointerCh, errCh), lockableCh, nil
|
2014-10-03 16:08:00 +00:00
|
|
|
}
|
2014-10-07 15:59:59 +00:00
|
|
|
|
2016-03-31 11:00:44 +00:00
|
|
|
// ChannelWrapper for pointer Scan* functions to more easily return async error data via Wait()
|
|
|
|
// See NewPointerChannelWrapper for construction / use
|
|
|
|
type PointerChannelWrapper struct {
|
2016-11-18 19:02:38 +00:00
|
|
|
*tools.BaseChannelWrapper
|
2016-03-31 11:00:44 +00:00
|
|
|
Results <-chan *WrappedPointer
|
|
|
|
}
|
|
|
|
|
|
|
|
// Construct a new channel wrapper for WrappedPointer
|
2016-03-31 11:04:59 +00:00
|
|
|
// Caller can use s.Results directly for normal processing then call Wait() to finish & check for errors
|
2016-03-31 11:00:44 +00:00
|
|
|
// Scan function is required to create error channel large enough not to block (usually 1 is ok)
|
|
|
|
func NewPointerChannelWrapper(pointerChan <-chan *WrappedPointer, errorChan <-chan error) *PointerChannelWrapper {
|
2016-11-18 19:02:38 +00:00
|
|
|
return &PointerChannelWrapper{tools.NewBaseChannelWrapper(errorChan), pointerChan}
|
2016-03-31 11:00:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ChannelWrapper for string channel functions to more easily return async error data via Wait()
|
2016-03-31 11:04:59 +00:00
|
|
|
// Caller can use s.Results directly for normal processing then call Wait() to finish & check for errors
|
2016-03-31 11:00:44 +00:00
|
|
|
// See NewStringChannelWrapper for construction / use
|
|
|
|
type StringChannelWrapper struct {
|
2016-11-18 19:02:38 +00:00
|
|
|
*tools.BaseChannelWrapper
|
2016-03-31 11:00:44 +00:00
|
|
|
Results <-chan string
|
|
|
|
}
|
|
|
|
|
|
|
|
// Construct a new channel wrapper for string
|
2016-03-31 11:04:59 +00:00
|
|
|
// Caller can use s.Results directly for normal processing then call Wait() to finish & check for errors
|
2016-03-31 11:00:44 +00:00
|
|
|
func NewStringChannelWrapper(stringChan <-chan string, errorChan <-chan error) *StringChannelWrapper {
|
2016-11-18 19:02:38 +00:00
|
|
|
return &StringChannelWrapper{tools.NewBaseChannelWrapper(errorChan), stringChan}
|
2016-03-31 11:00:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ChannelWrapper for TreeBlob channel functions to more easily return async error data via Wait()
|
|
|
|
// See NewTreeBlobChannelWrapper for construction / use
|
|
|
|
type TreeBlobChannelWrapper struct {
|
2016-11-18 19:02:38 +00:00
|
|
|
*tools.BaseChannelWrapper
|
2016-03-31 11:00:44 +00:00
|
|
|
Results <-chan TreeBlob
|
|
|
|
}
|
2015-08-03 15:58:34 +00:00
|
|
|
|
2016-03-31 11:00:44 +00:00
|
|
|
// Construct a new channel wrapper for TreeBlob
|
2016-03-31 11:04:59 +00:00
|
|
|
// Caller can use s.Results directly for normal processing then call Wait() to finish & check for errors
|
2016-03-31 11:00:44 +00:00
|
|
|
func NewTreeBlobChannelWrapper(treeBlobChan <-chan TreeBlob, errorChan <-chan error) *TreeBlobChannelWrapper {
|
2016-11-18 19:02:38 +00:00
|
|
|
return &TreeBlobChannelWrapper{tools.NewBaseChannelWrapper(errorChan), treeBlobChan}
|
2015-08-03 15:58:34 +00:00
|
|
|
}
|