github.com/maresnic/mr-kong@v1.0.0/context.go (about)

     1  package kong
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"os"
     7  	"reflect"
     8  	"sort"
     9  	"strconv"
    10  	"strings"
    11  )
    12  
    13  // Path records the nodes and parsed values from the current command-line.
    14  type Path struct {
    15  	Parent *Node
    16  
    17  	// One of these will be non-nil.
    18  	App        *Application
    19  	Positional *Positional
    20  	Flag       *Flag
    21  	Argument   *Argument
    22  	Command    *Command
    23  
    24  	// Flags added by this node.
    25  	Flags []*Flag
    26  
    27  	// True if this Path element was created as the result of a resolver.
    28  	Resolved bool
    29  }
    30  
    31  // Node returns the Node associated with this Path, or nil if Path is a non-Node.
    32  func (p *Path) Node() *Node {
    33  	switch {
    34  	case p.App != nil:
    35  		return p.App.Node
    36  
    37  	case p.Argument != nil:
    38  		return p.Argument
    39  
    40  	case p.Command != nil:
    41  		return p.Command
    42  	}
    43  	return nil
    44  }
    45  
    46  // Visitable returns the Visitable for this path element.
    47  func (p *Path) Visitable() Visitable {
    48  	switch {
    49  	case p.App != nil:
    50  		return p.App
    51  
    52  	case p.Argument != nil:
    53  		return p.Argument
    54  
    55  	case p.Command != nil:
    56  		return p.Command
    57  
    58  	case p.Flag != nil:
    59  		return p.Flag
    60  
    61  	case p.Positional != nil:
    62  		return p.Positional
    63  	}
    64  	return nil
    65  }
    66  
    67  // Context contains the current parse context.
    68  type Context struct {
    69  	*Kong
    70  	// A trace through parsed nodes.
    71  	Path []*Path
    72  	// Original command-line arguments.
    73  	Args []string
    74  	// Error that occurred during trace, if any.
    75  	Error error
    76  
    77  	values    map[*Value]reflect.Value // Temporary values during tracing.
    78  	bindings  bindings
    79  	resolvers []Resolver // Extra context-specific resolvers.
    80  	scan      *Scanner
    81  }
    82  
    83  // Trace path of "args" through the grammar tree.
    84  //
    85  // The returned Context will include a Path of all commands, arguments, positionals and flags.
    86  //
    87  // This just constructs a new trace. To fully apply the trace you must call Reset(), Resolve(),
    88  // Validate() and Apply().
    89  func Trace(k *Kong, args []string) (*Context, error) {
    90  	c := &Context{
    91  		Kong: k,
    92  		Args: args,
    93  		Path: []*Path{
    94  			{App: k.Model, Flags: k.Model.Flags},
    95  		},
    96  		values:   map[*Value]reflect.Value{},
    97  		scan:     Scan(args...),
    98  		bindings: bindings{},
    99  	}
   100  	c.Error = c.trace(c.Model.Node)
   101  	return c, nil
   102  }
   103  
   104  // Bind adds bindings to the Context.
   105  func (c *Context) Bind(args ...interface{}) {
   106  	c.bindings.add(args...)
   107  }
   108  
   109  // BindTo adds a binding to the Context.
   110  //
   111  // This will typically have to be called like so:
   112  //
   113  //	BindTo(impl, (*MyInterface)(nil))
   114  func (c *Context) BindTo(impl, iface interface{}) {
   115  	c.bindings.addTo(impl, iface)
   116  }
   117  
   118  // BindToProvider allows binding of provider functions.
   119  //
   120  // This is useful when the Run() function of different commands require different values that may
   121  // not all be initialisable from the main() function.
   122  func (c *Context) BindToProvider(provider interface{}) error {
   123  	return c.bindings.addProvider(provider)
   124  }
   125  
   126  // Value returns the value for a particular path element.
   127  func (c *Context) Value(path *Path) reflect.Value {
   128  	switch {
   129  	case path.Positional != nil:
   130  		return c.values[path.Positional]
   131  	case path.Flag != nil:
   132  		return c.values[path.Flag.Value]
   133  	case path.Argument != nil:
   134  		return c.values[path.Argument.Argument]
   135  	}
   136  	panic("can only retrieve value for flag, argument or positional")
   137  }
   138  
   139  // Selected command or argument.
   140  func (c *Context) Selected() *Node {
   141  	var selected *Node
   142  	for _, path := range c.Path {
   143  		switch {
   144  		case path.Command != nil:
   145  			selected = path.Command
   146  		case path.Argument != nil:
   147  			selected = path.Argument
   148  		}
   149  	}
   150  	return selected
   151  }
   152  
   153  // Empty returns true if there were no arguments provided.
   154  func (c *Context) Empty() bool {
   155  	for _, path := range c.Path {
   156  		if !path.Resolved && path.App == nil {
   157  			return false
   158  		}
   159  	}
   160  	return true
   161  }
   162  
   163  // Validate the current context.
   164  func (c *Context) Validate() error { //nolint: gocyclo
   165  	err := Visit(c.Model, func(node Visitable, next Next) error {
   166  		switch node := node.(type) {
   167  		case *Value:
   168  			ok := atLeastOneEnvSet(node.Tag.Envs)
   169  			if node.Enum != "" && (!node.Required || node.HasDefault || (len(node.Tag.Envs) != 0 && ok)) {
   170  				if err := checkEnum(node, node.Target); err != nil {
   171  					return err
   172  				}
   173  			}
   174  
   175  		case *Flag:
   176  			ok := atLeastOneEnvSet(node.Tag.Envs)
   177  			if node.Enum != "" && (!node.Required || node.HasDefault || (len(node.Tag.Envs) != 0 && ok)) {
   178  				if err := checkEnum(node.Value, node.Target); err != nil {
   179  					return err
   180  				}
   181  			}
   182  		}
   183  		return next(nil)
   184  	})
   185  	if err != nil {
   186  		return err
   187  	}
   188  	for _, el := range c.Path {
   189  		var (
   190  			value reflect.Value
   191  			desc  string
   192  		)
   193  		switch node := el.Visitable().(type) {
   194  		case *Value:
   195  			value = node.Target
   196  			desc = node.ShortSummary()
   197  
   198  		case *Flag:
   199  			value = node.Target
   200  			desc = node.ShortSummary()
   201  
   202  		case *Application:
   203  			value = node.Target
   204  			desc = ""
   205  
   206  		case *Node:
   207  			value = node.Target
   208  			desc = node.Path()
   209  		}
   210  		if validate := isValidatable(value); validate != nil {
   211  			if err := validate.Validate(); err != nil {
   212  				if desc != "" {
   213  					return fmt.Errorf("%s: %w", desc, err)
   214  				}
   215  				return err
   216  			}
   217  		}
   218  	}
   219  	for _, resolver := range c.combineResolvers() {
   220  		if err := resolver.Validate(c.Model); err != nil {
   221  			return err
   222  		}
   223  	}
   224  	for _, path := range c.Path {
   225  		var value *Value
   226  		switch {
   227  		case path.Flag != nil:
   228  			value = path.Flag.Value
   229  
   230  		case path.Positional != nil:
   231  			value = path.Positional
   232  		}
   233  		if value != nil && value.Tag.Enum != "" {
   234  			if err := checkEnum(value, value.Target); err != nil {
   235  				return err
   236  			}
   237  		}
   238  		if err := checkMissingFlags(path.Flags); err != nil {
   239  			return err
   240  		}
   241  	}
   242  	// Check the terminal node.
   243  	node := c.Selected()
   244  	if node == nil {
   245  		node = c.Model.Node
   246  	}
   247  
   248  	// Find deepest positional argument so we can check if all required positionals have been provided.
   249  	positionals := 0
   250  	for _, path := range c.Path {
   251  		if path.Positional != nil {
   252  			positionals = path.Positional.Position + 1
   253  		}
   254  	}
   255  
   256  	if err := checkMissingChildren(node); err != nil {
   257  		return err
   258  	}
   259  	if err := checkMissingPositionals(positionals, node.Positional); err != nil {
   260  		return err
   261  	}
   262  	if err := checkXorDuplicates(c.Path); err != nil {
   263  		return err
   264  	}
   265  
   266  	if node.Type == ArgumentNode {
   267  		value := node.Argument
   268  		if value.Required && !value.Set {
   269  			return fmt.Errorf("%s is required", node.Summary())
   270  		}
   271  	}
   272  	return nil
   273  }
   274  
   275  // Flags returns the accumulated available flags.
   276  func (c *Context) Flags() (flags []*Flag) {
   277  	for _, trace := range c.Path {
   278  		flags = append(flags, trace.Flags...)
   279  	}
   280  	return
   281  }
   282  
   283  // Command returns the full command path.
   284  func (c *Context) Command() string {
   285  	command := []string{}
   286  	for _, trace := range c.Path {
   287  		switch {
   288  		case trace.Positional != nil:
   289  			command = append(command, "<"+trace.Positional.Name+">")
   290  
   291  		case trace.Argument != nil:
   292  			command = append(command, "<"+trace.Argument.Name+">")
   293  
   294  		case trace.Command != nil:
   295  			command = append(command, trace.Command.Name)
   296  		}
   297  	}
   298  	return strings.Join(command, " ")
   299  }
   300  
   301  // AddResolver adds a context-specific resolver.
   302  //
   303  // This is most useful in the BeforeResolve() hook.
   304  func (c *Context) AddResolver(resolver Resolver) {
   305  	c.resolvers = append(c.resolvers, resolver)
   306  }
   307  
   308  // FlagValue returns the set value of a flag if it was encountered and exists, or its default value.
   309  func (c *Context) FlagValue(flag *Flag) interface{} {
   310  	for _, trace := range c.Path {
   311  		if trace.Flag == flag {
   312  			v, ok := c.values[trace.Flag.Value]
   313  			if !ok {
   314  				break
   315  			}
   316  			return v.Interface()
   317  		}
   318  	}
   319  	if flag.Target.IsValid() {
   320  		return flag.Target.Interface()
   321  	}
   322  	return flag.DefaultValue.Interface()
   323  }
   324  
   325  // Reset recursively resets values to defaults (as specified in the grammar) or the zero value.
   326  func (c *Context) Reset() error {
   327  	return Visit(c.Model.Node, func(node Visitable, next Next) error {
   328  		if value, ok := node.(*Value); ok {
   329  			return next(value.Reset())
   330  		}
   331  		return next(nil)
   332  	})
   333  }
   334  
   335  func (c *Context) endParsing() {
   336  	args := []string{}
   337  	for {
   338  		token := c.scan.Pop()
   339  		if token.Type == EOLToken {
   340  			break
   341  		}
   342  		args = append(args, token.String())
   343  	}
   344  	// Note: tokens must be pushed in reverse order.
   345  	for i := range args {
   346  		c.scan.PushTyped(args[len(args)-1-i], PositionalArgumentToken)
   347  	}
   348  }
   349  
   350  func (c *Context) trace(node *Node) (err error) { //nolint: gocyclo
   351  	positional := 0
   352  	node.Active = true
   353  
   354  	flags := []*Flag{}
   355  	flagNode := node
   356  	if node.DefaultCmd != nil && node.DefaultCmd.Tag.Default == "withargs" {
   357  		// Add flags of the default command if the current node has one
   358  		// and that default command allows args / flags without explicitly
   359  		// naming the command on the CLI.
   360  		flagNode = node.DefaultCmd
   361  	}
   362  	for _, group := range flagNode.AllFlags(false) {
   363  		flags = append(flags, group...)
   364  	}
   365  
   366  	if node.Passthrough {
   367  		c.endParsing()
   368  	}
   369  
   370  	for !c.scan.Peek().IsEOL() {
   371  		token := c.scan.Peek()
   372  		switch token.Type {
   373  		case UntypedToken:
   374  			switch v := token.Value.(type) {
   375  			case string:
   376  
   377  				switch {
   378  				case v == "-":
   379  					fallthrough
   380  				default: //nolint
   381  					c.scan.Pop()
   382  					c.scan.PushTyped(token.Value, PositionalArgumentToken)
   383  
   384  				// Indicates end of parsing. All remaining arguments are treated as positional arguments only.
   385  				case v == "--":
   386  					c.scan.Pop()
   387  					c.endParsing()
   388  
   389  				// Long flag.
   390  				case strings.HasPrefix(v, "--"):
   391  					c.scan.Pop()
   392  					// Parse it and push the tokens.
   393  					parts := strings.SplitN(v[2:], "=", 2)
   394  					if len(parts) > 1 {
   395  						c.scan.PushTyped(parts[1], FlagValueToken)
   396  					}
   397  					c.scan.PushTyped(parts[0], FlagToken)
   398  
   399  				// Short flag.
   400  				case strings.HasPrefix(v, "-"):
   401  					c.scan.Pop()
   402  					// Note: tokens must be pushed in reverse order.
   403  					if tail := v[2:]; tail != "" {
   404  						tail = strings.TrimLeft(tail, " =")
   405  						c.scan.PushTyped(tail, ShortFlagTailToken)
   406  					}
   407  					c.scan.PushTyped(v[1:2], ShortFlagToken)
   408  				}
   409  			default:
   410  				c.scan.Pop()
   411  				c.scan.PushTyped(token.Value, PositionalArgumentToken)
   412  			}
   413  
   414  		case ShortFlagTailToken:
   415  			c.scan.Pop()
   416  			// Note: tokens must be pushed in reverse order.
   417  			if tail := token.String()[1:]; tail != "" {
   418  				c.scan.PushTyped(tail, ShortFlagTailToken)
   419  			}
   420  			c.scan.PushTyped(token.String()[0:1], ShortFlagToken)
   421  
   422  		case FlagToken:
   423  			if err := c.parseFlag(flags, token.String()); err != nil {
   424  				return err
   425  			}
   426  
   427  		case ShortFlagToken:
   428  			if err := c.parseFlag(flags, token.String()); err != nil {
   429  				return err
   430  			}
   431  
   432  		case FlagValueToken:
   433  			return fmt.Errorf("unexpected flag argument %q", token.Value)
   434  
   435  		case PositionalArgumentToken:
   436  			candidates := []string{}
   437  
   438  			// Ensure we've consumed all positional arguments.
   439  			if positional < len(node.Positional) {
   440  				arg := node.Positional[positional]
   441  
   442  				if arg.Passthrough {
   443  					c.endParsing()
   444  				}
   445  
   446  				arg.Active = true
   447  				err := arg.Parse(c.scan, c.getValue(arg))
   448  				if err != nil {
   449  					return err
   450  				}
   451  				c.Path = append(c.Path, &Path{
   452  					Parent:     node,
   453  					Positional: arg,
   454  				})
   455  				positional++
   456  				break
   457  			}
   458  
   459  			// Assign token value to a branch name if tagged as an alias
   460  			// An alias will be ignored in the case of an existing command
   461  			cmds := make(map[string]bool)
   462  			for _, branch := range node.Children {
   463  				if branch.Type == CommandNode {
   464  					cmds[branch.Name] = true
   465  				}
   466  			}
   467  			for _, branch := range node.Children {
   468  				for _, a := range branch.Aliases {
   469  					_, ok := cmds[a]
   470  					if token.Value == a && !ok {
   471  						token.Value = branch.Name
   472  						break
   473  					}
   474  				}
   475  			}
   476  
   477  			// After positional arguments have been consumed, check commands next...
   478  			for _, branch := range node.Children {
   479  				if branch.Type == CommandNode && !branch.Hidden {
   480  					candidates = append(candidates, branch.Name)
   481  				}
   482  				if branch.Type == CommandNode && branch.Name == token.Value {
   483  					c.scan.Pop()
   484  					c.Path = append(c.Path, &Path{
   485  						Parent:  node,
   486  						Command: branch,
   487  						Flags:   branch.Flags,
   488  					})
   489  					return c.trace(branch)
   490  				}
   491  			}
   492  
   493  			// Finally, check arguments.
   494  			for _, branch := range node.Children {
   495  				if branch.Type == ArgumentNode {
   496  					arg := branch.Argument
   497  					if err := arg.Parse(c.scan, c.getValue(arg)); err == nil {
   498  						c.Path = append(c.Path, &Path{
   499  							Parent:   node,
   500  							Argument: branch,
   501  							Flags:    branch.Flags,
   502  						})
   503  						return c.trace(branch)
   504  					}
   505  				}
   506  			}
   507  
   508  			// If there is a default command that allows args and nothing else
   509  			// matches, take the branch of the default command
   510  			if node.DefaultCmd != nil && node.DefaultCmd.Tag.Default == "withargs" {
   511  				c.Path = append(c.Path, &Path{
   512  					Parent:  node,
   513  					Command: node.DefaultCmd,
   514  					Flags:   node.DefaultCmd.Flags,
   515  				})
   516  				return c.trace(node.DefaultCmd)
   517  			}
   518  
   519  			return findPotentialCandidates(token.String(), candidates, "unexpected argument %s", token)
   520  		default:
   521  			return fmt.Errorf("unexpected token %s", token)
   522  		}
   523  	}
   524  	return c.maybeSelectDefault(flags, node)
   525  }
   526  
   527  // End of the line, check for a default command, but only if we're not displaying help,
   528  // otherwise we'd only ever display the help for the default command.
   529  func (c *Context) maybeSelectDefault(flags []*Flag, node *Node) error {
   530  	for _, flag := range flags {
   531  		if flag.Name == "help" && flag.Set {
   532  			return nil
   533  		}
   534  	}
   535  	if node.DefaultCmd != nil {
   536  		c.Path = append(c.Path, &Path{
   537  			Parent:  node.DefaultCmd,
   538  			Command: node.DefaultCmd,
   539  			Flags:   node.DefaultCmd.Flags,
   540  		})
   541  	}
   542  	return nil
   543  }
   544  
   545  // Resolve walks through the traced path, applying resolvers to any unset flags.
   546  func (c *Context) Resolve() error {
   547  	resolvers := c.combineResolvers()
   548  	if len(resolvers) == 0 {
   549  		return nil
   550  	}
   551  
   552  	inserted := []*Path{}
   553  	for _, path := range c.Path {
   554  		for _, flag := range path.Flags {
   555  			// Flag has already been set on the command-line.
   556  			if _, ok := c.values[flag.Value]; ok {
   557  				continue
   558  			}
   559  
   560  			// Pick the last resolved value.
   561  			var selected interface{}
   562  			for _, resolver := range resolvers {
   563  				s, err := resolver.Resolve(c, path, flag)
   564  				if err != nil {
   565  					return fmt.Errorf("%s: %w", flag.ShortSummary(), err)
   566  				}
   567  				if s == nil {
   568  					continue
   569  				}
   570  				selected = s
   571  			}
   572  
   573  			if selected == nil {
   574  				continue
   575  			}
   576  
   577  			scan := Scan().PushTyped(selected, FlagValueToken)
   578  			delete(c.values, flag.Value)
   579  			err := flag.Parse(scan, c.getValue(flag.Value))
   580  			if err != nil {
   581  				return err
   582  			}
   583  			inserted = append(inserted, &Path{
   584  				Flag:     flag,
   585  				Resolved: true,
   586  			})
   587  		}
   588  	}
   589  	c.Path = append(c.Path, inserted...)
   590  	return nil
   591  }
   592  
   593  // Combine application-level resolvers and context resolvers.
   594  func (c *Context) combineResolvers() []Resolver {
   595  	resolvers := []Resolver{}
   596  	resolvers = append(resolvers, c.Kong.resolvers...)
   597  	resolvers = append(resolvers, c.resolvers...)
   598  	return resolvers
   599  }
   600  
   601  func (c *Context) getValue(value *Value) reflect.Value {
   602  	v, ok := c.values[value]
   603  	if !ok {
   604  		v = reflect.New(value.Target.Type()).Elem()
   605  		switch v.Kind() {
   606  		case reflect.Ptr:
   607  			v.Set(reflect.New(v.Type().Elem()))
   608  		case reflect.Slice:
   609  			v.Set(reflect.MakeSlice(v.Type(), 0, 0))
   610  		case reflect.Map:
   611  			v.Set(reflect.MakeMap(v.Type()))
   612  		default:
   613  		}
   614  		c.values[value] = v
   615  	}
   616  	return v
   617  }
   618  
   619  // ApplyDefaults if they are not already set.
   620  func (c *Context) ApplyDefaults() error {
   621  	return Visit(c.Model.Node, func(node Visitable, next Next) error {
   622  		var value *Value
   623  		switch node := node.(type) {
   624  		case *Flag:
   625  			value = node.Value
   626  		case *Node:
   627  			value = node.Argument
   628  		case *Value:
   629  			value = node
   630  		default:
   631  		}
   632  		if value != nil {
   633  			if err := value.ApplyDefault(); err != nil {
   634  				return err
   635  			}
   636  		}
   637  		return next(nil)
   638  	})
   639  }
   640  
   641  // Apply traced context to the target grammar.
   642  func (c *Context) Apply() (string, error) {
   643  	path := []string{}
   644  
   645  	for _, trace := range c.Path {
   646  		var value *Value
   647  		switch {
   648  		case trace.App != nil:
   649  		case trace.Argument != nil:
   650  			path = append(path, "<"+trace.Argument.Name+">")
   651  			value = trace.Argument.Argument
   652  		case trace.Command != nil:
   653  			path = append(path, trace.Command.Name)
   654  		case trace.Flag != nil:
   655  			value = trace.Flag.Value
   656  		case trace.Positional != nil:
   657  			path = append(path, "<"+trace.Positional.Name+">")
   658  			value = trace.Positional
   659  		default:
   660  			panic("unsupported path ?!")
   661  		}
   662  		if value != nil {
   663  			value.Apply(c.getValue(value))
   664  		}
   665  	}
   666  
   667  	return strings.Join(path, " "), nil
   668  }
   669  
   670  func flipBoolValue(value reflect.Value) error {
   671  	if value.Kind() == reflect.Bool {
   672  		value.SetBool(!value.Bool())
   673  		return nil
   674  	}
   675  
   676  	if value.Kind() == reflect.Ptr {
   677  		if !value.IsNil() {
   678  			return flipBoolValue(value.Elem())
   679  		}
   680  		return nil
   681  	}
   682  
   683  	return fmt.Errorf("cannot negate a value of %s", value.Type().String())
   684  }
   685  
   686  func (c *Context) parseFlag(flags []*Flag, match string) (err error) {
   687  	candidates := []string{}
   688  
   689  	for _, flag := range flags {
   690  		long := "--" + flag.Name
   691  		matched := long == match
   692  		candidates = append(candidates, long)
   693  		if flag.Short != 0 {
   694  			short := "-" + string(flag.Short)
   695  			matched = matched || (short == match)
   696  			candidates = append(candidates, short)
   697  		}
   698  		for _, alias := range flag.Aliases {
   699  			alias = "--" + alias
   700  			matched = matched || (alias == match)
   701  			candidates = append(candidates, alias)
   702  		}
   703  
   704  		neg := "--no-" + flag.Name
   705  		if !matched && !(match == neg && flag.Tag.Negatable) {
   706  			continue
   707  		}
   708  		// Found a matching flag.
   709  		c.scan.Pop()
   710  		if match == neg && flag.Tag.Negatable {
   711  			flag.Negated = true
   712  		}
   713  		err := flag.Parse(c.scan, c.getValue(flag.Value))
   714  		if err != nil {
   715  			var expected *expectedError
   716  			if errors.As(err, &expected) && expected.token.InferredType().IsAny(FlagToken, ShortFlagToken) {
   717  				return fmt.Errorf("%s; perhaps try %s=%q?", err.Error(), flag.ShortSummary(), expected.token)
   718  			}
   719  			return err
   720  		}
   721  		if flag.Negated {
   722  			value := c.getValue(flag.Value)
   723  			err := flipBoolValue(value)
   724  			if err != nil {
   725  				return err
   726  			}
   727  			flag.Value.Apply(value)
   728  		}
   729  		c.Path = append(c.Path, &Path{Flag: flag})
   730  		return nil
   731  	}
   732  	return findPotentialCandidates(match, candidates, "unknown flag %s", match)
   733  }
   734  
   735  // Call an arbitrary function filling arguments with bound values.
   736  func (c *Context) Call(fn any, binds ...interface{}) (out []interface{}, err error) {
   737  	fv := reflect.ValueOf(fn)
   738  	bindings := c.Kong.bindings.clone().add(binds...).add(c).merge(c.bindings) //nolint:govet
   739  	return callAnyFunction(fv, bindings)
   740  }
   741  
   742  // RunNode calls the Run() method on an arbitrary node.
   743  //
   744  // This is useful in conjunction with Visit(), for dynamically running commands.
   745  //
   746  // Any passed values will be bindable to arguments of the target Run() method. Additionally,
   747  // all parent nodes in the command structure will be bound.
   748  func (c *Context) RunNode(node *Node, binds ...interface{}) (err error) {
   749  	type targetMethod struct {
   750  		node   *Node
   751  		method reflect.Value
   752  		binds  bindings
   753  	}
   754  	methodBinds := c.Kong.bindings.clone().add(binds...).add(c).merge(c.bindings)
   755  	methods := []targetMethod{}
   756  	for i := 0; node != nil; i, node = i+1, node.Parent {
   757  		method := getMethod(node.Target, "Run")
   758  		methodBinds = methodBinds.clone()
   759  		for p := node; p != nil; p = p.Parent {
   760  			methodBinds = methodBinds.add(p.Target.Addr().Interface())
   761  		}
   762  		if method.IsValid() {
   763  			methods = append(methods, targetMethod{node, method, methodBinds})
   764  		}
   765  	}
   766  	if len(methods) == 0 {
   767  		return fmt.Errorf("no Run() method found in hierarchy of %s", c.Selected().Summary())
   768  	}
   769  	_, err = c.Apply()
   770  	if err != nil {
   771  		return err
   772  	}
   773  
   774  	for _, method := range methods {
   775  		if err = callFunction(method.method, method.binds); err != nil {
   776  			return err
   777  		}
   778  	}
   779  	return nil
   780  }
   781  
   782  // Run executes the Run() method on the selected command, which must exist.
   783  //
   784  // Any passed values will be bindable to arguments of the target Run() method. Additionally,
   785  // all parent nodes in the command structure will be bound.
   786  func (c *Context) Run(binds ...interface{}) (err error) {
   787  	node := c.Selected()
   788  	if node == nil {
   789  		if len(c.Path) > 0 {
   790  			selected := c.Path[0].Node()
   791  			if selected.Type == ApplicationNode {
   792  				method := getMethod(selected.Target, "Run")
   793  				if method.IsValid() {
   794  					return c.RunNode(selected, binds...)
   795  				}
   796  			}
   797  		}
   798  		return fmt.Errorf("no command selected")
   799  	}
   800  	return c.RunNode(node, binds...)
   801  }
   802  
   803  // PrintUsage to Kong's stdout.
   804  //
   805  // If summary is true, a summarised version of the help will be output.
   806  func (c *Context) PrintUsage(summary bool) error {
   807  	options := c.helpOptions
   808  	options.Summary = summary
   809  	return c.help(options, c)
   810  }
   811  
   812  func checkMissingFlags(flags []*Flag) error {
   813  	xorGroupSet := map[string]bool{}
   814  	xorGroup := map[string][]string{}
   815  	missing := []string{}
   816  	for _, flag := range flags {
   817  		if flag.Set {
   818  			for _, xor := range flag.Xor {
   819  				xorGroupSet[xor] = true
   820  			}
   821  		}
   822  		if !flag.Required || flag.Set {
   823  			continue
   824  		}
   825  		if len(flag.Xor) > 0 {
   826  			for _, xor := range flag.Xor {
   827  				if xorGroupSet[xor] {
   828  					continue
   829  				}
   830  				xorGroup[xor] = append(xorGroup[xor], flag.Summary())
   831  			}
   832  		} else {
   833  			missing = append(missing, flag.Summary())
   834  		}
   835  	}
   836  	for xor, flags := range xorGroup {
   837  		if !xorGroupSet[xor] && len(flags) > 1 {
   838  			missing = append(missing, strings.Join(flags, " or "))
   839  		}
   840  	}
   841  
   842  	if len(missing) == 0 {
   843  		return nil
   844  	}
   845  
   846  	sort.Strings(missing)
   847  
   848  	return fmt.Errorf("missing flags: %s", strings.Join(missing, ", "))
   849  }
   850  
   851  func checkMissingChildren(node *Node) error {
   852  	missing := []string{}
   853  
   854  	missingArgs := []string{}
   855  	for _, arg := range node.Positional {
   856  		if arg.Required && !arg.Set {
   857  			missingArgs = append(missingArgs, arg.Summary())
   858  		}
   859  	}
   860  	if len(missingArgs) > 0 {
   861  		missing = append(missing, strconv.Quote(strings.Join(missingArgs, " ")))
   862  	}
   863  
   864  	for _, child := range node.Children {
   865  		if child.Hidden {
   866  			continue
   867  		}
   868  		if child.Argument != nil {
   869  			if !child.Argument.Required {
   870  				continue
   871  			}
   872  			missing = append(missing, strconv.Quote(child.Summary()))
   873  		} else {
   874  			missing = append(missing, strconv.Quote(child.Name))
   875  		}
   876  	}
   877  	if len(missing) == 0 {
   878  		return nil
   879  	}
   880  
   881  	if len(missing) > 5 {
   882  		missing = append(missing[:5], "...")
   883  	}
   884  	if len(missing) == 1 {
   885  		return fmt.Errorf("expected %s", missing[0])
   886  	}
   887  	return fmt.Errorf("expected one of %s", strings.Join(missing, ",  "))
   888  }
   889  
   890  // If we're missing any positionals and they're required, return an error.
   891  func checkMissingPositionals(positional int, values []*Value) error {
   892  	// All the positionals are in.
   893  	if positional >= len(values) {
   894  		return nil
   895  	}
   896  
   897  	// We're low on supplied positionals, but the missing one is optional.
   898  	if !values[positional].Required {
   899  		return nil
   900  	}
   901  
   902  	missing := []string{}
   903  	for ; positional < len(values); positional++ {
   904  		arg := values[positional]
   905  		// TODO(aat): Fix hardcoding of these env checks all over the place :\
   906  		if len(arg.Tag.Envs) != 0 {
   907  			if atLeastOneEnvSet(arg.Tag.Envs) {
   908  				continue
   909  			}
   910  		}
   911  		missing = append(missing, "<"+arg.Name+">")
   912  	}
   913  	if len(missing) == 0 {
   914  		return nil
   915  	}
   916  	return fmt.Errorf("missing positional arguments %s", strings.Join(missing, " "))
   917  }
   918  
   919  func checkEnum(value *Value, target reflect.Value) error {
   920  	switch target.Kind() {
   921  	case reflect.Slice, reflect.Array:
   922  		for i := 0; i < target.Len(); i++ {
   923  			if err := checkEnum(value, target.Index(i)); err != nil {
   924  				return err
   925  			}
   926  		}
   927  		return nil
   928  
   929  	case reflect.Map, reflect.Struct:
   930  		return errors.New("enum can only be applied to a slice or value")
   931  
   932  	case reflect.Ptr:
   933  		if target.IsNil() {
   934  			return nil
   935  		}
   936  		return checkEnum(value, target.Elem())
   937  	default:
   938  		enumSlice := value.EnumSlice()
   939  		v := fmt.Sprintf("%v", target)
   940  		enums := []string{}
   941  		for _, enum := range enumSlice {
   942  			if enum == v {
   943  				return nil
   944  			}
   945  			enums = append(enums, fmt.Sprintf("%q", enum))
   946  		}
   947  		return fmt.Errorf("%s must be one of %s but got %q", value.ShortSummary(), strings.Join(enums, ","), target.Interface())
   948  	}
   949  }
   950  
   951  func checkPassthroughArg(target reflect.Value) bool {
   952  	typ := target.Type()
   953  	switch typ.Kind() {
   954  	case reflect.Slice:
   955  		return typ.Elem().Kind() == reflect.String
   956  	default:
   957  		return false
   958  	}
   959  }
   960  
   961  func checkXorDuplicates(paths []*Path) error {
   962  	for _, path := range paths {
   963  		seen := map[string]*Flag{}
   964  		for _, flag := range path.Flags {
   965  			if !flag.Set {
   966  				continue
   967  			}
   968  			for _, xor := range flag.Xor {
   969  				if seen[xor] != nil {
   970  					return fmt.Errorf("--%s and --%s can't be used together", seen[xor].Name, flag.Name)
   971  				}
   972  				seen[xor] = flag
   973  			}
   974  		}
   975  	}
   976  	return nil
   977  }
   978  
   979  func findPotentialCandidates(needle string, haystack []string, format string, args ...interface{}) error {
   980  	if len(haystack) == 0 {
   981  		return fmt.Errorf(format, args...)
   982  	}
   983  	closestCandidates := []string{}
   984  	for _, candidate := range haystack {
   985  		if strings.HasPrefix(candidate, needle) || levenshtein(candidate, needle) <= 2 {
   986  			closestCandidates = append(closestCandidates, fmt.Sprintf("%q", candidate))
   987  		}
   988  	}
   989  	prefix := fmt.Sprintf(format, args...)
   990  	if len(closestCandidates) == 1 {
   991  		return fmt.Errorf("%s, did you mean %s?", prefix, closestCandidates[0])
   992  	} else if len(closestCandidates) > 1 {
   993  		return fmt.Errorf("%s, did you mean one of %s?", prefix, strings.Join(closestCandidates, ", "))
   994  	}
   995  	return fmt.Errorf("%s", prefix)
   996  }
   997  
   998  type validatable interface{ Validate() error }
   999  
  1000  func isValidatable(v reflect.Value) validatable {
  1001  	if !v.IsValid() || (v.Kind() == reflect.Ptr || v.Kind() == reflect.Slice || v.Kind() == reflect.Map) && v.IsNil() {
  1002  		return nil
  1003  	}
  1004  	if validate, ok := v.Interface().(validatable); ok {
  1005  		return validate
  1006  	}
  1007  	if v.CanAddr() {
  1008  		return isValidatable(v.Addr())
  1009  	}
  1010  	return nil
  1011  }
  1012  
  1013  func atLeastOneEnvSet(envs []string) bool {
  1014  	for _, env := range envs {
  1015  		if _, ok := os.LookupEnv(env); ok {
  1016  			return true
  1017  		}
  1018  	}
  1019  	return false
  1020  }