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.

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