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.

206 lines
4.3 KiB

6 years ago
6 years ago
6 years ago
4 years ago
6 years ago
6 years ago
3 years ago
3 years ago
3 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.LoopConnectToMaster()
  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. fmt.Printf("master: %s ", *options.Masters)
  55. if len(filers) > 0 {
  56. fmt.Printf("filers: %v", filers)
  57. commandEnv.option.FilerAddress = filers[rand.Intn(len(filers))]
  58. }
  59. fmt.Println()
  60. }
  61. if commandEnv.option.FilerAddress != "" {
  62. commandEnv.WithFilerClient(func(filerClient filer_pb.SeaweedFilerClient) error {
  63. resp, err := filerClient.GetFilerConfiguration(context.Background(), &filer_pb.GetFilerConfigurationRequest{})
  64. if err != nil {
  65. return err
  66. }
  67. if resp.ClusterId != "" {
  68. fmt.Printf(`
  69. ---
  70. Free Monitoring Data URL:
  71. https://cloud.seaweedfs.com/ui/%s
  72. ---
  73. `, resp.ClusterId)
  74. }
  75. return nil
  76. })
  77. }
  78. for {
  79. cmd, err := line.Prompt("> ")
  80. if err != nil {
  81. if err != io.EOF {
  82. fmt.Printf("%v\n", err)
  83. }
  84. return
  85. }
  86. for _, c := range strings.Split(cmd, ";") {
  87. if processEachCmd(reg, c, commandEnv) {
  88. return
  89. }
  90. }
  91. }
  92. }
  93. func processEachCmd(reg *regexp.Regexp, cmd string, commandEnv *CommandEnv) bool {
  94. cmds := reg.FindAllString(cmd, -1)
  95. line.AppendHistory(cmd)
  96. if len(cmds) == 0 {
  97. return false
  98. } else {
  99. args := make([]string, len(cmds[1:]))
  100. for i := range args {
  101. args[i] = strings.Trim(string(cmds[1+i]), "\"'")
  102. }
  103. cmd := cmds[0]
  104. if cmd == "help" || cmd == "?" {
  105. printHelp(cmds)
  106. } else if cmd == "exit" || cmd == "quit" {
  107. return true
  108. } else {
  109. foundCommand := false
  110. for _, c := range Commands {
  111. if c.Name() == cmd || c.Name() == "fs."+cmd {
  112. if err := c.Do(args, commandEnv, os.Stdout); err != nil {
  113. fmt.Fprintf(os.Stderr, "error: %v\n", err)
  114. }
  115. foundCommand = true
  116. }
  117. }
  118. if !foundCommand {
  119. fmt.Fprintf(os.Stderr, "unknown command: %v\n", cmd)
  120. }
  121. }
  122. }
  123. return false
  124. }
  125. func printGenericHelp() {
  126. msg :=
  127. `Type: "help <command>" for help on <command>. Most commands support "<command> -h" also for options.
  128. `
  129. fmt.Print(msg)
  130. for _, c := range Commands {
  131. helpTexts := strings.SplitN(c.Help(), "\n", 2)
  132. fmt.Printf(" %-30s\t# %s \n", c.Name(), helpTexts[0])
  133. }
  134. }
  135. func printHelp(cmds []string) {
  136. args := cmds[1:]
  137. if len(args) == 0 {
  138. printGenericHelp()
  139. } else if len(args) > 1 {
  140. fmt.Println()
  141. } else {
  142. cmd := strings.ToLower(args[0])
  143. for _, c := range Commands {
  144. if c.Name() == cmd {
  145. fmt.Printf(" %s\t# %s\n", c.Name(), c.Help())
  146. }
  147. }
  148. }
  149. }
  150. func setCompletionHandler() {
  151. line.SetCompleter(func(line string) (c []string) {
  152. for _, i := range Commands {
  153. if strings.HasPrefix(i.Name(), strings.ToLower(line)) {
  154. c = append(c, i.Name())
  155. }
  156. }
  157. return
  158. })
  159. }
  160. func loadHistory() {
  161. if f, err := os.Open(historyPath); err == nil {
  162. line.ReadHistory(f)
  163. f.Close()
  164. }
  165. }
  166. func saveHistory() {
  167. if f, err := os.Create(historyPath); err != nil {
  168. fmt.Printf("Error creating history file: %v\n", err)
  169. } else {
  170. if _, err = line.WriteHistory(f); err != nil {
  171. fmt.Printf("Error writing history file: %v\n", err)
  172. }
  173. f.Close()
  174. }
  175. }