Skip to content

Commit 20feca1

Browse files
mpvlneild
authored andcommitted
xerrors: copied files from x/exp/errors
changed paths and removed experimental notice Also made panic test pass: the output differed for different Go versions. Change-Id: Iadd367fb253459d288c3ec7e3aaafce9af939983 Reviewed-on: https://go-review.googlesource.com/c/159777 Run-TryBot: Marcel van Lohuizen <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Damien Neil <[email protected]>
1 parent faf7c54 commit 20feca1

16 files changed

+1504
-0
lines changed

adaptor.go

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
// Copyright 2018 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package xerrors
6+
7+
import (
8+
"bytes"
9+
"fmt"
10+
"io"
11+
"reflect"
12+
"strconv"
13+
)
14+
15+
// FormatError calls the FormatError method of f with an errors.Printer
16+
// configured according to s and verb, and writes the result to s.
17+
func FormatError(f Formatter, s fmt.State, verb rune) {
18+
// Assuming this function is only called from the Format method, and given
19+
// that FormatError takes precedence over Format, it cannot be called from
20+
// any package that supports errors.Formatter. It is therefore safe to
21+
// disregard that State may be a specific printer implementation and use one
22+
// of our choice instead.
23+
24+
// limitations: does not support printing error as Go struct.
25+
26+
var (
27+
sep = " " // separator before next error
28+
p = &state{State: s}
29+
direct = true
30+
)
31+
32+
var err error = f
33+
34+
switch verb {
35+
// Note that this switch must match the preference order
36+
// for ordinary string printing (%#v before %+v, and so on).
37+
38+
case 'v':
39+
if s.Flag('#') {
40+
if stringer, ok := err.(fmt.GoStringer); ok {
41+
io.WriteString(&p.buf, stringer.GoString())
42+
goto exit
43+
}
44+
// proceed as if it were %v
45+
} else if s.Flag('+') {
46+
p.printDetail = true
47+
sep = "\n - "
48+
}
49+
case 's':
50+
case 'q', 'x', 'X':
51+
// Use an intermediate buffer in the rare cases that precision,
52+
// truncation, or one of the alternative verbs (q, x, and X) are
53+
// specified.
54+
direct = false
55+
56+
default:
57+
p.buf.WriteString("%!")
58+
p.buf.WriteRune(verb)
59+
p.buf.WriteByte('(')
60+
switch {
61+
case err != nil:
62+
p.buf.WriteString(reflect.TypeOf(f).String())
63+
default:
64+
p.buf.WriteString("<nil>")
65+
}
66+
p.buf.WriteByte(')')
67+
io.Copy(s, &p.buf)
68+
return
69+
}
70+
71+
loop:
72+
for {
73+
p.inDetail = false
74+
75+
switch v := err.(type) {
76+
case Formatter:
77+
err = v.FormatError((*printer)(p))
78+
case fmt.Formatter:
79+
v.Format(p, 'v')
80+
break loop
81+
default:
82+
io.WriteString(&p.buf, v.Error())
83+
break loop
84+
}
85+
if err == nil {
86+
break
87+
}
88+
if !p.inDetail || !p.printDetail {
89+
p.buf.WriteByte(':')
90+
}
91+
// Strip last newline of detail.
92+
if bytes.HasSuffix(p.buf.Bytes(), detailSep) {
93+
p.buf.Truncate(p.buf.Len() - len(detailSep))
94+
}
95+
p.buf.WriteString(sep)
96+
p.inDetail = false
97+
}
98+
99+
exit:
100+
width, okW := s.Width()
101+
prec, okP := s.Precision()
102+
103+
if !direct || (okW && width > 0) || okP {
104+
// Construct format string from State s.
105+
format := []byte{'%'}
106+
if s.Flag('-') {
107+
format = append(format, '-')
108+
}
109+
if s.Flag('+') {
110+
format = append(format, '+')
111+
}
112+
if s.Flag(' ') {
113+
format = append(format, ' ')
114+
}
115+
if okW {
116+
format = strconv.AppendInt(format, int64(width), 10)
117+
}
118+
if okP {
119+
format = append(format, '.')
120+
format = strconv.AppendInt(format, int64(prec), 10)
121+
}
122+
format = append(format, string(verb)...)
123+
fmt.Fprintf(s, string(format), p.buf.String())
124+
} else {
125+
io.Copy(s, &p.buf)
126+
}
127+
}
128+
129+
var detailSep = []byte("\n ")
130+
131+
// state tracks error printing state. It implements fmt.State.
132+
type state struct {
133+
fmt.State
134+
buf bytes.Buffer
135+
136+
printDetail bool
137+
inDetail bool
138+
needNewline bool
139+
}
140+
141+
func (s *state) Write(b []byte) (n int, err error) {
142+
if s.printDetail {
143+
if len(b) == 0 {
144+
return 0, nil
145+
}
146+
if s.inDetail && s.needNewline {
147+
s.needNewline = false
148+
s.buf.WriteByte(':')
149+
s.buf.Write(detailSep)
150+
if b[0] == '\n' {
151+
b = b[1:]
152+
}
153+
}
154+
k := 0
155+
for i, c := range b {
156+
if c == '\n' {
157+
s.buf.Write(b[k:i])
158+
s.buf.Write(detailSep)
159+
k = i + 1
160+
}
161+
}
162+
s.buf.Write(b[k:])
163+
s.needNewline = !s.inDetail
164+
} else if !s.inDetail {
165+
s.buf.Write(b)
166+
}
167+
return len(b), nil
168+
}
169+
170+
// printer wraps a state to implement an xerrors.Printer.
171+
type printer state
172+
173+
func (s *printer) Print(args ...interface{}) {
174+
if !s.inDetail || s.printDetail {
175+
fmt.Fprint((*state)(s), args...)
176+
}
177+
}
178+
179+
func (s *printer) Printf(format string, args ...interface{}) {
180+
if !s.inDetail || s.printDetail {
181+
fmt.Fprintf((*state)(s), format, args...)
182+
}
183+
}
184+
185+
func (s *printer) Detail() bool {
186+
s.inDetail = true
187+
return s.printDetail
188+
}

doc.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright 2019 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
// Package xerrors implements functions to manipulate errors.
6+
//
7+
// This package supports transitioning to the Go 2 proposal for error values:
8+
// https://golang.org/design/29934-error-values
9+
//
10+
// Most of the functions and types in this package will be incorporated into the
11+
// standard library's errors package in Go 1.13; the behavior of this package's
12+
// Errorf function will be incorporated into the standard library's fmt.Errorf.
13+
// Use this package to get equivalent behavior in all supported Go versions. For
14+
// example, create errors using
15+
//
16+
// xerrors.New("write failed")
17+
//
18+
// or
19+
//
20+
// xerrors.Errorf("while reading: %v", err)
21+
//
22+
// If you want your error type to participate in the new formatting
23+
// implementation for %v and %+v, provide it with a Format method that calls
24+
// xerrors.FormatError, as shown in the example for FormatError.
25+
package xerrors // import "golang.org/x/xerrors"

errors.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Copyright 2011 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package xerrors
6+
7+
// errorString is a trivial implementation of error.
8+
type errorString struct {
9+
s string
10+
frame Frame
11+
}
12+
13+
// New returns an error that formats as the given text.
14+
//
15+
// The returned error contains a Frame set to the caller's location and
16+
// implements Formatter to show this information when printed with details.
17+
func New(text string) error {
18+
return &errorString{text, Caller(1)}
19+
}
20+
21+
func (e *errorString) Error() string {
22+
return e.s
23+
}
24+
25+
func (e *errorString) FormatError(p Printer) (next error) {
26+
p.Print(e.s)
27+
e.frame.Format(p)
28+
return nil
29+
}

errors_test.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// Copyright 2011 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package xerrors_test
6+
7+
import (
8+
"fmt"
9+
"testing"
10+
11+
"golang.org/x/xerrors"
12+
)
13+
14+
func TestNewEqual(t *testing.T) {
15+
// Different allocations should not be equal.
16+
if xerrors.New("abc") == xerrors.New("abc") {
17+
t.Errorf(`New("abc") == New("abc")`)
18+
}
19+
if xerrors.New("abc") == xerrors.New("xyz") {
20+
t.Errorf(`New("abc") == New("xyz")`)
21+
}
22+
23+
// Same allocation should be equal to itself (not crash).
24+
err := xerrors.New("jkl")
25+
if err != err {
26+
t.Errorf(`err != err`)
27+
}
28+
}
29+
30+
func TestErrorMethod(t *testing.T) {
31+
err := xerrors.New("abc")
32+
if err.Error() != "abc" {
33+
t.Errorf(`New("abc").Error() = %q, want %q`, err.Error(), "abc")
34+
}
35+
}
36+
37+
func ExampleNew() {
38+
err := xerrors.New("emit macho dwarf: elf header corrupted")
39+
if err != nil {
40+
fmt.Print(err)
41+
}
42+
// Output: emit macho dwarf: elf header corrupted
43+
}
44+
45+
// The fmt package's Errorf function lets us use the package's formatting
46+
// features to create descriptive error messages.
47+
func ExampleNew_errorf() {
48+
const name, id = "bimmler", 17
49+
err := fmt.Errorf("user %q (id %d) not found", name, id)
50+
if err != nil {
51+
fmt.Print(err)
52+
}
53+
// Output: user "bimmler" (id 17) not found
54+
}

example_As_test.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright 2019 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package xerrors_test
6+
7+
import (
8+
"fmt"
9+
"os"
10+
11+
"golang.org/x/xerrors"
12+
)
13+
14+
func ExampleAs() {
15+
_, err := os.Open("non-existing")
16+
if err != nil {
17+
var pathError *os.PathError
18+
if xerrors.As(err, &pathError) {
19+
fmt.Println("Failed at path:", pathError.Path)
20+
}
21+
}
22+
23+
// Output:
24+
// Failed at path: non-existing
25+
}

example_FormatError_test.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Copyright 2019 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package xerrors_test
6+
7+
import (
8+
"fmt"
9+
10+
"golang.org/x/xerrors"
11+
)
12+
13+
type MyError2 struct {
14+
Message string
15+
frame xerrors.Frame
16+
}
17+
18+
func (m *MyError2) Error() string {
19+
return m.Message
20+
}
21+
22+
func (m *MyError2) Format(f fmt.State, c rune) { // implements fmt.Formatter
23+
xerrors.FormatError(m, f, c)
24+
}
25+
26+
func (m *MyError2) FormatError(p xerrors.Printer) error { // implements xerrors.Formatter
27+
p.Print(m.Message)
28+
if p.Detail() {
29+
m.frame.Format(p)
30+
}
31+
return nil
32+
}
33+
34+
func ExampleFormatError() {
35+
err := &MyError2{Message: "oops", frame: xerrors.Caller(1)}
36+
fmt.Printf("%v\n", err)
37+
fmt.Println()
38+
fmt.Printf("%+v\n", err)
39+
}

0 commit comments

Comments
 (0)