* Use vendored go-swagger * vendor go-swagger * revert un wanteed change * remove un-needed GO111MODULE * Update Makefile Co-Authored-By: techknowlogick <matti@mdranta.net>
		
			
				
	
	
		
			466 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Go
		
	
	
	
		
			Vendored
		
	
	
	
			
		
		
	
	
			466 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Go
		
	
	
	
		
			Vendored
		
	
	
	
| package flags
 | |
| 
 | |
| import (
 | |
| 	"reflect"
 | |
| 	"sort"
 | |
| 	"strconv"
 | |
| 	"strings"
 | |
| )
 | |
| 
 | |
| // Command represents an application command. Commands can be added to the
 | |
| // parser (which itself is a command) and are selected/executed when its name
 | |
| // is specified on the command line. The Command type embeds a Group and
 | |
| // therefore also carries a set of command specific options.
 | |
| type Command struct {
 | |
| 	// Embedded, see Group for more information
 | |
| 	*Group
 | |
| 
 | |
| 	// The name by which the command can be invoked
 | |
| 	Name string
 | |
| 
 | |
| 	// The active sub command (set by parsing) or nil
 | |
| 	Active *Command
 | |
| 
 | |
| 	// Whether subcommands are optional
 | |
| 	SubcommandsOptional bool
 | |
| 
 | |
| 	// Aliases for the command
 | |
| 	Aliases []string
 | |
| 
 | |
| 	// Whether positional arguments are required
 | |
| 	ArgsRequired bool
 | |
| 
 | |
| 	commands            []*Command
 | |
| 	hasBuiltinHelpGroup bool
 | |
| 	args                []*Arg
 | |
| }
 | |
| 
 | |
| // Commander is an interface which can be implemented by any command added in
 | |
| // the options. When implemented, the Execute method will be called for the last
 | |
| // specified (sub)command providing the remaining command line arguments.
 | |
| type Commander interface {
 | |
| 	// Execute will be called for the last active (sub)command. The
 | |
| 	// args argument contains the remaining command line arguments. The
 | |
| 	// error that Execute returns will be eventually passed out of the
 | |
| 	// Parse method of the Parser.
 | |
| 	Execute(args []string) error
 | |
| }
 | |
| 
 | |
| // Usage is an interface which can be implemented to show a custom usage string
 | |
| // in the help message shown for a command.
 | |
| type Usage interface {
 | |
| 	// Usage is called for commands to allow customized printing of command
 | |
| 	// usage in the generated help message.
 | |
| 	Usage() string
 | |
| }
 | |
| 
 | |
| type lookup struct {
 | |
| 	shortNames map[string]*Option
 | |
| 	longNames  map[string]*Option
 | |
| 
 | |
| 	commands map[string]*Command
 | |
| }
 | |
| 
 | |
| // AddCommand adds a new command to the parser with the given name and data. The
 | |
| // data needs to be a pointer to a struct from which the fields indicate which
 | |
| // options are in the command. The provided data can implement the Command and
 | |
| // Usage interfaces.
 | |
| func (c *Command) AddCommand(command string, shortDescription string, longDescription string, data interface{}) (*Command, error) {
 | |
| 	cmd := newCommand(command, shortDescription, longDescription, data)
 | |
| 
 | |
| 	cmd.parent = c
 | |
| 
 | |
| 	if err := cmd.scan(); err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	c.commands = append(c.commands, cmd)
 | |
| 	return cmd, nil
 | |
| }
 | |
| 
 | |
| // AddGroup adds a new group to the command with the given name and data. The
 | |
| // data needs to be a pointer to a struct from which the fields indicate which
 | |
| // options are in the group.
 | |
| func (c *Command) AddGroup(shortDescription string, longDescription string, data interface{}) (*Group, error) {
 | |
| 	group := newGroup(shortDescription, longDescription, data)
 | |
| 
 | |
| 	group.parent = c
 | |
| 
 | |
| 	if err := group.scanType(c.scanSubcommandHandler(group)); err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	c.groups = append(c.groups, group)
 | |
| 	return group, nil
 | |
| }
 | |
| 
 | |
| // Commands returns a list of subcommands of this command.
 | |
| func (c *Command) Commands() []*Command {
 | |
| 	return c.commands
 | |
| }
 | |
| 
 | |
| // Find locates the subcommand with the given name and returns it. If no such
 | |
| // command can be found Find will return nil.
 | |
| func (c *Command) Find(name string) *Command {
 | |
| 	for _, cc := range c.commands {
 | |
| 		if cc.match(name) {
 | |
| 			return cc
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // FindOptionByLongName finds an option that is part of the command, or any of
 | |
| // its parent commands, by matching its long name (including the option
 | |
| // namespace).
 | |
| func (c *Command) FindOptionByLongName(longName string) (option *Option) {
 | |
| 	for option == nil && c != nil {
 | |
| 		option = c.Group.FindOptionByLongName(longName)
 | |
| 
 | |
| 		c, _ = c.parent.(*Command)
 | |
| 	}
 | |
| 
 | |
| 	return option
 | |
| }
 | |
| 
 | |
| // FindOptionByShortName finds an option that is part of the command, or any of
 | |
| // its parent commands, by matching its long name (including the option
 | |
| // namespace).
 | |
| func (c *Command) FindOptionByShortName(shortName rune) (option *Option) {
 | |
| 	for option == nil && c != nil {
 | |
| 		option = c.Group.FindOptionByShortName(shortName)
 | |
| 
 | |
| 		c, _ = c.parent.(*Command)
 | |
| 	}
 | |
| 
 | |
| 	return option
 | |
| }
 | |
| 
 | |
| // Args returns a list of positional arguments associated with this command.
 | |
| func (c *Command) Args() []*Arg {
 | |
| 	ret := make([]*Arg, len(c.args))
 | |
| 	copy(ret, c.args)
 | |
| 
 | |
| 	return ret
 | |
| }
 | |
| 
 | |
| func newCommand(name string, shortDescription string, longDescription string, data interface{}) *Command {
 | |
| 	return &Command{
 | |
| 		Group: newGroup(shortDescription, longDescription, data),
 | |
| 		Name:  name,
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (c *Command) scanSubcommandHandler(parentg *Group) scanHandler {
 | |
| 	f := func(realval reflect.Value, sfield *reflect.StructField) (bool, error) {
 | |
| 		mtag := newMultiTag(string(sfield.Tag))
 | |
| 
 | |
| 		if err := mtag.Parse(); err != nil {
 | |
| 			return true, err
 | |
| 		}
 | |
| 
 | |
| 		positional := mtag.Get("positional-args")
 | |
| 
 | |
| 		if len(positional) != 0 {
 | |
| 			stype := realval.Type()
 | |
| 
 | |
| 			for i := 0; i < stype.NumField(); i++ {
 | |
| 				field := stype.Field(i)
 | |
| 
 | |
| 				m := newMultiTag((string(field.Tag)))
 | |
| 
 | |
| 				if err := m.Parse(); err != nil {
 | |
| 					return true, err
 | |
| 				}
 | |
| 
 | |
| 				name := m.Get("positional-arg-name")
 | |
| 
 | |
| 				if len(name) == 0 {
 | |
| 					name = field.Name
 | |
| 				}
 | |
| 
 | |
| 				required := -1
 | |
| 				requiredMaximum := -1
 | |
| 
 | |
| 				sreq := m.Get("required")
 | |
| 
 | |
| 				if sreq != "" {
 | |
| 					required = 1
 | |
| 
 | |
| 					rng := strings.SplitN(sreq, "-", 2)
 | |
| 
 | |
| 					if len(rng) > 1 {
 | |
| 						if preq, err := strconv.ParseInt(rng[0], 10, 32); err == nil {
 | |
| 							required = int(preq)
 | |
| 						}
 | |
| 
 | |
| 						if preq, err := strconv.ParseInt(rng[1], 10, 32); err == nil {
 | |
| 							requiredMaximum = int(preq)
 | |
| 						}
 | |
| 					} else {
 | |
| 						if preq, err := strconv.ParseInt(sreq, 10, 32); err == nil {
 | |
| 							required = int(preq)
 | |
| 						}
 | |
| 					}
 | |
| 				}
 | |
| 
 | |
| 				arg := &Arg{
 | |
| 					Name:            name,
 | |
| 					Description:     m.Get("description"),
 | |
| 					Required:        required,
 | |
| 					RequiredMaximum: requiredMaximum,
 | |
| 
 | |
| 					value: realval.Field(i),
 | |
| 					tag:   m,
 | |
| 				}
 | |
| 
 | |
| 				c.args = append(c.args, arg)
 | |
| 
 | |
| 				if len(mtag.Get("required")) != 0 {
 | |
| 					c.ArgsRequired = true
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			return true, nil
 | |
| 		}
 | |
| 
 | |
| 		subcommand := mtag.Get("command")
 | |
| 
 | |
| 		if len(subcommand) != 0 {
 | |
| 			var ptrval reflect.Value
 | |
| 
 | |
| 			if realval.Kind() == reflect.Ptr {
 | |
| 				ptrval = realval
 | |
| 
 | |
| 				if ptrval.IsNil() {
 | |
| 					ptrval.Set(reflect.New(ptrval.Type().Elem()))
 | |
| 				}
 | |
| 			} else {
 | |
| 				ptrval = realval.Addr()
 | |
| 			}
 | |
| 
 | |
| 			shortDescription := mtag.Get("description")
 | |
| 			longDescription := mtag.Get("long-description")
 | |
| 			subcommandsOptional := mtag.Get("subcommands-optional")
 | |
| 			aliases := mtag.GetMany("alias")
 | |
| 
 | |
| 			subc, err := c.AddCommand(subcommand, shortDescription, longDescription, ptrval.Interface())
 | |
| 
 | |
| 			if err != nil {
 | |
| 				return true, err
 | |
| 			}
 | |
| 
 | |
| 			subc.Hidden = mtag.Get("hidden") != ""
 | |
| 
 | |
| 			if len(subcommandsOptional) > 0 {
 | |
| 				subc.SubcommandsOptional = true
 | |
| 			}
 | |
| 
 | |
| 			if len(aliases) > 0 {
 | |
| 				subc.Aliases = aliases
 | |
| 			}
 | |
| 
 | |
| 			return true, nil
 | |
| 		}
 | |
| 
 | |
| 		return parentg.scanSubGroupHandler(realval, sfield)
 | |
| 	}
 | |
| 
 | |
| 	return f
 | |
| }
 | |
| 
 | |
| func (c *Command) scan() error {
 | |
| 	return c.scanType(c.scanSubcommandHandler(c.Group))
 | |
| }
 | |
| 
 | |
| func (c *Command) eachOption(f func(*Command, *Group, *Option)) {
 | |
| 	c.eachCommand(func(c *Command) {
 | |
| 		c.eachGroup(func(g *Group) {
 | |
| 			for _, option := range g.options {
 | |
| 				f(c, g, option)
 | |
| 			}
 | |
| 		})
 | |
| 	}, true)
 | |
| }
 | |
| 
 | |
| func (c *Command) eachCommand(f func(*Command), recurse bool) {
 | |
| 	f(c)
 | |
| 
 | |
| 	for _, cc := range c.commands {
 | |
| 		if recurse {
 | |
| 			cc.eachCommand(f, true)
 | |
| 		} else {
 | |
| 			f(cc)
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (c *Command) eachActiveGroup(f func(cc *Command, g *Group)) {
 | |
| 	c.eachGroup(func(g *Group) {
 | |
| 		f(c, g)
 | |
| 	})
 | |
| 
 | |
| 	if c.Active != nil {
 | |
| 		c.Active.eachActiveGroup(f)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (c *Command) addHelpGroups(showHelp func() error) {
 | |
| 	if !c.hasBuiltinHelpGroup {
 | |
| 		c.addHelpGroup(showHelp)
 | |
| 		c.hasBuiltinHelpGroup = true
 | |
| 	}
 | |
| 
 | |
| 	for _, cc := range c.commands {
 | |
| 		cc.addHelpGroups(showHelp)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (c *Command) makeLookup() lookup {
 | |
| 	ret := lookup{
 | |
| 		shortNames: make(map[string]*Option),
 | |
| 		longNames:  make(map[string]*Option),
 | |
| 		commands:   make(map[string]*Command),
 | |
| 	}
 | |
| 
 | |
| 	parent := c.parent
 | |
| 
 | |
| 	var parents []*Command
 | |
| 
 | |
| 	for parent != nil {
 | |
| 		if cmd, ok := parent.(*Command); ok {
 | |
| 			parents = append(parents, cmd)
 | |
| 			parent = cmd.parent
 | |
| 		} else {
 | |
| 			parent = nil
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	for i := len(parents) - 1; i >= 0; i-- {
 | |
| 		parents[i].fillLookup(&ret, true)
 | |
| 	}
 | |
| 
 | |
| 	c.fillLookup(&ret, false)
 | |
| 	return ret
 | |
| }
 | |
| 
 | |
| func (c *Command) fillLookup(ret *lookup, onlyOptions bool) {
 | |
| 	c.eachGroup(func(g *Group) {
 | |
| 		for _, option := range g.options {
 | |
| 			if option.ShortName != 0 {
 | |
| 				ret.shortNames[string(option.ShortName)] = option
 | |
| 			}
 | |
| 
 | |
| 			if len(option.LongName) > 0 {
 | |
| 				ret.longNames[option.LongNameWithNamespace()] = option
 | |
| 			}
 | |
| 		}
 | |
| 	})
 | |
| 
 | |
| 	if onlyOptions {
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	for _, subcommand := range c.commands {
 | |
| 		ret.commands[subcommand.Name] = subcommand
 | |
| 
 | |
| 		for _, a := range subcommand.Aliases {
 | |
| 			ret.commands[a] = subcommand
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (c *Command) groupByName(name string) *Group {
 | |
| 	if grp := c.Group.groupByName(name); grp != nil {
 | |
| 		return grp
 | |
| 	}
 | |
| 
 | |
| 	for _, subc := range c.commands {
 | |
| 		prefix := subc.Name + "."
 | |
| 
 | |
| 		if strings.HasPrefix(name, prefix) {
 | |
| 			if grp := subc.groupByName(name[len(prefix):]); grp != nil {
 | |
| 				return grp
 | |
| 			}
 | |
| 		} else if name == subc.Name {
 | |
| 			return subc.Group
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| type commandList []*Command
 | |
| 
 | |
| func (c commandList) Less(i, j int) bool {
 | |
| 	return c[i].Name < c[j].Name
 | |
| }
 | |
| 
 | |
| func (c commandList) Len() int {
 | |
| 	return len(c)
 | |
| }
 | |
| 
 | |
| func (c commandList) Swap(i, j int) {
 | |
| 	c[i], c[j] = c[j], c[i]
 | |
| }
 | |
| 
 | |
| func (c *Command) sortedVisibleCommands() []*Command {
 | |
| 	ret := commandList(c.visibleCommands())
 | |
| 	sort.Sort(ret)
 | |
| 
 | |
| 	return []*Command(ret)
 | |
| }
 | |
| 
 | |
| func (c *Command) visibleCommands() []*Command {
 | |
| 	ret := make([]*Command, 0, len(c.commands))
 | |
| 
 | |
| 	for _, cmd := range c.commands {
 | |
| 		if !cmd.Hidden {
 | |
| 			ret = append(ret, cmd)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return ret
 | |
| }
 | |
| 
 | |
| func (c *Command) match(name string) bool {
 | |
| 	if c.Name == name {
 | |
| 		return true
 | |
| 	}
 | |
| 
 | |
| 	for _, v := range c.Aliases {
 | |
| 		if v == name {
 | |
| 			return true
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return false
 | |
| }
 | |
| 
 | |
| func (c *Command) hasCliOptions() bool {
 | |
| 	ret := false
 | |
| 
 | |
| 	c.eachGroup(func(g *Group) {
 | |
| 		if g.isBuiltinHelp {
 | |
| 			return
 | |
| 		}
 | |
| 
 | |
| 		for _, opt := range g.options {
 | |
| 			if opt.canCli() {
 | |
| 				ret = true
 | |
| 			}
 | |
| 		}
 | |
| 	})
 | |
| 
 | |
| 	return ret
 | |
| }
 | |
| 
 | |
| func (c *Command) fillParseState(s *parseState) {
 | |
| 	s.positional = make([]*Arg, len(c.args))
 | |
| 	copy(s.positional, c.args)
 | |
| 
 | |
| 	s.lookup = c.makeLookup()
 | |
| 	s.command = c
 | |
| }
 |