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

     1  // Package semerrgroup wraps an 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/goreleaser/goreleaser/internal/pipe"
     9  	"github.com/hashicorp/go-multierror"
    10  	"golang.org/x/sync/errgroup"
    11  )
    12  
    13  // Group is the Semaphore ErrorGroup itself.
    14  type Group interface {
    15  	Go(func() error)
    16  	Wait() error
    17  }
    18  
    19  // New returns a new Group of a given size.
    20  func New(size int) Group {
    21  	var g errgroup.Group
    22  	g.SetLimit(size)
    23  	return &g
    24  }
    25  
    26  var _ Group = &skipAwareGroup{}
    27  
    28  // NewSkipAware returns a new Group of a given size and aware of pipe skips.
    29  func NewSkipAware(g Group) Group {
    30  	return &skipAwareGroup{g: g}
    31  }
    32  
    33  type skipAwareGroup struct {
    34  	g       Group
    35  	skipErr *multierror.Error
    36  	l       sync.Mutex
    37  }
    38  
    39  // Go execs runs `fn` and saves the result if no error has been encountered.
    40  func (s *skipAwareGroup) Go(fn func() error) {
    41  	s.g.Go(func() error {
    42  		err := fn()
    43  		// if the err is a skip, set it for later, but return nil for now so the
    44  		// group proceeds.
    45  		if pipe.IsSkip(err) {
    46  			s.l.Lock()
    47  			defer s.l.Unlock()
    48  			s.skipErr = multierror.Append(s.skipErr, err)
    49  			return nil
    50  		}
    51  		return err
    52  	})
    53  }
    54  
    55  // Wait waits for Go to complete and returns the first error encountered.
    56  func (s *skipAwareGroup) Wait() error {
    57  	// if we got a "real error", return it, otherwise return skipErr or nil.
    58  	if err := s.g.Wait(); err != nil {
    59  		return err
    60  	}
    61  	if s.skipErr == nil {
    62  		return nil
    63  	}
    64  
    65  	if s.skipErr.Len() == 1 {
    66  		return s.skipErr.Errors[0]
    67  	}
    68  
    69  	return s.skipErr
    70  }