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.

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