| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490 | package cliimport (	"fmt"	"io"	"io/ioutil"	"os"	"path/filepath"	"sort"	"time")var (	changeLogURL                    = "https://github.com/urfave/cli/blob/master/CHANGELOG.md"	appActionDeprecationURL         = fmt.Sprintf("%s#deprecated-cli-app-action-signature", changeLogURL)	runAndExitOnErrorDeprecationURL = fmt.Sprintf("%s#deprecated-cli-app-runandexitonerror", changeLogURL)	contactSysadmin = "This is an error in the application.  Please contact the distributor of this application if this is not you."	errInvalidActionType = NewExitError("ERROR invalid Action type. "+		fmt.Sprintf("Must be `func(*Context`)` or `func(*Context) error).  %s", contactSysadmin)+		fmt.Sprintf("See %s", appActionDeprecationURL), 2))// App is the main structure of a cli application. It is recommended that// an app be created with the cli.NewApp() functiontype App struct {	// The name of the program. Defaults to path.Base(os.Args[0])	Name string	// Full name of command for help, defaults to Name	HelpName string	// Description of the program.	Usage string	// Text to override the USAGE section of help	UsageText string	// Description of the program argument format.	ArgsUsage string	// Version of the program	Version string	// Description of the program	Description string	// List of commands to execute	Commands []Command	// List of flags to parse	Flags []Flag	// Boolean to enable bash completion commands	EnableBashCompletion bool	// Boolean to hide built-in help command	HideHelp bool	// Boolean to hide built-in version flag and the VERSION section of help	HideVersion bool	// Populate on app startup, only gettable through method Categories()	categories CommandCategories	// An action to execute when the bash-completion flag is set	BashComplete BashCompleteFunc	// An action to execute before any subcommands are run, but after the context is ready	// If a non-nil error is returned, no 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 action to execute when no subcommands are specified	// Expects a `cli.ActionFunc` but will accept the *deprecated* signature of `func(*cli.Context) {}`	// *Note*: support for the deprecated `Action` signature will be removed in a future version	Action interface{}	// Execute this function if the proper command cannot be found	CommandNotFound CommandNotFoundFunc	// Execute this function if an usage error occurs	OnUsageError OnUsageErrorFunc	// Compilation date	Compiled time.Time	// List of all authors who contributed	Authors []Author	// Copyright of the binary if any	Copyright string	// Name of Author (Note: Use App.Authors, this is deprecated)	Author string	// Email of Author (Note: Use App.Authors, this is deprecated)	Email string	// Writer writer to write output to	Writer io.Writer	// ErrWriter writes error output	ErrWriter io.Writer	// Other custom info	Metadata map[string]interface{}	didSetup bool}// Tries to find out when this binary was compiled.// Returns the current time if it fails to find it.func compileTime() time.Time {	info, err := os.Stat(os.Args[0])	if err != nil {		return time.Now()	}	return info.ModTime()}// NewApp creates a new cli Application with some reasonable defaults for Name,// Usage, Version and Action.func NewApp() *App {	return &App{		Name:         filepath.Base(os.Args[0]),		HelpName:     filepath.Base(os.Args[0]),		Usage:        "A new cli application",		UsageText:    "",		Version:      "0.0.0",		BashComplete: DefaultAppComplete,		Action:       helpCommand.Action,		Compiled:     compileTime(),		Writer:       os.Stdout,	}}// Setup runs initialization code to ensure all data structures are ready for// `Run` or inspection prior to `Run`.  It is internally called by `Run`, but// will return early if setup has already happened.func (a *App) Setup() {	if a.didSetup {		return	}	a.didSetup = true	if a.Author != "" || a.Email != "" {		a.Authors = append(a.Authors, Author{Name: a.Author, Email: a.Email})	}	newCmds := []Command{}	for _, c := range a.Commands {		if c.HelpName == "" {			c.HelpName = fmt.Sprintf("%s %s", a.HelpName, c.Name)		}		newCmds = append(newCmds, c)	}	a.Commands = newCmds	if a.Command(helpCommand.Name) == nil && !a.HideHelp {		a.Commands = append(a.Commands, helpCommand)		if (HelpFlag != BoolFlag{}) {			a.appendFlag(HelpFlag)		}	}	if !a.HideVersion {		a.appendFlag(VersionFlag)	}	a.categories = CommandCategories{}	for _, command := range a.Commands {		a.categories = a.categories.AddCommand(command.Category, command)	}	sort.Sort(a.categories)	if a.Metadata == nil {		a.Metadata = make(map[string]interface{})	}	if a.Writer == nil {		a.Writer = os.Stdout	}}// Run is the entry point to the cli app. Parses the arguments slice and routes// to the proper flag/args combinationfunc (a *App) Run(arguments []string) (err error) {	a.Setup()	// handle the completion flag separately from the flagset since	// completion could be attempted after a flag, but before its value was put	// on the command line. this causes the flagset to interpret the completion	// flag name as the value of the flag before it which is undesirable	// note that we can only do this because the shell autocomplete function	// always appends the completion flag at the end of the command	shellComplete, arguments := checkShellCompleteFlag(a, arguments)	// parse flags	set, err := flagSet(a.Name, a.Flags)	if err != nil {		return err	}	set.SetOutput(ioutil.Discard)	err = set.Parse(arguments[1:])	nerr := normalizeFlags(a.Flags, set)	context := NewContext(a, set, nil)	if nerr != nil {		fmt.Fprintln(a.Writer, nerr)		ShowAppHelp(context)		return nerr	}	context.shellComplete = shellComplete	if checkCompletions(context) {		return nil	}	if err != nil {		if a.OnUsageError != nil {			err := a.OnUsageError(context, err, false)			HandleExitCoder(err)			return err		}		fmt.Fprintf(a.Writer, "%s %s\n\n", "Incorrect Usage.", err.Error())		ShowAppHelp(context)		return err	}	if !a.HideHelp && checkHelp(context) {		ShowAppHelp(context)		return nil	}	if !a.HideVersion && checkVersion(context) {		ShowVersion(context)		return nil	}	if a.After != nil {		defer func() {			if afterErr := a.After(context); afterErr != nil {				if err != nil {					err = NewMultiError(err, afterErr)				} else {					err = afterErr				}			}		}()	}	if a.Before != nil {		beforeErr := a.Before(context)		if beforeErr != nil {			fmt.Fprintf(a.Writer, "%v\n\n", beforeErr)			ShowAppHelp(context)			HandleExitCoder(beforeErr)			err = beforeErr			return err		}	}	args := context.Args()	if args.Present() {		name := args.First()		c := a.Command(name)		if c != nil {			return c.Run(context)		}	}	if a.Action == nil {		a.Action = helpCommand.Action	}	// Run default Action	err = HandleAction(a.Action, context)	HandleExitCoder(err)	return err}// RunAndExitOnError calls .Run() and exits non-zero if an error was returned//// Deprecated: instead you should return an error that fulfills cli.ExitCoder// to cli.App.Run. This will cause the application to exit with the given eror// code in the cli.ExitCoderfunc (a *App) RunAndExitOnError() {	if err := a.Run(os.Args); err != nil {		fmt.Fprintln(a.errWriter(), err)		OsExiter(1)	}}// RunAsSubcommand invokes the subcommand given the context, parses ctx.Args() to// generate command-specific flagsfunc (a *App) RunAsSubcommand(ctx *Context) (err error) {	// append help to commands	if len(a.Commands) > 0 {		if a.Command(helpCommand.Name) == nil && !a.HideHelp {			a.Commands = append(a.Commands, helpCommand)			if (HelpFlag != BoolFlag{}) {				a.appendFlag(HelpFlag)			}		}	}	newCmds := []Command{}	for _, c := range a.Commands {		if c.HelpName == "" {			c.HelpName = fmt.Sprintf("%s %s", a.HelpName, c.Name)		}		newCmds = append(newCmds, c)	}	a.Commands = newCmds	// parse flags	set, err := flagSet(a.Name, a.Flags)	if err != nil {		return err	}	set.SetOutput(ioutil.Discard)	err = set.Parse(ctx.Args().Tail())	nerr := normalizeFlags(a.Flags, set)	context := NewContext(a, set, ctx)	if nerr != nil {		fmt.Fprintln(a.Writer, nerr)		fmt.Fprintln(a.Writer)		if len(a.Commands) > 0 {			ShowSubcommandHelp(context)		} else {			ShowCommandHelp(ctx, context.Args().First())		}		return nerr	}	if checkCompletions(context) {		return nil	}	if err != nil {		if a.OnUsageError != nil {			err = a.OnUsageError(context, err, true)			HandleExitCoder(err)			return err		}		fmt.Fprintf(a.Writer, "%s %s\n\n", "Incorrect Usage.", err.Error())		ShowSubcommandHelp(context)		return err	}	if len(a.Commands) > 0 {		if checkSubcommandHelp(context) {			return nil		}	} else {		if checkCommandHelp(ctx, context.Args().First()) {			return nil		}	}	if a.After != nil {		defer func() {			afterErr := a.After(context)			if afterErr != nil {				HandleExitCoder(err)				if err != nil {					err = NewMultiError(err, afterErr)				} else {					err = afterErr				}			}		}()	}	if a.Before != nil {		beforeErr := a.Before(context)		if beforeErr != nil {			HandleExitCoder(beforeErr)			err = beforeErr			return err		}	}	args := context.Args()	if args.Present() {		name := args.First()		c := a.Command(name)		if c != nil {			return c.Run(context)		}	}	// Run default Action	err = HandleAction(a.Action, context)	HandleExitCoder(err)	return err}// Command returns the named command on App. Returns nil if the command does not existfunc (a *App) Command(name string) *Command {	for _, c := range a.Commands {		if c.HasName(name) {			return &c		}	}	return nil}// Categories returns a slice containing all the categories with the commands they containfunc (a *App) Categories() CommandCategories {	return a.categories}// VisibleCategories returns a slice of categories and commands that are// Hidden=falsefunc (a *App) VisibleCategories() []*CommandCategory {	ret := []*CommandCategory{}	for _, category := range a.categories {		if visible := func() *CommandCategory {			for _, command := range category.Commands {				if !command.Hidden {					return category				}			}			return nil		}(); visible != nil {			ret = append(ret, visible)		}	}	return ret}// VisibleCommands returns a slice of the Commands with Hidden=falsefunc (a *App) VisibleCommands() []Command {	ret := []Command{}	for _, command := range a.Commands {		if !command.Hidden {			ret = append(ret, command)		}	}	return ret}// VisibleFlags returns a slice of the Flags with Hidden=falsefunc (a *App) VisibleFlags() []Flag {	return visibleFlags(a.Flags)}func (a *App) hasFlag(flag Flag) bool {	for _, f := range a.Flags {		if flag == f {			return true		}	}	return false}func (a *App) errWriter() io.Writer {	// When the app ErrWriter is nil use the package level one.	if a.ErrWriter == nil {		return ErrWriter	}	return a.ErrWriter}func (a *App) appendFlag(flag Flag) {	if !a.hasFlag(flag) {		a.Flags = append(a.Flags, flag)	}}// Author represents someone who has contributed to a cli project.type Author struct {	Name  string // The Authors name	Email string // The Authors email}// String makes Author comply to the Stringer interface, to allow an easy print in the templating processfunc (a Author) String() string {	e := ""	if a.Email != "" {		e = " <" + a.Email + ">"	}	return fmt.Sprintf("%v%v", a.Name, e)}// HandleAction attempts to figure out which Action signature was used.  If// it's an ActionFunc or a func with the legacy signature for Action, the func// is run!func HandleAction(action interface{}, context *Context) (err error) {	if a, ok := action.(func(*Context) error); ok {		return a(context)	} else if a, ok := action.(func(*Context)); ok { // deprecated function signature		a(context)		return nil	} else {		return errInvalidActionType	}}
 |