cli-utils/pkg/multierror/multierror.go

92 lines
1.9 KiB
Go

// Copyright 2022 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package multierror
import (
"fmt"
"strings"
)
const Prefix = "- "
const Indent = " "
type Interface interface {
Errors() []error
}
// New returns a new MultiError wrapping the specified error list.
func New(causes ...error) *MultiError {
return &MultiError{
Causes: causes,
}
}
// MultiError wraps multiple errors and formats them for multi-line output.
type MultiError struct {
Causes []error
}
func (mve *MultiError) Errors() []error {
return mve.Causes
}
func (mve *MultiError) Error() string {
if len(mve.Causes) == 1 {
return mve.Causes[0].Error()
}
var b strings.Builder
_, _ = fmt.Fprintf(&b, "%d errors:\n", len(mve.Causes))
for _, err := range mve.Causes {
_, _ = fmt.Fprintf(&b, "%s\n", formatError(err))
}
return b.String()
}
func formatError(err error) string {
lines := strings.Split(err.Error(), "\n")
return Prefix + strings.Join(lines, fmt.Sprintf("\n%s", Indent))
}
// Wrap merges zero or more errors and/or MultiErrors into one error.
// MultiErrors are recursively unwrapped to reduce depth.
// If only one error is received, that error is returned without a wrapper.
func Wrap(errs ...error) error {
if len(errs) == 0 {
return nil
}
errs = Unwrap(errs...)
var err error
switch {
case len(errs) == 0:
err = nil
case len(errs) == 1:
err = errs[0]
case len(errs) > 1:
err = &MultiError{
Causes: errs,
}
}
return err
}
// Unwrap flattens zero or more errors and/or MultiErrors into a list of errors.
// MultiErrors are recursively unwrapped to reduce depth.
func Unwrap(errs ...error) []error {
if len(errs) == 0 {
return nil
}
var errors []error
for _, err := range errs {
if mve, ok := err.(Interface); ok {
// Recursively unwrap MultiErrors
for _, cause := range mve.Errors() {
errors = append(errors, Unwrap(cause)...)
}
} else {
errors = append(errors, err)
}
}
return errors
}