executor.go 4.8 KB

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