...
1
2 package xdefer
3
4 import (
5 "fmt"
6 "strings"
7
8 "golang.org/x/xerrors"
9 )
10
11 type deferError struct {
12 s string
13 err error
14 frame xerrors.Frame
15 }
16
17 var _ interface {
18 xerrors.Wrapper
19 xerrors.Formatter
20 Is(error) bool
21 } = deferError{}
22
23 func (e deferError) Unwrap() error {
24 return e.err
25 }
26
27 func (e deferError) Format(f fmt.State, c rune) {
28 xerrors.FormatError(e, f, c)
29 }
30
31
32
33 type fakeXerrorsPrinter struct {
34 s []string
35 }
36
37 func (fp *fakeXerrorsPrinter) Print(v ...interface{}) {
38 fp.s = append(fp.s, fmt.Sprint(v...))
39 }
40
41 func (fp *fakeXerrorsPrinter) Printf(f string, v ...interface{}) {
42 fp.s = append(fp.s, fmt.Sprintf(f, v...))
43 }
44
45 func (fp *fakeXerrorsPrinter) Detail() bool {
46 return true
47 }
48
49 func (e deferError) shouldPrintFrame(p xerrors.Printer) bool {
50 fm, ok := e.err.(xerrors.Formatter)
51 if !ok {
52 return true
53 }
54
55 fp := &fakeXerrorsPrinter{}
56 e.frame.Format(fp)
57 fp2 := &fakeXerrorsPrinter{}
58 _ = fm.FormatError(fp2)
59 if len(fp.s) >= 2 && len(fp2.s) >= 3 {
60 if fp.s[1] == fp2.s[2] {
61
62
63 return false
64 }
65 }
66 return true
67 }
68
69 func (e deferError) FormatError(p xerrors.Printer) error {
70 if e.s == "" {
71 if e.shouldPrintFrame(p) {
72 e.frame.Format(p)
73 }
74 return e.err
75 }
76
77 p.Print(e.s)
78 if p.Detail() && e.shouldPrintFrame(p) {
79 e.frame.Format(p)
80 }
81 return e.err
82 }
83
84 func (e deferError) Is(err error) bool {
85 return xerrors.Is(e.err, err)
86 }
87
88 func (e deferError) Error() string {
89 if e.s == "" {
90 fp := &fakeXerrorsPrinter{}
91 e.frame.Format(fp)
92 if len(fp.s) < 1 {
93 return e.err.Error()
94 }
95 return fmt.Sprintf("%v: %v", strings.TrimSpace(fp.s[0]), e.err)
96 }
97 return fmt.Sprintf("%v: %v", e.s, e.err)
98 }
99
100
101
102
103
104 func Errorf(err *error, s string, v ...interface{}) {
105 if *err != nil {
106 *err = deferError{
107 s: fmt.Sprintf(s, v...),
108 err: *err,
109 frame: xerrors.Caller(1),
110 }
111 }
112 }
113
View as plain text