github.com/hasnat/dolt/go@v0.0.0-20210628190320-9eb5d843fbb7/store/d/try.go (about) 1 // Copyright 2019 Dolthub, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 // 15 // This file incorporates work covered by the following copyright and 16 // permission notice: 17 // 18 // Copyright 2016 Attic Labs, Inc. All rights reserved. 19 // Licensed under the Apache License, version 2.0: 20 // http://www.apache.org/licenses/LICENSE-2.0 21 22 // Package d implements several debug, error and assertion functions used throughout Noms. 23 package d 24 25 import ( 26 "errors" 27 "fmt" 28 "reflect" 29 30 "github.com/stretchr/testify/assert" 31 ) 32 33 // d.Chk.<Method>() -- used in test cases and as assertions 34 var ( 35 Chk = assert.New(&panicker{}) 36 ) 37 38 type panicker struct { 39 } 40 41 func (s panicker) Errorf(format string, args ...interface{}) { 42 panic(fmt.Sprintf(format, args...)) 43 } 44 45 // Panic(err) creates an error using format and args and wraps it in a 46 // WrappedError which can be handled using Try() and TryCatch() 47 func Panic(format string, args ...interface{}) { 48 49 if len(args) == 0 { 50 err := errors.New(format) 51 panic(Wrap(err)) 52 } 53 err := fmt.Errorf(format, args...) 54 panic(Wrap(err)) 55 } 56 57 // PanicIfError(err) && PanicIfTrue(expr) can be used to panic in a way that's 58 // easily handled by Try() and TryCatch() 59 func PanicIfError(err error) { 60 if err != nil { 61 panic(Wrap(err)) 62 } 63 } 64 65 // If b is true, creates a default error, wraps it and panics. 66 func PanicIfTrue(b bool) { 67 if b { 68 panic(Wrap(errors.New("expected true"))) 69 } 70 } 71 72 // If b is false, creates a default error, wraps it and panics. 73 func PanicIfFalse(b bool) { 74 if !b { 75 panic(Wrap(errors.New("expected false"))) 76 } 77 } 78 79 type WrappedError interface { 80 Error() string 81 Cause() error 82 } 83 84 // Wraps an error. The enclosing error has a default Error() that contains the error msg along 85 // with a backtrace. The original error can be retrieved by calling err.Cause(). 86 func Wrap(err error) WrappedError { 87 if err == nil { 88 return nil 89 } 90 if we, ok := err.(WrappedError); ok { 91 return we 92 } 93 94 st := stackTracer{} 95 assert := assert.New(&st) 96 assert.Fail(err.Error()) 97 98 return wrappedError{st.stackTrace, err} 99 } 100 101 // If err is a WrappedError, then Cause() is returned, otherwise returns err. 102 func Unwrap(err error) error { 103 cause := err 104 we, ok := err.(WrappedError) 105 if ok { 106 cause = we.Cause() 107 } 108 return cause 109 } 110 111 func causeInTypes(err error, types ...interface{}) bool { 112 cause := Unwrap(err) 113 typ := reflect.TypeOf(cause) 114 for _, t := range types { 115 if typ == reflect.TypeOf(t) { 116 return true 117 } 118 } 119 return false 120 } 121 122 // Utility method, that checks type of error and panics with wrapped error not one of the listed types. 123 func PanicIfNotType(err error, types ...interface{}) error { 124 if err == nil { 125 return nil 126 } 127 if !causeInTypes(err, types...) { 128 we, ok := err.(WrappedError) 129 if !ok { 130 we = Wrap(err) 131 } 132 panic(we) 133 } 134 return Unwrap(err) 135 } 136 137 type wrappedError struct { 138 msg string 139 cause error 140 } 141 142 func (we wrappedError) Error() string { return we.msg } 143 func (we wrappedError) Cause() error { return we.cause } 144 145 type stackTracer struct { 146 stackTrace string 147 } 148 149 func (s *stackTracer) Errorf(format string, args ...interface{}) { 150 s.stackTrace = fmt.Sprintf(format, args...) 151 } 152 153 func recoverWrappedTypes(errp *error, types []interface{}) { 154 if r := recover(); r != nil { 155 if wrapper, ok := r.(wrappedError); !ok { 156 panic(r) 157 } else if len(types) > 0 && !causeInTypes(wrapper, types...) { 158 panic(r) 159 } else if len(types) > 0 { 160 *errp = wrapper.Cause() 161 } else { 162 *errp = wrapper 163 } 164 } 165 } 166 167 func recoverWrapped(errp *error, catch func(err error) error) { 168 if r := recover(); r != nil { 169 we, ok := r.(wrappedError) 170 if !ok { 171 panic(r) 172 } 173 if catch != nil { 174 *errp = catch(we) 175 } else { 176 *errp = Unwrap(we) 177 } 178 } 179 }