code.vegaprotocol.io/vega@v0.79.0/libs/errors/errors.go (about) 1 // Copyright (C) 2023 Gobalsky Labs Limited 2 // 3 // This program is free software: you can redistribute it and/or modify 4 // it under the terms of the GNU Affero General Public License as 5 // published by the Free Software Foundation, either version 3 of the 6 // License, or (at your option) any later version. 7 // 8 // This program is distributed in the hope that it will be useful, 9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 // GNU Affero General Public License for more details. 12 // 13 // You should have received a copy of the GNU Affero General Public License 14 // along with this program. If not, see <http://www.gnu.org/licenses/>. 15 16 package errors 17 18 import ( 19 "fmt" 20 "strings" 21 ) 22 23 var ( 24 errSelfReference = fmt.Errorf("<self reference>") 25 errParentReference = fmt.Errorf("<parent reference>") 26 ) 27 28 type CumulatedErrors struct { 29 Errors []error 30 } 31 32 func NewCumulatedErrors() *CumulatedErrors { 33 return &CumulatedErrors{} 34 } 35 36 func (e *CumulatedErrors) Add(err error) { 37 // prevent adding this instance of cumulatedErrors to itself. 38 if err == e { 39 err = errSelfReference 40 } else if cerr, ok := err.(*CumulatedErrors); ok { 41 // nothing to add. 42 if !cerr.HasAny() { 43 return 44 } 45 // create a copy of the error we're adding 46 cpy := &CumulatedErrors{ 47 Errors: append([]error{}, cerr.Errors...), 48 } 49 // remove any references to the parent from the error we're adding. 50 err = cpy.checkRef(e, errParentReference) 51 } 52 e.Errors = append(e.Errors, err) 53 } 54 55 // check recursively if a cumulated errors object contains a certain reference, and if so, replace with a placehold, simple error. 56 // returns either itself (with the replaced references), or a replacement error. 57 func (e *CumulatedErrors) checkRef(ref *CumulatedErrors, repl error) error { 58 if e == ref { 59 return repl 60 } 61 // recursively remove a given reference. 62 for i, subE := range e.Errors { 63 if subE == ref { 64 e.Errors[i] = repl 65 } else if cErr, ok := subE.(*CumulatedErrors); ok { 66 e.Errors[i] = cErr.checkRef(ref, repl) 67 } 68 } 69 return e 70 } 71 72 func (e *CumulatedErrors) HasAny() bool { 73 return len(e.Errors) > 0 74 } 75 76 func (e *CumulatedErrors) Error() string { 77 fmtErrors := make([]string, 0, len(e.Errors)) 78 for _, err := range e.Errors { 79 fmtErrors = append(fmtErrors, err.Error()) 80 } 81 82 return strings.Join(fmtErrors, ", also ") 83 }