| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286 | package cliimport (	"fmt"	"io/ioutil"	"sort"	"strings")// Command is a subcommand for a cli.App.type Command struct {	// The name of the command	Name string	// short name of the command. Typically one character (deprecated, use `Aliases`)	ShortName string	// A list of aliases for the command	Aliases []string	// A short description of the usage of this command	Usage string	// Custom text to show on USAGE section of help	UsageText string	// A longer explanation of how the command works	Description string	// A short description of the arguments of this command	ArgsUsage string	// The category the command is part of	Category string	// The function to call when checking for bash command completions	BashComplete BashCompleteFunc	// An action to execute before any sub-subcommands are run, but after the context is ready	// If a non-nil error is returned, no sub-subcommands are run	Before BeforeFunc	// An action to execute after any subcommands are run, but after the subcommand has finished	// It is run even if Action() panics	After AfterFunc	// The function to call when this command is invoked	Action interface{}	// TODO: replace `Action: interface{}` with `Action: ActionFunc` once some kind	// of deprecation period has passed, maybe?	// Execute this function if a usage error occurs.	OnUsageError OnUsageErrorFunc	// List of child commands	Subcommands Commands	// List of flags to parse	Flags []Flag	// Treat all flags as normal arguments if true	SkipFlagParsing bool	// Skip argument reordering which attempts to move flags before arguments,	// but only works if all flags appear after all arguments. This behavior was	// removed n version 2 since it only works under specific conditions so we	// backport here by exposing it as an option for compatibility.	SkipArgReorder bool	// Boolean to hide built-in help command	HideHelp bool	// Boolean to hide this command from help or completion	Hidden bool	// Full name of command for help, defaults to full command name, including parent commands.	HelpName        string	commandNamePath []string}// FullName returns the full name of the command.// For subcommands this ensures that parent commands are part of the command pathfunc (c Command) FullName() string {	if c.commandNamePath == nil {		return c.Name	}	return strings.Join(c.commandNamePath, " ")}// Commands is a slice of Commandtype Commands []Command// Run invokes the command given the context, parses ctx.Args() to generate command-specific flagsfunc (c Command) Run(ctx *Context) (err error) {	if len(c.Subcommands) > 0 {		return c.startApp(ctx)	}	if !c.HideHelp && (HelpFlag != BoolFlag{}) {		// append help to flags		c.Flags = append(			c.Flags,			HelpFlag,		)	}	set, err := flagSet(c.Name, c.Flags)	if err != nil {		return err	}	set.SetOutput(ioutil.Discard)	if c.SkipFlagParsing {		err = set.Parse(append([]string{"--"}, ctx.Args().Tail()...))	} else if !c.SkipArgReorder {		firstFlagIndex := -1		terminatorIndex := -1		for index, arg := range ctx.Args() {			if arg == "--" {				terminatorIndex = index				break			} else if arg == "-" {				// Do nothing. A dash alone is not really a flag.				continue			} else if strings.HasPrefix(arg, "-") && firstFlagIndex == -1 {				firstFlagIndex = index			}		}		if firstFlagIndex > -1 {			args := ctx.Args()			regularArgs := make([]string, len(args[1:firstFlagIndex]))			copy(regularArgs, args[1:firstFlagIndex])			var flagArgs []string			if terminatorIndex > -1 {				flagArgs = args[firstFlagIndex:terminatorIndex]				regularArgs = append(regularArgs, args[terminatorIndex:]...)			} else {				flagArgs = args[firstFlagIndex:]			}			err = set.Parse(append(flagArgs, regularArgs...))		} else {			err = set.Parse(ctx.Args().Tail())		}	} else {		err = set.Parse(ctx.Args().Tail())	}	nerr := normalizeFlags(c.Flags, set)	if nerr != nil {		fmt.Fprintln(ctx.App.Writer, nerr)		fmt.Fprintln(ctx.App.Writer)		ShowCommandHelp(ctx, c.Name)		return nerr	}	context := NewContext(ctx.App, set, ctx)	if checkCommandCompletions(context, c.Name) {		return nil	}	if err != nil {		if c.OnUsageError != nil {			err := c.OnUsageError(ctx, err, false)			HandleExitCoder(err)			return err		}		fmt.Fprintln(ctx.App.Writer, "Incorrect Usage:", err.Error())		fmt.Fprintln(ctx.App.Writer)		ShowCommandHelp(ctx, c.Name)		return err	}	if checkCommandHelp(context, c.Name) {		return nil	}	if c.After != nil {		defer func() {			afterErr := c.After(context)			if afterErr != nil {				HandleExitCoder(err)				if err != nil {					err = NewMultiError(err, afterErr)				} else {					err = afterErr				}			}		}()	}	if c.Before != nil {		err = c.Before(context)		if err != nil {			fmt.Fprintln(ctx.App.Writer, err)			fmt.Fprintln(ctx.App.Writer)			ShowCommandHelp(ctx, c.Name)			HandleExitCoder(err)			return err		}	}	if c.Action == nil {		c.Action = helpSubcommand.Action	}	context.Command = c	err = HandleAction(c.Action, context)	if err != nil {		HandleExitCoder(err)	}	return err}// Names returns the names including short names and aliases.func (c Command) Names() []string {	names := []string{c.Name}	if c.ShortName != "" {		names = append(names, c.ShortName)	}	return append(names, c.Aliases...)}// HasName returns true if Command.Name or Command.ShortName matches given namefunc (c Command) HasName(name string) bool {	for _, n := range c.Names() {		if n == name {			return true		}	}	return false}func (c Command) startApp(ctx *Context) error {	app := NewApp()	app.Metadata = ctx.App.Metadata	// set the name and usage	app.Name = fmt.Sprintf("%s %s", ctx.App.Name, c.Name)	if c.HelpName == "" {		app.HelpName = c.HelpName	} else {		app.HelpName = app.Name	}	if c.Description != "" {		app.Usage = c.Description	} else {		app.Usage = c.Usage	}	// set CommandNotFound	app.CommandNotFound = ctx.App.CommandNotFound	// set the flags and commands	app.Commands = c.Subcommands	app.Flags = c.Flags	app.HideHelp = c.HideHelp	app.Version = ctx.App.Version	app.HideVersion = ctx.App.HideVersion	app.Compiled = ctx.App.Compiled	app.Author = ctx.App.Author	app.Email = ctx.App.Email	app.Writer = ctx.App.Writer	app.categories = CommandCategories{}	for _, command := range c.Subcommands {		app.categories = app.categories.AddCommand(command.Category, command)	}	sort.Sort(app.categories)	// bash completion	app.EnableBashCompletion = ctx.App.EnableBashCompletion	if c.BashComplete != nil {		app.BashComplete = c.BashComplete	}	// set the actions	app.Before = c.Before	app.After = c.After	if c.Action != nil {		app.Action = c.Action	} else {		app.Action = helpSubcommand.Action	}	for index, cc := range app.Commands {		app.Commands[index].commandNamePath = []string{c.Name, cc.Name}	}	return app.RunAsSubcommand(ctx)}// VisibleFlags returns a slice of the Flags with Hidden=falsefunc (c Command) VisibleFlags() []Flag {	return visibleFlags(c.Flags)}
 |