Skip to content

Commit

Permalink
console: history handling implementation
Browse files Browse the repository at this point in the history
Part of #1050
  • Loading branch information
dmyger committed Dec 26, 2024
1 parent 92b0434 commit 81f879f
Show file tree
Hide file tree
Showing 2 changed files with 131 additions and 5 deletions.
5 changes: 5 additions & 0 deletions cli/cmd/aeon.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,13 @@ func aeonConnectValidateArgs(cmd *cobra.Command, args []string) error {
}

func internalAeonConnect(cmdCtx *cmdcontext.CmdCtx, args []string) error {
hist, err := console.DefaultHistoryFile()
if err != nil {
return fmt.Errorf("can't open history file: %w", err)
}
opts := console.ConsoleOpts{
Handler: aeon.NewAeonHandler(connectCtx),
History: &hist,
Format: console.FormatAsTable(),
}
c, err := console.NewConsole(opts)
Expand Down
131 changes: 126 additions & 5 deletions cli/console/history.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,134 @@
package console

import (
"bytes"
"fmt"
"os"
"path/filepath"
"regexp"
"strconv"
"strings"
"time"

"github.com/tarantool/tt/cli/util"
)

const (
DefaultHistoryFileName = ".tarantool_history"
DefaultHistoryLines = 10000
)

type History interface {
Open(fileName string, maxCommands int) error
AppendCommand(input string)
Command() []string
Close()
type History struct {
filepath string
maxCommands int
commands []string
timestamps []int64
}

// NewHistory create/open specified file.
func NewHistory(file string, maxCommands int) (History, error) {
h := History{
filepath: file,
maxCommands: maxCommands,
commands: make([]string, 0),
timestamps: make([]int64, 0),
}
err := h.load()
return h, err
}

// DefaultHistoryFile create/open history file with default parameters.
func DefaultHistoryFile() (History, error) {
dir, err := util.GetHomeDir()
if err != nil {
return History{}, fmt.Errorf("failed to get home directory: %w", err)
}
file := filepath.Join(dir, DefaultHistoryFileName)
return NewHistory(file, DefaultHistoryLines)
}

func (h *History) load() error {
rawLines, err := util.GetLastNLines(h.filepath, h.maxCommands)
if err != nil {
return err
}

h.parseCells(rawLines)
return nil

}

func (h *History) parseCells(lines []string) {
timeRecord := regexp.MustCompile(`^#\d+$`)

// startPos is the first position of a timestamp.
startPos := -1
for i, line := range lines {
if timeRecord.MatchString(line) {
startPos = i
break
}
}
if startPos == -1 {
// Read one line per command.
// Set the current timestamp for each command.
h.commands = lines
now := time.Now().Unix()
for range lines {
h.timestamps = append(h.timestamps, now)
}
return
}

for startPos < len(lines) {
j := startPos + 1

// Move pointer to the next timestamp.
for j < len(lines) && !timeRecord.MatchString(lines[j]) {
j++
}

// Extract the current timestamp.
timestamp, err := strconv.ParseInt(lines[startPos][1:], 10, 0)

if j != startPos+1 && err == nil {
h.timestamps = append(h.timestamps, timestamp)
h.commands = append(h.commands, strings.Join(lines[startPos+1:j], "\n"))
}
startPos = j
}
}

// writeToFile writes console history to the file.
func (h *History) writeToFile() error {
buff := bytes.Buffer{}
for i, c := range h.commands {
buff.WriteString(fmt.Sprintf("#%d\n%s\n", h.timestamps[i], c))
}
if err := os.WriteFile(h.filepath, buff.Bytes(), 0640); err != nil {
return fmt.Errorf("failed to write to history file: %s", err)
}

return nil
}

// AppendCommand insert new command to the history file.
// Implements HistoryKeeper.AppendCommand interface method.
func (h *History) AppendCommand(input string) {
h.commands = append(h.commands, input)
h.timestamps = append(h.timestamps, time.Now().Unix())
if len(h.commands) > h.maxCommands {
h.commands = h.commands[1:]
h.timestamps = h.timestamps[1:]
}
h.writeToFile()
}

// Commands implements HistoryKeeper.Commands interface method.
func (h *History) Commands() []string {
return h.commands
}

// Close implements HistoryKeeper.Close interface method.
func (h *History) Close() {
}

0 comments on commit 81f879f

Please sign in to comment.