-
Notifications
You must be signed in to change notification settings - Fork 123
/
repl.go
115 lines (88 loc) · 2.21 KB
/
repl.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
// Copyright 2021-2023 Zenauth Ltd.
// SPDX-License-Identifier: Apache-2.0
package repl
import (
"errors"
"fmt"
"io"
"os"
"path/filepath"
"github.com/adrg/xdg"
"github.com/alecthomas/kong"
"github.com/peterh/liner"
"github.com/cerbos/cerbos/cmd/cerbos/repl/internal"
)
type Cmd struct {
History string `help:"Path to history file" type:"path"`
}
func (c *Cmd) clear(stdout io.Writer) {
fmt.Fprintf(stdout, "\033[H\033[2J")
}
func (c *Cmd) Run(k *kong.Kong) error {
c.clear(k.Stdout)
histFile := getHistoryFile(c.History)
reader := liner.NewLiner()
reader.SetCtrlCAborts(true)
reader.SetMultiLineMode(true)
defer func() {
if err := writeHistory(reader, histFile); err != nil {
fmt.Fprintf(os.Stderr, "Failed to persist history: %v", err)
}
_ = reader.Close()
}()
if err := loadHistory(reader, histFile); err != nil {
fmt.Fprintf(os.Stderr, "Failed to read history: %v", err)
}
r, err := internal.NewREPL(reader, internal.NewPrinterOutput(k.Stdout, k.Stderr))
if err != nil {
return fmt.Errorf("failed to initialize the REPL: %w", err)
}
return r.Loop()
}
func getHistoryFile(path string) string {
if path == "" {
dir := filepath.Join(xdg.DataHome, "cerbos")
//nolint:gomnd
if err := os.MkdirAll(dir, 0o744); err != nil {
fmt.Fprintf(os.Stderr, "Failed to create directory %q (%v): history is disabled", dir, err)
return ""
}
return filepath.Join(dir, ".cerbos_repl_history")
}
finfo, err := os.Stat(path)
if err != nil && !errors.Is(err, os.ErrNotExist) {
fmt.Fprintf(os.Stderr, "Failed to stat history file %q (%v): history is disabled", path, err)
return ""
}
if finfo != nil && finfo.IsDir() {
return filepath.Join(path, ".cerbos_repl_history")
}
return path
}
func loadHistory(reader *liner.State, histFile string) error {
if histFile == "" {
return nil
}
f, err := os.Open(histFile)
if err != nil {
if errors.Is(err, os.ErrNotExist) {
return nil
}
return err
}
defer f.Close()
_, err = reader.ReadHistory(f)
return err
}
func writeHistory(reader *liner.State, histFile string) error {
if histFile == "" {
return nil
}
f, err := os.Create(histFile)
if err != nil {
return err
}
defer f.Close()
_, err = reader.WriteHistory(f)
return err
}