Skip to content

Commit

Permalink
ExitIf panics instead of exiting; Return catches
Browse files Browse the repository at this point in the history
- allow Return to take either &err or &rc
- Makefile: `go vet` examples
- rename package statement to goadapt
- unexport adaptErr
  • Loading branch information
stevegt committed Apr 19, 2021
1 parent 27b4f4d commit d435e83
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 26 deletions.
7 changes: 6 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,16 @@ coverpkgs = $(shell echo $(packages) | tr ' ' ',')
pkg = $(shell basename `go list`)
cov = /tmp/$(pkg)-coverage

test:
test: main eg

main:
go vet
go test -coverprofile=$(cov).out -coverpkg=$(coverpkgs)
go tool cover -html=$(cov).out -o $(cov).html

eg:
for f in examples/*.go; do go vet $$f || exit 1; done

testloop:
while true; do inotifywait -e MOVE *; sleep 1; make test; done

11 changes: 10 additions & 1 deletion examples/exitif.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,19 @@ import (
var FooError = errors.New("foo error")

func main() {
rc := run()
os.Exit(rc)
}

func run() (rc int) {
defer Return(&rc)
rand.Seed(time.Now().UnixNano())
err := mid()
ExitIf(err, FooError)
ExitIf(err, syscall.EPIPE, "pipeline %d error", 7)
ExitIf(err, syscall.ENOENT)
Ck(err)
return
}

func adapted() (err error) {
Expand All @@ -37,14 +44,16 @@ func mid() (err error) {

func SomeFunc() (err error) {
defer Return(&err)
switch rand.Intn(3) {
switch rand.Intn(4) {
case 0:
return syscall.EPIPE
case 1:
return FooError
case 2:
_, err = os.Stat("/notafileordir")
Ck(err)
case 3:
Assert(false, "lksadjfslkjf dsalkjf")
}
return
}
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
module github.com/stevegt/goadapt

go 1.13

require github.com/sirupsen/logrus v1.8.1 // indirect
7 changes: 7 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
54 changes: 35 additions & 19 deletions main.go
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
package adapt
package goadapt

import (
"errors"
"fmt"
"log"
"os"
"runtime"
"strings"
"syscall"
)

type AdaptErr struct {
type adaptErr struct {
File string
Line int
Msg string
Err error
Rc int
}

func (e AdaptErr) Error() string {
func (e adaptErr) Error() string {
var s []string
if len(e.File) > 0 {
s = append(s, fmt.Sprintf("%s:%d", e.File, e.Line))
Expand All @@ -31,15 +31,15 @@ func (e AdaptErr) Error() string {
return strings.Join(s, ": ")
}

func (e AdaptErr) Unwrap() error {
func (e adaptErr) Unwrap() error {
return e.Err
}

func Ck(err error, args ...interface{}) {
if err != nil {
_, file, line, _ := runtime.Caller(1)
msg := formatArgs(args...)
e := AdaptErr{file, line, msg, err}
e := adaptErr{file, line, msg, err, 0}
panic(&e)
}
}
Expand All @@ -65,38 +65,50 @@ func Assert(cond bool, args ...interface{}) {
if len(args) > 1 {
msg += ": " + fmt.Sprintf(args[0].(string), args[1:]...)
}
e := AdaptErr{file, line, msg, nil}
e := adaptErr{file, line, msg, nil, 0}
panic(&e)
}
}

// convert panic into returned err
// see https://github.com/lainio/err2 and https://blog.golang.org/go1.13-errors
func Return(err *error, args ...interface{}) {
func Return(out interface{}, args ...interface{}) {
r := recover()
if r == nil {
return
}
// r is interface{}
// r is an interface{}

e, ok := r.(*AdaptErr)
e, ok := r.(*adaptErr)
if !ok {
// wasn't us -- let the panic continue
panic(r)
}
// e is *AdaptErr
// e.Err is the original error thrown by lower call
// e is an *adaptErr
// e.Err is the error thrown by lower call

msg := formatArgs(args...)

*err = &AdaptErr{Msg: msg, Err: e}
switch res := out.(type) {
case *error:
// return a wrapper err
*res = &adaptErr{Msg: msg, Err: e}
case *int:
if e.Rc == 0 {
// we had an adaptErr panic but no Rc
log.Println(e)
*res = 1
}
log.Println(e.Msg)
*res = e.Rc
}
}

func ExitIf(err, target error, args ...interface{}) {
// fmt.Printf("%T %T\n", err, target)
if errors.Is(err, target) {
rc := int(syscall.EPERM)
stack := ErrStack(err)
stack := errStack(err)
// fmt.Printf("%#v\n", stack)
root := stack[0]
parent := err
Expand All @@ -107,20 +119,24 @@ func ExitIf(err, target error, args ...interface{}) {
if ok {
rc = int(errno)
}

msg := formatArgs(args...)
if len(msg) > 0 {
fmt.Printf("%s: ", msg)
msg = fmt.Sprintf("%s: ", msg)
}
fmt.Printf("%v\n", parent)
os.Exit(rc)
msg = fmt.Sprintf("%v", parent)

_, file, line, _ := runtime.Caller(1)
e := adaptErr{file, line, msg, parent, rc}
panic(&e)
}
}

func ErrStack(e error) (stack []error) {
func errStack(e error) (stack []error) {
stack = append(stack, e)
child := errors.Unwrap(e)
if child != nil {
stack = append(ErrStack(child), stack...)
stack = append(errStack(child), stack...)
}
return
}
Expand Down
10 changes: 5 additions & 5 deletions main_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package adapt
package goadapt

import (
"bytes"
Expand Down Expand Up @@ -154,8 +154,8 @@ func TestUnwrap(t *testing.T) {
loop:
for i := 0; i < 10; i++ {
switch y := x.(type) {
case *AdaptErr:
// fmt.Printf("%d AdaptErr x %T y %T\n", i, x, y)
case *adaptErr:
// fmt.Printf("%d adaptErr x %T y %T\n", i, x, y)
x = y.Unwrap()
case *miderr:
// fmt.Printf("%d miderr x %T y %T\n", i, x, y)
Expand All @@ -168,8 +168,8 @@ loop:
}
}

var e *AdaptErr
tassert(t, errors.As(err, &e), "err not unwrapping to AdaptErr")
var e *adaptErr
tassert(t, errors.As(err, &e), "err not unwrapping to adaptErr")

var l *miderr
tassert(t, errors.As(err, &l), "err %T not unwrapping to miderr: %v", err, err)
Expand Down

0 comments on commit d435e83

Please sign in to comment.