This commit is contained in:
kingecg 2024-10-24 07:15:25 +08:00
parent ff4c06dd0a
commit cf86d63d24
3 changed files with 110 additions and 5 deletions

74
flag.go
View File

@ -4,7 +4,9 @@ import (
"errors" "errors"
"flag" "flag"
"reflect" "reflect"
"regexp"
"strconv" "strconv"
"strings"
) )
type FVSet struct { type FVSet struct {
@ -19,6 +21,56 @@ func (f *FVSet) Parse(args []string) error {
func isPtr(v interface{}) bool { func isPtr(v interface{}) bool {
return reflect.TypeOf(v).Kind() == reflect.Ptr return reflect.TypeOf(v).Kind() == reflect.Ptr
} }
func (f *FVSet) Args() interface{} {
return f.flags.Args()
}
func (f *FVSet) Usage() {
f.flags.Usage()
}
type FVSets struct {
flagSets []*FVSet
subcommands []string
}
func (f *FVSets) Add(v interface{}) error {
fv, err := NewFVSet(v)
if err != nil {
return err
}
fv.flags.Usage = func() {
f.Usage()
}
f.flagSets = append(f.flagSets, fv)
return nil
}
func (f *FVSets) Parse(args []string) error {
for _, v := range f.flagSets {
err := v.Parse(args)
if err != nil {
return err
}
}
return nil
}
func (f *FVSets) Usage() {
//for _, v := range f.flagSets {
//
//}
}
func ToKebabCase(input string) string {
// 将字符串中的大写字母前插入连字符,并转换为小写
re := regexp.MustCompile("([a-z])([A-Z])")
kebab := re.ReplaceAllString(input, "${1}-${2}")
kebab = strings.ToLower(kebab)
// 去除字符串开头和结尾的连字符
kebab = strings.Trim(kebab, "-")
return kebab
}
// NewFVSet 创建一个新的FVSet实例用于处理命令行标志。 // NewFVSet 创建一个新的FVSet实例用于处理命令行标志。
// 参数v是一个指向结构体的指针该结构体的字段将被用作命令行标志。 // 参数v是一个指向结构体的指针该结构体的字段将被用作命令行标志。
@ -51,23 +103,35 @@ func NewFVSet(v interface{}) (*FVSet, error) {
if flaName == "" { if flaName == "" {
flaName = stField.Name flaName = stField.Name
} }
flaName = ToKebabCase(flaName)
flShort := stField.Tag.Get("flag_short")
defVal := stField.Tag.Get("flag_default") defVal := stField.Tag.Get("flag_default")
usageStr := stField.Tag.Get("flag_usage") usageStr := stField.Tag.Get("flag_usage")
if usageStr == "" { if usageStr == "" {
usageStr = "Set " + flaName + "(default " + defVal + ")" usageStr = "Set " + flaName + "(default " + defVal + ")"
} }
addr := field.Addr()
if field.CanSet() { if field.CanSet() {
switch expression := field.Interface().(type) { switch field.Interface().(type) {
case string: case string:
flags.StringVar(&expression, flaName, defVal, usageStr) flags.StringVar(addr.Interface().(*string), flaName, defVal, usageStr)
if flShort != "" {
flags.StringVar(addr.Interface().(*string), flShort, defVal, usageStr)
}
break break
case int: case int:
v, _ := strconv.Atoi(defVal) v, _ := strconv.Atoi(defVal)
flags.IntVar(&expression, flaName, v, usageStr) flags.IntVar(addr.Interface().(*int), flaName, v, usageStr)
if flShort != "" {
flags.IntVar(addr.Interface().(*int), flShort, v, usageStr)
}
break break
case bool: case bool:
flags.BoolVar(&expression, flaName, false, usageStr) flags.BoolVar(addr.Interface().(*bool), flaName, false, usageStr)
if flShort != "" {
flags.BoolVar(addr.Interface().(*bool), flShort, false, usageStr)
}
break break
default: default:

29
flag_test.go Normal file
View File

@ -0,0 +1,29 @@
package command
import (
"testing"
)
func TestParseSingle(t *testing.T) {
type targs struct {
Test string `flag_default:"test" flag_usage:"this is test"`
TestBool bool `flag_short:"b"`
TestInt int
}
sargs := &targs{}
v, _ := NewFVSet(sargs)
v.Usage()
err := Parse([]string{"--test", "test", "--test-bool", "--test-int", "1"}, v)
if err != nil {
t.Error(err)
}
if sargs.Test != "test" {
t.Error("test failed")
}
if !sargs.TestBool {
t.Error("test failed")
}
if sargs.TestInt != 1 {
t.Error("test failed")
}
}

12
usage.go Normal file
View File

@ -0,0 +1,12 @@
package command
type FlagUsage struct {
LongName string
ShortName string
Usage string
}
type Usage struct {
commands []string
flags []string
}