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