Compare commits

..

No commits in common. "74e7586c36630dcdb39de7ee5c44e977f0b36803" and "9f26d1cf299205ce5a9f993eb9fd77658912c028" have entirely different histories.

5 changed files with 19 additions and 217 deletions

19
.vscode/launch.json vendored
View File

@ -1,19 +0,0 @@
{
// 使 IntelliSense
//
// 访: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Launch Package",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "${fileDirname}",
"args":[
"-a",
"ssd"
]
}
]
}

View File

@ -1,47 +1,3 @@
# command # command
utils for command line app utils for command line app
Provide two style for command line args parse:
- use struct field tag
- use command
## Usage
use struct field tag
```go
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)
```
use command style
```go
package main
import (
"fmt"
"os"
"git.pyer.club/kingecg/command"
)
func main() {
var cmd = command.NewCommand("test", "test command")
cmd.AddArg("arg1", "a", "arg1 description", "default value")
cmd.AddArg("arg2", "b", "arg2 description", "default value")
cmd.AddSubCommand("sub1", "sub1 description")
cmd.Parse(os.Args[1:])
fmt.Println(cmd.GetGlobalOptions())
}
```

View File

@ -2,12 +2,9 @@ package command
import ( import (
"errors" "errors"
"fmt"
"os"
"reflect" "reflect"
"strconv" "strconv"
"strings" "strings"
"text/template"
) )
type Option struct { type Option struct {
@ -18,48 +15,17 @@ type Option struct {
OType string OType string
DefaultValue interface{} DefaultValue interface{}
} }
var UsageTemplate, _ = template.New("Usage").Parse(`Usage:
{{if .ParentCommand }} {{.ParentCommand.Name}} {{end}} {{.Name}} [OPTIONS] [ARGS]
{{ if .Description }}
Description:
{{.Description}}
{{ end }}
{{ if .Args }}
Options:
{{range .Args}}
-{{.ShortName}}|--{{.LongName}} {{.OType}} {{.Description}} default:{{.DefaultValue}}
{{end}}
{{ end }}
{{ if .SubCommands }}
Sub Commands:
{{range .SubCommands}}
{{.Name}} {{.Description}}
{{end}}
{{end}}
`)
type Command struct { type Command struct {
Name string Name string
Description string Description string
Args []*Option Args []*Option
SubCommands []*Command SubCommands []*Command
ParentCommand *Command parentCommand *Command
subcommand string subcommand string
globalOptions map[string]interface{} globalOptions map[string]interface{}
subcommandOptions map[string]interface{} subcommandOptions map[string]interface{}
remainArgs []string
} }
func (c *Command) GetGlobalOptions() map[string]interface{} {
return c.globalOptions
}
func (c *Command) GetSubCommandOptions() map[string]interface{} {
return c.subcommandOptions
}
func (c *Command) GetSubCommand() string {
return c.subcommand
}
func (c *Command) AddArg(name string, shortName string, description string, defaultValue interface{}) { func (c *Command) AddArg(name string, shortName string, description string, defaultValue interface{}) {
oType := reflect.TypeOf(defaultValue).String() oType := reflect.TypeOf(defaultValue).String()
c.Args = append(c.Args, &Option{ c.Args = append(c.Args, &Option{
@ -73,19 +39,19 @@ func (c *Command) AddArg(name string, shortName string, description string, defa
} }
func (c *Command) AddSubCommand(name string, description string) *Command { func (c *Command) AddSubCommand(name string, description string) *Command {
if c.ParentCommand != nil { if c.parentCommand != nil {
panic("Sub commands can only be added to top level commands") panic("Sub commands can only be added to top level commands")
} }
command := &Command{ command := &Command{
Name: name, Name: name,
Description: description, Description: description,
ParentCommand: c, parentCommand: c,
} }
c.SubCommands = append(c.SubCommands, command) c.SubCommands = append(c.SubCommands, command)
return command return command
} }
func (c *Command) Usage() { func (c *Command) Usage() {
UsageTemplate.Execute(os.Stdout, c) panic("not implemented")
} }
func (c *Command) GetOption(name string) *Option { func (c *Command) GetOption(name string) *Option {
if len(name) > 1 { if len(name) > 1 {
@ -102,91 +68,17 @@ func (c *Command) GetOption(name string) *Option {
} }
return nil return nil
} }
func (c *Command) parseError(errMsg string) {
fmt.Println(errMsg) func (c *Command) parse(args []string) {
os.Exit(1)
}
func (c *Command) showHelpWithOption(args []string) {
if len(args) > 0 && (args[0] == "-h" || args[0] == "--help") {
c.Usage()
os.Exit(0)
}
}
func (c *Command) showSubCommandHelp(args []string) {
if len(args) == 2 && args[0] == "help" {
cmd := c.findSubcommand(args[1])
if cmd == nil {
c.parseError("Unknown subcommand " + args[1])
}
cmd.Usage()
os.Exit(0)
}
}
func (c *Command) Parse(args []string) ([]string, error) {
c.showHelpWithOption(args)
c.showSubCommandHelp(args)
if len(args) == 0 { if len(args) == 0 {
if len(c.Args) != 0 || len(c.SubCommands) != 0 || c.ParentCommand == nil { if len(c.Args) != 0 || len(c.SubCommands) != 0 || c.parentCommand == nil {
c.Usage() c.Usage()
} }
if c.ParentCommand != nil { if c.parentCommand != nil {
c.ParentCommand.subcommand = c.Name c.parentCommand.subcommand = c.Name
} }
} }
vargs := args
for {
if len(vargs) == 0 {
break
}
var parsed bool
var err error
vargs, parsed, err = c.longOption(vargs)
if err != nil {
c.parseError(err.Error())
}
if parsed {
continue
}
vargs, parsed, err = c.shortOption(vargs)
if err != nil {
c.parseError(err.Error())
}
if parsed {
continue
}
if len(c.SubCommands) > 0 {
cmd := c.findSubcommand(args[0])
if cmd != nil {
c.subcommand = cmd.Name
vargs = vargs[1:]
vargs, err = cmd.Parse(vargs)
if err != nil {
c.parseError(err.Error())
}
} else {
c.parseError("Unknown subcommand " + args[0])
}
} else {
if c.ParentCommand != nil {
c.ParentCommand.remainArgs = append(c.ParentCommand.remainArgs, vargs[0])
} else {
c.remainArgs = append(c.remainArgs, vargs[0])
}
vargs = vargs[1:]
}
}
return vargs, nil
}
func (c *Command) findSubcommand(cmd string) *Command {
for _, subCmd := range c.SubCommands {
if subCmd.Name == cmd {
return subCmd
}
}
return nil
} }
func (c *Command) longOption(args []string) ([]string, bool, error) { func (c *Command) longOption(args []string) ([]string, bool, error) {
@ -206,8 +98,8 @@ func (c *Command) longOption(args []string) ([]string, bool, error) {
return args, false, err return args, false, err
} }
} }
if c.ParentCommand != nil { if c.parentCommand != nil {
return c.ParentCommand.longOption(args) return c.parentCommand.longOption(args)
} }
return args, false, errors.New("Unknown option " + args[0]) return args, false, errors.New("Unknown option " + args[0])
} }
@ -237,10 +129,10 @@ func (c *Command) shortOption(args []string) ([]string, bool, error) {
} }
} else { } else {
if c.ParentCommand != nil { if c.parentCommand != nil {
opt = c.ParentCommand.GetOption(string(s)) opt = c.parentCommand.GetOption(string(s))
if opt != nil { if opt != nil {
rargs, _, err := c.ParentCommand.getOptValue(args[i:], opt, i != last) rargs, _, err := c.parentCommand.getOptValue(args[i:], opt, i != last)
if err == nil { if err == nil {
return rargs, true, nil return rargs, true, nil
} else { } else {
@ -258,8 +150,8 @@ func (c *Command) shortOption(args []string) ([]string, bool, error) {
func (c *Command) getOptValue(args []string, opt *Option, isFixBool bool) ([]string, interface{}, error) { func (c *Command) getOptValue(args []string, opt *Option, isFixBool bool) ([]string, interface{}, error) {
paramMap := c.globalOptions paramMap := c.globalOptions
if c.ParentCommand != nil { if c.parentCommand != nil {
paramMap = c.ParentCommand.subcommandOptions paramMap = c.parentCommand.subcommandOptions
} }
if isFixBool { if isFixBool {
if opt.OType != "bool" { if opt.OType != "bool" {
@ -304,18 +196,8 @@ func (c *Command) getOptValue(args []string, opt *Option, isFixBool bool) ([]str
return args[2:], true, nil return args[2:], true, nil
} }
case "default": case "default":
return args, nil, errors.New("unsupported type") return args, nil, errors.New("Unsupported type")
} }
} }
return args, nil, errors.New("unsupported type") return args, nil, errors.New("Unsupported type")
}
func NewCommand(name string, desc string) *Command {
return &Command{
Name: name,
Description: desc,
globalOptions: map[string]interface{}{},
subcommandOptions: map[string]interface{}{},
remainArgs: []string{},
}
} }

View File

@ -1,17 +0,0 @@
package main
import (
"fmt"
"os"
"git.pyer.club/kingecg/command"
)
func main() {
var cmd = command.NewCommand("test", "test command")
cmd.AddArg("arg1", "a", "arg1 description", "default value")
cmd.AddArg("arg2", "b", "arg2 description", "default value")
cmd.AddSubCommand("sub1", "sub1 description")
cmd.Parse(os.Args[1:])
fmt.Println(cmd.GetGlobalOptions())
}