gcmd_command.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. // Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
  2. //
  3. // This Source Code Form is subject to the terms of the MIT License.
  4. // If a copy of the MIT was not distributed with this file,
  5. // You can obtain one at https://github.com/gogf/gf.
  6. //
  7. package gcmd
  8. import (
  9. "context"
  10. "github.com/gogf/gf/v2/container/gset"
  11. "github.com/gogf/gf/v2/errors/gerror"
  12. "github.com/gogf/gf/v2/text/gstr"
  13. )
  14. // Command holds the info about an argument that can handle custom logic.
  15. type Command struct {
  16. Name string // Command name(case-sensitive).
  17. Usage string // A brief line description about its usage, eg: gf build main.go [OPTION]
  18. Brief string // A brief info that describes what this command will do.
  19. Description string // A detailed description.
  20. Arguments []Argument // Argument array, configuring how this command act.
  21. Func Function // Custom function.
  22. FuncWithValue FuncWithValue // Custom function with output parameters that can interact with command caller.
  23. HelpFunc Function // Custom help function
  24. Examples string // Usage examples.
  25. Additional string // Additional info about this command, which will be appended to the end of help info.
  26. Strict bool // Strict parsing options, which means it returns error if invalid option given.
  27. CaseSensitive bool // CaseSensitive parsing options, which means it parses input options in case-sensitive way.
  28. Config string // Config node name, which also retrieves the values from config component along with command line.
  29. parent *Command // Parent command for internal usage.
  30. commands []*Command // Sub commands of this command.
  31. }
  32. // Function is a custom command callback function that is bound to a certain argument.
  33. type Function func(ctx context.Context, parser *Parser) (err error)
  34. // FuncWithValue is similar like Func but with output parameters that can interact with command caller.
  35. type FuncWithValue func(ctx context.Context, parser *Parser) (out interface{}, err error)
  36. // Argument is the command value that are used by certain command.
  37. type Argument struct {
  38. Name string // Option name.
  39. Short string // Option short.
  40. Brief string // Brief info about this Option, which is used in help info.
  41. IsArg bool // IsArg marks this argument taking value from command line argument instead of option.
  42. Orphan bool // Whether this Option having or having no value bound to it.
  43. }
  44. var (
  45. // defaultHelpOption is the default help option that will be automatically added to each command.
  46. defaultHelpOption = Argument{
  47. Name: `help`,
  48. Short: `h`,
  49. Brief: `more information about this command`,
  50. Orphan: true,
  51. }
  52. )
  53. // CommandFromCtx retrieves and returns Command from context.
  54. func CommandFromCtx(ctx context.Context) *Command {
  55. if v := ctx.Value(CtxKeyCommand); v != nil {
  56. if p, ok := v.(*Command); ok {
  57. return p
  58. }
  59. }
  60. return nil
  61. }
  62. // AddCommand adds one or more sub-commands to current command.
  63. func (c *Command) AddCommand(commands ...*Command) error {
  64. for _, cmd := range commands {
  65. if err := c.doAddCommand(cmd); err != nil {
  66. return err
  67. }
  68. }
  69. return nil
  70. }
  71. // doAddCommand adds one sub-command to current command.
  72. func (c *Command) doAddCommand(command *Command) error {
  73. command.Name = gstr.Trim(command.Name)
  74. if command.Name == "" {
  75. return gerror.New("command name should not be empty")
  76. }
  77. // Repeated check.
  78. var (
  79. commandNameSet = gset.NewStrSet()
  80. )
  81. for _, cmd := range c.commands {
  82. commandNameSet.Add(cmd.Name)
  83. }
  84. if commandNameSet.Contains(command.Name) {
  85. return gerror.Newf(`command "%s" is already added to command "%s"`, command.Name, c.Name)
  86. }
  87. // Add the given command to its sub-commands array.
  88. command.parent = c
  89. c.commands = append(c.commands, command)
  90. return nil
  91. }
  92. // AddObject adds one or more sub-commands to current command using struct object.
  93. func (c *Command) AddObject(objects ...interface{}) error {
  94. var (
  95. commands []*Command
  96. )
  97. for _, object := range objects {
  98. rootCommand, err := NewFromObject(object)
  99. if err != nil {
  100. return err
  101. }
  102. commands = append(commands, rootCommand)
  103. }
  104. return c.AddCommand(commands...)
  105. }