2
0
config/cmd/cmd.go
2017-12-10 11:33:03 +08:00

140 lines
2.9 KiB
Go

package cmd
import (
"flag"
"fmt"
"reflect"
"strings"
"github.com/eschao/config/util"
)
type anyValue struct {
any reflect.Value
}
func newAnyValue(v Value) *anyValue {
return anyValue{any: v}
}
func (this *anyValue) String() string {
return this.any.Kind().String()
}
func (this *anyValue) Set(v string) error {
kind := this.any.Kind()
switch kind {
case reflect.Bool:
}
return nil
}
type Command struct {
Name string
FlagSet *flag.FlagSet
Usage string
SubCommands map[string]*Command
}
func New(name string) *Command {
cmd := Command{
Name: name,
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
SubCommands: make(map[string]*Command),
}
return &cmd
}
func (this *Command) Init(i interface{}) error {
ptrRef := reflect.ValueOf(i)
if ptrRef.IsNil() || ptrRef.Kind() != reflect.Ptr {
return fmt.Errorf("Expect a structure pointer type instead of %s",
ptrRef.Kind().String())
}
valueOfStruct := ptrRef.Elem()
if valueOfStruct.Kind() != reflect.Struct {
return fmt.Errorf("Expect a structure type instead of %s",
valueOfStruct.Kind().String())
}
return this.parseValue(valueOfStruct)
}
func (this *Command) parseValue(v reflect.Value) error {
typeOfStruct := v.Type()
for i := 0; i < v.NumField(); i++ {
valueOfField := v.Field(i)
kindOfField := valueOfField.Kind()
structOfField := typeOfStruct.Field(i)
if kindOfField == reflect.Ptr {
if !valueOfField.IsNil() && valueOfField.CanSet() {
cmd := this.createCliFlagSet(structOfField.Tag)
if err := cmd.Init(valueOfField.Interface()); err != nil {
return err
}
}
} else if kindOfField == reflect.Struct {
cmd := this.createCliFlagSet(structOfField.Tag)
if err := cmd.parseValue(valueOfField); err != nil {
return err
}
} else {
this.addFlag(valueOfField, structOfField)
}
}
return nil
}
func (this *Command) addFlag(v reflect.Value, f reflect.StructField) {
cmdTag, ok := f.Tag.Lookup("cmd")
if !ok || cmdTag == "" {
return
}
firstSpace := strings.Index(cmdTag, " ")
name := cmdTag
usage := ""
if firstSpace > 0 {
name = cmdTag[0:firstSpace]
usage = cmdTag[firstSpace+1:]
}
//defValue, ok := f.Tag.Lookup("default")
vFlag := ValueFlag{Value: v}
this.FlagSet.Var(&vFlag, name, usage)
//fmt.Printf("[%s]: Added Flag: %s\n", this.Name, name)
}
func (this *Command) createCliFlagSet(tag reflect.StructTag) *Command {
cmdTag, ok := tag.Lookup("cmd")
if !ok || cmdTag == "" {
return this
}
cmd := Command{SubCommands: make(map[string]*Command)}
firstSpace := strings.Index(cmdTag, " ")
name := cmdTag
usage := ""
if firstSpace > 0 {
name = cmdTag[0:firstSpace]
usage = cmdTag[firstSpace+1:]
}
cmd.Name = name
cmd.FlagSet = flag.NewFlagSet(name, flag.ExitOnError)
cmd.Usage = usage
this.SubCommands[name] = &cmd
return &cmd
}
func (this *Command) Parse(i interface{}, args []string) error {
return nil
}