vendor/github.com/spf13/cobra/command.go
changeset 265 05c40b36d3b2
parent 260 445e01aede7e
equal deleted inserted replaced
264:8f478162d991 265:05c40b36d3b2
     1 // Copyright © 2013 Steve Francia <spf@spf13.com>.
     1 // Copyright 2013-2022 The Cobra Authors
     2 //
     2 //
     3 // Licensed under the Apache License, Version 2.0 (the "License");
     3 // Licensed under the Apache License, Version 2.0 (the "License");
     4 // you may not use this file except in compliance with 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
     5 // You may obtain a copy of the License at
     6 // http://www.apache.org/licenses/LICENSE-2.0
     6 //
       
     7 //      http://www.apache.org/licenses/LICENSE-2.0
     7 //
     8 //
     8 // Unless required by applicable law or agreed to in writing, software
     9 // Unless required by applicable law or agreed to in writing, software
     9 // distributed under the License is distributed on an "AS IS" BASIS,
    10 // distributed under the License is distributed on an "AS IS" BASIS,
    10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11 // See the License for the specific language governing permissions and
    12 // See the License for the specific language governing permissions and
    27 	"strings"
    28 	"strings"
    28 
    29 
    29 	flag "github.com/spf13/pflag"
    30 	flag "github.com/spf13/pflag"
    30 )
    31 )
    31 
    32 
       
    33 const FlagSetByCobraAnnotation = "cobra_annotation_flag_set_by_cobra"
       
    34 
    32 // FParseErrWhitelist configures Flag parse errors to be ignored
    35 // FParseErrWhitelist configures Flag parse errors to be ignored
    33 type FParseErrWhitelist flag.ParseErrorsWhitelist
    36 type FParseErrWhitelist flag.ParseErrorsWhitelist
       
    37 
       
    38 // Structure to manage groups for commands
       
    39 type Group struct {
       
    40 	ID    string
       
    41 	Title string
       
    42 }
    34 
    43 
    35 // Command is just that, a command for your application.
    44 // Command is just that, a command for your application.
    36 // E.g.  'go run ...' - 'run' is the command. Cobra requires
    45 // E.g.  'go run ...' - 'run' is the command. Cobra requires
    37 // you to define the usage and description as part of your command
    46 // you to define the usage and description as part of your command
    38 // definition to ensure usability.
    47 // definition to ensure usability.
    55 	// similar to aliases but only suggests.
    64 	// similar to aliases but only suggests.
    56 	SuggestFor []string
    65 	SuggestFor []string
    57 
    66 
    58 	// Short is the short description shown in the 'help' output.
    67 	// Short is the short description shown in the 'help' output.
    59 	Short string
    68 	Short string
       
    69 
       
    70 	// The group id under which this subcommand is grouped in the 'help' output of its parent.
       
    71 	GroupID string
    60 
    72 
    61 	// Long is the long message shown in the 'help <this-command>' output.
    73 	// Long is the long message shown in the 'help <this-command>' output.
    62 	Long string
    74 	Long string
    63 
    75 
    64 	// Example is examples of how to use the command.
    76 	// Example is examples of how to use the command.
   123 	// PersistentPostRun: children of this command will inherit and execute after PostRun.
   135 	// PersistentPostRun: children of this command will inherit and execute after PostRun.
   124 	PersistentPostRun func(cmd *Command, args []string)
   136 	PersistentPostRun func(cmd *Command, args []string)
   125 	// PersistentPostRunE: PersistentPostRun but returns an error.
   137 	// PersistentPostRunE: PersistentPostRun but returns an error.
   126 	PersistentPostRunE func(cmd *Command, args []string) error
   138 	PersistentPostRunE func(cmd *Command, args []string) error
   127 
   139 
       
   140 	// groups for subcommands
       
   141 	commandgroups []*Group
       
   142 
   128 	// args is actual args parsed from flags.
   143 	// args is actual args parsed from flags.
   129 	args []string
   144 	args []string
   130 	// flagErrorBuf contains all error messages from pflag.
   145 	// flagErrorBuf contains all error messages from pflag.
   131 	flagErrorBuf *bytes.Buffer
   146 	flagErrorBuf *bytes.Buffer
   132 	// flags is full set of flags.
   147 	// flags is full set of flags.
   155 	// helpFunc is help func defined by user.
   170 	// helpFunc is help func defined by user.
   156 	helpFunc func(*Command, []string)
   171 	helpFunc func(*Command, []string)
   157 	// helpCommand is command with usage 'help'. If it's not defined by user,
   172 	// helpCommand is command with usage 'help'. If it's not defined by user,
   158 	// cobra uses default help command.
   173 	// cobra uses default help command.
   159 	helpCommand *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 
   160 	// versionTemplate is the version template defined by user.
   181 	// versionTemplate is the version template defined by user.
   161 	versionTemplate string
   182 	versionTemplate string
   162 
   183 
   163 	// inReader is a reader defined by the user that replaces stdin
   184 	// inReader is a reader defined by the user that replaces stdin
   164 	inReader io.Reader
   185 	inReader io.Reader
   234 // returned by Context after one of these functions has been called.
   255 // returned by Context after one of these functions has been called.
   235 func (c *Command) Context() context.Context {
   256 func (c *Command) Context() context.Context {
   236 	return c.ctx
   257 	return c.ctx
   237 }
   258 }
   238 
   259 
   239 // SetContext sets context for the command. It is set to context.Background by default and will be overwritten by
   260 // SetContext sets context for the command. This context will be overwritten by
   240 // Command.ExecuteContext or Command.ExecuteContextC
   261 // Command.ExecuteContext or Command.ExecuteContextC.
   241 func (c *Command) SetContext(ctx context.Context) {
   262 func (c *Command) SetContext(ctx context.Context) {
   242 	c.ctx = ctx
   263 	c.ctx = ctx
   243 }
   264 }
   244 
   265 
   245 // SetArgs sets arguments for the command. It is set to os.Args[1:] by default, if desired, can be overridden
   266 // SetArgs sets arguments for the command. It is set to os.Args[1:] by default, if desired, can be overridden
   296 }
   317 }
   297 
   318 
   298 // SetHelpCommand sets help command.
   319 // SetHelpCommand sets help command.
   299 func (c *Command) SetHelpCommand(cmd *Command) {
   320 func (c *Command) SetHelpCommand(cmd *Command) {
   300 	c.helpCommand = cmd
   321 	c.helpCommand = cmd
       
   322 }
       
   323 
       
   324 // SetHelpCommandGroup 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 // SetCompletionCommandGroup 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
   301 }
   337 }
   302 
   338 
   303 // SetHelpTemplate sets help template to be used. Application can use it to set custom template.
   339 // SetHelpTemplate sets help template to be used. Application can use it to set custom template.
   304 func (c *Command) SetHelpTemplate(s string) {
   340 func (c *Command) SetHelpTemplate(s string) {
   305 	c.helpTemplate = s
   341 	c.helpTemplate = s
   506 
   542 
   507 Aliases:
   543 Aliases:
   508   {{.NameAndAliases}}{{end}}{{if .HasExample}}
   544   {{.NameAndAliases}}{{end}}{{if .HasExample}}
   509 
   545 
   510 Examples:
   546 Examples:
   511 {{.Example}}{{end}}{{if .HasAvailableSubCommands}}
   547 {{.Example}}{{end}}{{if .HasAvailableSubCommands}}{{$cmds := .Commands}}{{if eq (len .Groups) 0}}
   512 
   548 
   513 Available Commands:{{range .Commands}}{{if (or .IsAvailableCommand (eq .Name "help"))}}
   549 Available Commands:{{range $cmds}}{{if (or .IsAvailableCommand (eq .Name "help"))}}
   514   {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableLocalFlags}}
   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}}
   515 
   557 
   516 Flags:
   558 Flags:
   517 {{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasAvailableInheritedFlags}}
   559 {{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasAvailableInheritedFlags}}
   518 
   560 
   519 Global Flags:
   561 Global Flags:
   674 }
   716 }
   675 
   717 
   676 func (c *Command) findNext(next string) *Command {
   718 func (c *Command) findNext(next string) *Command {
   677 	matches := make([]*Command, 0)
   719 	matches := make([]*Command, 0)
   678 	for _, cmd := range c.commands {
   720 	for _, cmd := range c.commands {
   679 		if cmd.Name() == next || cmd.HasAlias(next) {
   721 		if commandNameMatches(cmd.Name(), next) || cmd.HasAlias(next) {
   680 			cmd.commandCalledAs.name = next
   722 			cmd.commandCalledAs.name = next
   681 			return cmd
   723 			return cmd
   682 		}
   724 		}
   683 		if EnablePrefixMatching && cmd.hasNameOrAliasPrefix(next) {
   725 		if EnablePrefixMatching && cmd.hasNameOrAliasPrefix(next) {
   684 			matches = append(matches, cmd)
   726 			matches = append(matches, cmd)
   831 		return flag.ErrHelp
   873 		return flag.ErrHelp
   832 	}
   874 	}
   833 
   875 
   834 	c.preRun()
   876 	c.preRun()
   835 
   877 
       
   878 	defer c.postRun()
       
   879 
   836 	argWoFlags := c.Flags().Args()
   880 	argWoFlags := c.Flags().Args()
   837 	if c.DisableFlagParsing {
   881 	if c.DisableFlagParsing {
   838 		argWoFlags = a
   882 		argWoFlags = a
   839 	}
   883 	}
   840 
   884 
   859 		}
   903 		}
   860 	} else if c.PreRun != nil {
   904 	} else if c.PreRun != nil {
   861 		c.PreRun(c, argWoFlags)
   905 		c.PreRun(c, argWoFlags)
   862 	}
   906 	}
   863 
   907 
   864 	if err := c.validateRequiredFlags(); err != nil {
   908 	if err := c.ValidateRequiredFlags(); err != nil {
   865 		return err
   909 		return err
   866 	}
   910 	}
   867 	if err := c.validateFlagGroups(); err != nil {
   911 	if err := c.ValidateFlagGroups(); err != nil {
   868 		return err
   912 		return err
   869 	}
   913 	}
   870 
   914 
   871 	if c.RunE != nil {
   915 	if c.RunE != nil {
   872 		if err := c.RunE(c, argWoFlags); err != nil {
   916 		if err := c.RunE(c, argWoFlags); err != nil {
   901 	for _, x := range initializers {
   945 	for _, x := range initializers {
   902 		x()
   946 		x()
   903 	}
   947 	}
   904 }
   948 }
   905 
   949 
       
   950 func (c *Command) postRun() {
       
   951 	for _, x := range finalizers {
       
   952 		x()
       
   953 	}
       
   954 }
       
   955 
   906 // ExecuteContext is the same as Execute(), but sets the ctx on the command.
   956 // ExecuteContext is the same as Execute(), but sets the ctx on the command.
   907 // Retrieve ctx by calling cmd.Context() inside your *Run lifecycle or ValidArgs
   957 // Retrieve ctx by calling cmd.Context() inside your *Run lifecycle or ValidArgs
   908 // functions.
   958 // functions.
   909 func (c *Command) ExecuteContext(ctx context.Context) error {
   959 func (c *Command) ExecuteContext(ctx context.Context) error {
   910 	c.ctx = ctx
   960 	c.ctx = ctx
   944 	}
   994 	}
   945 
   995 
   946 	// initialize help at the last point to allow for user overriding
   996 	// initialize help at the last point to allow for user overriding
   947 	c.InitDefaultHelpCmd()
   997 	c.InitDefaultHelpCmd()
   948 	// initialize completion at the last point to allow for user overriding
   998 	// initialize completion at the last point to allow for user overriding
   949 	c.initDefaultCompletionCmd()
   999 	c.InitDefaultCompletionCmd()
       
  1000 
       
  1001 	// Now that all commands have been created, let's make sure all groups
       
  1002 	// are properly created also
       
  1003 	c.checkCommandGroups()
   950 
  1004 
   951 	args := c.args
  1005 	args := c.args
   952 
  1006 
   953 	// Workaround FAIL with "go test -v" or "cobra.test -test.v", see #155
  1007 	// Workaround FAIL with "go test -v" or "cobra.test -test.v", see #155
   954 	if c.args == nil && filepath.Base(os.Args[0]) != "cobra.test" {
  1008 	if c.args == nil && filepath.Base(os.Args[0]) != "cobra.test" {
  1016 		return ArbitraryArgs(c, args)
  1070 		return ArbitraryArgs(c, args)
  1017 	}
  1071 	}
  1018 	return c.Args(c, args)
  1072 	return c.Args(c, args)
  1019 }
  1073 }
  1020 
  1074 
  1021 func (c *Command) validateRequiredFlags() error {
  1075 // ValidateRequiredFlags validates all required flags are present and returns an error otherwise
       
  1076 func (c *Command) ValidateRequiredFlags() error {
  1022 	if c.DisableFlagParsing {
  1077 	if c.DisableFlagParsing {
  1023 		return nil
  1078 		return nil
  1024 	}
  1079 	}
  1025 
  1080 
  1026 	flags := c.Flags()
  1081 	flags := c.Flags()
  1037 
  1092 
  1038 	if len(missingFlagNames) > 0 {
  1093 	if len(missingFlagNames) > 0 {
  1039 		return fmt.Errorf(`required flag(s) "%s" not set`, strings.Join(missingFlagNames, `", "`))
  1094 		return fmt.Errorf(`required flag(s) "%s" not set`, strings.Join(missingFlagNames, `", "`))
  1040 	}
  1095 	}
  1041 	return nil
  1096 	return nil
       
  1097 }
       
  1098 
       
  1099 // checkCommandGroups checks if a command has been added to a group that does not exists.
       
  1100 // If so, we panic because it indicates a coding error that should be corrected.
       
  1101 func (c *Command) checkCommandGroups() {
       
  1102 	for _, sub := range c.commands {
       
  1103 		// if Group is not defined let the developer know right away
       
  1104 		if sub.GroupID != "" && !c.ContainsGroup(sub.GroupID) {
       
  1105 			panic(fmt.Sprintf("group id '%s' is not defined for subcommand '%s'", sub.GroupID, sub.CommandPath()))
       
  1106 		}
       
  1107 
       
  1108 		sub.checkCommandGroups()
       
  1109 	}
  1042 }
  1110 }
  1043 
  1111 
  1044 // InitDefaultHelpFlag adds default help flag to c.
  1112 // InitDefaultHelpFlag adds default help flag to c.
  1045 // It is called automatically by executing the c or by calling help and usage.
  1113 // It is called automatically by executing the c or by calling help and usage.
  1046 // If c already has help flag, it will do nothing.
  1114 // If c already has help flag, it will do nothing.
  1052 			usage += "this command"
  1120 			usage += "this command"
  1053 		} else {
  1121 		} else {
  1054 			usage += c.Name()
  1122 			usage += c.Name()
  1055 		}
  1123 		}
  1056 		c.Flags().BoolP("help", "h", false, usage)
  1124 		c.Flags().BoolP("help", "h", false, usage)
       
  1125 		_ = c.Flags().SetAnnotation("help", FlagSetByCobraAnnotation, []string{"true"})
  1057 	}
  1126 	}
  1058 }
  1127 }
  1059 
  1128 
  1060 // InitDefaultVersionFlag adds default version flag to c.
  1129 // InitDefaultVersionFlag adds default version flag to c.
  1061 // It is called automatically by executing the c.
  1130 // It is called automatically by executing the c.
  1077 		if c.Flags().ShorthandLookup("v") == nil {
  1146 		if c.Flags().ShorthandLookup("v") == nil {
  1078 			c.Flags().BoolP("version", "v", false, usage)
  1147 			c.Flags().BoolP("version", "v", false, usage)
  1079 		} else {
  1148 		} else {
  1080 			c.Flags().Bool("version", false, usage)
  1149 			c.Flags().Bool("version", false, usage)
  1081 		}
  1150 		}
       
  1151 		_ = c.Flags().SetAnnotation("version", FlagSetByCobraAnnotation, []string{"true"})
  1082 	}
  1152 	}
  1083 }
  1153 }
  1084 
  1154 
  1085 // InitDefaultHelpCmd adds default help command to c.
  1155 // InitDefaultHelpCmd adds default help command to c.
  1086 // It is called automatically by executing the c or by calling help and usage.
  1156 // It is called automatically by executing the c or by calling help and usage.
  1119 				cmd, _, e := c.Root().Find(args)
  1189 				cmd, _, e := c.Root().Find(args)
  1120 				if cmd == nil || e != nil {
  1190 				if cmd == nil || e != nil {
  1121 					c.Printf("Unknown help topic %#q\n", args)
  1191 					c.Printf("Unknown help topic %#q\n", args)
  1122 					CheckErr(c.Root().Usage())
  1192 					CheckErr(c.Root().Usage())
  1123 				} else {
  1193 				} else {
  1124 					cmd.InitDefaultHelpFlag() // make possible 'help' flag to be shown
  1194 					cmd.InitDefaultHelpFlag()    // make possible 'help' flag to be shown
       
  1195 					cmd.InitDefaultVersionFlag() // make possible 'version' flag to be shown
  1125 					CheckErr(cmd.Help())
  1196 					CheckErr(cmd.Help())
  1126 				}
  1197 				}
  1127 			},
  1198 			},
       
  1199 			GroupID: c.helpCommandGroupID,
  1128 		}
  1200 		}
  1129 	}
  1201 	}
  1130 	c.RemoveCommand(c.helpCommand)
  1202 	c.RemoveCommand(c.helpCommand)
  1131 	c.AddCommand(c.helpCommand)
  1203 	c.AddCommand(c.helpCommand)
  1132 }
  1204 }
  1181 			x.SetGlobalNormalizationFunc(c.globNormFunc)
  1253 			x.SetGlobalNormalizationFunc(c.globNormFunc)
  1182 		}
  1254 		}
  1183 		c.commands = append(c.commands, x)
  1255 		c.commands = append(c.commands, x)
  1184 		c.commandsAreSorted = false
  1256 		c.commandsAreSorted = false
  1185 	}
  1257 	}
       
  1258 }
       
  1259 
       
  1260 // Groups returns a slice of child command groups.
       
  1261 func (c *Command) Groups() []*Group {
       
  1262 	return c.commandgroups
       
  1263 }
       
  1264 
       
  1265 // AllChildCommandsHaveGroup returns if all subcommands are assigned to a group
       
  1266 func (c *Command) AllChildCommandsHaveGroup() bool {
       
  1267 	for _, sub := range c.commands {
       
  1268 		if (sub.IsAvailableCommand() || sub == c.helpCommand) && sub.GroupID == "" {
       
  1269 			return false
       
  1270 		}
       
  1271 	}
       
  1272 	return true
       
  1273 }
       
  1274 
       
  1275 // ContainGroups return if groupID exists in the list of command groups.
       
  1276 func (c *Command) ContainsGroup(groupID string) bool {
       
  1277 	for _, x := range c.commandgroups {
       
  1278 		if x.ID == groupID {
       
  1279 			return true
       
  1280 		}
       
  1281 	}
       
  1282 	return false
       
  1283 }
       
  1284 
       
  1285 // AddGroup adds one or more command groups to this parent command.
       
  1286 func (c *Command) AddGroup(groups ...*Group) {
       
  1287 	c.commandgroups = append(c.commandgroups, groups...)
  1186 }
  1288 }
  1187 
  1289 
  1188 // RemoveCommand removes one or more commands from a parent command.
  1290 // RemoveCommand removes one or more commands from a parent command.
  1189 func (c *Command) RemoveCommand(cmds ...*Command) {
  1291 func (c *Command) RemoveCommand(cmds ...*Command) {
  1190 	commands := []*Command{}
  1292 	commands := []*Command{}
  1326 }
  1428 }
  1327 
  1429 
  1328 // HasAlias determines if a given string is an alias of the command.
  1430 // HasAlias determines if a given string is an alias of the command.
  1329 func (c *Command) HasAlias(s string) bool {
  1431 func (c *Command) HasAlias(s string) bool {
  1330 	for _, a := range c.Aliases {
  1432 	for _, a := range c.Aliases {
  1331 		if a == s {
  1433 		if commandNameMatches(a, s) {
  1332 			return true
  1434 			return true
  1333 		}
  1435 		}
  1334 	}
  1436 	}
  1335 	return false
  1437 	return false
  1336 }
  1438 }
  1503 	if c.globNormFunc != nil {
  1605 	if c.globNormFunc != nil {
  1504 		c.lflags.SetNormalizeFunc(c.globNormFunc)
  1606 		c.lflags.SetNormalizeFunc(c.globNormFunc)
  1505 	}
  1607 	}
  1506 
  1608 
  1507 	addToLocal := func(f *flag.Flag) {
  1609 	addToLocal := func(f *flag.Flag) {
  1508 		if c.lflags.Lookup(f.Name) == nil && c.parentsPflags.Lookup(f.Name) == nil {
  1610 		// Add the flag if it is not a parent PFlag, or it shadows a parent PFlag
       
  1611 		if c.lflags.Lookup(f.Name) == nil && f != c.parentsPflags.Lookup(f.Name) {
  1509 			c.lflags.AddFlag(f)
  1612 			c.lflags.AddFlag(f)
  1510 		}
  1613 		}
  1511 	}
  1614 	}
  1512 	c.Flags().VisitAll(addToLocal)
  1615 	c.Flags().VisitAll(addToLocal)
  1513 	c.PersistentFlags().VisitAll(addToLocal)
  1616 	c.PersistentFlags().VisitAll(addToLocal)
  1692 
  1795 
  1693 	c.VisitParents(func(parent *Command) {
  1796 	c.VisitParents(func(parent *Command) {
  1694 		c.parentsPflags.AddFlagSet(parent.PersistentFlags())
  1797 		c.parentsPflags.AddFlagSet(parent.PersistentFlags())
  1695 	})
  1798 	})
  1696 }
  1799 }
       
  1800 
       
  1801 // commandNameMatches checks if two command names are equal
       
  1802 // taking into account case sensitivity according to
       
  1803 // EnableCaseInsensitive global configuration.
       
  1804 func commandNameMatches(s string, t string) bool {
       
  1805 	if EnableCaseInsensitive {
       
  1806 		return strings.EqualFold(s, t)
       
  1807 	}
       
  1808 
       
  1809 	return s == t
       
  1810 }