istio.io/istio@v0.0.0-20240520182934-d79c90f27776/operator/pkg/util/errs.go (about)

     1  // Copyright Istio Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package util
    16  
    17  import (
    18  	"fmt"
    19  )
    20  
    21  const (
    22  	defaultSeparator = ", "
    23  )
    24  
    25  // Errors is a slice of error.
    26  type Errors []error
    27  
    28  // Error implements the error#Error method.
    29  func (e Errors) Error() string {
    30  	return ToString(e, defaultSeparator)
    31  }
    32  
    33  // String implements the stringer#String method.
    34  func (e Errors) String() string {
    35  	return e.Error()
    36  }
    37  
    38  // ToError returns an error from Errors.
    39  func (e Errors) ToError() error {
    40  	if len(e) == 0 {
    41  		return nil
    42  	}
    43  	return fmt.Errorf("%s", e)
    44  }
    45  
    46  // Dedup removes any duplicated errors.
    47  func (e Errors) Dedup() Errors {
    48  	logCountMap := make(map[string]int)
    49  	for _, ee := range e {
    50  		if ee == nil {
    51  			continue
    52  		}
    53  		item := ee.Error()
    54  		_, exist := logCountMap[item]
    55  		if exist {
    56  			logCountMap[item]++
    57  		} else {
    58  			logCountMap[item] = 1
    59  		}
    60  	}
    61  	var out Errors
    62  	for _, ee := range e {
    63  		item := ee.Error()
    64  		count := logCountMap[item]
    65  		if count == 0 {
    66  			continue
    67  		}
    68  		times := ""
    69  		if count > 1 {
    70  			times = fmt.Sprintf(" (repeated %d times)", count)
    71  		}
    72  		out = AppendErr(out, fmt.Errorf("%s%s", ee, times))
    73  		// reset seen log count
    74  		logCountMap[item] = 0
    75  	}
    76  	return out
    77  }
    78  
    79  // NewErrs returns a slice of error with a single element err.
    80  // If err is nil, returns nil.
    81  func NewErrs(err error) Errors {
    82  	if err == nil {
    83  		return nil
    84  	}
    85  	return []error{err}
    86  }
    87  
    88  // AppendErr appends err to errors if it is not nil and returns the result.
    89  // If err is nil, it is not appended.
    90  func AppendErr(errors []error, err error) Errors {
    91  	if err == nil {
    92  		if len(errors) == 0 {
    93  			return nil
    94  		}
    95  		return errors
    96  	}
    97  	return append(errors, err)
    98  }
    99  
   100  // AppendErrs appends newErrs to errors and returns the result.
   101  // If newErrs is empty, nothing is appended.
   102  func AppendErrs(errors []error, newErrs []error) Errors {
   103  	if len(newErrs) == 0 {
   104  		return errors
   105  	}
   106  	for _, e := range newErrs {
   107  		errors = AppendErr(errors, e)
   108  	}
   109  	if len(errors) == 0 {
   110  		return nil
   111  	}
   112  	return errors
   113  }
   114  
   115  // ToString returns a string representation of errors, with elements separated by separator string. Any nil errors in the
   116  // slice are skipped.
   117  func ToString(errors []error, separator string) string {
   118  	var out string
   119  	for i, e := range errors {
   120  		if e == nil {
   121  			continue
   122  		}
   123  		if i != 0 {
   124  			out += separator
   125  		}
   126  		out += e.Error()
   127  	}
   128  	return out
   129  }
   130  
   131  // EqualErrors reports whether a and b are equal, regardless of ordering.
   132  func EqualErrors(a, b Errors) bool {
   133  	if len(a) != len(b) {
   134  		return false
   135  	}
   136  	m := make(map[string]bool)
   137  	for _, e := range b {
   138  		m[e.Error()] = true
   139  	}
   140  	for _, ea := range a {
   141  		if !m[ea.Error()] {
   142  			return false
   143  		}
   144  	}
   145  	return true
   146  }