Add option parsing
This commit is contained in:
		
							parent
							
								
									9079086626
								
							
						
					
					
						commit
						34bd7544b1
					
				
							
								
								
									
										29
									
								
								command.go
								
								
								
								
							
							
						
						
									
										29
									
								
								command.go
								
								
								
								
							| 
						 | 
					@ -67,27 +67,34 @@ func (c *Command) Execute(args []string) {
 | 
				
			||||||
		args = args[1:]
 | 
							args = args[1:]
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := c.opts.Parse(args); err != nil {
 | 
						restArgs, err := c.opts.Parse(args)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
		c.ShowHelp()
 | 
							c.ShowHelp()
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if len(args) > 0 {
 | 
						restArgs, err = opts.Globals().Parse(restArgs)
 | 
				
			||||||
		sc, ok := c.subcommands.Get(args[0])
 | 
						if err != nil {
 | 
				
			||||||
		if ok {
 | 
							c.ShowHelp()
 | 
				
			||||||
			sc.Execute(args[1:])
 | 
							return
 | 
				
			||||||
			return
 | 
						}
 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// TODO: remove when done with option parsing
 | 
						if len(restArgs) > 0 {
 | 
				
			||||||
		if args[0] == "--help" {
 | 
							sc, ok := c.subcommands.Get(restArgs[0])
 | 
				
			||||||
			c.ShowHelp()
 | 
							if ok {
 | 
				
			||||||
 | 
								sc.Execute(restArgs[1:])
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						helpOpt, ok := opts.Globals().GetBool("help")
 | 
				
			||||||
 | 
						if ok && helpOpt.Value() {
 | 
				
			||||||
 | 
							c.ShowHelp()
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if c.CanRun() {
 | 
						if c.CanRun() {
 | 
				
			||||||
		c.Run(args)
 | 
							c.Run(restArgs)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,7 +9,7 @@ type BoolOption struct {
 | 
				
			||||||
	value       bool
 | 
						value       bool
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var _ Option = (*StringOption)(nil)
 | 
					var _ Option = (*BoolOption)(nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func Bool(name, shortName string, defaultValue bool, description string) *BoolOption {
 | 
					func Bool(name, shortName string, defaultValue bool, description string) *BoolOption {
 | 
				
			||||||
	return &BoolOption{
 | 
						return &BoolOption{
 | 
				
			||||||
| 
						 | 
					@ -39,6 +39,7 @@ func (o *BoolOption) ShortName() string {
 | 
				
			||||||
// Value implements Option.
 | 
					// Value implements Option.
 | 
				
			||||||
func (o *BoolOption) Parse(raw string) error {
 | 
					func (o *BoolOption) Parse(raw string) error {
 | 
				
			||||||
	if raw == "" {
 | 
						if raw == "" {
 | 
				
			||||||
 | 
							o.value = !o.value
 | 
				
			||||||
		return nil
 | 
							return nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -51,6 +52,11 @@ func (o *BoolOption) Parse(raw string) error {
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TakesArg implements Option.
 | 
				
			||||||
 | 
					func (*BoolOption) TakesArg() bool {
 | 
				
			||||||
 | 
						return false
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (o *BoolOption) Value() bool {
 | 
					func (o *BoolOption) Value() bool {
 | 
				
			||||||
	return o.value
 | 
						return o.value
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -51,6 +51,11 @@ func (o *FloatOption) Parse(raw string) error {
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TakesArg implements Option.
 | 
				
			||||||
 | 
					func (*FloatOption) TakesArg() bool {
 | 
				
			||||||
 | 
						return true
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (o *FloatOption) Value() float64 {
 | 
					func (o *FloatOption) Value() float64 {
 | 
				
			||||||
	return o.value
 | 
						return o.value
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,7 +9,7 @@ type IntOption struct {
 | 
				
			||||||
	value       int
 | 
						value       int
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var _ Option = (*StringOption)(nil)
 | 
					var _ Option = (*IntOption)(nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func Int(name, shortName string, defaultValue int, description string) *IntOption {
 | 
					func Int(name, shortName string, defaultValue int, description string) *IntOption {
 | 
				
			||||||
	return &IntOption{
 | 
						return &IntOption{
 | 
				
			||||||
| 
						 | 
					@ -51,6 +51,11 @@ func (o *IntOption) Parse(raw string) error {
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TakesArg implements Option.
 | 
				
			||||||
 | 
					func (*IntOption) TakesArg() bool {
 | 
				
			||||||
 | 
						return true
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (o *IntOption) Value() int {
 | 
					func (o *IntOption) Value() int {
 | 
				
			||||||
	return o.value
 | 
						return o.value
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,6 +7,7 @@ type Option interface {
 | 
				
			||||||
	ShortName() string
 | 
						ShortName() string
 | 
				
			||||||
	Description() string
 | 
						Description() string
 | 
				
			||||||
	Parse(raw string) error
 | 
						Parse(raw string) error
 | 
				
			||||||
 | 
						TakesArg() bool
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func Names(o Option) string {
 | 
					func Names(o Option) string {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,143 @@
 | 
				
			||||||
 | 
					package opts
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var (
 | 
				
			||||||
 | 
						ErrInvalidShortOption = errors.New("invalid short option")
 | 
				
			||||||
 | 
						ErrCannotChainOption  = errors.New("cannot chain option as it takes an argument")
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (s Set) Parse(args []string) (restArgs []string, err error) {
 | 
				
			||||||
 | 
						for i := 0; i < len(args); i++ {
 | 
				
			||||||
 | 
							arg := args[i]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Handle regular argument
 | 
				
			||||||
 | 
							if !strings.HasPrefix(arg, "-") {
 | 
				
			||||||
 | 
								restArgs = append(restArgs, arg)
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Handle options terminator
 | 
				
			||||||
 | 
							if arg == "--" {
 | 
				
			||||||
 | 
								restArgs = append(restArgs, args[i+1:]...)
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Handle long option
 | 
				
			||||||
 | 
							if strings.HasPrefix(arg, "--") {
 | 
				
			||||||
 | 
								longName := arg[2:]
 | 
				
			||||||
 | 
								value := ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								equals := strings.Index(longName, "=")
 | 
				
			||||||
 | 
								if equals > 0 {
 | 
				
			||||||
 | 
									longName = longName[:equals]
 | 
				
			||||||
 | 
									value = longName[equals+1:]
 | 
				
			||||||
 | 
								} else if i < len(args)-1 && !strings.HasPrefix(args[i+1], "-") {
 | 
				
			||||||
 | 
									value = args[i+1]
 | 
				
			||||||
 | 
									i++
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								parsed := false
 | 
				
			||||||
 | 
								for _, opt := range s {
 | 
				
			||||||
 | 
									if opt.Name() != longName {
 | 
				
			||||||
 | 
										continue
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if err = opt.Parse(value); err != nil {
 | 
				
			||||||
 | 
										return
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									parsed = true
 | 
				
			||||||
 | 
									break
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if !parsed {
 | 
				
			||||||
 | 
									restArgs = append(restArgs, arg)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Handle short option
 | 
				
			||||||
 | 
							shortNames := arg[1:]
 | 
				
			||||||
 | 
							if len(shortNames) == 0 {
 | 
				
			||||||
 | 
								err = ErrInvalidShortOption
 | 
				
			||||||
 | 
							} else if len(shortNames) == 1 {
 | 
				
			||||||
 | 
								parsed := false
 | 
				
			||||||
 | 
								value := ""
 | 
				
			||||||
 | 
								if i < len(args)-1 && !strings.HasPrefix(args[i+1], "-") {
 | 
				
			||||||
 | 
									value = args[i+1]
 | 
				
			||||||
 | 
									i++
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								for _, opt := range s {
 | 
				
			||||||
 | 
									if opt.ShortName() != shortNames {
 | 
				
			||||||
 | 
										continue
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if err = opt.Parse(value); err != nil {
 | 
				
			||||||
 | 
										return
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									parsed = true
 | 
				
			||||||
 | 
									break
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if !parsed {
 | 
				
			||||||
 | 
									restArgs = append(restArgs, arg)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								for j := 0; j < len(shortNames); j++ {
 | 
				
			||||||
 | 
									shortName := shortNames[j]
 | 
				
			||||||
 | 
									value := ""
 | 
				
			||||||
 | 
									takesValue := false
 | 
				
			||||||
 | 
									parsed := false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									for _, opt := range s {
 | 
				
			||||||
 | 
										if opt.ShortName() != string(shortName) {
 | 
				
			||||||
 | 
											continue
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										if opt.TakesArg() {
 | 
				
			||||||
 | 
											if j > 0 {
 | 
				
			||||||
 | 
												err = ErrCannotChainOption
 | 
				
			||||||
 | 
												return
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
											takesValue = true
 | 
				
			||||||
 | 
											value = shortNames[j+1:]
 | 
				
			||||||
 | 
											value = strings.TrimPrefix(value, "=")
 | 
				
			||||||
 | 
											if len(value) == 0 && i < len(args)-1 && !strings.HasPrefix(args[i+1], "-") {
 | 
				
			||||||
 | 
												value = args[i+1]
 | 
				
			||||||
 | 
												i++
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
											j = len(shortNames)
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										parsed = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										if err = opt.Parse(value); err != nil {
 | 
				
			||||||
 | 
											return
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										break
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if !parsed {
 | 
				
			||||||
 | 
										if takesValue {
 | 
				
			||||||
 | 
											restArgs = append(restArgs, arg)
 | 
				
			||||||
 | 
											break
 | 
				
			||||||
 | 
										} else {
 | 
				
			||||||
 | 
											restArgs = append(restArgs, fmt.Sprintf("-%c", shortName))
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										91
									
								
								opts/set.go
								
								
								
								
							
							
						
						
									
										91
									
								
								opts/set.go
								
								
								
								
							| 
						 | 
					@ -6,23 +6,6 @@ func NewSet() Set {
 | 
				
			||||||
	return Set{}
 | 
						return Set{}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (s *Set) Add(f Option) {
 | 
					 | 
				
			||||||
	*s = append(*s, f)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (s Set) Get(name string) (Option, bool) {
 | 
					 | 
				
			||||||
	for _, f := range s {
 | 
					 | 
				
			||||||
		if f.Name() == name {
 | 
					 | 
				
			||||||
			return f, true
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if f.ShortName() == name {
 | 
					 | 
				
			||||||
			return f, true
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return nil, false
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (s Set) MaxWidth() int {
 | 
					func (s Set) MaxWidth() int {
 | 
				
			||||||
	max := 0
 | 
						max := 0
 | 
				
			||||||
	for _, f := range s {
 | 
						for _, f := range s {
 | 
				
			||||||
| 
						 | 
					@ -33,7 +16,75 @@ func (s Set) MaxWidth() int {
 | 
				
			||||||
	return max
 | 
						return max
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// TODO: Implement
 | 
					func (s *Set) Add(f Option) {
 | 
				
			||||||
func (s Set) Parse(args []string) error {
 | 
						*s = append(*s, f)
 | 
				
			||||||
	return nil
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (s Set) Get(name string) (Option, bool) {
 | 
				
			||||||
 | 
						for _, o := range s {
 | 
				
			||||||
 | 
							if o.Name() == name {
 | 
				
			||||||
 | 
								return o, true
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if o.ShortName() == name {
 | 
				
			||||||
 | 
								return o, true
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil, false
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (s Set) GetBool(name string) (*BoolOption, bool) {
 | 
				
			||||||
 | 
						o, ok := s.Get(name)
 | 
				
			||||||
 | 
						if !ok {
 | 
				
			||||||
 | 
							return nil, false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						b, ok := o.(*BoolOption)
 | 
				
			||||||
 | 
						if !ok {
 | 
				
			||||||
 | 
							return nil, false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return b, true
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (s Set) GetString(name string) (*StringOption, bool) {
 | 
				
			||||||
 | 
						o, ok := s.Get(name)
 | 
				
			||||||
 | 
						if !ok {
 | 
				
			||||||
 | 
							return nil, false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						b, ok := o.(*StringOption)
 | 
				
			||||||
 | 
						if !ok {
 | 
				
			||||||
 | 
							return nil, false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return b, true
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (s Set) GetInt(name string) (*IntOption, bool) {
 | 
				
			||||||
 | 
						o, ok := s.Get(name)
 | 
				
			||||||
 | 
						if !ok {
 | 
				
			||||||
 | 
							return nil, false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						b, ok := o.(*IntOption)
 | 
				
			||||||
 | 
						if !ok {
 | 
				
			||||||
 | 
							return nil, false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return b, true
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (s Set) GetFloat(name string) (*FloatOption, bool) {
 | 
				
			||||||
 | 
						o, ok := s.Get(name)
 | 
				
			||||||
 | 
						if !ok {
 | 
				
			||||||
 | 
							return nil, false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						b, ok := o.(*FloatOption)
 | 
				
			||||||
 | 
						if !ok {
 | 
				
			||||||
 | 
							return nil, false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return b, true
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -43,6 +43,11 @@ func (o *StringOption) Parse(raw string) error {
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TakesArg implements Option.
 | 
				
			||||||
 | 
					func (*StringOption) TakesArg() bool {
 | 
				
			||||||
 | 
						return true
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (o *StringOption) Value() string {
 | 
					func (o *StringOption) Value() string {
 | 
				
			||||||
	return o.value
 | 
						return o.value
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue