update
This commit is contained in:
		
							parent
							
								
									8f6edca654
								
							
						
					
					
						commit
						26b2fecb36
					
				
							
								
								
									
										118
									
								
								cli/cli.go
									
									
									
									
									
								
							
							
						
						
									
										118
									
								
								cli/cli.go
									
									
									
									
									
								
							@ -1,118 +0,0 @@
 | 
				
			|||||||
package cli
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"flag"
 | 
					 | 
				
			||||||
	"fmt"
 | 
					 | 
				
			||||||
	"reflect"
 | 
					 | 
				
			||||||
	"strings"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type CliFlag struct {
 | 
					 | 
				
			||||||
	Name     string
 | 
					 | 
				
			||||||
	Usage    string
 | 
					 | 
				
			||||||
	DefValue *string
 | 
					 | 
				
			||||||
	CliFlags *[]CliFlag
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type ValueFlag struct {
 | 
					 | 
				
			||||||
	Value reflect.Value
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (this *ValueFlag) String() string {
 | 
					 | 
				
			||||||
	return this.Value.Kind().String()
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (this *ValueFlag) Set(v string) error {
 | 
					 | 
				
			||||||
	return nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func Parse(i interface{}, cliFlag *CliFlag) 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 parseValue(valueOfStruct, cliFlag)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func parseValue(v reflect.Value, cliParent *CliFlag) error {
 | 
					 | 
				
			||||||
	cliFlags := []CliFlag{}
 | 
					 | 
				
			||||||
	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() {
 | 
					 | 
				
			||||||
				cliFlag := createCliFlagFromTag(structOfField.Tag)
 | 
					 | 
				
			||||||
				if cliFlag != nil {
 | 
					 | 
				
			||||||
					cliFlags = append(cliFlags, *cliFlag)
 | 
					 | 
				
			||||||
				} else {
 | 
					 | 
				
			||||||
					cliFlag = cliParent
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				Parse(valueOfField.Interface(), cliFlag)
 | 
					 | 
				
			||||||
			} else {
 | 
					 | 
				
			||||||
				continue
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		} else if kindOfField == reflect.Struct {
 | 
					 | 
				
			||||||
			cliFlag := createCliFlagFromTag(structOfField.Tag)
 | 
					 | 
				
			||||||
			if cliFlag != nil {
 | 
					 | 
				
			||||||
				cliFlags = append(cliFlags, *cliFlag)
 | 
					 | 
				
			||||||
			} else {
 | 
					 | 
				
			||||||
				cliFlag = cliParent
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			parseValue(valueOfField, cliFlag)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if cliFlag := installFlag(valueOfField, structOfField); cliFlag != nil {
 | 
					 | 
				
			||||||
			cliFlags = append(cliFlags, *cliFlag)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if len(cliFlags) > 0 {
 | 
					 | 
				
			||||||
		cliParent.CliFlags = &cliFlags
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func installFlag(v reflect.Value, f reflect.StructField) *CliFlag {
 | 
					 | 
				
			||||||
	cliFlag := createCliFlagFromTag(f.Tag)
 | 
					 | 
				
			||||||
	if cliFlag != nil {
 | 
					 | 
				
			||||||
		vFlag := ValueFlag{Value: v}
 | 
					 | 
				
			||||||
		flag.Var(&vFlag, cliFlag.Name, cliFlag.Usage)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	fmt.Printf("Installed flag: %d", cliFlag.Name)
 | 
					 | 
				
			||||||
	return cliFlag
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func createCliFlagFromTag(tag reflect.StructTag) *CliFlag {
 | 
					 | 
				
			||||||
	cliTag, ok := tag.Lookup("cli")
 | 
					 | 
				
			||||||
	if !ok || cliTag == "" {
 | 
					 | 
				
			||||||
		return nil
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	cliFlag := CliFlag{}
 | 
					 | 
				
			||||||
	firstSpace := strings.Index(cliTag, " ")
 | 
					 | 
				
			||||||
	cliFlag.Name = cliTag
 | 
					 | 
				
			||||||
	if firstSpace > 0 {
 | 
					 | 
				
			||||||
		cliFlag.Name = cliTag[0:firstSpace]
 | 
					 | 
				
			||||||
		cliFlag.Usage = cliTag[firstSpace+1:]
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	defValue, ok := tag.Lookup("default")
 | 
					 | 
				
			||||||
	if !ok {
 | 
					 | 
				
			||||||
		cliFlag.DefValue = &defValue
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return &cliFlag
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,38 +0,0 @@
 | 
				
			|||||||
package cli
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"flag"
 | 
					 | 
				
			||||||
	"fmt"
 | 
					 | 
				
			||||||
	"testing"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type DBCli struct {
 | 
					 | 
				
			||||||
	Host     string `cli:"hostname database server hostname"`
 | 
					 | 
				
			||||||
	Port     string `cli:"port database server port"`
 | 
					 | 
				
			||||||
	User     string `cli:"user database username"`
 | 
					 | 
				
			||||||
	Password string `cli:"password database user password"`
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type MyCli struct {
 | 
					 | 
				
			||||||
	Server string `cli:"-server server URL"`
 | 
					 | 
				
			||||||
	DBCli  DBCli  `cli:"database database information"`
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestMain(m *testing.M) {
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestCli(t *testing.T) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	hostname := flag.String("hostanme", "127.0.0.1", "hostanme value")
 | 
					 | 
				
			||||||
	fmt.Printf("Hostname: %s", hostname)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	cli := DBCli{}
 | 
					 | 
				
			||||||
	root := CliFlag{}
 | 
					 | 
				
			||||||
	err := Parse(&cli, &root)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Errorf("Can't parse cli. %s", err.Error())
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	flag.Parse()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								cmd/.cli.go.swp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								cmd/.cli.go.swp
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								cmd/.cli_test.go.swp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								cmd/.cli_test.go.swp
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										139
									
								
								cmd/cmd.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										139
									
								
								cmd/cmd.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,139 @@
 | 
				
			|||||||
 | 
					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
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										120
									
								
								cmd/cmd_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								cmd/cmd_test.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,120 @@
 | 
				
			|||||||
 | 
					package cmd
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/stretchr/testify/assert"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type dbConfig struct {
 | 
				
			||||||
 | 
						Host     string    `cmd:"dbHost database server hostname"`
 | 
				
			||||||
 | 
						Port     int       `cmd:"dbPort database server port"`
 | 
				
			||||||
 | 
						User     string    `cmd:"dbUser database username"`
 | 
				
			||||||
 | 
						Password string    `cmd:"dbPassword database user password"`
 | 
				
			||||||
 | 
						Log      logConfig `cmd:"log database log configuration"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type loginConfig struct {
 | 
				
			||||||
 | 
						User     string `cmd:"user login username"`
 | 
				
			||||||
 | 
						Password string `cmd:"password login password"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type logConfig struct {
 | 
				
			||||||
 | 
						Path  string `cmd:"path log path"`
 | 
				
			||||||
 | 
						Level string `cmd:"level log level {debug|warning|error}"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type serviceConfig struct {
 | 
				
			||||||
 | 
						Host     string       `cmd:"hostname service hostname"`
 | 
				
			||||||
 | 
						Port     int          `cmd:"port service port"`
 | 
				
			||||||
 | 
						DBConfig dbConfig     `cmd:"database database configuration"`
 | 
				
			||||||
 | 
						Login    *loginConfig `cmd:"login login user and password"`
 | 
				
			||||||
 | 
						Log      logConfig    `cmd:"log service log configuration"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestServiceCommand(t *testing.T) {
 | 
				
			||||||
 | 
						assert := assert.New(t)
 | 
				
			||||||
 | 
						serviceConfig := serviceConfig{}
 | 
				
			||||||
 | 
						cmd := New("Service")
 | 
				
			||||||
 | 
						err := cmd.Init(&serviceConfig)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Errorf("Can't init service command. %s", err.Error())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// assert service cmd
 | 
				
			||||||
 | 
						assert.NotNil(cmd.FlagSet)
 | 
				
			||||||
 | 
						assert.NotNil(cmd.FlagSet.Lookup("hostname"),
 | 
				
			||||||
 | 
							"service cmd should have {hostname} parameter")
 | 
				
			||||||
 | 
						assert.NotNil(cmd.FlagSet.Lookup("port"),
 | 
				
			||||||
 | 
							"service cmd should have {port} parameter")
 | 
				
			||||||
 | 
						assert.Equal(2, len(cmd.SubCommands),
 | 
				
			||||||
 | 
							"service cmd should have 2 sub cmds")
 | 
				
			||||||
 | 
						assert.Nil(cmd.SubCommands["login"],
 | 
				
			||||||
 | 
							"service cmd shouldn't have {login} sub cmd")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// assert database sub cmd
 | 
				
			||||||
 | 
						dbCmd := cmd.SubCommands["database"]
 | 
				
			||||||
 | 
						assert.NotNil(dbCmd, "service cmd should have {database} sub cmd")
 | 
				
			||||||
 | 
						assert.NotNil(dbCmd.FlagSet.Lookup("dbHost"),
 | 
				
			||||||
 | 
							"database cmd should have {dbHost} parameter")
 | 
				
			||||||
 | 
						assert.NotNil(dbCmd.FlagSet.Lookup("dbPort"),
 | 
				
			||||||
 | 
							"database cmd should have {dbPort} parameter")
 | 
				
			||||||
 | 
						assert.NotNil(dbCmd.FlagSet.Lookup("dbUser"),
 | 
				
			||||||
 | 
							"database cmd should have {dbUser} parameter")
 | 
				
			||||||
 | 
						assert.NotNil(dbCmd.FlagSet.Lookup("dbPassword"),
 | 
				
			||||||
 | 
							"database cmd should have {dbPassword} parameter")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// assert database log sub cmd
 | 
				
			||||||
 | 
						dbLogCmd := dbCmd.SubCommands["log"]
 | 
				
			||||||
 | 
						assert.NotNil(dbCmd, "database cmd should have {log} sub cmd")
 | 
				
			||||||
 | 
						assert.NotNil(dbLogCmd.FlagSet.Lookup("path"),
 | 
				
			||||||
 | 
							"database log cmd should have {path} parameter")
 | 
				
			||||||
 | 
						assert.NotNil(dbLogCmd.FlagSet.Lookup("level"),
 | 
				
			||||||
 | 
							"database log cmd should have {level} parameter")
 | 
				
			||||||
 | 
						assert.Equal(0, len(dbLogCmd.SubCommands),
 | 
				
			||||||
 | 
							"database log cmd shouldn't have sub cmd")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// assert log cmd
 | 
				
			||||||
 | 
						logCmd := cmd.SubCommands["log"]
 | 
				
			||||||
 | 
						assert.NotNil(logCmd, "service cmd should have {log} sub cmd")
 | 
				
			||||||
 | 
						assert.NotNil(logCmd.FlagSet.Lookup("path"),
 | 
				
			||||||
 | 
							"log cmd should have {path} parameter")
 | 
				
			||||||
 | 
						assert.NotNil(logCmd.FlagSet.Lookup("level"),
 | 
				
			||||||
 | 
							"log cmd should have {level} parameter")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestLoginSubCommand(t *testing.T) {
 | 
				
			||||||
 | 
						assert := assert.New(t)
 | 
				
			||||||
 | 
						serviceConfig := serviceConfig{Login: &loginConfig{}}
 | 
				
			||||||
 | 
						cmd := New("Service")
 | 
				
			||||||
 | 
						err := cmd.Init(&serviceConfig)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Errorf("Can't init service command. %s", err.Error())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// assert login sub command
 | 
				
			||||||
 | 
						loginCmd := cmd.SubCommands["login"]
 | 
				
			||||||
 | 
						assert.NotNil(loginCmd, "service cmd should have {login} sub cmd")
 | 
				
			||||||
 | 
						assert.NotNil(loginCmd.FlagSet.Lookup("user"),
 | 
				
			||||||
 | 
							"login cmd should have {user} parameter")
 | 
				
			||||||
 | 
						assert.NotNil(loginCmd.FlagSet.Lookup("password"),
 | 
				
			||||||
 | 
							"login cmd should have {password} parameter")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestLoginCommand(t *testing.T) {
 | 
				
			||||||
 | 
						loginConfig := loginConfig{}
 | 
				
			||||||
 | 
						cmd := New("Login")
 | 
				
			||||||
 | 
						if err := cmd.Init(&loginConfig); err != nil {
 | 
				
			||||||
 | 
							t.Errorf("Can't init login command. %s", err.Error())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						args := []string{"-user", "test", "-password", "pass", "log", "database"}
 | 
				
			||||||
 | 
						if err := cmd.FlagSet.Parse(args); err != nil {
 | 
				
			||||||
 | 
							t.Errorf("Can't parse login command. %s", err.Error())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						uknArgs := cmd.FlagSet.Args()
 | 
				
			||||||
 | 
						for i, arg := range uknArgs {
 | 
				
			||||||
 | 
							t.Logf("arg[%d]=%s", i, arg)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										106
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										106
									
								
								main.go
									
									
									
									
									
								
							@ -1,10 +1,114 @@
 | 
				
			|||||||
package main
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"flag"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
 | 
						"os"
 | 
				
			||||||
 | 
						//"github.com/eschao/Config/cli"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type DBCli struct {
 | 
				
			||||||
 | 
						Host     string `cli:"hostname database server hostname"`
 | 
				
			||||||
 | 
						Port     string `cli:"port database server port"`
 | 
				
			||||||
 | 
						User     string `cli:"user database username"`
 | 
				
			||||||
 | 
						Password string `cli:"password database user password"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func main() {
 | 
					func main() {
 | 
				
			||||||
	cli := DBCli{}
 | 
					
 | 
				
			||||||
 | 
						countCommand := flag.NewFlagSet("count", flag.ExitOnError)
 | 
				
			||||||
 | 
						listCommand := flag.NewFlagSet("list", flag.ExitOnError)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Count subcommand flag pointers
 | 
				
			||||||
 | 
						// Adding a new choice for --metric of 'substring' and a new --substring flag
 | 
				
			||||||
 | 
						countTextPtr := countCommand.String("text", "", "Text to parse. (Required)")
 | 
				
			||||||
 | 
						countMetricPtr := countCommand.String("metric", "chars", "Metric {chars|words|lines|substring}. (Required)")
 | 
				
			||||||
 | 
						countSubstringPtr := countCommand.String("substring", "", "The substring to be counted. Required for --metric=substring")
 | 
				
			||||||
 | 
						countUniquePtr := countCommand.Bool("unique", false, "Measure unique values of a metric.")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// List subcommand flag pointers
 | 
				
			||||||
 | 
						listTextPtr := listCommand.String("text", "", "Text to parse. (Required)")
 | 
				
			||||||
 | 
						listMetricPtr := listCommand.String("metric", "chars", "Metric <chars|words|lines>. (Required)")
 | 
				
			||||||
 | 
						listUniquePtr := listCommand.Bool("unique", false, "Measure unique values of a metric.")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Verify that a subcommand has been provided
 | 
				
			||||||
 | 
						// os.Arg[0] is the main command
 | 
				
			||||||
 | 
						// os.Arg[1] will be the subcommand
 | 
				
			||||||
 | 
						if len(os.Args) < 2 {
 | 
				
			||||||
 | 
							//fmt.Println("list or count subcommand is required")
 | 
				
			||||||
 | 
							flag.PrintDefaults()
 | 
				
			||||||
 | 
							os.Exit(1)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Switch on the subcommand
 | 
				
			||||||
 | 
						// Parse the flags for appropriate FlagSet
 | 
				
			||||||
 | 
						// FlagSet.Parse() requires a set of arguments to parse as input
 | 
				
			||||||
 | 
						// os.Args[2:] will be all arguments starting after the subcommand at os.Args[1]
 | 
				
			||||||
 | 
						switch os.Args[1] {
 | 
				
			||||||
 | 
						case "list":
 | 
				
			||||||
 | 
							listCommand.Parse(os.Args[2:])
 | 
				
			||||||
 | 
						case "count":
 | 
				
			||||||
 | 
							countCommand.Parse(os.Args[2:])
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							flag.PrintDefaults()
 | 
				
			||||||
 | 
							os.Exit(1)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Check which subcommand was Parsed using the FlagSet.Parsed() function. Handle each case accordingly.
 | 
				
			||||||
 | 
						// FlagSet.Parse() will evaluate to false if no flags were parsed (i.e. the user did not provide any flags)
 | 
				
			||||||
 | 
						if listCommand.Parsed() {
 | 
				
			||||||
 | 
							// Required Flags
 | 
				
			||||||
 | 
							if *listTextPtr == "" {
 | 
				
			||||||
 | 
								listCommand.PrintDefaults()
 | 
				
			||||||
 | 
								os.Exit(1)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							//Choice flag
 | 
				
			||||||
 | 
							metricChoices := map[string]bool{"chars": true, "words": true, "lines": true}
 | 
				
			||||||
 | 
							if _, validChoice := metricChoices[*listMetricPtr]; !validChoice {
 | 
				
			||||||
 | 
								listCommand.PrintDefaults()
 | 
				
			||||||
 | 
								os.Exit(1)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							// Print
 | 
				
			||||||
 | 
							fmt.Printf("textPtr: %s, metricPtr: %s, uniquePtr: %t\n", *listTextPtr, *listMetricPtr, *listUniquePtr)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if countCommand.Parsed() {
 | 
				
			||||||
 | 
							// Required Flags
 | 
				
			||||||
 | 
							if *countTextPtr == "" {
 | 
				
			||||||
 | 
								countCommand.PrintDefaults()
 | 
				
			||||||
 | 
								os.Exit(1)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							// If the metric flag is substring, the substring flag is required
 | 
				
			||||||
 | 
							if *countMetricPtr == "substring" && *countSubstringPtr == "" {
 | 
				
			||||||
 | 
								countCommand.PrintDefaults()
 | 
				
			||||||
 | 
								os.Exit(1)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							//If the metric flag is not substring, the substring flag must not be used
 | 
				
			||||||
 | 
							if *countMetricPtr != "substring" && *countSubstringPtr != "" {
 | 
				
			||||||
 | 
								fmt.Println("--substring may only be used with --metric=substring.")
 | 
				
			||||||
 | 
								countCommand.PrintDefaults()
 | 
				
			||||||
 | 
								os.Exit(1)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							//Choice flag
 | 
				
			||||||
 | 
							metricChoices := map[string]bool{"chars": true, "words": true, "lines": true, "substring": true}
 | 
				
			||||||
 | 
							if _, validChoice := metricChoices[*listMetricPtr]; !validChoice {
 | 
				
			||||||
 | 
								countCommand.PrintDefaults()
 | 
				
			||||||
 | 
								os.Exit(1)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							//Print
 | 
				
			||||||
 | 
							fmt.Printf("textPtr: %s, metricPtr: %s, substringPtr: %v, uniquePtr: %t\n", *countTextPtr, *countMetricPtr, *countSubstringPtr, *countUniquePtr)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
							config := DBCli{}
 | 
				
			||||||
 | 
							root := cli.CliFlag{}
 | 
				
			||||||
 | 
							err := cli.Parse(&config, &root)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								fmt.Printf("Can't parse cli. %s", err.Error())
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							flag.Parse()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							fmt.Printf("Host=%s\n", config.Host)
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										113
									
								
								util/util.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								util/util.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,113 @@
 | 
				
			|||||||
 | 
					package util
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"reflect"
 | 
				
			||||||
 | 
						"strconv"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func SetValueWithBool(v reflect.Value, boolValue string) error {
 | 
				
			||||||
 | 
						value, err := strconv.ParseBool(boolValue)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						v.SetBool(value)
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func SetValueWithFloatX(v reflect.Value, floatValue string, bitSize int) error {
 | 
				
			||||||
 | 
						value, err := strconv.ParseFloat(floatValue, bitSize)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						v.SetFloat(value)
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func SetValueWithIntX(v reflect.Value, intValue string, bitSize int) error {
 | 
				
			||||||
 | 
						value, err := strconv.ParseInt(envValue, 10, bitSize)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						v.SetInt(value)
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func SetValueWithUintX(v reflect.Value, envValue string, bitSize int) error {
 | 
				
			||||||
 | 
						value, err := strconv.ParseUint(envValue, 10, bitSize)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						v.SetUint(value)
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					func setFieldValueWithSlice(name string, v reflect.Value, envValue string,
 | 
				
			||||||
 | 
						separator string) error {
 | 
				
			||||||
 | 
						data := strings.Split(envValue, separator)
 | 
				
			||||||
 | 
						size := len(data)
 | 
				
			||||||
 | 
						if size > 0 {
 | 
				
			||||||
 | 
							slice := reflect.MakeSlice(v.Type(), size, size)
 | 
				
			||||||
 | 
							for i := 0; i < size; i++ {
 | 
				
			||||||
 | 
								ele := slice.Index(i)
 | 
				
			||||||
 | 
								kind := ele.Kind()
 | 
				
			||||||
 | 
								switch kind {
 | 
				
			||||||
 | 
								case reflect.Bool:
 | 
				
			||||||
 | 
									if err := setFieldValueWithBool(name, ele, data[i]); err != nil {
 | 
				
			||||||
 | 
										return err
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								case reflect.String:
 | 
				
			||||||
 | 
									ele.SetString(data[i])
 | 
				
			||||||
 | 
								case reflect.Uint8:
 | 
				
			||||||
 | 
									if err := setFieldValueWithUintX(name, ele, data[i], 8); err != nil {
 | 
				
			||||||
 | 
										return err
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								case reflect.Uint16:
 | 
				
			||||||
 | 
									if err := setFieldValueWithUintX(name, ele, data[i], 16); err != nil {
 | 
				
			||||||
 | 
										return err
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								case reflect.Uint, reflect.Uint32:
 | 
				
			||||||
 | 
									if err := setFieldValueWithUintX(name, ele, data[i], 32); err != nil {
 | 
				
			||||||
 | 
										return err
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								case reflect.Uint64:
 | 
				
			||||||
 | 
									if err := setFieldValueWithUintX(name, ele, data[i], 64); err != nil {
 | 
				
			||||||
 | 
										return err
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								case reflect.Int8:
 | 
				
			||||||
 | 
									if err := setFieldValueWithIntX(name, ele, data[i], 8); err != nil {
 | 
				
			||||||
 | 
										return err
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								case reflect.Int16:
 | 
				
			||||||
 | 
									if err := setFieldValueWithIntX(name, ele, data[i], 16); err != nil {
 | 
				
			||||||
 | 
										return err
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								case reflect.Int, reflect.Int32:
 | 
				
			||||||
 | 
									if err := setFieldValueWithIntX(name, ele, data[i], 32); err != nil {
 | 
				
			||||||
 | 
										return err
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								case reflect.Int64:
 | 
				
			||||||
 | 
									if err := setFieldValueWithIntX(name, ele, data[i], 64); err != nil {
 | 
				
			||||||
 | 
										return err
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								case reflect.Float32:
 | 
				
			||||||
 | 
									if err := setFieldValueWithFloatX(name, ele, data[i], 32); err != nil {
 | 
				
			||||||
 | 
										return err
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								case reflect.Float64:
 | 
				
			||||||
 | 
									if err := setFieldValueWithFloatX(name, ele, data[i], 64); err != nil {
 | 
				
			||||||
 | 
										return err
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								default:
 | 
				
			||||||
 | 
									return fmt.Errorf("%s: can't support type: %s", name, kind.String())
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							v.Set(slice)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}*/
 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user