This commit is contained in:
kingecg 2024-10-22 01:21:09 +08:00
parent 8df9a5b232
commit ff4c06dd0a
1 changed files with 110 additions and 0 deletions

110
flag.go Normal file
View File

@ -0,0 +1,110 @@
package command
import (
"errors"
"flag"
"reflect"
"strconv"
)
type FVSet struct {
Name string
Value *any
flags flag.FlagSet
}
func (f *FVSet) Parse(args []string) error {
return f.flags.Parse(args)
}
func isPtr(v interface{}) bool {
return reflect.TypeOf(v).Kind() == reflect.Ptr
}
// NewFVSet 创建一个新的FVSet实例用于处理命令行标志。
// 参数v是一个指向结构体的指针该结构体的字段将被用作命令行标志。
// 返回值是一个指向FVSet的指针和一个错误对象如果操作成功错误对象为nil。
// 如果v不是指向结构体的指针函数将返回错误。
func NewFVSet(v interface{}) (*FVSet, error) {
// 判断v是不是指针
vv := reflect.ValueOf(v)
if !isPtr(v) {
return nil, errors.New("v must be a pointer")
}
// 判断指针指向的值是不是结构体
vvv := vv.Elem()
if vvv.Kind() != reflect.Struct {
return nil, errors.New("v must be a pointer to a struct")
}
flags := flag.NewFlagSet(vvv.Type().Name(), flag.ContinueOnError)
name := vvv.Type().Name()
// 遍历结构体字段
for i := 0; i < vvv.NumField(); i++ {
//skip private field
stField := vvv.Type().Field(i)
if stField.PkgPath != "" {
continue
}
// 获取字段名
field := vvv.Field(i)
nameTag := stField.Tag.Get("flag_name")
flaName := nameTag
if flaName == "" {
flaName = stField.Name
}
defVal := stField.Tag.Get("flag_default")
usageStr := stField.Tag.Get("flag_usage")
if usageStr == "" {
usageStr = "Set " + flaName + "(default " + defVal + ")"
}
if field.CanSet() {
switch expression := field.Interface().(type) {
case string:
flags.StringVar(&expression, flaName, defVal, usageStr)
break
case int:
v, _ := strconv.Atoi(defVal)
flags.IntVar(&expression, flaName, v, usageStr)
break
case bool:
flags.BoolVar(&expression, flaName, false, usageStr)
break
default:
return nil, errors.New("unsupported type")
}
}
}
return &FVSet{
Name: name,
Value: &v,
flags: *flags,
}, nil
}
// Parse is used to parse command line arguments based on one or more flag sets.
// args represents the list of command line arguments.
// flagSet is a variable-length parameter that contains the flag sets to be parsed.
// If no flag set is provided, it throws a panic exception.
// If only one flag set is provided, it directly parses the arguments with that flag set.
// If multiple flag sets are provided, it attempts to match and parse based on the first argument in args.
// If no matching flag set is found, it returns an error.
func Parse(args []string, flagSet ...*FVSet) error {
// Check if the flag set is missing, if so, throw a panic exception.
if len(flagSet) == 0 {
panic("flag set missing")
}
// If only one flag set is provided, directly parse the arguments with that flag set.
if len(flagSet) == 1 {
return flagSet[0].Parse(args)
}
// Iterate through the flag sets to find a match for parsing.
for _, f := range flagSet {
// If a matching flag set is found, parse the remaining arguments with that flag set.
if f.Name == args[0] {
return f.Parse(args[1:])
}
}
// If no matching flag set is found, return an error.
return errors.New("flag set not found")
}