group_private.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. package flags
  2. import (
  3. "reflect"
  4. "unicode/utf8"
  5. "unsafe"
  6. )
  7. type scanHandler func(reflect.Value, *reflect.StructField) (bool, error)
  8. func newGroup(shortDescription string, longDescription string, data interface{}) *Group {
  9. return &Group{
  10. ShortDescription: shortDescription,
  11. LongDescription: longDescription,
  12. data: data,
  13. }
  14. }
  15. func (g *Group) optionByName(name string, namematch func(*Option, string) bool) *Option {
  16. prio := 0
  17. var retopt *Option
  18. for _, opt := range g.options {
  19. if namematch != nil && namematch(opt, name) && prio < 4 {
  20. retopt = opt
  21. prio = 4
  22. }
  23. if name == opt.field.Name && prio < 3 {
  24. retopt = opt
  25. prio = 3
  26. }
  27. if name == opt.LongName && prio < 2 {
  28. retopt = opt
  29. prio = 2
  30. }
  31. if opt.ShortName != 0 && name == string(opt.ShortName) && prio < 1 {
  32. retopt = opt
  33. prio = 1
  34. }
  35. }
  36. return retopt
  37. }
  38. func (g *Group) storeDefaults() {
  39. for _, option := range g.options {
  40. // First. empty out the value
  41. if len(option.Default) > 0 {
  42. option.clear()
  43. }
  44. for _, d := range option.Default {
  45. option.set(&d)
  46. }
  47. if !option.value.CanSet() {
  48. continue
  49. }
  50. option.defaultValue = reflect.ValueOf(option.value.Interface())
  51. }
  52. }
  53. func (g *Group) eachGroup(f func(*Group)) {
  54. f(g)
  55. for _, gg := range g.groups {
  56. gg.eachGroup(f)
  57. }
  58. }
  59. func (g *Group) scanStruct(realval reflect.Value, sfield *reflect.StructField, handler scanHandler) error {
  60. stype := realval.Type()
  61. if sfield != nil {
  62. if ok, err := handler(realval, sfield); err != nil {
  63. return err
  64. } else if ok {
  65. return nil
  66. }
  67. }
  68. for i := 0; i < stype.NumField(); i++ {
  69. field := stype.Field(i)
  70. // PkgName is set only for non-exported fields, which we ignore
  71. if field.PkgPath != "" {
  72. continue
  73. }
  74. mtag := newMultiTag(string(field.Tag))
  75. if err := mtag.Parse(); err != nil {
  76. return err
  77. }
  78. // Skip fields with the no-flag tag
  79. if mtag.Get("no-flag") != "" {
  80. continue
  81. }
  82. // Dive deep into structs or pointers to structs
  83. kind := field.Type.Kind()
  84. fld := realval.Field(i)
  85. if kind == reflect.Struct {
  86. if err := g.scanStruct(fld, &field, handler); err != nil {
  87. return err
  88. }
  89. } else if kind == reflect.Ptr && field.Type.Elem().Kind() == reflect.Struct {
  90. if fld.IsNil() {
  91. fld.Set(reflect.New(fld.Type().Elem()))
  92. }
  93. if err := g.scanStruct(reflect.Indirect(fld), &field, handler); err != nil {
  94. return err
  95. }
  96. }
  97. longname := mtag.Get("long")
  98. shortname := mtag.Get("short")
  99. // Need at least either a short or long name
  100. if longname == "" && shortname == "" && mtag.Get("ini-name") == "" {
  101. continue
  102. }
  103. short := rune(0)
  104. rc := utf8.RuneCountInString(shortname)
  105. if rc > 1 {
  106. return newErrorf(ErrShortNameTooLong,
  107. "short names can only be 1 character long, not `%s'",
  108. shortname)
  109. } else if rc == 1 {
  110. short, _ = utf8.DecodeRuneInString(shortname)
  111. }
  112. description := mtag.Get("description")
  113. def := mtag.GetMany("default")
  114. optionalValue := mtag.GetMany("optional-value")
  115. valueName := mtag.Get("value-name")
  116. defaultMask := mtag.Get("default-mask")
  117. optional := (mtag.Get("optional") != "")
  118. required := (mtag.Get("required") != "")
  119. option := &Option{
  120. Description: description,
  121. ShortName: short,
  122. LongName: longname,
  123. Default: def,
  124. OptionalArgument: optional,
  125. OptionalValue: optionalValue,
  126. Required: required,
  127. ValueName: valueName,
  128. DefaultMask: defaultMask,
  129. field: field,
  130. value: realval.Field(i),
  131. tag: mtag,
  132. }
  133. g.options = append(g.options, option)
  134. }
  135. return nil
  136. }
  137. func (g *Group) checkForDuplicateFlags() *Error {
  138. shortNames := make(map[rune]*Option)
  139. longNames := make(map[string]*Option)
  140. var duplicateError *Error
  141. g.eachGroup(func(g *Group) {
  142. for _, option := range g.options {
  143. if option.LongName != "" {
  144. if otherOption, ok := longNames[option.LongName]; ok {
  145. duplicateError = newErrorf(ErrDuplicatedFlag, "option `%s' uses the same long name as option `%s'", option, otherOption)
  146. return
  147. }
  148. longNames[option.LongName] = option
  149. }
  150. if option.ShortName != 0 {
  151. if otherOption, ok := shortNames[option.ShortName]; ok {
  152. duplicateError = newErrorf(ErrDuplicatedFlag, "option `%s' uses the same short name as option `%s'", option, otherOption)
  153. return
  154. }
  155. shortNames[option.ShortName] = option
  156. }
  157. }
  158. })
  159. return duplicateError
  160. }
  161. func (g *Group) scanSubGroupHandler(realval reflect.Value, sfield *reflect.StructField) (bool, error) {
  162. mtag := newMultiTag(string(sfield.Tag))
  163. if err := mtag.Parse(); err != nil {
  164. return true, err
  165. }
  166. subgroup := mtag.Get("group")
  167. if len(subgroup) != 0 {
  168. ptrval := reflect.NewAt(realval.Type(), unsafe.Pointer(realval.UnsafeAddr()))
  169. description := mtag.Get("description")
  170. if _, err := g.AddGroup(subgroup, description, ptrval.Interface()); err != nil {
  171. return true, err
  172. }
  173. return true, nil
  174. }
  175. return false, nil
  176. }
  177. func (g *Group) scanType(handler scanHandler) error {
  178. // Get all the public fields in the data struct
  179. ptrval := reflect.ValueOf(g.data)
  180. if ptrval.Type().Kind() != reflect.Ptr {
  181. panic(ErrNotPointerToStruct)
  182. }
  183. stype := ptrval.Type().Elem()
  184. if stype.Kind() != reflect.Struct {
  185. panic(ErrNotPointerToStruct)
  186. }
  187. realval := reflect.Indirect(ptrval)
  188. if err := g.scanStruct(realval, nil, handler); err != nil {
  189. return err
  190. }
  191. if err := g.checkForDuplicateFlags(); err != nil {
  192. return err
  193. }
  194. return nil
  195. }
  196. func (g *Group) scan() error {
  197. return g.scanType(g.scanSubGroupHandler)
  198. }
  199. func (g *Group) groupByName(name string) *Group {
  200. if len(name) == 0 {
  201. return g
  202. }
  203. return g.Find(name)
  204. }