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 }