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