storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/cmd/config/errors-utils.go (about)

     1  /*
     2   * MinIO Cloud Storage, (C) 2018-2019 MinIO, Inc.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package config
    18  
    19  import (
    20  	"errors"
    21  	"fmt"
    22  	"net"
    23  	"syscall"
    24  
    25  	"storj.io/minio/pkg/color"
    26  )
    27  
    28  // Err is a structure which contains all information
    29  // to print a fatal error message in json or pretty mode
    30  // Err implements error so we can use it anywhere
    31  type Err struct {
    32  	msg    string
    33  	detail string
    34  	action string
    35  	hint   string
    36  }
    37  
    38  // Clone returns a new Err struct with the same information
    39  func (u Err) Clone() Err {
    40  	return Err{
    41  		msg:    u.msg,
    42  		detail: u.detail,
    43  		action: u.action,
    44  		hint:   u.hint,
    45  	}
    46  }
    47  
    48  // Error returns the error message
    49  func (u Err) Error() string {
    50  	if u.detail == "" {
    51  		if u.msg != "" {
    52  			return u.msg
    53  		}
    54  		return "<nil>"
    55  	}
    56  	return u.detail
    57  }
    58  
    59  // Msg - Replace the current error's message
    60  func (u Err) Msg(m string, args ...interface{}) Err {
    61  	e := u.Clone()
    62  	e.msg = fmt.Sprintf(m, args...)
    63  	return e
    64  }
    65  
    66  // Hint - Replace the current error's message
    67  func (u Err) Hint(m string, args ...interface{}) Err {
    68  	e := u.Clone()
    69  	e.hint = fmt.Sprintf(m, args...)
    70  	return e
    71  }
    72  
    73  // ErrFn function wrapper
    74  type ErrFn func(err error) Err
    75  
    76  // Create a UI error generator, this is needed to simplify
    77  // the update of the detailed error message in several places
    78  // in MinIO code
    79  func newErrFn(msg, action, hint string) ErrFn {
    80  	return func(err error) Err {
    81  		u := Err{
    82  			msg:    msg,
    83  			action: action,
    84  			hint:   hint,
    85  		}
    86  		if err != nil {
    87  			u.detail = err.Error()
    88  		}
    89  		return u
    90  	}
    91  }
    92  
    93  // ErrorToErr inspects the passed error and transforms it
    94  // to the appropriate UI error.
    95  func ErrorToErr(err error) Err {
    96  	if err == nil {
    97  		return Err{}
    98  	}
    99  
   100  	// If this is already a Err, do nothing
   101  	if e, ok := err.(Err); ok {
   102  		return e
   103  	}
   104  
   105  	// Show a generic message for known golang errors
   106  	if errors.Is(err, syscall.EADDRINUSE) {
   107  		return ErrPortAlreadyInUse(err).Msg("Specified port is already in use")
   108  	} else if errors.Is(err, syscall.EACCES) || errors.Is(err, syscall.EPERM) {
   109  		switch err.(type) {
   110  		case *net.OpError:
   111  			return ErrPortAccess(err).Msg("Insufficient permissions to use specified port")
   112  		}
   113  	}
   114  
   115  	// Failed to identify what type of error this, return a simple UI error
   116  	return Err{msg: err.Error()}
   117  }
   118  
   119  // FmtError converts a fatal error message to a more clear error
   120  // using some colors
   121  func FmtError(introMsg string, err error, jsonFlag bool) string {
   122  
   123  	renderedTxt := ""
   124  	uiErr := ErrorToErr(err)
   125  	// JSON print
   126  	if jsonFlag {
   127  		// Message text in json should be simple
   128  		if uiErr.detail != "" {
   129  			return uiErr.msg + ": " + uiErr.detail
   130  		}
   131  		return uiErr.msg
   132  	}
   133  	// Pretty print error message
   134  	introMsg += ": "
   135  	if uiErr.msg != "" {
   136  		introMsg += color.Bold(uiErr.msg)
   137  	} else {
   138  		introMsg += color.Bold(err.Error())
   139  	}
   140  	renderedTxt += color.Red(introMsg) + "\n"
   141  	// Add action message
   142  	if uiErr.action != "" {
   143  		renderedTxt += "> " + color.BgYellow(color.Black(uiErr.action)) + "\n"
   144  	}
   145  	// Add hint
   146  	if uiErr.hint != "" {
   147  		renderedTxt += color.Bold("HINT:") + "\n"
   148  		renderedTxt += "  " + uiErr.hint
   149  	}
   150  	return renderedTxt
   151  }