You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

204 lines
4.2 KiB

6 years ago
6 years ago
6 years ago
4 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
  1. package shell
  2. import (
  3. "context"
  4. "fmt"
  5. "github.com/chrislusf/seaweedfs/weed/pb"
  6. "github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
  7. "github.com/chrislusf/seaweedfs/weed/pb/master_pb"
  8. "github.com/chrislusf/seaweedfs/weed/util/grace"
  9. "io"
  10. "math/rand"
  11. "os"
  12. "path"
  13. "regexp"
  14. "sort"
  15. "strings"
  16. "github.com/peterh/liner"
  17. )
  18. var (
  19. line *liner.State
  20. historyPath = path.Join(os.TempDir(), "weed-shell")
  21. )
  22. func RunShell(options ShellOptions) {
  23. sort.Slice(Commands, func(i, j int) bool {
  24. return strings.Compare(Commands[i].Name(), Commands[j].Name()) < 0
  25. })
  26. line = liner.NewLiner()
  27. defer line.Close()
  28. grace.OnInterrupt(func() {
  29. line.Close()
  30. })
  31. line.SetCtrlCAborts(true)
  32. line.SetTabCompletionStyle(liner.TabPrints)
  33. setCompletionHandler()
  34. loadHistory()
  35. defer saveHistory()
  36. reg, _ := regexp.Compile(`'.*?'|".*?"|\S+`)
  37. commandEnv := NewCommandEnv(options)
  38. go commandEnv.MasterClient.KeepConnectedToMaster()
  39. commandEnv.MasterClient.WaitUntilConnected()
  40. if commandEnv.option.FilerAddress == "" {
  41. var filers []pb.ServerAddress
  42. commandEnv.MasterClient.WithClient(func(client master_pb.SeaweedClient) error {
  43. resp, err := client.ListClusterNodes(context.Background(), &master_pb.ListClusterNodesRequest{
  44. ClientType: "filer",
  45. })
  46. if err != nil {
  47. return err
  48. }
  49. for _, clusterNode := range resp.ClusterNodes {
  50. filers = append(filers, pb.ServerAddress(clusterNode.Address))
  51. }
  52. return nil
  53. })
  54. if len(filers) > 0 {
  55. fmt.Printf("filers: %v\n", filers)
  56. commandEnv.option.FilerAddress = filers[rand.Intn(len(filers))]
  57. }
  58. }
  59. if commandEnv.option.FilerAddress != "" {
  60. commandEnv.WithFilerClient(func(filerClient filer_pb.SeaweedFilerClient) error {
  61. resp, err := filerClient.GetFilerConfiguration(context.Background(), &filer_pb.GetFilerConfigurationRequest{})
  62. if err != nil {
  63. return err
  64. }
  65. if resp.ClusterId != "" {
  66. fmt.Printf(`
  67. ---
  68. Free Monitoring Data URL:
  69. https://cloud.seaweedfs.com/ui/%s
  70. ---
  71. `, resp.ClusterId)
  72. }
  73. return nil
  74. })
  75. }
  76. for {
  77. cmd, err := line.Prompt("> ")
  78. if err != nil {
  79. if err != io.EOF {
  80. fmt.Printf("%v\n", err)
  81. }
  82. return
  83. }
  84. for _, c := range strings.Split(cmd, ";") {
  85. if processEachCmd(reg, c, commandEnv) {
  86. return
  87. }
  88. }
  89. }
  90. }
  91. func processEachCmd(reg *regexp.Regexp, cmd string, commandEnv *CommandEnv) bool {
  92. cmds := reg.FindAllString(cmd, -1)
  93. line.AppendHistory(cmd)
  94. if len(cmds) == 0 {
  95. return false
  96. } else {
  97. args := make([]string, len(cmds[1:]))
  98. for i := range args {
  99. args[i] = strings.Trim(string(cmds[1+i]), "\"'")
  100. }
  101. cmd := cmds[0]
  102. if cmd == "help" || cmd == "?" {
  103. printHelp(cmds)
  104. } else if cmd == "exit" || cmd == "quit" {
  105. return true
  106. } else {
  107. foundCommand := false
  108. for _, c := range Commands {
  109. if c.Name() == cmd || c.Name() == "fs."+cmd {
  110. if err := c.Do(args, commandEnv, os.Stdout); err != nil {
  111. fmt.Fprintf(os.Stderr, "error: %v\n", err)
  112. }
  113. foundCommand = true
  114. }
  115. }
  116. if !foundCommand {
  117. fmt.Fprintf(os.Stderr, "unknown command: %v\n", cmd)
  118. }
  119. }
  120. }
  121. return false
  122. }
  123. func printGenericHelp() {
  124. msg :=
  125. `Type: "help <command>" for help on <command>. Most commands support "<command> -h" also for options.
  126. `
  127. fmt.Print(msg)
  128. for _, c := range Commands {
  129. helpTexts := strings.SplitN(c.Help(), "\n", 2)
  130. fmt.Printf(" %-30s\t# %s \n", c.Name(), helpTexts[0])
  131. }
  132. }
  133. func printHelp(cmds []string) {
  134. args := cmds[1:]
  135. if len(args) == 0 {
  136. printGenericHelp()
  137. } else if len(args) > 1 {
  138. fmt.Println()
  139. } else {
  140. cmd := strings.ToLower(args[0])
  141. for _, c := range Commands {
  142. if c.Name() == cmd {
  143. fmt.Printf(" %s\t# %s\n", c.Name(), c.Help())
  144. }
  145. }
  146. }
  147. }
  148. func setCompletionHandler() {
  149. line.SetCompleter(func(line string) (c []string) {
  150. for _, i := range Commands {
  151. if strings.HasPrefix(i.Name(), strings.ToLower(line)) {
  152. c = append(c, i.Name())
  153. }
  154. }
  155. return
  156. })
  157. }
  158. func loadHistory() {
  159. if f, err := os.Open(historyPath); err == nil {
  160. line.ReadHistory(f)
  161. f.Close()
  162. }
  163. }
  164. func saveHistory() {
  165. if f, err := os.Create(historyPath); err != nil {
  166. fmt.Printf("Error creating history file: %v\n", err)
  167. } else {
  168. if _, err = line.WriteHistory(f); err != nil {
  169. fmt.Printf("Error writing history file: %v\n", err)
  170. }
  171. f.Close()
  172. }
  173. }