github.com/turbot/steampipe@v1.7.0-rc.0.0.20240517123944-7cef272d4458/pkg/error_helpers/utils.go (about) 1 package error_helpers 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "os" 8 "strings" 9 10 "golang.org/x/exp/maps" 11 12 "github.com/fatih/color" 13 "github.com/shiena/ansicolor" 14 "github.com/spf13/viper" 15 "github.com/turbot/steampipe/pkg/constants" 16 "github.com/turbot/steampipe/pkg/statushooks" 17 ) 18 19 func init() { 20 color.Output = ansicolor.NewAnsiColorWriter(os.Stderr) 21 } 22 23 func WrapError(err error) error { 24 if err == nil { 25 return nil 26 } 27 return HandleCancelError(err) 28 } 29 30 func FailOnError(err error) { 31 if err != nil { 32 err = HandleCancelError(err) 33 panic(err) 34 } 35 } 36 37 func FailOnErrorWithMessage(err error, message string) { 38 if err != nil { 39 err = HandleCancelError(err) 40 panic(fmt.Sprintf("%s: %s", message, err.Error())) 41 } 42 } 43 44 func ShowError(ctx context.Context, err error) { 45 if err == nil { 46 return 47 } 48 err = HandleCancelError(err) 49 statushooks.Done(ctx) 50 fmt.Fprintf(color.Error, "%s: %v\n", constants.ColoredErr, TransformErrorToSteampipe(err)) 51 } 52 53 // ShowErrorWithMessage displays the given error nicely with the given message 54 func ShowErrorWithMessage(ctx context.Context, err error, message string) { 55 if err == nil { 56 return 57 } 58 err = HandleCancelError(err) 59 statushooks.Done(ctx) 60 fmt.Fprintf(color.Error, "%s: %s - %v\n", constants.ColoredErr, message, TransformErrorToSteampipe(err)) 61 } 62 63 // TransformErrorToSteampipe removes the pq: and rpc error prefixes along 64 // with all the unnecessary information that comes from the 65 // drivers and libraries 66 func TransformErrorToSteampipe(err error) error { 67 if err == nil { 68 return err 69 } 70 // transform to a context 71 err = HandleCancelError(err) 72 73 errString := strings.TrimSpace(err.Error()) 74 75 // an error that originated from our database/sql driver (always prefixed with "ERROR:") 76 if strings.HasPrefix(errString, "ERROR:") { 77 errString = strings.TrimSpace(strings.TrimPrefix(errString, "ERROR:")) 78 79 // if this is an RPC Error while talking with the plugin 80 if strings.HasPrefix(errString, "rpc error") { 81 // trim out "rpc error: code = Unknown desc =" 82 errString = strings.TrimPrefix(errString, "rpc error: code = Unknown desc =") 83 } 84 } 85 return fmt.Errorf(strings.TrimSpace(errString)) 86 } 87 88 // HandleCancelError modifies a context.Canceled error into a readable error that can 89 // be printed on the console 90 func HandleCancelError(err error) error { 91 if IsCancelledError(err) { 92 err = errors.New("execution cancelled") 93 } 94 95 return err 96 } 97 98 func HandleQueryTimeoutError(err error) error { 99 if errors.Is(err, context.DeadlineExceeded) { 100 err = fmt.Errorf("query timeout exceeded (%ds)", viper.GetInt(constants.ArgDatabaseQueryTimeout)) 101 } 102 return err 103 } 104 105 func IsCancelledError(err error) bool { 106 return errors.Is(err, context.Canceled) || strings.Contains(err.Error(), "canceling statement due to user request") 107 } 108 109 func ShowWarning(warning string) { 110 if len(warning) == 0 { 111 return 112 } 113 fmt.Fprintf(color.Error, "%s: %v\n", constants.ColoredWarn, warning) 114 } 115 116 func CombineErrorsWithPrefix(prefix string, errors ...error) error { 117 if len(errors) == 0 { 118 return nil 119 } 120 121 if allErrorsNil(errors...) { 122 return nil 123 } 124 125 if len(errors) == 1 { 126 if len(prefix) == 0 { 127 return errors[0] 128 } else { 129 return fmt.Errorf("%s - %s", prefix, errors[0].Error()) 130 } 131 } 132 133 combinedErrorString := map[string]struct{}{prefix: {}} 134 for _, e := range errors { 135 if e == nil { 136 continue 137 } 138 combinedErrorString[e.Error()] = struct{}{} 139 } 140 141 return fmt.Errorf(strings.Join(maps.Keys(combinedErrorString), "\n\t")) 142 } 143 144 func allErrorsNil(errors ...error) bool { 145 for _, e := range errors { 146 if e != nil { 147 return false 148 } 149 } 150 return true 151 } 152 153 func CombineErrors(errors ...error) error { 154 return CombineErrorsWithPrefix("", errors...) 155 } 156 157 func PrefixError(err error, prefix string) error { 158 return fmt.Errorf("%s: %s\n", prefix, TransformErrorToSteampipe(err).Error()) 159 }