268 lines
6.2 KiB
Go
268 lines
6.2 KiB
Go
package argparse
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"reflect"
|
|
"strings"
|
|
)
|
|
|
|
type Parser struct {
|
|
args []*arg
|
|
showHelp bool
|
|
parsed bool
|
|
}
|
|
|
|
type Option struct {
|
|
Require bool
|
|
}
|
|
|
|
type arg struct {
|
|
sname string
|
|
lname string
|
|
// value item count
|
|
size int
|
|
value interface{}
|
|
defaultValue interface{}
|
|
description string
|
|
unique bool
|
|
parsed bool
|
|
opts *Option
|
|
}
|
|
|
|
func New() *Parser {
|
|
return &Parser{
|
|
args: make([]*arg, 0),
|
|
}
|
|
}
|
|
|
|
func (p *Parser) addArg(a *arg) error {
|
|
for _, v := range p.args {
|
|
if (a.sname != "" && v.sname == a.sname) || (a.lname != "" && v.lname == a.lname) {
|
|
return errors.New("option name dup")
|
|
}
|
|
}
|
|
p.args = append(p.args, a)
|
|
|
|
return nil
|
|
}
|
|
|
|
func (p *Parser) typeVar(i interface{}, defVal interface{}, short, long, description string, size int, unique bool, opts *Option) {
|
|
t := reflect.ValueOf(i)
|
|
if t.Kind() != reflect.Ptr {
|
|
panic(errors.New("var type not ptr"))
|
|
}
|
|
if short == "" && long == "" {
|
|
panic(errors.New("short name and long name is empty"))
|
|
}
|
|
|
|
a := &arg{
|
|
sname: short,
|
|
lname: long,
|
|
value: i,
|
|
defaultValue: defVal,
|
|
description: description,
|
|
size: size,
|
|
unique: unique,
|
|
opts: opts,
|
|
}
|
|
|
|
if err := p.addArg(a); err != nil {
|
|
panic(fmt.Errorf("unable to add String: %s\n", err))
|
|
}
|
|
}
|
|
|
|
func (p *Parser) Help(short, long string) {
|
|
p.typeVar(&p.showHelp, false, short, long, "show usage help", 0, true, nil)
|
|
}
|
|
|
|
func (p *Parser) printHelp() {
|
|
sb := &strings.Builder{}
|
|
sb.WriteString("Usage:\n")
|
|
for _, v := range p.args {
|
|
if _, err := sb.WriteString(fmt.Sprintf("\t%s\t%s\t\t%s\n", v.name(), v.getType(), v.description)); err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
fmt.Println(sb.String())
|
|
// if flag.Lookup("test.v") == nil {
|
|
os.Exit(2)
|
|
// }
|
|
}
|
|
|
|
func (p *Parser) Parse(a []string) error {
|
|
copyArg := make([]string, len(a))
|
|
copy(copyArg, a)
|
|
|
|
err := p.parse(©Arg)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (p *Parser) parse(args *[]string) error {
|
|
if p.parsed {
|
|
return nil
|
|
}
|
|
if len(p.args) < 1 {
|
|
return nil
|
|
}
|
|
|
|
err := p.parseArguemtns(args)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
p.parsed = true
|
|
|
|
if p.showHelp == true {
|
|
p.printHelp()
|
|
}
|
|
|
|
p.setDefaultValue()
|
|
|
|
return p.checkRequired()
|
|
}
|
|
|
|
func (p *Parser) setDefaultValue() {
|
|
for _, v := range p.args {
|
|
// fmt.Printf("show %s , parsed: %v, defVal: %v\n", v.name(), v.parsed, v.defaultValue)
|
|
if !v.parsed {
|
|
t := reflect.ValueOf(v.value)
|
|
if t.Kind() == reflect.Ptr {
|
|
t = t.Elem()
|
|
}
|
|
t.Set(reflect.ValueOf(v.defaultValue))
|
|
// *v.value = v.defaultValue
|
|
}
|
|
}
|
|
}
|
|
|
|
func (p *Parser) checkRequired() (err error) {
|
|
for _, v := range p.args {
|
|
if v.opts != nil && v.opts.Require && !v.parsed {
|
|
return fmt.Errorf("[%s] is required", v.name())
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func (p *Parser) parseArguemtns(args *[]string) error {
|
|
n := len(p.args)
|
|
|
|
for i := 0; i < n; i++ {
|
|
nn := len(*args)
|
|
oarg := p.args[i]
|
|
|
|
for j := 0; j < nn; j++ {
|
|
s := (*args)[j]
|
|
if s == "" {
|
|
continue
|
|
}
|
|
ct, err := oarg.check(s)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if ct > 0 {
|
|
valpos := j + 1
|
|
if len(*args) < valpos+oarg.size {
|
|
return fmt.Errorf("no enough arguments for %s", oarg.name())
|
|
}
|
|
err := oarg.parse((*args)[valpos : valpos+oarg.size])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
oarg.reduce(j, args)
|
|
continue
|
|
}
|
|
}
|
|
// if oarg.opts != nil && oarg.opts.Require && !oarg.parsed {
|
|
// return fmt.Errorf("[%s] is required", oarg.name())
|
|
// }
|
|
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (p *Parser) String(defaultValue, short, long, description string, opts *Option) *string {
|
|
var result string
|
|
|
|
p.typeVar(&result, defaultValue, short, long, description, 1, true, opts)
|
|
|
|
return &result
|
|
}
|
|
func (p *Parser) StringVar(i *string, defaultValue, short, long, description string, opts *Option) {
|
|
p.typeVar(i, defaultValue, short, long, description, 1, true, opts)
|
|
}
|
|
|
|
func (p *Parser) Int(defaultValue int, short, long, description string, opts *Option) *int {
|
|
var result int
|
|
|
|
p.typeVar(&result, defaultValue, short, long, description, 1, true, opts)
|
|
|
|
return &result
|
|
}
|
|
func (p *Parser) IntVar(i *int, defaultValue int, short, long, description string, opts *Option) {
|
|
p.typeVar(i, defaultValue, short, long, description, 1, true, opts)
|
|
}
|
|
|
|
func (p *Parser) Bool(defaultValue bool, short, long, description string, opts *Option) *bool {
|
|
var result bool
|
|
|
|
p.typeVar(&result, defaultValue, short, long, description, 0, true, opts)
|
|
|
|
return &result
|
|
}
|
|
func (p *Parser) BoolVar(i *bool, defaultValue bool, short, long, description string, opts *Option) {
|
|
p.typeVar(i, defaultValue, short, long, description, 0, true, opts)
|
|
}
|
|
|
|
func (p *Parser) Float(defaultValue float64, short, long, description string, opts *Option) *float64 {
|
|
var result float64
|
|
|
|
p.typeVar(&result, defaultValue, short, long, description, 1, true, opts)
|
|
|
|
return &result
|
|
}
|
|
func (p *Parser) FloatVar(i *float64, defaultValue float64, short, long, description string, opts *Option) {
|
|
p.typeVar(i, defaultValue, short, long, description, 1, true, opts)
|
|
}
|
|
|
|
func (p *Parser) StringSlice(defaultValue []string, short, long, description string, opts *Option) *[]string {
|
|
var result []string
|
|
|
|
p.typeVar(&result, defaultValue, short, long, description, 1, false, opts)
|
|
|
|
return &result
|
|
}
|
|
func (p *Parser) StringSliceVar(i *[]string, defaultValue []string, short, long, description string, opts *Option) {
|
|
p.typeVar(i, defaultValue, short, long, description, 1, false, opts)
|
|
}
|
|
|
|
func (p *Parser) IntSlice(defaultValue []int, short, long, description string, opts *Option) *[]int {
|
|
var result []int
|
|
|
|
p.typeVar(&result, defaultValue, short, long, description, 1, false, opts)
|
|
|
|
return &result
|
|
}
|
|
func (p *Parser) IntSliceVar(i *[]int, defaultValue []int, short, long, description string, opts *Option) {
|
|
p.typeVar(i, defaultValue, short, long, description, 1, false, opts)
|
|
}
|
|
|
|
func (p *Parser) FloatSlice(defaultValue []float64, short, long, description string, opts *Option) *[]float64 {
|
|
var result []float64
|
|
|
|
p.typeVar(&result, defaultValue, short, long, description, 1, false, opts)
|
|
|
|
return &result
|
|
}
|
|
func (p *Parser) FloatSliceVar(i *[]float64, defaultValue []float64, short, long, description string, opts *Option) {
|
|
p.typeVar(i, defaultValue, short, long, description, 1, false, opts)
|
|
}
|