aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/Azure/azure-pipeline-go/pipeline/error.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/Azure/azure-pipeline-go/pipeline/error.go')
-rwxr-xr-xvendor/github.com/Azure/azure-pipeline-go/pipeline/error.go121
1 files changed, 121 insertions, 0 deletions
diff --git a/vendor/github.com/Azure/azure-pipeline-go/pipeline/error.go b/vendor/github.com/Azure/azure-pipeline-go/pipeline/error.go
new file mode 100755
index 000000000..fd008364d
--- /dev/null
+++ b/vendor/github.com/Azure/azure-pipeline-go/pipeline/error.go
@@ -0,0 +1,121 @@
+package pipeline
+
+import (
+ "fmt"
+ "runtime"
+)
+
+type causer interface {
+ Cause() error
+}
+
+// ErrorNode can be an embedded field in a private error object. This field
+// adds Program Counter support and a 'cause' (reference to a preceding error).
+// When initializing a error type with this embedded field, initialize the
+// ErrorNode field by calling ErrorNode{}.Initialize(cause).
+type ErrorNode struct {
+ pc uintptr // Represents a Program Counter that you can get symbols for.
+ cause error // Refers to the preceding error (or nil)
+}
+
+// Error returns a string with the PC's symbols or "" if the PC is invalid.
+// When defining a new error type, have its Error method call this one passing
+// it the string representation of the error.
+func (e *ErrorNode) Error(msg string) string {
+ s := ""
+ if fn := runtime.FuncForPC(e.pc); fn != nil {
+ file, line := fn.FileLine(e.pc)
+ s = fmt.Sprintf("-> %v, %v:%v\n", fn.Name(), file, line)
+ }
+ s += msg + "\n\n"
+ if e.cause != nil {
+ s += e.cause.Error() + "\n"
+ }
+ return s
+}
+
+// Cause returns the error that preceded this error.
+func (e *ErrorNode) Cause() error { return e.cause }
+
+// Temporary returns true if the error occurred due to a temporary condition.
+func (e ErrorNode) Temporary() bool {
+ type temporary interface {
+ Temporary() bool
+ }
+
+ for err := e.cause; err != nil; {
+ if t, ok := err.(temporary); ok {
+ return t.Temporary()
+ }
+
+ if cause, ok := err.(causer); ok {
+ err = cause.Cause()
+ } else {
+ err = nil
+ }
+ }
+ return false
+}
+
+// Timeout returns true if the error occurred due to time expiring.
+func (e ErrorNode) Timeout() bool {
+ type timeout interface {
+ Timeout() bool
+ }
+
+ for err := e.cause; err != nil; {
+ if t, ok := err.(timeout); ok {
+ return t.Timeout()
+ }
+
+ if cause, ok := err.(causer); ok {
+ err = cause.Cause()
+ } else {
+ err = nil
+ }
+ }
+ return false
+}
+
+// Initialize is used to initialize an embedded ErrorNode field.
+// It captures the caller's program counter and saves the cause (preceding error).
+// To initialize the field, use "ErrorNode{}.Initialize(cause, 3)". A callersToSkip
+// value of 3 is very common; but, depending on your code nesting, you may need
+// a different value.
+func (ErrorNode) Initialize(cause error, callersToSkip int) ErrorNode {
+ // Get the PC of Initialize method's caller.
+ pc := [1]uintptr{}
+ _ = runtime.Callers(callersToSkip, pc[:])
+ return ErrorNode{pc: pc[0], cause: cause}
+}
+
+// Cause walks all the preceding errors and return the originating error.
+func Cause(err error) error {
+ for err != nil {
+ cause, ok := err.(causer)
+ if !ok {
+ break
+ }
+ err = cause.Cause()
+ }
+ return err
+}
+
+// NewError creates a simple string error (like Error.New). But, this
+// error also captures the caller's Program Counter and the preceding error.
+func NewError(cause error, msg string) error {
+ return &pcError{
+ ErrorNode: ErrorNode{}.Initialize(cause, 3),
+ msg: msg,
+ }
+}
+
+// pcError is a simple string error (like error.New) with an ErrorNode (PC & cause).
+type pcError struct {
+ ErrorNode
+ msg string
+}
+
+// Error satisfies the error interface. It shows the error with Program Counter
+// symbols and calls Error on the preceding error so you can see the full error chain.
+func (e *pcError) Error() string { return e.ErrorNode.Error(e.msg) }