github.com/triarius/goreleaser@v1.12.5/internal/semerrgroup/sem.go (about)

     1  // Package semerrgroup wraps a error group with a semaphore with configurable
     2  // size, so you can control the number of tasks being executed simultaneously.
     3  package semerrgroup
     4  
     5  import (
     6  	"sync"
     7  
     8  	"github.com/triarius/goreleaser/internal/pipe"
     9  	"golang.org/x/sync/errgroup"
    10  )
    11  
    12  // Group is the Semphore ErrorGroup itself.
    13  type Group interface {
    14  	Go(func() error)
    15  	Wait() error
    16  }
    17  
    18  // New returns a new Group of a given size.
    19  func New(size int) Group {
    20  	var g errgroup.Group
    21  	g.SetLimit(size)
    22  	return &g
    23  }
    24  
    25  var _ Group = &skipAwareGroup{}
    26  
    27  // NewSkipAware returns a new Group of a given size and aware of pipe skips.
    28  func NewSkipAware(g Group) Group {
    29  	return &skipAwareGroup{g: g}
    30  }
    31  
    32  type skipAwareGroup struct {
    33  	g        Group
    34  	skipErr  error
    35  	skipOnce sync.Once
    36  }
    37  
    38  // Go execs runs `fn` and saves the result if no error has been encountered.
    39  func (s *skipAwareGroup) Go(fn func() error) {
    40  	s.g.Go(func() error {
    41  		err := fn()
    42  		// if the err is a skip, set it for later, but return nil for now so the
    43  		// group proceeds.
    44  		if pipe.IsSkip(err) {
    45  			s.skipOnce.Do(func() {
    46  				s.skipErr = err
    47  			})
    48  			return nil
    49  		}
    50  		return err
    51  	})
    52  }
    53  
    54  // Wait waits for Go to complete and returns the first error encountered.
    55  func (s *skipAwareGroup) Wait() error {
    56  	// if we got a "real error", return it, otherwise return skipErr or nil.
    57  	if err := s.g.Wait(); err != nil {
    58  		return err
    59  	}
    60  	return s.skipErr
    61  }