This repository has been archived by the owner on Aug 19, 2023. It is now read-only.
/
errors.go
140 lines (118 loc) · 2.7 KB
/
errors.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package service
import (
"errors"
"fmt"
"strings"
)
type (
errRunnerNotEnabled int
errAlreadyRunning int
)
// ErrServiceEnded is a sentinel error used to indicate that a service ended
// prematurely but no obvious error that could be returned.
//
// It is a part of the public API so that consumers of this package can return
// it from their own services.
var ErrServiceEnded = errors.New("service ended")
func (errRunnerNotEnabled) Error() string { return "service: runner not enabled" }
func (errAlreadyRunning) Error() string { return "service: already running" }
func IsRunnerNotEnabled(err error) bool { _, ok := cause(err).(errRunnerNotEnabled); return ok }
func IsEnded(err error) bool { return cause(err) == ErrServiceEnded }
func IsAlreadyRunning(err error) bool { _, ok := cause(err).(errAlreadyRunning); return ok }
type Error interface {
error
causer
Name() Name
}
func Errors(err error) []error {
if err == nil {
return nil
}
if errs, ok := err.(errorGroup); ok {
return errs.Errors()
}
return []error{err}
}
func WrapError(err error, svc *Service) Error {
if err == nil {
return nil
}
sname := svc.Name
if serr, ok := err.(*serviceError); ok {
if serr.Name() == sname {
return serr
}
}
return &serviceError{cause: err, name: sname}
}
type errorGroup interface {
Errors() []error
}
type serviceErrors struct {
errors []error
}
func (s *serviceErrors) Cause() error {
if len(s.errors) == 1 {
return s.errors[0]
} else {
return nil
}
}
func (s *serviceErrors) Errors() []error { return s.errors }
func (s *serviceErrors) Error() string {
if len(s.errors) == 1 {
return s.errors[0].Error()
} else {
var b strings.Builder
b.WriteString(fmt.Sprintf("%d service error(s) occurred:\n", len(s.errors)))
for _, e := range s.errors {
b.WriteString(" - ")
b.WriteString(e.Error())
b.WriteString("\n")
}
return b.String()
}
}
type serviceError struct {
cause error
name Name
}
func (s *serviceError) Cause() error { return s.cause }
func (s *serviceError) Name() Name { return s.name }
func (s *serviceError) Error() string {
return fmt.Sprintf("service %q error: %v", s.name, s.cause)
}
type errState struct {
Expected, To, Current State
}
func (e *errState) Error() string {
return fmt.Sprintf(
"service state error: expected %q; found %q when transitioning to %q",
e.Expected, e.Current, e.To)
}
type causer interface {
Cause() error
}
func cause(err error) error {
var last = err
var rerr = err
for rerr != nil {
cause, ok := rerr.(causer)
if !ok {
break
}
rerr = cause.Cause()
if rerr == nil {
rerr = last
break
}
if rerr == last {
break
}
last = rerr
}
if rerr == nil {
rerr = err
}
return rerr
}