github.com/telepresenceio/telepresence/v2@v2.20.0-pro.6.0.20240517030216-236ea954e789/pkg/errcat/errors.go (about) 1 package errcat 2 3 import ( 4 "errors" 5 "fmt" 6 7 "github.com/telepresenceio/telepresence/rpc/v2/common" 8 ) 9 10 // The Category is used for categorizing errors so that we can know when 11 // to point the user to the logs or not. 12 type Category int 13 14 type categorized struct { 15 error 16 category Category 17 } 18 19 const ( 20 OK = Category(iota) 21 User // User made an error 22 Config // Errors in config.yml, extensions, or kubeconfig 23 NoDaemonLogs // Other error generated in the CLI process, so no use pointing the user to logs 24 Unknown // Something else. Consult the logs 25 ) 26 27 // New creates a new categorized error based in its argument. The argument 28 // can be an error or a string. If it isn't, it will be converted to a string 29 // using its '%v' formatter. 30 func (c Category) New(untypedErr any) error { 31 var err error 32 switch untypedErr := untypedErr.(type) { 33 case nil: 34 return nil 35 case error: 36 err = untypedErr 37 case string: 38 err = errors.New(untypedErr) 39 default: 40 err = fmt.Errorf("%v", untypedErr) 41 } 42 return &categorized{error: err, category: c} 43 } 44 45 // Newf creates a new categorized error based on a format string with arguments. The 46 // error is created using fmt.Errorf() so using '%w' is relevant for error arguments. 47 func (c Category) Newf(format string, a ...any) error { 48 return &categorized{error: fmt.Errorf(format, a...), category: c} 49 } 50 51 // Unwrap this categorized error. 52 func (ce *categorized) Unwrap() error { 53 return ce.error 54 } 55 56 // GetCategory returns the error category for a categorized error, OK for nil, and 57 // Unknown for other errors. 58 func GetCategory(err error) Category { 59 if err == nil { 60 return OK 61 } 62 // Keep unwrapping until a category is found (or not) 63 for { 64 if ce, ok := err.(*categorized); ok { 65 return ce.category 66 } 67 if err = errors.Unwrap(err); err == nil { 68 return Unknown 69 } 70 } 71 } 72 73 func FromResult(r *common.Result) error { 74 if r == nil { 75 return nil 76 } 77 c := Category(r.ErrorCategory) 78 if c == OK { 79 return nil 80 } 81 return &categorized{error: errors.New(string(r.Data)), category: c} 82 } 83 84 func ToResult(err error) *common.Result { 85 r := &common.Result{} 86 if err != nil { 87 r.Data = []byte(err.Error()) 88 r.ErrorCategory = common.Result_ErrorCategory(GetCategory(err)) 89 } 90 return r 91 }