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.

152 lines
2.9 KiB

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