package lfs
import (
"errors"
"time"
"github.com/git-lfs/git-lfs/v3/config"
"github.com/git-lfs/git-lfs/v3/filepathfilter"
"github.com/git-lfs/git-lfs/v3/tr"
"github.com/rubyist/tracerx"
)
var missingCallbackErr = errors.New(tr.Tr.Get("no callback given"))
func IsCallbackMissing(err error) bool {
return err == missingCallbackErr
}
type GitScanner struct {
Filter *filepathfilter.Filter
cfg *config.Configuration
mode ScanningMode
skipDeletedBlobs bool
commitsOnly bool
foundPointer GitScannerFoundPointer
remote string
skippedRefs []string
foundLockable GitScannerFoundLockable
potentialLockables GitScannerSet
}
type GitScannerFoundPointer func(*WrappedPointer, error)
type GitScannerFoundLockable func(filename string)
type GitScannerSet interface {
Contains(string) bool
}
type ScanningMode int
const (
ScanRefsMode = ScanningMode(iota)
ScanAllMode = ScanningMode(iota)
ScanRangeToRemoteMode = ScanningMode(iota)
)
func NewGitScanner(cfg *config.Configuration, cb GitScannerFoundPointer) *GitScanner {
return &GitScanner{cfg: cfg, foundPointer: cb}
}
func NewGitScannerForPush(cfg *config.Configuration, remote string, cb GitScannerFoundLockable, potentialLockables GitScannerSet) *GitScanner {
return &GitScanner{
cfg: cfg,
remote: remote,
skippedRefs: calcSkippedRefs(remote),
foundLockable: cb,
potentialLockables: potentialLockables,
}
}
func (s *GitScanner) ScanMultiRangeToRemote(include string, exclude []string, cb GitScannerFoundPointer) error {
callback, err := firstGitScannerCallback(cb, s.foundPointer)
if err != nil {
return err
}
if len(s.remote) == 0 {
return errors.New(tr.Tr.Get("unable to scan starting at %q: no remote set", include))
}
s.mode = ScanRangeToRemoteMode
start := time.Now()
err = scanRefsToChanSingleIncludeMultiExclude(s, callback, include, exclude, s.cfg.GitEnv(), s.cfg.OSEnv())
tracerx.PerformanceSince("ScanMultiRangeToRemote", start)
return err
}
func (s *GitScanner) ScanRefs(include, exclude []string, cb GitScannerFoundPointer) error {
callback, err := firstGitScannerCallback(cb, s.foundPointer)
if err != nil {
return err
}
start := time.Now()
err = scanRefsToChan(s, callback, include, exclude, s.cfg.GitEnv(), s.cfg.OSEnv())
tracerx.PerformanceSince("ScanRefs", start)
return err
}
func (s *GitScanner) ScanRefRange(include, exclude string, cb GitScannerFoundPointer) error {
callback, err := firstGitScannerCallback(cb, s.foundPointer)
if err != nil {
return err
}
start := time.Now()
err = scanRefsToChanSingleIncludeExclude(s, callback, include, exclude, s.cfg.GitEnv(), s.cfg.OSEnv())
tracerx.PerformanceSince("ScanRefRange", start)
return err
}
func (s *GitScanner) ScanRefRangeByTree(include, exclude string, cb GitScannerFoundPointer) error {
callback, err := firstGitScannerCallback(cb, s.foundPointer)
if err != nil {
return err
}
s.commitsOnly = true
start := time.Now()
err = scanRefsByTree(s, callback, []string{include}, []string{exclude}, s.cfg.GitEnv(), s.cfg.OSEnv())
tracerx.PerformanceSince("ScanRefRangeByTree", start)
return err
}
func (s *GitScanner) ScanRefWithDeleted(ref string, cb GitScannerFoundPointer) error {
return s.ScanRefRange(ref, "", cb)
}
func (s *GitScanner) ScanRef(ref string, cb GitScannerFoundPointer) error {
callback, err := firstGitScannerCallback(cb, s.foundPointer)
if err != nil {
return err
}
s.skipDeletedBlobs = true
start := time.Now()
err = scanRefsToChanSingleIncludeExclude(s, callback, ref, "", s.cfg.GitEnv(), s.cfg.OSEnv())
tracerx.PerformanceSince("ScanRef", start)
return err
}
func (s *GitScanner) ScanRefByTree(ref string, cb GitScannerFoundPointer) error {
callback, err := firstGitScannerCallback(cb, s.foundPointer)
if err != nil {
return err
}
s.skipDeletedBlobs = true
s.commitsOnly = true
start := time.Now()
err = scanRefsByTree(s, callback, []string{ref}, []string{}, s.cfg.GitEnv(), s.cfg.OSEnv())
tracerx.PerformanceSince("ScanRefByTree", start)
return err
}
func (s *GitScanner) ScanAll(cb GitScannerFoundPointer) error {
callback, err := firstGitScannerCallback(cb, s.foundPointer)
if err != nil {
return err
}
s.mode = ScanAllMode
start := time.Now()
err = scanRefsToChanSingleIncludeExclude(s, callback, "", "", s.cfg.GitEnv(), s.cfg.OSEnv())
tracerx.PerformanceSince("ScanAll", start)
return err
}
func (s *GitScanner) ScanTree(ref string, cb GitScannerFoundPointer) error {
callback, err := firstGitScannerCallback(cb, s.foundPointer)
if err != nil {
return err
}
start := time.Now()
err = runScanTree(callback, ref, s.Filter, s.cfg.GitEnv(), s.cfg.OSEnv())
tracerx.PerformanceSince("ScanTree", start)
return err
}
func (s *GitScanner) ScanLFSFiles(ref string, cb GitScannerFoundPointer) error {
callback, err := firstGitScannerCallback(cb, s.foundPointer)
if err != nil {
return err
}
start := time.Now()
err = runScanLFSFiles(callback, ref, s.Filter, s.cfg.GitEnv(), s.cfg.OSEnv())
tracerx.PerformanceSince("ScanLFSFiles", start)
return err
}
func (s *GitScanner) ScanUnpushed(remote string, cb GitScannerFoundPointer) error {
callback, err := firstGitScannerCallback(cb, s.foundPointer)
if err != nil {
return err
}
start := time.Now()
err = scanUnpushed(callback, remote)
tracerx.PerformanceSince("ScanUnpushed", start)
return err
}
func (s *GitScanner) ScanStashed(cb GitScannerFoundPointer) error {
callback, err := firstGitScannerCallback(cb, s.foundPointer)
if err != nil {
return err
}
start := time.Now()
err = scanStashed(callback)
tracerx.PerformanceSince("ScanStashed", start)
return err
}
func (s *GitScanner) ScanPreviousVersions(ref string, since time.Time, cb GitScannerFoundPointer) error {
callback, err := firstGitScannerCallback(cb, s.foundPointer)
if err != nil {
return err
}
start := time.Now()
err = logPreviousSHAs(callback, ref, s.Filter, since)
tracerx.PerformanceSince("ScanPreviousVersions", start)
return err
}
func (s *GitScanner) ScanIndex(ref string, workingDir string, cb GitScannerFoundPointer) error {
callback, err := firstGitScannerCallback(cb, s.foundPointer)
if err != nil {
return err
}
start := time.Now()
err = scanIndex(callback, ref, workingDir, s.Filter, s.cfg.GitEnv(), s.cfg.OSEnv())
tracerx.PerformanceSince("ScanIndex", start)
return err
}
func firstGitScannerCallback(callbacks ...GitScannerFoundPointer) (GitScannerFoundPointer, error) {
for _, cb := range callbacks {
if cb == nil {
continue
}
return cb, nil
}
return nil, missingCallbackErr
}