github.com/hxx258456/fabric-ca-gm@v0.0.3-0.20221111064038-a268ad7e3a37/internal/pkg/util/flag.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package util
     8  
     9  import (
    10  	"fmt"
    11  	"reflect"
    12  	"strconv"
    13  	"time"
    14  
    15  	log "gitee.com/zhaochuninhefei/zcgolog/zclog"
    16  	logging "github.com/op/go-logging"
    17  	"github.com/pkg/errors"
    18  	"github.com/spf13/pflag"
    19  	"github.com/spf13/viper"
    20  )
    21  
    22  const (
    23  	// TagDefault is the tag name for a default value of a field as recognized
    24  	// by RegisterFlags.
    25  	TagDefault = "def"
    26  	// TagHelp is the tag name for a help message of a field as recognized
    27  	// by RegisterFlags.
    28  	TagHelp = "help"
    29  	// TagOpt is the tag name for a one character option of a field as recognized
    30  	// by RegisterFlags.  For example, a value of "d" reserves "-d" for the
    31  	// command line argument.
    32  	TagOpt = "opt"
    33  	// TagSkip is the tag name which causes the field to be skipped by
    34  	// RegisterFlags.
    35  	TagSkip = "skip"
    36  	// TagHide is the tag name which causes the field to be hidden
    37  	TagHide = "hide"
    38  )
    39  
    40  // RegisterFlags registers flags for all fields in an arbitrary 'config' object.
    41  // This method recognizes the following field tags:
    42  // "def" - the default value of the field;
    43  // "opt" - the optional one character short name to use on the command line;
    44  // "help" - the help message to display on the command line;
    45  // "skip" - to skip the field.
    46  func RegisterFlags(v *viper.Viper, flags *pflag.FlagSet, config interface{},
    47  	tags map[string]string) error {
    48  	fr := &flagRegistrar{flags: flags, tags: tags, viper: v}
    49  	return ParseObj(config, fr.Register, tags)
    50  }
    51  
    52  type flagRegistrar struct {
    53  	flags *pflag.FlagSet
    54  	tags  map[string]string
    55  	viper *viper.Viper
    56  }
    57  
    58  func (fr *flagRegistrar) Register(f *Field) (err error) {
    59  	// Don't register non-leaf fields
    60  	if !f.Leaf {
    61  		return nil
    62  	}
    63  	// Don't register fields with no address
    64  	if f.Addr == nil {
    65  		return errors.Errorf("Field is not addressable: %s", f.Path)
    66  	}
    67  	skip := fr.getTag(f, TagSkip)
    68  	if skip != "" {
    69  		return nil
    70  	}
    71  
    72  	help := fr.getTag(f, TagHelp)
    73  	opt := fr.getTag(f, TagOpt)
    74  	def := fr.getTag(f, TagDefault)
    75  	hide := fr.getHideBooleanTag(f)
    76  	switch f.Kind {
    77  
    78  	case reflect.String:
    79  		if help == "" && !hide {
    80  			return errors.Errorf("Field is missing a help tag: %s", f.Path)
    81  		}
    82  		fr.flags.StringVarP(f.Addr.(*string), f.Path, opt, def, help)
    83  	case reflect.Int:
    84  		if help == "" && !hide {
    85  			return errors.Errorf("Field is missing a help tag: %s", f.Path)
    86  		}
    87  		var intDef int
    88  		if def != "" {
    89  			intDef, err = strconv.Atoi(def)
    90  			if err != nil {
    91  				return errors.Errorf("Invalid integer value in 'def' tag of %s field", f.Path)
    92  			}
    93  		}
    94  		fr.flags.IntVarP(f.Addr.(*int), f.Path, opt, intDef, help)
    95  	case reflect.Int64:
    96  		if help == "" && !hide {
    97  			return errors.Errorf("Field is missing a help tag: %s", f.Path)
    98  		}
    99  		d, ok := f.Addr.(*time.Duration)
   100  		if !ok {
   101  			var intDef int64
   102  			if def != "" {
   103  				intDef, err = strconv.ParseInt(def, 10, 64)
   104  				if err != nil {
   105  					return errors.Errorf("Invalid int64 value in 'def' tag of %s field", f.Path)
   106  				}
   107  			}
   108  			fr.flags.Int64VarP(f.Addr.(*int64), f.Path, opt, intDef, help)
   109  		} else {
   110  			var intDef time.Duration
   111  			if def != "" {
   112  				intDef, err = time.ParseDuration(def)
   113  				if err != nil {
   114  					return errors.Errorf("Invalid duration value in 'def' tag of %s field", f.Path)
   115  				}
   116  			}
   117  			fr.flags.DurationVarP(d, f.Path, opt, intDef, help)
   118  		}
   119  	case reflect.Bool:
   120  		if help == "" && !hide {
   121  			return errors.Errorf("Field is missing a help tag: %s", f.Path)
   122  		}
   123  		var boolDef bool
   124  		if def != "" {
   125  			boolDef, err = strconv.ParseBool(def)
   126  			if err != nil {
   127  				return errors.Errorf("Invalid boolean value in 'def' tag of %s field", f.Path)
   128  			}
   129  		}
   130  		fr.flags.BoolVarP(f.Addr.(*bool), f.Path, opt, boolDef, help)
   131  	case reflect.Slice:
   132  		if f.Type.Elem().Kind() == reflect.String {
   133  			if help == "" && !hide {
   134  				return errors.Errorf("Field is missing a help tag: %s", f.Path)
   135  			}
   136  			fr.flags.StringSliceVarP(f.Addr.(*[]string), f.Path, opt, nil, help)
   137  		} else {
   138  			return nil
   139  		}
   140  	default:
   141  		log.Debugf("Not registering flag for '%s' because it is a currently unsupported type: %s",
   142  			f.Path, f.Kind)
   143  		return nil
   144  	}
   145  	if hide {
   146  		fr.flags.MarkHidden(f.Path)
   147  	}
   148  	bindFlag(fr.viper, fr.flags, f.Path)
   149  	return nil
   150  }
   151  
   152  func (fr *flagRegistrar) getTag(f *Field, tagName string) string {
   153  	var key, val string
   154  	key = fmt.Sprintf("%s.%s", tagName, f.Path)
   155  	if fr.tags != nil {
   156  		val = fr.tags[key]
   157  	}
   158  	if val == "" {
   159  		val = f.Tag.Get(tagName)
   160  	}
   161  	return val
   162  }
   163  
   164  func (fr *flagRegistrar) getHideBooleanTag(f *Field) bool {
   165  	boolVal, err := strconv.ParseBool(f.Hide)
   166  	if err != nil {
   167  		return false
   168  	}
   169  	return boolVal
   170  }
   171  
   172  // CmdRunBegin is called at the beginning of each cobra run function
   173  func CmdRunBegin(v *viper.Viper) {
   174  	// If -d or --debug, set debug logging level
   175  	if v.GetBool("debug") {
   176  		log.Level = log.LOG_LEVEL_DEBUG
   177  
   178  		logging.SetLevel(logging.INFO, "bccsp")
   179  		logging.SetLevel(logging.INFO, "bccsp_p11")
   180  		logging.SetLevel(logging.INFO, "bccsp_sw")
   181  	}
   182  }
   183  
   184  // FlagString sets up a flag for a string, binding it to its name
   185  func FlagString(v *viper.Viper, flags *pflag.FlagSet, name, short string, def string, desc string) {
   186  	flags.StringP(name, short, def, desc)
   187  	bindFlag(v, flags, name)
   188  }
   189  
   190  // common binding function
   191  func bindFlag(v *viper.Viper, flags *pflag.FlagSet, name string) {
   192  	flag := flags.Lookup(name)
   193  	if flag == nil {
   194  		panic(fmt.Errorf("failed to lookup '%s'", name))
   195  	}
   196  	v.BindPFlag(name, flag)
   197  }