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