term.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. /*
  2. * Rufs - Remote Union File System
  3. *
  4. * Copyright 2017 Matthias Ladkau. All rights reserved.
  5. *
  6. * This Source Code Form is subject to the terms of the MIT
  7. * License, If a copy of the MIT License was not distributed with this
  8. * file, You can obtain one at https://opensource.org/licenses/MIT.
  9. */
  10. package term
  11. import (
  12. "fmt"
  13. "io"
  14. "path"
  15. "sort"
  16. "strings"
  17. "unicode/utf8"
  18. "devt.de/krotik/common/stringutil"
  19. "devt.de/krotik/rufs"
  20. )
  21. /*
  22. TreeTerm models a command processor for Rufs trees.
  23. */
  24. type TreeTerm struct {
  25. tree *rufs.Tree // Tree which we operate on
  26. cd string // Current directory
  27. out io.Writer // Output writer
  28. lastStatus string // Last status line
  29. }
  30. /*
  31. NewTreeTerm returns a new command processor for Rufs trees.
  32. */
  33. func NewTreeTerm(t *rufs.Tree, out io.Writer) *TreeTerm {
  34. return &TreeTerm{t, "/", out, ""}
  35. }
  36. /*
  37. WriteStatus writes a status line to the output writer.
  38. */
  39. func (tt *TreeTerm) WriteStatus(line string) {
  40. fmt.Fprint(tt.out, "\r")
  41. fmt.Fprint(tt.out, line)
  42. ll := len(tt.lastStatus)
  43. lc := len(line)
  44. if ll > lc {
  45. fmt.Fprint(tt.out, stringutil.GenerateRollingString(" ", ll-lc))
  46. }
  47. tt.lastStatus = line
  48. }
  49. /*
  50. ClearStatus removes the last status line and returns the cursor to the initial position.
  51. */
  52. func (tt *TreeTerm) ClearStatus() {
  53. if tt.lastStatus != "" {
  54. toClear := utf8.RuneCountInString(tt.lastStatus)
  55. fmt.Fprint(tt.out, "\r")
  56. fmt.Fprint(tt.out, stringutil.GenerateRollingString(" ", toClear))
  57. fmt.Fprint(tt.out, "\r")
  58. }
  59. }
  60. /*
  61. CurrentDir returns the current directory of this TreeTerm.
  62. */
  63. func (tt *TreeTerm) CurrentDir() string {
  64. return tt.cd
  65. }
  66. /*
  67. AddCmd adds a new command to the terminal
  68. */
  69. func (tt *TreeTerm) AddCmd(cmd, helpusage, help string,
  70. cmdFunc func(*TreeTerm, ...string) (string, error)) {
  71. cmdMap[cmd] = cmdFunc
  72. helpMap[helpusage] = help
  73. }
  74. /*
  75. Cmds returns a list of available terminal commands.
  76. */
  77. func (tt *TreeTerm) Cmds() []string {
  78. var cmds []string
  79. for k := range cmdMap {
  80. cmds = append(cmds, k)
  81. }
  82. sort.Strings(cmds)
  83. return cmds
  84. }
  85. /*
  86. Run executes a given command line. And return its output as a string. File
  87. output and other streams to the console are written to the output writer.
  88. */
  89. func (tt *TreeTerm) Run(line string) (string, error) {
  90. var err error
  91. var res string
  92. var arg []string
  93. // Parse the input
  94. c := strings.Split(line, " ")
  95. cmd := c[0]
  96. if len(c) > 1 {
  97. arg = c[1:]
  98. }
  99. // Execute the given command
  100. if f, ok := cmdMap[cmd]; ok {
  101. res, err = f(tt, arg...)
  102. } else {
  103. err = fmt.Errorf("Unknown command: %s", cmd)
  104. }
  105. return res, err
  106. }
  107. /*
  108. cmdPing pings a remote branch.
  109. */
  110. func cmdPing(tt *TreeTerm, arg ...string) (string, error) {
  111. var res string
  112. err := fmt.Errorf("ping requires at least a branch name")
  113. if len(arg) > 0 {
  114. var fp, rpc string
  115. if len(arg) > 1 {
  116. rpc = arg[1]
  117. }
  118. if fp, err = tt.tree.PingBranch(arg[0], rpc); err == nil {
  119. res = fmt.Sprint("Response ok - fingerprint: ", fp, "\n")
  120. }
  121. }
  122. return res, err
  123. }
  124. /*
  125. cmdRefresh refreshes all known branches and connects depending on if the
  126. branches are reachable.
  127. */
  128. func cmdRefresh(tt *TreeTerm, arg ...string) (string, error) {
  129. tt.tree.Refresh()
  130. return "Done", nil
  131. }
  132. /*
  133. parsePathParam parse a given path parameter and return an absolute path.
  134. */
  135. func (tt *TreeTerm) parsePathParam(p string) string {
  136. if !strings.HasPrefix(p, "/") {
  137. p = path.Join(tt.cd, p) // Take care of relative paths
  138. }
  139. return p
  140. }