1// Copyright © 2013 Steve Francia <spf@spf13.com>. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// http://www.apache.org/licenses/LICENSE-2.0 7// 8// Unless required by applicable law or agreed to in writing, software 9// distributed under the License is distributed on an "AS IS" BASIS, 10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11// See the License for the specific language governing permissions and 12// limitations under the License. 13 14// Package cobra is a commander providing a simple interface to create powerful modern CLI interfaces. 15// In addition to providing an interface, Cobra simultaneously provides a controller to organize your application code. 16package cobra 17 18import ( 19 "bytes" 20 "fmt" 21 "io" 22 "os" 23 "path/filepath" 24 "sort" 25 "strings" 26 27 flag "github.com/spf13/pflag" 28) 29 30// FParseErrWhitelist configures Flag parse errors to be ignored 31type FParseErrWhitelist flag.ParseErrorsWhitelist 32 33// Command is just that, a command for your application. 34// E.g. 'go run ...' - 'run' is the command. Cobra requires 35// you to define the usage and description as part of your command 36// definition to ensure usability. 37type Command struct { 38 // Use is the one-line usage message. 39 Use string 40 41 // Aliases is an array of aliases that can be used instead of the first word in Use. 42 Aliases []string 43 44 // SuggestFor is an array of command names for which this command will be suggested - 45 // similar to aliases but only suggests. 46 SuggestFor []string 47 48 // Short is the short description shown in the 'help' output. 49 Short string 50 51 // Long is the long message shown in the 'help <this-command>' output. 52 Long string 53 54 // Example is examples of how to use the command. 55 Example string 56 57 // ValidArgs is list of all valid non-flag arguments that are accepted in bash completions 58 ValidArgs []string 59 60 // Expected arguments 61 Args PositionalArgs 62 63 // ArgAliases is List of aliases for ValidArgs. 64 // These are not suggested to the user in the bash completion, 65 // but accepted if entered manually. 66 ArgAliases []string 67 68 // BashCompletionFunction is custom functions used by the bash autocompletion generator. 69 BashCompletionFunction string 70 71 // Deprecated defines, if this command is deprecated and should print this string when used. 72 Deprecated string 73 74 // Hidden defines, if this command is hidden and should NOT show up in the list of available commands. 75 Hidden bool 76 77 // Annotations are key/value pairs that can be used by applications to identify or 78 // group commands. 79 Annotations map[string]string 80 81 // Version defines the version for this command. If this value is non-empty and the command does not 82 // define a "version" flag, a "version" boolean flag will be added to the command and, if specified, 83 // will print content of the "Version" variable. 84 Version string 85 86 // The *Run functions are executed in the following order: 87 // * PersistentPreRun() 88 // * PreRun() 89 // * Run() 90 // * PostRun() 91 // * PersistentPostRun() 92 // All functions get the same args, the arguments after the command name. 93 // 94 // PersistentPreRun: children of this command will inherit and execute. 95 PersistentPreRun func(cmd *Command, args []string) 96 // PersistentPreRunE: PersistentPreRun but returns an error. 97 PersistentPreRunE func(cmd *Command, args []string) error 98 // PreRun: children of this command will not inherit. 99 PreRun func(cmd *Command, args []string) 100 // PreRunE: PreRun but returns an error. 101 PreRunE func(cmd *Command, args []string) error 102 // Run: Typically the actual work function. Most commands will only implement this. 103 Run func(cmd *Command, args []string) 104 // RunE: Run but returns an error. 105 RunE func(cmd *Command, args []string) error 106 // PostRun: run after the Run command. 107 PostRun func(cmd *Command, args []string) 108 // PostRunE: PostRun but returns an error. 109 PostRunE func(cmd *Command, args []string) error 110 // PersistentPostRun: children of this command will inherit and execute after PostRun. 111 PersistentPostRun func(cmd *Command, args []string) 112 // PersistentPostRunE: PersistentPostRun but returns an error. 113 PersistentPostRunE func(cmd *Command, args []string) error 114 115 // SilenceErrors is an option to quiet errors down stream. 116 SilenceErrors bool 117 118 // SilenceUsage is an option to silence usage when an error occurs. 119 SilenceUsage bool 120 121 // DisableFlagParsing disables the flag parsing. 122 // If this is true all flags will be passed to the command as arguments. 123 DisableFlagParsing bool 124 125 // DisableAutoGenTag defines, if gen tag ("Auto generated by spf13/cobra...") 126 // will be printed by generating docs for this command. 127 DisableAutoGenTag bool 128 129 // DisableFlagsInUseLine will disable the addition of [flags] to the usage 130 // line of a command when printing help or generating docs 131 DisableFlagsInUseLine bool 132 133 // DisableSuggestions disables the suggestions based on Levenshtein distance 134 // that go along with 'unknown command' messages. 135 DisableSuggestions bool 136 // SuggestionsMinimumDistance defines minimum levenshtein distance to display suggestions. 137 // Must be > 0. 138 SuggestionsMinimumDistance int 139 140 // TraverseChildren parses flags on all parents before executing child command. 141 TraverseChildren bool 142 143 //FParseErrWhitelist flag parse errors to be ignored 144 FParseErrWhitelist FParseErrWhitelist 145 146 // commands is the list of commands supported by this program. 147 commands []*Command 148 // parent is a parent command for this command. 149 parent *Command 150 // Max lengths of commands' string lengths for use in padding. 151 commandsMaxUseLen int 152 commandsMaxCommandPathLen int 153 commandsMaxNameLen int 154 // commandsAreSorted defines, if command slice are sorted or not. 155 commandsAreSorted bool 156 // commandCalledAs is the name or alias value used to call this command. 157 commandCalledAs struct { 158 name string 159 called bool 160 } 161 162 // args is actual args parsed from flags. 163 args []string 164 // flagErrorBuf contains all error messages from pflag. 165 flagErrorBuf *bytes.Buffer 166 // flags is full set of flags. 167 flags *flag.FlagSet 168 // pflags contains persistent flags. 169 pflags *flag.FlagSet 170 // lflags contains local flags. 171 lflags *flag.FlagSet 172 // iflags contains inherited flags. 173 iflags *flag.FlagSet 174 // parentsPflags is all persistent flags of cmd's parents. 175 parentsPflags *flag.FlagSet 176 // globNormFunc is the global normalization function 177 // that we can use on every pflag set and children commands 178 globNormFunc func(f *flag.FlagSet, name string) flag.NormalizedName 179 180 // usageFunc is usage func defined by user. 181 usageFunc func(*Command) error 182 // usageTemplate is usage template defined by user. 183 usageTemplate string 184 // flagErrorFunc is func defined by user and it's called when the parsing of 185 // flags returns an error. 186 flagErrorFunc func(*Command, error) error 187 // helpTemplate is help template defined by user. 188 helpTemplate string 189 // helpFunc is help func defined by user. 190 helpFunc func(*Command, []string) 191 // helpCommand is command with usage 'help'. If it's not defined by user, 192 // cobra uses default help command. 193 helpCommand *Command 194 // versionTemplate is the version template defined by user. 195 versionTemplate string 196 197 // inReader is a reader defined by the user that replaces stdin 198 inReader io.Reader 199 // outWriter is a writer defined by the user that replaces stdout 200 outWriter io.Writer 201 // errWriter is a writer defined by the user that replaces stderr 202 errWriter io.Writer 203} 204 205// SetArgs sets arguments for the command. It is set to os.Args[1:] by default, if desired, can be overridden 206// particularly useful when testing. 207func (c *Command) SetArgs(a []string) { 208 c.args = a 209} 210 211// SetOutput sets the destination for usage and error messages. 212// If output is nil, os.Stderr is used. 213// Deprecated: Use SetOut and/or SetErr instead 214func (c *Command) SetOutput(output io.Writer) { 215 c.outWriter = output 216 c.errWriter = output 217} 218 219// SetOut sets the destination for usage messages. 220// If newOut is nil, os.Stdout is used. 221func (c *Command) SetOut(newOut io.Writer) { 222 c.outWriter = newOut 223} 224 225// SetErr sets the destination for error messages. 226// If newErr is nil, os.Stderr is used. 227func (c *Command) SetErr(newErr io.Writer) { 228 c.errWriter = newErr 229} 230 231// SetOut sets the source for input data 232// If newIn is nil, os.Stdin is used. 233func (c *Command) SetIn(newIn io.Reader) { 234 c.inReader = newIn 235} 236 237// SetUsageFunc sets usage function. Usage can be defined by application. 238func (c *Command) SetUsageFunc(f func(*Command) error) { 239 c.usageFunc = f 240} 241 242// SetUsageTemplate sets usage template. Can be defined by Application. 243func (c *Command) SetUsageTemplate(s string) { 244 c.usageTemplate = s 245} 246 247// SetFlagErrorFunc sets a function to generate an error when flag parsing 248// fails. 249func (c *Command) SetFlagErrorFunc(f func(*Command, error) error) { 250 c.flagErrorFunc = f 251} 252 253// SetHelpFunc sets help function. Can be defined by Application. 254func (c *Command) SetHelpFunc(f func(*Command, []string)) { 255 c.helpFunc = f 256} 257 258// SetHelpCommand sets help command. 259func (c *Command) SetHelpCommand(cmd *Command) { 260 c.helpCommand = cmd 261} 262 263// SetHelpTemplate sets help template to be used. Application can use it to set custom template. 264func (c *Command) SetHelpTemplate(s string) { 265 c.helpTemplate = s 266} 267 268// SetVersionTemplate sets version template to be used. Application can use it to set custom template. 269func (c *Command) SetVersionTemplate(s string) { 270 c.versionTemplate = s 271} 272 273// SetGlobalNormalizationFunc sets a normalization function to all flag sets and also to child commands. 274// The user should not have a cyclic dependency on commands. 275func (c *Command) SetGlobalNormalizationFunc(n func(f *flag.FlagSet, name string) flag.NormalizedName) { 276 c.Flags().SetNormalizeFunc(n) 277 c.PersistentFlags().SetNormalizeFunc(n) 278 c.globNormFunc = n 279 280 for _, command := range c.commands { 281 command.SetGlobalNormalizationFunc(n) 282 } 283} 284 285// OutOrStdout returns output to stdout. 286func (c *Command) OutOrStdout() io.Writer { 287 return c.getOut(os.Stdout) 288} 289 290// OutOrStderr returns output to stderr 291func (c *Command) OutOrStderr() io.Writer { 292 return c.getOut(os.Stderr) 293} 294 295// ErrOrStderr returns output to stderr 296func (c *Command) ErrOrStderr() io.Writer { 297 return c.getErr(os.Stderr) 298} 299 300// ErrOrStderr returns output to stderr 301func (c *Command) InOrStdin() io.Reader { 302 return c.getIn(os.Stdin) 303} 304 305func (c *Command) getOut(def io.Writer) io.Writer { 306 if c.outWriter != nil { 307 return c.outWriter 308 } 309 if c.HasParent() { 310 return c.parent.getOut(def) 311 } 312 return def 313} 314 315func (c *Command) getErr(def io.Writer) io.Writer { 316 if c.errWriter != nil { 317 return c.errWriter 318 } 319 if c.HasParent() { 320 return c.parent.getErr(def) 321 } 322 return def 323} 324 325func (c *Command) getIn(def io.Reader) io.Reader { 326 if c.inReader != nil { 327 return c.inReader 328 } 329 if c.HasParent() { 330 return c.parent.getIn(def) 331 } 332 return def 333} 334 335// UsageFunc returns either the function set by SetUsageFunc for this command 336// or a parent, or it returns a default usage function. 337func (c *Command) UsageFunc() (f func(*Command) error) { 338 if c.usageFunc != nil { 339 return c.usageFunc 340 } 341 if c.HasParent() { 342 return c.Parent().UsageFunc() 343 } 344 return func(c *Command) error { 345 c.mergePersistentFlags() 346 err := tmpl(c.OutOrStderr(), c.UsageTemplate(), c) 347 if err != nil { 348 c.Println(err) 349 } 350 return err 351 } 352} 353 354// Usage puts out the usage for the command. 355// Used when a user provides invalid input. 356// Can be defined by user by overriding UsageFunc. 357func (c *Command) Usage() error { 358 return c.UsageFunc()(c) 359} 360 361// HelpFunc returns either the function set by SetHelpFunc for this command 362// or a parent, or it returns a function with default help behavior. 363func (c *Command) HelpFunc() func(*Command, []string) { 364 if c.helpFunc != nil { 365 return c.helpFunc 366 } 367 if c.HasParent() { 368 return c.Parent().HelpFunc() 369 } 370 return func(c *Command, a []string) { 371 c.mergePersistentFlags() 372 err := tmpl(c.OutOrStdout(), c.HelpTemplate(), c) 373 if err != nil { 374 c.Println(err) 375 } 376 } 377} 378 379// Help puts out the help for the command. 380// Used when a user calls help [command]. 381// Can be defined by user by overriding HelpFunc. 382func (c *Command) Help() error { 383 c.HelpFunc()(c, []string{}) 384 return nil 385} 386 387// UsageString returns usage string. 388func (c *Command) UsageString() string { 389 // Storing normal writers 390 tmpOutput := c.outWriter 391 tmpErr := c.errWriter 392 393 bb := new(bytes.Buffer) 394 c.outWriter = bb 395 c.errWriter = bb 396 397 c.Usage() 398 399 // Setting things back to normal 400 c.outWriter = tmpOutput 401 c.errWriter = tmpErr 402 403 return bb.String() 404} 405 406// FlagErrorFunc returns either the function set by SetFlagErrorFunc for this 407// command or a parent, or it returns a function which returns the original 408// error. 409func (c *Command) FlagErrorFunc() (f func(*Command, error) error) { 410 if c.flagErrorFunc != nil { 411 return c.flagErrorFunc 412 } 413 414 if c.HasParent() { 415 return c.parent.FlagErrorFunc() 416 } 417 return func(c *Command, err error) error { 418 return err 419 } 420} 421 422var minUsagePadding = 25 423 424// UsagePadding return padding for the usage. 425func (c *Command) UsagePadding() int { 426 if c.parent == nil || minUsagePadding > c.parent.commandsMaxUseLen { 427 return minUsagePadding 428 } 429 return c.parent.commandsMaxUseLen 430} 431 432var minCommandPathPadding = 11 433 434// CommandPathPadding return padding for the command path. 435func (c *Command) CommandPathPadding() int { 436 if c.parent == nil || minCommandPathPadding > c.parent.commandsMaxCommandPathLen { 437 return minCommandPathPadding 438 } 439 return c.parent.commandsMaxCommandPathLen 440} 441 442var minNamePadding = 11 443 444// NamePadding returns padding for the name. 445func (c *Command) NamePadding() int { 446 if c.parent == nil || minNamePadding > c.parent.commandsMaxNameLen { 447 return minNamePadding 448 } 449 return c.parent.commandsMaxNameLen 450} 451 452// UsageTemplate returns usage template for the command. 453func (c *Command) UsageTemplate() string { 454 if c.usageTemplate != "" { 455 return c.usageTemplate 456 } 457 458 if c.HasParent() { 459 return c.parent.UsageTemplate() 460 } 461 return `Usage:{{if .Runnable}} 462 {{.UseLine}}{{end}}{{if .HasAvailableSubCommands}} 463 {{.CommandPath}} [command]{{end}}{{if gt (len .Aliases) 0}} 464 465Aliases: 466 {{.NameAndAliases}}{{end}}{{if .HasExample}} 467 468Examples: 469{{.Example}}{{end}}{{if .HasAvailableSubCommands}} 470 471Available Commands:{{range .Commands}}{{if (or .IsAvailableCommand (eq .Name "help"))}} 472 {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableLocalFlags}} 473 474Flags: 475{{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasAvailableInheritedFlags}} 476 477Global Flags: 478{{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasHelpSubCommands}} 479 480Additional help topics:{{range .Commands}}{{if .IsAdditionalHelpTopicCommand}} 481 {{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableSubCommands}} 482 483Use "{{.CommandPath}} [command] --help" for more information about a command.{{end}} 484` 485} 486 487// HelpTemplate return help template for the command. 488func (c *Command) HelpTemplate() string { 489 if c.helpTemplate != "" { 490 return c.helpTemplate 491 } 492 493 if c.HasParent() { 494 return c.parent.HelpTemplate() 495 } 496 return `{{with (or .Long .Short)}}{{. | trimTrailingWhitespaces}} 497 498{{end}}{{if or .Runnable .HasSubCommands}}{{.UsageString}}{{end}}` 499} 500 501// VersionTemplate return version template for the command. 502func (c *Command) VersionTemplate() string { 503 if c.versionTemplate != "" { 504 return c.versionTemplate 505 } 506 507 if c.HasParent() { 508 return c.parent.VersionTemplate() 509 } 510 return `{{with .Name}}{{printf "%s " .}}{{end}}{{printf "version %s" .Version}} 511` 512} 513 514func hasNoOptDefVal(name string, fs *flag.FlagSet) bool { 515 flag := fs.Lookup(name) 516 if flag == nil { 517 return false 518 } 519 return flag.NoOptDefVal != "" 520} 521 522func shortHasNoOptDefVal(name string, fs *flag.FlagSet) bool { 523 if len(name) == 0 { 524 return false 525 } 526 527 flag := fs.ShorthandLookup(name[:1]) 528 if flag == nil { 529 return false 530 } 531 return flag.NoOptDefVal != "" 532} 533 534func stripFlags(args []string, c *Command) []string { 535 if len(args) == 0 { 536 return args 537 } 538 c.mergePersistentFlags() 539 540 commands := []string{} 541 flags := c.Flags() 542 543Loop: 544 for len(args) > 0 { 545 s := args[0] 546 args = args[1:] 547 switch { 548 case s == "--": 549 // "--" terminates the flags 550 break Loop 551 case strings.HasPrefix(s, "--") && !strings.Contains(s, "=") && !hasNoOptDefVal(s[2:], flags): 552 // If '--flag arg' then 553 // delete arg from args. 554 fallthrough // (do the same as below) 555 case strings.HasPrefix(s, "-") && !strings.Contains(s, "=") && len(s) == 2 && !shortHasNoOptDefVal(s[1:], flags): 556 // If '-f arg' then 557 // delete 'arg' from args or break the loop if len(args) <= 1. 558 if len(args) <= 1 { 559 break Loop 560 } else { 561 args = args[1:] 562 continue 563 } 564 case s != "" && !strings.HasPrefix(s, "-"): 565 commands = append(commands, s) 566 } 567 } 568 569 return commands 570} 571 572// argsMinusFirstX removes only the first x from args. Otherwise, commands that look like 573// openshift admin policy add-role-to-user admin my-user, lose the admin argument (arg[4]). 574func argsMinusFirstX(args []string, x string) []string { 575 for i, y := range args { 576 if x == y { 577 ret := []string{} 578 ret = append(ret, args[:i]...) 579 ret = append(ret, args[i+1:]...) 580 return ret 581 } 582 } 583 return args 584} 585 586func isFlagArg(arg string) bool { 587 return ((len(arg) >= 3 && arg[1] == '-') || 588 (len(arg) >= 2 && arg[0] == '-' && arg[1] != '-')) 589} 590 591// Find the target command given the args and command tree 592// Meant to be run on the highest node. Only searches down. 593func (c *Command) Find(args []string) (*Command, []string, error) { 594 var innerfind func(*Command, []string) (*Command, []string) 595 596 innerfind = func(c *Command, innerArgs []string) (*Command, []string) { 597 argsWOflags := stripFlags(innerArgs, c) 598 if len(argsWOflags) == 0 { 599 return c, innerArgs 600 } 601 nextSubCmd := argsWOflags[0] 602 603 cmd := c.findNext(nextSubCmd) 604 if cmd != nil { 605 return innerfind(cmd, argsMinusFirstX(innerArgs, nextSubCmd)) 606 } 607 return c, innerArgs 608 } 609 610 commandFound, a := innerfind(c, args) 611 if commandFound.Args == nil { 612 return commandFound, a, legacyArgs(commandFound, stripFlags(a, commandFound)) 613 } 614 return commandFound, a, nil 615} 616 617func (c *Command) findSuggestions(arg string) string { 618 if c.DisableSuggestions { 619 return "" 620 } 621 if c.SuggestionsMinimumDistance <= 0 { 622 c.SuggestionsMinimumDistance = 2 623 } 624 suggestionsString := "" 625 if suggestions := c.SuggestionsFor(arg); len(suggestions) > 0 { 626 suggestionsString += "\n\nDid you mean this?\n" 627 for _, s := range suggestions { 628 suggestionsString += fmt.Sprintf("\t%v\n", s) 629 } 630 } 631 return suggestionsString 632} 633 634func (c *Command) findNext(next string) *Command { 635 matches := make([]*Command, 0) 636 for _, cmd := range c.commands { 637 if cmd.Name() == next || cmd.HasAlias(next) { 638 cmd.commandCalledAs.name = next 639 return cmd 640 } 641 if EnablePrefixMatching && cmd.hasNameOrAliasPrefix(next) { 642 matches = append(matches, cmd) 643 } 644 } 645 646 if len(matches) == 1 { 647 return matches[0] 648 } 649 650 return nil 651} 652 653// Traverse the command tree to find the command, and parse args for 654// each parent. 655func (c *Command) Traverse(args []string) (*Command, []string, error) { 656 flags := []string{} 657 inFlag := false 658 659 for i, arg := range args { 660 switch { 661 // A long flag with a space separated value 662 case strings.HasPrefix(arg, "--") && !strings.Contains(arg, "="): 663 // TODO: this isn't quite right, we should really check ahead for 'true' or 'false' 664 inFlag = !hasNoOptDefVal(arg[2:], c.Flags()) 665 flags = append(flags, arg) 666 continue 667 // A short flag with a space separated value 668 case strings.HasPrefix(arg, "-") && !strings.Contains(arg, "=") && len(arg) == 2 && !shortHasNoOptDefVal(arg[1:], c.Flags()): 669 inFlag = true 670 flags = append(flags, arg) 671 continue 672 // The value for a flag 673 case inFlag: 674 inFlag = false 675 flags = append(flags, arg) 676 continue 677 // A flag without a value, or with an `=` separated value 678 case isFlagArg(arg): 679 flags = append(flags, arg) 680 continue 681 } 682 683 cmd := c.findNext(arg) 684 if cmd == nil { 685 return c, args, nil 686 } 687 688 if err := c.ParseFlags(flags); err != nil { 689 return nil, args, err 690 } 691 return cmd.Traverse(args[i+1:]) 692 } 693 return c, args, nil 694} 695 696// SuggestionsFor provides suggestions for the typedName. 697func (c *Command) SuggestionsFor(typedName string) []string { 698 suggestions := []string{} 699 for _, cmd := range c.commands { 700 if cmd.IsAvailableCommand() { 701 levenshteinDistance := ld(typedName, cmd.Name(), true) 702 suggestByLevenshtein := levenshteinDistance <= c.SuggestionsMinimumDistance 703 suggestByPrefix := strings.HasPrefix(strings.ToLower(cmd.Name()), strings.ToLower(typedName)) 704 if suggestByLevenshtein || suggestByPrefix { 705 suggestions = append(suggestions, cmd.Name()) 706 } 707 for _, explicitSuggestion := range cmd.SuggestFor { 708 if strings.EqualFold(typedName, explicitSuggestion) { 709 suggestions = append(suggestions, cmd.Name()) 710 } 711 } 712 } 713 } 714 return suggestions 715} 716 717// VisitParents visits all parents of the command and invokes fn on each parent. 718func (c *Command) VisitParents(fn func(*Command)) { 719 if c.HasParent() { 720 fn(c.Parent()) 721 c.Parent().VisitParents(fn) 722 } 723} 724 725// Root finds root command. 726func (c *Command) Root() *Command { 727 if c.HasParent() { 728 return c.Parent().Root() 729 } 730 return c 731} 732 733// ArgsLenAtDash will return the length of c.Flags().Args at the moment 734// when a -- was found during args parsing. 735func (c *Command) ArgsLenAtDash() int { 736 return c.Flags().ArgsLenAtDash() 737} 738 739func (c *Command) execute(a []string) (err error) { 740 if c == nil { 741 return fmt.Errorf("Called Execute() on a nil Command") 742 } 743 744 if len(c.Deprecated) > 0 { 745 c.Printf("Command %q is deprecated, %s\n", c.Name(), c.Deprecated) 746 } 747 748 // initialize help and version flag at the last point possible to allow for user 749 // overriding 750 c.InitDefaultHelpFlag() 751 c.InitDefaultVersionFlag() 752 753 err = c.ParseFlags(a) 754 if err != nil { 755 return c.FlagErrorFunc()(c, err) 756 } 757 758 // If help is called, regardless of other flags, return we want help. 759 // Also say we need help if the command isn't runnable. 760 helpVal, err := c.Flags().GetBool("help") 761 if err != nil { 762 // should be impossible to get here as we always declare a help 763 // flag in InitDefaultHelpFlag() 764 c.Println("\"help\" flag declared as non-bool. Please correct your code") 765 return err 766 } 767 768 if helpVal { 769 return flag.ErrHelp 770 } 771 772 // for back-compat, only add version flag behavior if version is defined 773 if c.Version != "" { 774 versionVal, err := c.Flags().GetBool("version") 775 if err != nil { 776 c.Println("\"version\" flag declared as non-bool. Please correct your code") 777 return err 778 } 779 if versionVal { 780 err := tmpl(c.OutOrStdout(), c.VersionTemplate(), c) 781 if err != nil { 782 c.Println(err) 783 } 784 return err 785 } 786 } 787 788 if !c.Runnable() { 789 return flag.ErrHelp 790 } 791 792 c.preRun() 793 794 argWoFlags := c.Flags().Args() 795 if c.DisableFlagParsing { 796 argWoFlags = a 797 } 798 799 if err := c.ValidateArgs(argWoFlags); err != nil { 800 return err 801 } 802 803 for p := c; p != nil; p = p.Parent() { 804 if p.PersistentPreRunE != nil { 805 if err := p.PersistentPreRunE(c, argWoFlags); err != nil { 806 return err 807 } 808 break 809 } else if p.PersistentPreRun != nil { 810 p.PersistentPreRun(c, argWoFlags) 811 break 812 } 813 } 814 if c.PreRunE != nil { 815 if err := c.PreRunE(c, argWoFlags); err != nil { 816 return err 817 } 818 } else if c.PreRun != nil { 819 c.PreRun(c, argWoFlags) 820 } 821 822 if err := c.validateRequiredFlags(); err != nil { 823 return err 824 } 825 if c.RunE != nil { 826 if err := c.RunE(c, argWoFlags); err != nil { 827 return err 828 } 829 } else { 830 c.Run(c, argWoFlags) 831 } 832 if c.PostRunE != nil { 833 if err := c.PostRunE(c, argWoFlags); err != nil { 834 return err 835 } 836 } else if c.PostRun != nil { 837 c.PostRun(c, argWoFlags) 838 } 839 for p := c; p != nil; p = p.Parent() { 840 if p.PersistentPostRunE != nil { 841 if err := p.PersistentPostRunE(c, argWoFlags); err != nil { 842 return err 843 } 844 break 845 } else if p.PersistentPostRun != nil { 846 p.PersistentPostRun(c, argWoFlags) 847 break 848 } 849 } 850 851 return nil 852} 853 854func (c *Command) preRun() { 855 for _, x := range initializers { 856 x() 857 } 858} 859 860// Execute uses the args (os.Args[1:] by default) 861// and run through the command tree finding appropriate matches 862// for commands and then corresponding flags. 863func (c *Command) Execute() error { 864 _, err := c.ExecuteC() 865 return err 866} 867 868// ExecuteC executes the command. 869func (c *Command) ExecuteC() (cmd *Command, err error) { 870 // Regardless of what command execute is called on, run on Root only 871 if c.HasParent() { 872 return c.Root().ExecuteC() 873 } 874 875 // windows hook 876 if preExecHookFn != nil { 877 preExecHookFn(c) 878 } 879 880 // initialize help as the last point possible to allow for user 881 // overriding 882 c.InitDefaultHelpCmd() 883 884 args := c.args 885 886 // Workaround FAIL with "go test -v" or "cobra.test -test.v", see #155 887 if c.args == nil && filepath.Base(os.Args[0]) != "cobra.test" { 888 args = os.Args[1:] 889 } 890 891 var flags []string 892 if c.TraverseChildren { 893 cmd, flags, err = c.Traverse(args) 894 } else { 895 cmd, flags, err = c.Find(args) 896 } 897 if err != nil { 898 // If found parse to a subcommand and then failed, talk about the subcommand 899 if cmd != nil { 900 c = cmd 901 } 902 if !c.SilenceErrors { 903 c.Println("Error:", err.Error()) 904 c.Printf("Run '%v --help' for usage.\n", c.CommandPath()) 905 } 906 return c, err 907 } 908 909 cmd.commandCalledAs.called = true 910 if cmd.commandCalledAs.name == "" { 911 cmd.commandCalledAs.name = cmd.Name() 912 } 913 914 err = cmd.execute(flags) 915 if err != nil { 916 // Always show help if requested, even if SilenceErrors is in 917 // effect 918 if err == flag.ErrHelp { 919 cmd.HelpFunc()(cmd, args) 920 return cmd, nil 921 } 922 923 // If root command has SilentErrors flagged, 924 // all subcommands should respect it 925 if !cmd.SilenceErrors && !c.SilenceErrors { 926 c.Println("Error:", err.Error()) 927 } 928 929 // If root command has SilentUsage flagged, 930 // all subcommands should respect it 931 if !cmd.SilenceUsage && !c.SilenceUsage { 932 c.Println(cmd.UsageString()) 933 } 934 } 935 return cmd, err 936} 937 938func (c *Command) ValidateArgs(args []string) error { 939 if c.Args == nil { 940 return nil 941 } 942 return c.Args(c, args) 943} 944 945func (c *Command) validateRequiredFlags() error { 946 flags := c.Flags() 947 missingFlagNames := []string{} 948 flags.VisitAll(func(pflag *flag.Flag) { 949 requiredAnnotation, found := pflag.Annotations[BashCompOneRequiredFlag] 950 if !found { 951 return 952 } 953 if (requiredAnnotation[0] == "true") && !pflag.Changed { 954 missingFlagNames = append(missingFlagNames, pflag.Name) 955 } 956 }) 957 958 if len(missingFlagNames) > 0 { 959 return fmt.Errorf(`required flag(s) "%s" not set`, strings.Join(missingFlagNames, `", "`)) 960 } 961 return nil 962} 963 964// InitDefaultHelpFlag adds default help flag to c. 965// It is called automatically by executing the c or by calling help and usage. 966// If c already has help flag, it will do nothing. 967func (c *Command) InitDefaultHelpFlag() { 968 c.mergePersistentFlags() 969 if c.Flags().Lookup("help") == nil { 970 usage := "help for " 971 if c.Name() == "" { 972 usage += "this command" 973 } else { 974 usage += c.Name() 975 } 976 c.Flags().BoolP("help", "h", false, usage) 977 } 978} 979 980// InitDefaultVersionFlag adds default version flag to c. 981// It is called automatically by executing the c. 982// If c already has a version flag, it will do nothing. 983// If c.Version is empty, it will do nothing. 984func (c *Command) InitDefaultVersionFlag() { 985 if c.Version == "" { 986 return 987 } 988 989 c.mergePersistentFlags() 990 if c.Flags().Lookup("version") == nil { 991 usage := "version for " 992 if c.Name() == "" { 993 usage += "this command" 994 } else { 995 usage += c.Name() 996 } 997 c.Flags().Bool("version", false, usage) 998 } 999} 1000 1001// InitDefaultHelpCmd adds default help command to c. 1002// It is called automatically by executing the c or by calling help and usage. 1003// If c already has help command or c has no subcommands, it will do nothing. 1004func (c *Command) InitDefaultHelpCmd() { 1005 if !c.HasSubCommands() { 1006 return 1007 } 1008 1009 if c.helpCommand == nil { 1010 c.helpCommand = &Command{ 1011 Use: "help [command]", 1012 Short: "Help about any command", 1013 Long: `Help provides help for any command in the application. 1014Simply type ` + c.Name() + ` help [path to command] for full details.`, 1015 1016 Run: func(c *Command, args []string) { 1017 cmd, _, e := c.Root().Find(args) 1018 if cmd == nil || e != nil { 1019 c.Printf("Unknown help topic %#q\n", args) 1020 c.Root().Usage() 1021 } else { 1022 cmd.InitDefaultHelpFlag() // make possible 'help' flag to be shown 1023 cmd.Help() 1024 } 1025 }, 1026 } 1027 } 1028 c.RemoveCommand(c.helpCommand) 1029 c.AddCommand(c.helpCommand) 1030} 1031 1032// ResetCommands delete parent, subcommand and help command from c. 1033func (c *Command) ResetCommands() { 1034 c.parent = nil 1035 c.commands = nil 1036 c.helpCommand = nil 1037 c.parentsPflags = nil 1038} 1039 1040// Sorts commands by their names. 1041type commandSorterByName []*Command 1042 1043func (c commandSorterByName) Len() int { return len(c) } 1044func (c commandSorterByName) Swap(i, j int) { c[i], c[j] = c[j], c[i] } 1045func (c commandSorterByName) Less(i, j int) bool { return c[i].Name() < c[j].Name() } 1046 1047// Commands returns a sorted slice of child commands. 1048func (c *Command) Commands() []*Command { 1049 // do not sort commands if it already sorted or sorting was disabled 1050 if EnableCommandSorting && !c.commandsAreSorted { 1051 sort.Sort(commandSorterByName(c.commands)) 1052 c.commandsAreSorted = true 1053 } 1054 return c.commands 1055} 1056 1057// AddCommand adds one or more commands to this parent command. 1058func (c *Command) AddCommand(cmds ...*Command) { 1059 for i, x := range cmds { 1060 if cmds[i] == c { 1061 panic("Command can't be a child of itself") 1062 } 1063 cmds[i].parent = c 1064 // update max lengths 1065 usageLen := len(x.Use) 1066 if usageLen > c.commandsMaxUseLen { 1067 c.commandsMaxUseLen = usageLen 1068 } 1069 commandPathLen := len(x.CommandPath()) 1070 if commandPathLen > c.commandsMaxCommandPathLen { 1071 c.commandsMaxCommandPathLen = commandPathLen 1072 } 1073 nameLen := len(x.Name()) 1074 if nameLen > c.commandsMaxNameLen { 1075 c.commandsMaxNameLen = nameLen 1076 } 1077 // If global normalization function exists, update all children 1078 if c.globNormFunc != nil { 1079 x.SetGlobalNormalizationFunc(c.globNormFunc) 1080 } 1081 c.commands = append(c.commands, x) 1082 c.commandsAreSorted = false 1083 } 1084} 1085 1086// RemoveCommand removes one or more commands from a parent command. 1087func (c *Command) RemoveCommand(cmds ...*Command) { 1088 commands := []*Command{} 1089main: 1090 for _, command := range c.commands { 1091 for _, cmd := range cmds { 1092 if command == cmd { 1093 command.parent = nil 1094 continue main 1095 } 1096 } 1097 commands = append(commands, command) 1098 } 1099 c.commands = commands 1100 // recompute all lengths 1101 c.commandsMaxUseLen = 0 1102 c.commandsMaxCommandPathLen = 0 1103 c.commandsMaxNameLen = 0 1104 for _, command := range c.commands { 1105 usageLen := len(command.Use) 1106 if usageLen > c.commandsMaxUseLen { 1107 c.commandsMaxUseLen = usageLen 1108 } 1109 commandPathLen := len(command.CommandPath()) 1110 if commandPathLen > c.commandsMaxCommandPathLen { 1111 c.commandsMaxCommandPathLen = commandPathLen 1112 } 1113 nameLen := len(command.Name()) 1114 if nameLen > c.commandsMaxNameLen { 1115 c.commandsMaxNameLen = nameLen 1116 } 1117 } 1118} 1119 1120// Print is a convenience method to Print to the defined output, fallback to Stderr if not set. 1121func (c *Command) Print(i ...interface{}) { 1122 fmt.Fprint(c.OutOrStderr(), i...) 1123} 1124 1125// Println is a convenience method to Println to the defined output, fallback to Stderr if not set. 1126func (c *Command) Println(i ...interface{}) { 1127 c.Print(fmt.Sprintln(i...)) 1128} 1129 1130// Printf is a convenience method to Printf to the defined output, fallback to Stderr if not set. 1131func (c *Command) Printf(format string, i ...interface{}) { 1132 c.Print(fmt.Sprintf(format, i...)) 1133} 1134 1135// PrintErr is a convenience method to Print to the defined Err output, fallback to Stderr if not set. 1136func (c *Command) PrintErr(i ...interface{}) { 1137 fmt.Fprint(c.ErrOrStderr(), i...) 1138} 1139 1140// PrintErrln is a convenience method to Println to the defined Err output, fallback to Stderr if not set. 1141func (c *Command) PrintErrln(i ...interface{}) { 1142 c.Print(fmt.Sprintln(i...)) 1143} 1144 1145// PrintErrf is a convenience method to Printf to the defined Err output, fallback to Stderr if not set. 1146func (c *Command) PrintErrf(format string, i ...interface{}) { 1147 c.Print(fmt.Sprintf(format, i...)) 1148} 1149 1150// CommandPath returns the full path to this command. 1151func (c *Command) CommandPath() string { 1152 if c.HasParent() { 1153 return c.Parent().CommandPath() + " " + c.Name() 1154 } 1155 return c.Name() 1156} 1157 1158// UseLine puts out the full usage for a given command (including parents). 1159func (c *Command) UseLine() string { 1160 var useline string 1161 if c.HasParent() { 1162 useline = c.parent.CommandPath() + " " + c.Use 1163 } else { 1164 useline = c.Use 1165 } 1166 if c.DisableFlagsInUseLine { 1167 return useline 1168 } 1169 if c.HasAvailableFlags() && !strings.Contains(useline, "[flags]") { 1170 useline += " [flags]" 1171 } 1172 return useline 1173} 1174 1175// DebugFlags used to determine which flags have been assigned to which commands 1176// and which persist. 1177func (c *Command) DebugFlags() { 1178 c.Println("DebugFlags called on", c.Name()) 1179 var debugflags func(*Command) 1180 1181 debugflags = func(x *Command) { 1182 if x.HasFlags() || x.HasPersistentFlags() { 1183 c.Println(x.Name()) 1184 } 1185 if x.HasFlags() { 1186 x.flags.VisitAll(func(f *flag.Flag) { 1187 if x.HasPersistentFlags() && x.persistentFlag(f.Name) != nil { 1188 c.Println(" -"+f.Shorthand+",", "--"+f.Name, "["+f.DefValue+"]", "", f.Value, " [LP]") 1189 } else { 1190 c.Println(" -"+f.Shorthand+",", "--"+f.Name, "["+f.DefValue+"]", "", f.Value, " [L]") 1191 } 1192 }) 1193 } 1194 if x.HasPersistentFlags() { 1195 x.pflags.VisitAll(func(f *flag.Flag) { 1196 if x.HasFlags() { 1197 if x.flags.Lookup(f.Name) == nil { 1198 c.Println(" -"+f.Shorthand+",", "--"+f.Name, "["+f.DefValue+"]", "", f.Value, " [P]") 1199 } 1200 } else { 1201 c.Println(" -"+f.Shorthand+",", "--"+f.Name, "["+f.DefValue+"]", "", f.Value, " [P]") 1202 } 1203 }) 1204 } 1205 c.Println(x.flagErrorBuf) 1206 if x.HasSubCommands() { 1207 for _, y := range x.commands { 1208 debugflags(y) 1209 } 1210 } 1211 } 1212 1213 debugflags(c) 1214} 1215 1216// Name returns the command's name: the first word in the use line. 1217func (c *Command) Name() string { 1218 name := c.Use 1219 i := strings.Index(name, " ") 1220 if i >= 0 { 1221 name = name[:i] 1222 } 1223 return name 1224} 1225 1226// HasAlias determines if a given string is an alias of the command. 1227func (c *Command) HasAlias(s string) bool { 1228 for _, a := range c.Aliases { 1229 if a == s { 1230 return true 1231 } 1232 } 1233 return false 1234} 1235 1236// CalledAs returns the command name or alias that was used to invoke 1237// this command or an empty string if the command has not been called. 1238func (c *Command) CalledAs() string { 1239 if c.commandCalledAs.called { 1240 return c.commandCalledAs.name 1241 } 1242 return "" 1243} 1244 1245// hasNameOrAliasPrefix returns true if the Name or any of aliases start 1246// with prefix 1247func (c *Command) hasNameOrAliasPrefix(prefix string) bool { 1248 if strings.HasPrefix(c.Name(), prefix) { 1249 c.commandCalledAs.name = c.Name() 1250 return true 1251 } 1252 for _, alias := range c.Aliases { 1253 if strings.HasPrefix(alias, prefix) { 1254 c.commandCalledAs.name = alias 1255 return true 1256 } 1257 } 1258 return false 1259} 1260 1261// NameAndAliases returns a list of the command name and all aliases 1262func (c *Command) NameAndAliases() string { 1263 return strings.Join(append([]string{c.Name()}, c.Aliases...), ", ") 1264} 1265 1266// HasExample determines if the command has example. 1267func (c *Command) HasExample() bool { 1268 return len(c.Example) > 0 1269} 1270 1271// Runnable determines if the command is itself runnable. 1272func (c *Command) Runnable() bool { 1273 return c.Run != nil || c.RunE != nil 1274} 1275 1276// HasSubCommands determines if the command has children commands. 1277func (c *Command) HasSubCommands() bool { 1278 return len(c.commands) > 0 1279} 1280 1281// IsAvailableCommand determines if a command is available as a non-help command 1282// (this includes all non deprecated/hidden commands). 1283func (c *Command) IsAvailableCommand() bool { 1284 if len(c.Deprecated) != 0 || c.Hidden { 1285 return false 1286 } 1287 1288 if c.HasParent() && c.Parent().helpCommand == c { 1289 return false 1290 } 1291 1292 if c.Runnable() || c.HasAvailableSubCommands() { 1293 return true 1294 } 1295 1296 return false 1297} 1298 1299// IsAdditionalHelpTopicCommand determines if a command is an additional 1300// help topic command; additional help topic command is determined by the 1301// fact that it is NOT runnable/hidden/deprecated, and has no sub commands that 1302// are runnable/hidden/deprecated. 1303// Concrete example: https://github.com/spf13/cobra/issues/393#issuecomment-282741924. 1304func (c *Command) IsAdditionalHelpTopicCommand() bool { 1305 // if a command is runnable, deprecated, or hidden it is not a 'help' command 1306 if c.Runnable() || len(c.Deprecated) != 0 || c.Hidden { 1307 return false 1308 } 1309 1310 // if any non-help sub commands are found, the command is not a 'help' command 1311 for _, sub := range c.commands { 1312 if !sub.IsAdditionalHelpTopicCommand() { 1313 return false 1314 } 1315 } 1316 1317 // the command either has no sub commands, or no non-help sub commands 1318 return true 1319} 1320 1321// HasHelpSubCommands determines if a command has any available 'help' sub commands 1322// that need to be shown in the usage/help default template under 'additional help 1323// topics'. 1324func (c *Command) HasHelpSubCommands() bool { 1325 // return true on the first found available 'help' sub command 1326 for _, sub := range c.commands { 1327 if sub.IsAdditionalHelpTopicCommand() { 1328 return true 1329 } 1330 } 1331 1332 // the command either has no sub commands, or no available 'help' sub commands 1333 return false 1334} 1335 1336// HasAvailableSubCommands determines if a command has available sub commands that 1337// need to be shown in the usage/help default template under 'available commands'. 1338func (c *Command) HasAvailableSubCommands() bool { 1339 // return true on the first found available (non deprecated/help/hidden) 1340 // sub command 1341 for _, sub := range c.commands { 1342 if sub.IsAvailableCommand() { 1343 return true 1344 } 1345 } 1346 1347 // the command either has no sub commands, or no available (non deprecated/help/hidden) 1348 // sub commands 1349 return false 1350} 1351 1352// HasParent determines if the command is a child command. 1353func (c *Command) HasParent() bool { 1354 return c.parent != nil 1355} 1356 1357// GlobalNormalizationFunc returns the global normalization function or nil if it doesn't exist. 1358func (c *Command) GlobalNormalizationFunc() func(f *flag.FlagSet, name string) flag.NormalizedName { 1359 return c.globNormFunc 1360} 1361 1362// Flags returns the complete FlagSet that applies 1363// to this command (local and persistent declared here and by all parents). 1364func (c *Command) Flags() *flag.FlagSet { 1365 if c.flags == nil { 1366 c.flags = flag.NewFlagSet(c.Name(), flag.ContinueOnError) 1367 if c.flagErrorBuf == nil { 1368 c.flagErrorBuf = new(bytes.Buffer) 1369 } 1370 c.flags.SetOutput(c.flagErrorBuf) 1371 } 1372 1373 return c.flags 1374} 1375 1376// LocalNonPersistentFlags are flags specific to this command which will NOT persist to subcommands. 1377func (c *Command) LocalNonPersistentFlags() *flag.FlagSet { 1378 persistentFlags := c.PersistentFlags() 1379 1380 out := flag.NewFlagSet(c.Name(), flag.ContinueOnError) 1381 c.LocalFlags().VisitAll(func(f *flag.Flag) { 1382 if persistentFlags.Lookup(f.Name) == nil { 1383 out.AddFlag(f) 1384 } 1385 }) 1386 return out 1387} 1388 1389// LocalFlags returns the local FlagSet specifically set in the current command. 1390func (c *Command) LocalFlags() *flag.FlagSet { 1391 c.mergePersistentFlags() 1392 1393 if c.lflags == nil { 1394 c.lflags = flag.NewFlagSet(c.Name(), flag.ContinueOnError) 1395 if c.flagErrorBuf == nil { 1396 c.flagErrorBuf = new(bytes.Buffer) 1397 } 1398 c.lflags.SetOutput(c.flagErrorBuf) 1399 } 1400 c.lflags.SortFlags = c.Flags().SortFlags 1401 if c.globNormFunc != nil { 1402 c.lflags.SetNormalizeFunc(c.globNormFunc) 1403 } 1404 1405 addToLocal := func(f *flag.Flag) { 1406 if c.lflags.Lookup(f.Name) == nil && c.parentsPflags.Lookup(f.Name) == nil { 1407 c.lflags.AddFlag(f) 1408 } 1409 } 1410 c.Flags().VisitAll(addToLocal) 1411 c.PersistentFlags().VisitAll(addToLocal) 1412 return c.lflags 1413} 1414 1415// InheritedFlags returns all flags which were inherited from parent commands. 1416func (c *Command) InheritedFlags() *flag.FlagSet { 1417 c.mergePersistentFlags() 1418 1419 if c.iflags == nil { 1420 c.iflags = flag.NewFlagSet(c.Name(), flag.ContinueOnError) 1421 if c.flagErrorBuf == nil { 1422 c.flagErrorBuf = new(bytes.Buffer) 1423 } 1424 c.iflags.SetOutput(c.flagErrorBuf) 1425 } 1426 1427 local := c.LocalFlags() 1428 if c.globNormFunc != nil { 1429 c.iflags.SetNormalizeFunc(c.globNormFunc) 1430 } 1431 1432 c.parentsPflags.VisitAll(func(f *flag.Flag) { 1433 if c.iflags.Lookup(f.Name) == nil && local.Lookup(f.Name) == nil { 1434 c.iflags.AddFlag(f) 1435 } 1436 }) 1437 return c.iflags 1438} 1439 1440// NonInheritedFlags returns all flags which were not inherited from parent commands. 1441func (c *Command) NonInheritedFlags() *flag.FlagSet { 1442 return c.LocalFlags() 1443} 1444 1445// PersistentFlags returns the persistent FlagSet specifically set in the current command. 1446func (c *Command) PersistentFlags() *flag.FlagSet { 1447 if c.pflags == nil { 1448 c.pflags = flag.NewFlagSet(c.Name(), flag.ContinueOnError) 1449 if c.flagErrorBuf == nil { 1450 c.flagErrorBuf = new(bytes.Buffer) 1451 } 1452 c.pflags.SetOutput(c.flagErrorBuf) 1453 } 1454 return c.pflags 1455} 1456 1457// ResetFlags deletes all flags from command. 1458func (c *Command) ResetFlags() { 1459 c.flagErrorBuf = new(bytes.Buffer) 1460 c.flagErrorBuf.Reset() 1461 c.flags = flag.NewFlagSet(c.Name(), flag.ContinueOnError) 1462 c.flags.SetOutput(c.flagErrorBuf) 1463 c.pflags = flag.NewFlagSet(c.Name(), flag.ContinueOnError) 1464 c.pflags.SetOutput(c.flagErrorBuf) 1465 1466 c.lflags = nil 1467 c.iflags = nil 1468 c.parentsPflags = nil 1469} 1470 1471// HasFlags checks if the command contains any flags (local plus persistent from the entire structure). 1472func (c *Command) HasFlags() bool { 1473 return c.Flags().HasFlags() 1474} 1475 1476// HasPersistentFlags checks if the command contains persistent flags. 1477func (c *Command) HasPersistentFlags() bool { 1478 return c.PersistentFlags().HasFlags() 1479} 1480 1481// HasLocalFlags checks if the command has flags specifically declared locally. 1482func (c *Command) HasLocalFlags() bool { 1483 return c.LocalFlags().HasFlags() 1484} 1485 1486// HasInheritedFlags checks if the command has flags inherited from its parent command. 1487func (c *Command) HasInheritedFlags() bool { 1488 return c.InheritedFlags().HasFlags() 1489} 1490 1491// HasAvailableFlags checks if the command contains any flags (local plus persistent from the entire 1492// structure) which are not hidden or deprecated. 1493func (c *Command) HasAvailableFlags() bool { 1494 return c.Flags().HasAvailableFlags() 1495} 1496 1497// HasAvailablePersistentFlags checks if the command contains persistent flags which are not hidden or deprecated. 1498func (c *Command) HasAvailablePersistentFlags() bool { 1499 return c.PersistentFlags().HasAvailableFlags() 1500} 1501 1502// HasAvailableLocalFlags checks if the command has flags specifically declared locally which are not hidden 1503// or deprecated. 1504func (c *Command) HasAvailableLocalFlags() bool { 1505 return c.LocalFlags().HasAvailableFlags() 1506} 1507 1508// HasAvailableInheritedFlags checks if the command has flags inherited from its parent command which are 1509// not hidden or deprecated. 1510func (c *Command) HasAvailableInheritedFlags() bool { 1511 return c.InheritedFlags().HasAvailableFlags() 1512} 1513 1514// Flag climbs up the command tree looking for matching flag. 1515func (c *Command) Flag(name string) (flag *flag.Flag) { 1516 flag = c.Flags().Lookup(name) 1517 1518 if flag == nil { 1519 flag = c.persistentFlag(name) 1520 } 1521 1522 return 1523} 1524 1525// Recursively find matching persistent flag. 1526func (c *Command) persistentFlag(name string) (flag *flag.Flag) { 1527 if c.HasPersistentFlags() { 1528 flag = c.PersistentFlags().Lookup(name) 1529 } 1530 1531 if flag == nil { 1532 c.updateParentsPflags() 1533 flag = c.parentsPflags.Lookup(name) 1534 } 1535 return 1536} 1537 1538// ParseFlags parses persistent flag tree and local flags. 1539func (c *Command) ParseFlags(args []string) error { 1540 if c.DisableFlagParsing { 1541 return nil 1542 } 1543 1544 if c.flagErrorBuf == nil { 1545 c.flagErrorBuf = new(bytes.Buffer) 1546 } 1547 beforeErrorBufLen := c.flagErrorBuf.Len() 1548 c.mergePersistentFlags() 1549 1550 //do it here after merging all flags and just before parse 1551 c.Flags().ParseErrorsWhitelist = flag.ParseErrorsWhitelist(c.FParseErrWhitelist) 1552 1553 err := c.Flags().Parse(args) 1554 // Print warnings if they occurred (e.g. deprecated flag messages). 1555 if c.flagErrorBuf.Len()-beforeErrorBufLen > 0 && err == nil { 1556 c.Print(c.flagErrorBuf.String()) 1557 } 1558 1559 return err 1560} 1561 1562// Parent returns a commands parent command. 1563func (c *Command) Parent() *Command { 1564 return c.parent 1565} 1566 1567// mergePersistentFlags merges c.PersistentFlags() to c.Flags() 1568// and adds missing persistent flags of all parents. 1569func (c *Command) mergePersistentFlags() { 1570 c.updateParentsPflags() 1571 c.Flags().AddFlagSet(c.PersistentFlags()) 1572 c.Flags().AddFlagSet(c.parentsPflags) 1573} 1574 1575// updateParentsPflags updates c.parentsPflags by adding 1576// new persistent flags of all parents. 1577// If c.parentsPflags == nil, it makes new. 1578func (c *Command) updateParentsPflags() { 1579 if c.parentsPflags == nil { 1580 c.parentsPflags = flag.NewFlagSet(c.Name(), flag.ContinueOnError) 1581 c.parentsPflags.SetOutput(c.flagErrorBuf) 1582 c.parentsPflags.SortFlags = false 1583 } 1584 1585 if c.globNormFunc != nil { 1586 c.parentsPflags.SetNormalizeFunc(c.globNormFunc) 1587 } 1588 1589 c.Root().PersistentFlags().AddFlagSet(flag.CommandLine) 1590 1591 c.VisitParents(func(parent *Command) { 1592 c.parentsPflags.AddFlagSet(parent.PersistentFlags()) 1593 }) 1594} 1595