github.com/caos/orbos@v1.5.14-0.20221103111702-e6cd0cea7ad4/internal/helpers/errors.go (about) 1 package helpers 2 3 import ( 4 "errors" 5 "fmt" 6 "sync" 7 8 "github.com/caos/orbos/mntr" 9 ) 10 11 func Concat(left error, right error) error { 12 if left == nil { 13 return right 14 } 15 16 if right == nil { 17 return left 18 } 19 20 newErr := fmt.Errorf("%s: %s", right.Error(), left.Error()) 21 if errors.As(left, &mntr.UserError{}) && errors.As(right, &mntr.UserError{}) { 22 newErr = mntr.UserError{Err: newErr} 23 } 24 25 return newErr 26 } 27 28 // Synchronizer implements the error interface as well as 29 // the Causer interface from package github.com/pkg/errors 30 // It just returns the first error when Cause is called 31 // 32 // It is well suited for scatter and gather synchronization 33 type Synchronizer struct { 34 errors []error 35 wg *sync.WaitGroup 36 sync.RWMutex 37 } 38 39 func (s *Synchronizer) Cause() error { 40 return s.errors[0] 41 } 42 43 func NewSynchronizer(wg *sync.WaitGroup) *Synchronizer { 44 return &Synchronizer{errors: make([]error, 0), wg: wg} 45 } 46 47 func (s *Synchronizer) IsError() bool { 48 s.Lock() 49 defer s.Unlock() 50 return len(s.errors) > 0 51 } 52 53 func (s *Synchronizer) Done(err error) { 54 defer s.wg.Done() 55 s.Lock() 56 defer s.Unlock() 57 if err == nil { 58 return 59 } 60 s.errors = append(s.errors, err) 61 } 62 63 func (s Synchronizer) Error() string { 64 built := "" 65 for _, err := range s.errors { 66 built = built + ", " + err.Error() 67 } 68 if len(built) >= 2 { 69 built = built[2:] 70 } 71 return built 72 }