github.com/git-lfs/git-lfs@v2.5.2+incompatible/lfs/gitscanner_refs.go (about)

     1  package lfs
     2  
     3  import (
     4  	"encoding/hex"
     5  	"regexp"
     6  
     7  	"github.com/git-lfs/git-lfs/git"
     8  )
     9  
    10  var z40 = regexp.MustCompile(`\^?0{40}`)
    11  
    12  type lockableNameSet struct {
    13  	opt *ScanRefsOptions
    14  	set GitScannerSet
    15  }
    16  
    17  // Determines if the given blob sha matches a locked file.
    18  func (s *lockableNameSet) Check(blobSha string) (string, bool) {
    19  	if s == nil || s.opt == nil || s.set == nil {
    20  		return "", false
    21  	}
    22  
    23  	name, ok := s.opt.GetName(blobSha)
    24  	if !ok {
    25  		return name, ok
    26  	}
    27  
    28  	if s.set.Contains(name) {
    29  		return name, true
    30  	}
    31  	return name, false
    32  }
    33  
    34  func noopFoundLockable(name string) {}
    35  
    36  // scanRefsToChan scans through all commits reachable by refs contained in
    37  // "include" and not reachable by any refs included in "excluded" and returns
    38  // a channel of WrappedPointer objects for all Git LFS pointers it finds.
    39  // Reports unique oids once only, not multiple times if >1 file uses the same content
    40  func scanRefsToChan(scanner *GitScanner, pointerCb GitScannerFoundPointer, include, exclude []string, opt *ScanRefsOptions) error {
    41  	if opt == nil {
    42  		panic("no scan ref options")
    43  	}
    44  
    45  	revs, err := revListShas(include, exclude, opt)
    46  	if err != nil {
    47  		return err
    48  	}
    49  
    50  	lockableSet := &lockableNameSet{opt: opt, set: scanner.PotentialLockables}
    51  	smallShas, batchLockableCh, err := catFileBatchCheck(revs, lockableSet)
    52  	if err != nil {
    53  		return err
    54  	}
    55  
    56  	lockableCb := scanner.FoundLockable
    57  	if lockableCb == nil {
    58  		lockableCb = noopFoundLockable
    59  	}
    60  
    61  	go func(cb GitScannerFoundLockable, ch chan string) {
    62  		for name := range ch {
    63  			cb(name)
    64  		}
    65  	}(lockableCb, batchLockableCh)
    66  
    67  	pointers, checkLockableCh, err := catFileBatch(smallShas, lockableSet)
    68  	if err != nil {
    69  		return err
    70  	}
    71  
    72  	for p := range pointers.Results {
    73  		if name, ok := opt.GetName(p.Sha1); ok {
    74  			p.Name = name
    75  		}
    76  
    77  		if scanner.Filter.Allows(p.Name) {
    78  			pointerCb(p, nil)
    79  		}
    80  	}
    81  
    82  	for lockableName := range checkLockableCh {
    83  		if scanner.Filter.Allows(lockableName) {
    84  			lockableCb(lockableName)
    85  		}
    86  	}
    87  
    88  	if err := pointers.Wait(); err != nil {
    89  		pointerCb(nil, err)
    90  	}
    91  
    92  	return nil
    93  }
    94  
    95  // scanLeftRightToChan takes a ref and returns a channel of WrappedPointer objects
    96  // for all Git LFS pointers it finds for that ref.
    97  // Reports unique oids once only, not multiple times if >1 file uses the same content
    98  func scanLeftRightToChan(scanner *GitScanner, pointerCb GitScannerFoundPointer, refLeft, refRight string, opt *ScanRefsOptions) error {
    99  	return scanRefsToChan(scanner, pointerCb, []string{refLeft, refRight}, nil, opt)
   100  }
   101  
   102  // revListShas uses git rev-list to return the list of object sha1s
   103  // for the given ref. If all is true, ref is ignored. It returns a
   104  // channel from which sha1 strings can be read.
   105  func revListShas(include, exclude []string, opt *ScanRefsOptions) (*StringChannelWrapper, error) {
   106  	scanner, err := git.NewRevListScanner(include, exclude, &git.ScanRefsOptions{
   107  		Mode:             git.ScanningMode(opt.ScanMode),
   108  		Remote:           opt.RemoteName,
   109  		SkipDeletedBlobs: opt.SkipDeletedBlobs,
   110  		SkippedRefs:      opt.skippedRefs,
   111  		Mutex:            opt.mutex,
   112  		Names:            opt.nameMap,
   113  	})
   114  
   115  	if err != nil {
   116  		return nil, err
   117  	}
   118  
   119  	revs := make(chan string, chanBufSize)
   120  	errs := make(chan error, 5) // may be multiple errors
   121  
   122  	go func() {
   123  		for scanner.Scan() {
   124  			sha := hex.EncodeToString(scanner.OID())
   125  			if name := scanner.Name(); len(name) > 0 {
   126  				opt.SetName(sha, name)
   127  			}
   128  			revs <- sha
   129  		}
   130  
   131  		if err = scanner.Err(); err != nil {
   132  			errs <- err
   133  		}
   134  
   135  		if err = scanner.Close(); err != nil {
   136  			errs <- err
   137  		}
   138  
   139  		close(revs)
   140  		close(errs)
   141  	}()
   142  
   143  	return NewStringChannelWrapper(revs, errs), nil
   144  }