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.

146 lines
2.7 KiB

6 years ago
6 years ago
  1. package shell
  2. import (
  3. "context"
  4. "fmt"
  5. "github.com/chrislusf/seaweedfs/weed/wdclient"
  6. "io"
  7. "os"
  8. "regexp"
  9. "strings"
  10. "github.com/peterh/liner"
  11. "sort"
  12. )
  13. var (
  14. line *liner.State
  15. historyPath = "/tmp/weed-shell"
  16. )
  17. func RunShell(options ShellOptions) {
  18. line = liner.NewLiner()
  19. defer line.Close()
  20. line.SetCtrlCAborts(true)
  21. setCompletionHandler()
  22. loadHisotry()
  23. defer saveHisotry()
  24. reg, _ := regexp.Compile(`'.*?'|".*?"|\S+`)
  25. commandEnv := &commandEnv{
  26. env: make(map[string]string),
  27. masterClient: wdclient.NewMasterClient(context.Background(),
  28. options.GrpcDialOption, "shell", strings.Split(*options.Masters, ",")),
  29. }
  30. go commandEnv.masterClient.KeepConnectedToMaster()
  31. commandEnv.masterClient.WaitUntilConnected()
  32. for {
  33. cmd, err := line.Prompt("> ")
  34. if err != nil {
  35. if err != io.EOF {
  36. fmt.Printf("%v\n", err)
  37. }
  38. return
  39. }
  40. cmds := reg.FindAllString(cmd, -1)
  41. if len(cmds) == 0 {
  42. continue
  43. } else {
  44. line.AppendHistory(cmd)
  45. args := make([]string, len(cmds[1:]))
  46. for i := range args {
  47. args[i] = strings.Trim(string(cmds[1+i]), "\"'")
  48. }
  49. cmd := strings.ToLower(cmds[0])
  50. if cmd == "help" || cmd == "?" {
  51. printHelp(cmds)
  52. } else if cmd == "exit" || cmd == "quit" {
  53. return
  54. } else {
  55. for _, c := range commands {
  56. if c.Name() == cmd {
  57. if err := c.Do(args, commandEnv, os.Stderr); err != nil {
  58. fmt.Fprintf(os.Stderr, "error: %v\n", err)
  59. }
  60. }
  61. }
  62. }
  63. }
  64. }
  65. }
  66. func printGenericHelp() {
  67. msg :=
  68. `Type: "help <command>" for help on <command>
  69. `
  70. fmt.Print(msg)
  71. sort.Slice(commands, func(i, j int) bool {
  72. return strings.Compare(commands[i].Name(), commands[j].Name()) < 0
  73. })
  74. for _, c := range commands {
  75. fmt.Printf("\t%s %s \n", c.Name(), c.Help())
  76. }
  77. }
  78. func printHelp(cmds []string) {
  79. args := cmds[1:]
  80. if len(args) == 0 {
  81. printGenericHelp()
  82. } else if len(args) > 1 {
  83. fmt.Println()
  84. } else {
  85. cmd := strings.ToLower(args[0])
  86. sort.Slice(commands, func(i, j int) bool {
  87. return strings.Compare(commands[i].Name(), commands[j].Name()) < 0
  88. })
  89. for _, c := range commands {
  90. if c.Name() == cmd {
  91. fmt.Println()
  92. fmt.Printf("\t%s %s \n", c.Name(), c.Help())
  93. fmt.Println()
  94. }
  95. }
  96. }
  97. }
  98. func setCompletionHandler() {
  99. line.SetCompleter(func(line string) (c []string) {
  100. for _, i := range commands {
  101. if strings.HasPrefix(i.Name(), strings.ToLower(line)) {
  102. c = append(c, i.Name())
  103. }
  104. }
  105. return
  106. })
  107. }
  108. func loadHisotry() {
  109. if f, err := os.Open(historyPath); err == nil {
  110. line.ReadHistory(f)
  111. f.Close()
  112. }
  113. }
  114. func saveHisotry() {
  115. if f, err := os.Create(historyPath); err != nil {
  116. fmt.Printf("Error writing history file: %v\n", err)
  117. } else {
  118. line.WriteHistory(f)
  119. f.Close()
  120. }
  121. }