executor.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. package cli
  2. import (
  3. "errors"
  4. "fmt"
  5. "git.nspix.com/golang/micro/utils/console"
  6. "reflect"
  7. "sort"
  8. "strings"
  9. "sync"
  10. "sync/atomic"
  11. "time"
  12. )
  13. var (
  14. _seq int64
  15. ErrInvalidHandle = errors.New("invalid handle kind")
  16. ErrInvalidHandleResponse = errors.New("invalid handle response")
  17. errInterface = reflect.TypeOf((*error)(nil)).Elem()
  18. stringSliceKind = reflect.TypeOf([]string{}).Kind()
  19. )
  20. type Executor struct {
  21. name string
  22. parent *Executor
  23. usage string
  24. description string
  25. handleFunc HandleFunc
  26. children map[string]*Executor
  27. createdTime time.Time
  28. seq int64
  29. locker sync.RWMutex
  30. NotFoundHandle func(ctx *Context, cmd string) (*Response, error)
  31. }
  32. type (
  33. executors []*Executor
  34. )
  35. func (p executors) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
  36. func (p executors) Len() int { return len(p) }
  37. func (p executors) Less(i, j int) bool { return p[i].seq < p[j].seq }
  38. func (exec *Executor) hasChildren(name string) bool {
  39. exec.locker.RLock()
  40. defer exec.locker.RUnlock()
  41. if name == "" {
  42. return len(exec.children) > 0
  43. }
  44. if _, ok := exec.children[name]; ok {
  45. return true
  46. }
  47. return false
  48. }
  49. func (exec *Executor) getDescription() string {
  50. if exec.description != "" {
  51. return exec.description
  52. }
  53. var p *Executor
  54. var text string
  55. p = exec
  56. for {
  57. if p.parent == nil {
  58. break
  59. }
  60. text = p.name + " " + text
  61. p = p.parent
  62. }
  63. return text
  64. }
  65. func (exec *Executor) Children(name string) (*Executor, error) {
  66. exec.locker.RLock()
  67. defer exec.locker.RUnlock()
  68. if cmd, ok := exec.children[name]; ok {
  69. return cmd, nil
  70. }
  71. return nil, errors.New("children not found")
  72. }
  73. func (exec *Executor) Completer(tokens ...string) []string {
  74. exec.locker.RLock()
  75. defer exec.locker.RUnlock()
  76. p := exec.children
  77. length := len(tokens)
  78. var token, prefix string
  79. result := make([]string, 0)
  80. if length > 0 {
  81. for i := 0; i < length; i++ {
  82. token = tokens[i]
  83. if i == length-1 {
  84. for k, e := range p {
  85. if token == k {
  86. if e.children != nil {
  87. for kk, _ := range e.children {
  88. result = append(result, prefix+token+" "+kk)
  89. }
  90. }
  91. } else if strings.HasPrefix(k, token) {
  92. result = append(result, prefix+k)
  93. }
  94. }
  95. } else {
  96. if next, ok := p[token]; !ok || next.children == nil {
  97. return []string{}
  98. } else {
  99. p = next.children
  100. }
  101. }
  102. prefix += token + " "
  103. }
  104. } else {
  105. for k, _ := range p {
  106. result = append(result, k)
  107. }
  108. }
  109. return result
  110. }
  111. func (exec *Executor) String() string {
  112. values := make([][]interface{}, 0)
  113. var loop func(string, *Executor)
  114. loop = func(prefix string, e *Executor) {
  115. if e.children == nil {
  116. return
  117. }
  118. vs := make(executors, len(e.children))
  119. var i int
  120. for _, v := range e.children {
  121. vs[i] = v
  122. i++
  123. }
  124. sort.Sort(vs)
  125. for _, v := range vs {
  126. if prefix == "" {
  127. if v.handleFunc != nil {
  128. values = append(values, []interface{}{v.name, v.getDescription()})
  129. }
  130. } else {
  131. if v.handleFunc != nil {
  132. values = append(values, []interface{}{prefix + " " + v.name, v.getDescription()})
  133. }
  134. }
  135. if prefix == "" {
  136. loop(v.name, v)
  137. } else {
  138. loop(prefix+" "+v.name, v)
  139. }
  140. }
  141. }
  142. loop("", exec)
  143. return string(console.Pretty(values, nil))
  144. }
  145. func (exec *Executor) Append(child ...*Executor) *Executor {
  146. exec.locker.Lock()
  147. defer exec.locker.Unlock()
  148. for _, v := range child {
  149. v.parent = exec
  150. exec.children[v.name] = v
  151. }
  152. return exec
  153. }
  154. func (exec *Executor) WithHandle(cb HandleFunc) *Executor {
  155. exec.handleFunc = cb
  156. return exec
  157. }
  158. func (exec *Executor) Do(ctx *Context, args ...string) (res *Response, err error) {
  159. var (
  160. root interface{}
  161. )
  162. if root = ctx.Get("ROOT"); root == nil {
  163. ctx.Set("ROOT", exec)
  164. }
  165. ctx.Set("arguments", args)
  166. if len(args) > 0 && exec.hasChildren(args[0]) {
  167. if len(args) > 1 {
  168. return exec.children[args[0]].Do(ctx, args[1:]...)
  169. } else {
  170. return exec.children[args[0]].Do(ctx)
  171. }
  172. }
  173. if exec.handleFunc == nil {
  174. if exec.NotFoundHandle != nil {
  175. res, err = exec.NotFoundHandle(ctx, ctx.CmdStr)
  176. } else {
  177. err = fmt.Errorf("%s not found", ctx.CmdStr)
  178. }
  179. return
  180. }
  181. ctx.Args = args
  182. if err = exec.handleFunc(ctx); err == nil {
  183. res = ctx.response
  184. } else {
  185. if err == ErrInvalidArgument {
  186. res = &Response{Code: 1000, Error: fmt.Sprint(ctx.Get("usage"))}
  187. err = nil
  188. }
  189. }
  190. return
  191. }
  192. func NewExecutor(args ...string) *Executor {
  193. var (
  194. name string
  195. usage string
  196. description string
  197. )
  198. if len(args) > 0 {
  199. name = args[0]
  200. }
  201. if len(args) > 1 {
  202. usage = args[1]
  203. }
  204. if len(args) > 2 {
  205. description = args[2]
  206. }
  207. return &Executor{
  208. name: name,
  209. usage: usage,
  210. createdTime: time.Now(),
  211. description: description,
  212. children: make(map[string]*Executor),
  213. seq: atomic.AddInt64(&_seq, 1),
  214. }
  215. }