Add REPL autocompletion & go-prompt (#392)
* add v1-compatible query path and refactor other paths to de-duplicate "/query" * add initial influxQL repl * add ping endpoint to schema * improve prompt UX, implement some commands * fix json column type in schema and improve completion * feat: add table formatter and move to forked go-prompt * improve formatting and add table pagination * implement more REPL commands, including insert and history * implement "INSERT INTO" * move repl command to "v1 repl" * refactor and improve documentation * clean up v1_repl cmd * update to latest openapi, use some openapi paths instead of overrides * remove additional files that were moved to openapi * compute historyFilePath at REPL start * clean up REPL use command logic flow * clean up comments for TODOs now in issues * move gopher (chonky boi) * remove autocompletion for separate PR * run go mod tidy * add back autocompletion & go-prompt * add rfc3339 precision option * allow left and right column scrolling to display whole table * add error to JSON query response * add tags and partial to JSON response series schema * fix csv formatting and add column formatting * remove table format for separate PR * fix getDatabases * move from write to legacy write endpoint for INSERT * remove history vestiges * allow multiple spaces in INSERT commands * add precision comment * remove auth for separate PR * separate parseInsert and add unit test * add additional test case and improve error messages * fix missing errors import * fix format suggestion * re-add history implementation with history limit * build: upgrade to Go 1.18.3 (#395) * feat: add back the InfluxQL REPL (#386) * add v1-compatible query path and refactor other paths to de-duplicate "/query" * add initial influxQL repl * add ping endpoint to schema * improve prompt UX, implement some commands * fix json column type in schema and improve completion * feat: add table formatter and move to forked go-prompt * improve formatting and add table pagination * implement more REPL commands, including insert and history * implement "INSERT INTO" * move repl command to "v1 repl" * refactor and improve documentation * clean up v1_repl cmd * update to latest openapi, use some openapi paths instead of overrides * remove additional files that were moved to openapi * compute historyFilePath at REPL start * clean up REPL use command logic flow * clean up comments for TODOs now in issues * move gopher (chonky boi) * remove autocompletion for separate PR * run go mod tidy * add rfc3339 precision option * allow left and right column scrolling to display whole table * add error to JSON query response * add tags and partial to JSON response series schema * fix csv formatting and add column formatting * remove table format for separate PR * fix getDatabases * move from write to legacy write endpoint for INSERT * remove history vestiges * allow multiple spaces in INSERT commands * add precision comment * remove auth for separate PR * separate parseInsert and add unit test * add additional test case and improve error messages * fix missing errors import * print rfc3339 precision * add rfc3339 to help output * run tidy * restructure autocomplete and handle review items * improve autocompletion with leftover handling * improve comments and add autocomplete for DELETE & DROP MEASUREMENT * rename repl to shell * remove unsupported CREATE & DROP autocompletions * additional refactor for autocompletion Co-authored-by: Dane Strandboge <dstrandboge@influxdata.com>
This commit is contained in:
parent
0c17ebd621
commit
c695e601a5
@ -1 +1 @@
|
||||
Subproject commit 9b93b9e414c45537f6ebed0757ff4f764518e2b5
|
||||
Subproject commit 920d508ef5bb61e09885bd625c6e81734fc5cc99
|
213
clients/v1_shell/autocomplete.go
Normal file
213
clients/v1_shell/autocomplete.go
Normal file
@ -0,0 +1,213 @@
|
||||
package v1shell
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/influxdata/go-prompt"
|
||||
)
|
||||
|
||||
type subsuggestFnType = func(string) (map[string]SuggestNode, string)
|
||||
|
||||
type SuggestNode struct {
|
||||
Description string
|
||||
subsuggestFn subsuggestFnType
|
||||
}
|
||||
|
||||
func (c *Client) suggestUse(remainder string) (map[string]SuggestNode, string) {
|
||||
s := map[string]SuggestNode{}
|
||||
for _, db := range c.Databases {
|
||||
s["\""+db+"\""] = SuggestNode{Description: "Table Name"}
|
||||
}
|
||||
return s, remainder
|
||||
}
|
||||
|
||||
func (c *Client) suggestDropMeasurement(remainder string) (map[string]SuggestNode, string) {
|
||||
s := map[string]SuggestNode{}
|
||||
if c.Database != "" && c.RetentionPolicy != "" {
|
||||
for _, m := range c.Measurements {
|
||||
s["\""+m+"\""] = SuggestNode{Description: fmt.Sprintf("Measurement on \"%s\".\"%s\"", c.Database, c.RetentionPolicy)}
|
||||
}
|
||||
}
|
||||
return s, remainder
|
||||
}
|
||||
|
||||
func (c *Client) suggestDelete(remainder string) (map[string]SuggestNode, string) {
|
||||
s := map[string]SuggestNode{}
|
||||
fromReg := regexp.MustCompile(`(?i)FROM(\s+)` + identRegex("from_clause") + `?$`)
|
||||
matches := reSubMatchMap(fromReg, remainder)
|
||||
if matches != nil {
|
||||
if c.Database != "" && c.RetentionPolicy != "" {
|
||||
for _, m := range c.Measurements {
|
||||
s["\""+m+"\""] = SuggestNode{Description: fmt.Sprintf("Measurement on \"%s\".\"%s\"", c.Database, c.RetentionPolicy)}
|
||||
}
|
||||
}
|
||||
return s, getIdentFromMatches(matches, "from_clause")
|
||||
}
|
||||
return s, remainder
|
||||
}
|
||||
|
||||
func (c *Client) suggestSelect(remainder string) (map[string]SuggestNode, string) {
|
||||
s := map[string]SuggestNode{}
|
||||
fromReg := regexp.MustCompile(`(?i)FROM(\s+)` + identRegex("from_clause") + `?$`)
|
||||
matches := reSubMatchMap(fromReg, remainder)
|
||||
if matches != nil {
|
||||
if c.Database != "" && c.RetentionPolicy != "" {
|
||||
for _, m := range c.Measurements {
|
||||
s["\""+m+"\""] = SuggestNode{Description: fmt.Sprintf("Measurement on \"%s\".\"%s\"", c.Database, c.RetentionPolicy)}
|
||||
}
|
||||
}
|
||||
if c.Database != "" {
|
||||
for _, rp := range c.RetentionPolicies {
|
||||
s["\""+rp+"\""] = SuggestNode{Description: "Retention Policy on " + c.Database}
|
||||
}
|
||||
}
|
||||
for _, db := range c.Databases {
|
||||
s["\""+db+"\""] = SuggestNode{Description: "Table Name"}
|
||||
}
|
||||
return s, getIdentFromMatches(matches, "from_clause")
|
||||
}
|
||||
return s, remainder
|
||||
}
|
||||
|
||||
func getSuggestions(remainder string, s map[string]SuggestNode) ([]prompt.Suggest, string) {
|
||||
if len(remainder) > 0 {
|
||||
for term, node := range s {
|
||||
if strings.HasPrefix(strings.ToLower(remainder), term) || strings.HasPrefix(strings.ToUpper(remainder), term) {
|
||||
// if the cursor is at the end of a just completed word without trailing space, don't give autosuggestions yet
|
||||
if len(term) >= len(remainder) {
|
||||
return []prompt.Suggest{}, ""
|
||||
}
|
||||
// remainder is everything after the just-matched term
|
||||
rem := strings.TrimLeft(remainder[len(term):], " ")
|
||||
// if sugsuggestFn is nil, this is a terminating suggestion (leaf node with no more following suggestions)
|
||||
if node.subsuggestFn == nil {
|
||||
return []prompt.Suggest{}, rem
|
||||
}
|
||||
sugs, rem := node.subsuggestFn(rem)
|
||||
return getSuggestions(rem, sugs)
|
||||
}
|
||||
}
|
||||
}
|
||||
// if no match was found, convert the s map into suggestions and filter by the remaining characters
|
||||
var sugs []prompt.Suggest
|
||||
for text, node := range s {
|
||||
sugs = append(sugs, prompt.Suggest{Text: text, Description: node.Description})
|
||||
}
|
||||
return prompt.FilterFuzzy(sugs, remainder, true), remainder
|
||||
}
|
||||
|
||||
// recursively creates a SuggestNode for each space-delimited word for each subsuggestion
|
||||
func newSugNodeFn(subsugs ...string) subsuggestFnType {
|
||||
s := make(map[string]SuggestNode)
|
||||
for _, sug := range subsugs {
|
||||
word, rest, found := strings.Cut(sug, " ")
|
||||
if !found {
|
||||
s[word] = SuggestNode{}
|
||||
} else {
|
||||
s[word] = SuggestNode{subsuggestFn: newSugNodeFn(rest)}
|
||||
}
|
||||
}
|
||||
return func(rem string) (map[string]SuggestNode, string) {
|
||||
return s, rem
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) completer(d prompt.Document) []prompt.Suggest {
|
||||
// the commented-out lines are unsupported in 2.x
|
||||
suggestions := map[string]SuggestNode{
|
||||
"use": {Description: "Set current database", subsuggestFn: c.suggestUse},
|
||||
"pretty": {Description: "Toggle pretty print for the json format"},
|
||||
"precision": {Description: "Specify the format of the timestamp",
|
||||
subsuggestFn: newSugNodeFn(
|
||||
"rfc3339",
|
||||
"ns",
|
||||
"u",
|
||||
"ms",
|
||||
"s",
|
||||
"m",
|
||||
"h",
|
||||
)},
|
||||
"history": {Description: "Display shell history"},
|
||||
"settings": {Description: "Output the current shell settings"},
|
||||
"clear": {Description: "Clears settings such as database",
|
||||
subsuggestFn: newSugNodeFn(
|
||||
"db",
|
||||
"database",
|
||||
"retention policy",
|
||||
"rp",
|
||||
)},
|
||||
"exit": {Description: "Exit the InfluxQL shell"},
|
||||
"quit": {Description: "Exit the InfluxQL shell"},
|
||||
"gopher": {Description: "Display the Go Gopher"},
|
||||
"help": {Description: "Display help options"},
|
||||
"format": {Description: "Specify the data display format",
|
||||
subsuggestFn: newSugNodeFn(
|
||||
"column",
|
||||
"csv",
|
||||
"json",
|
||||
)},
|
||||
"SELECT": {subsuggestFn: c.suggestSelect},
|
||||
"INSERT": {},
|
||||
"INSERT INTO": {},
|
||||
"DELETE": {subsuggestFn: c.suggestDelete},
|
||||
"SHOW": {subsuggestFn: newSugNodeFn(
|
||||
// "CONTINUOUS QUERIES",
|
||||
"DATABASES",
|
||||
// "DIAGNOSTICS",
|
||||
"FIELD KEY CARDINALITY",
|
||||
"FIELD KEYS",
|
||||
// "GRANTS",
|
||||
// "MEASUREMENT CARDINALITY",
|
||||
"MEASUREMENT EXACT CARDINALITY",
|
||||
"MEASUREMENTS",
|
||||
// "QUERIES",
|
||||
// "RETENTION POLICIES",
|
||||
"SERIES",
|
||||
// "SERIES CARDINALITY",
|
||||
"SERIES EXACT CARDINALITY",
|
||||
// "SHARD GROUPS",
|
||||
// "SHARDS",
|
||||
// "STATS",
|
||||
// "SUBSCRIPTIONS",
|
||||
"TAG KEY CARDINALITY",
|
||||
"TAG KEY EXACT CARDINALITY",
|
||||
"TAG KEYS",
|
||||
"TAG VALUES",
|
||||
// "USERS",
|
||||
)},
|
||||
// "CREATE": {subsuggestFn: newSugNodeFn(
|
||||
// "CONTINUOUS QUERY",
|
||||
// "DATABASE",
|
||||
// "USER",
|
||||
// "RETENTION POLICY",
|
||||
// "SUBSCRIPTION",
|
||||
// )},
|
||||
"DROP": {subsuggestFn: func(rem string) (map[string]SuggestNode, string) {
|
||||
return map[string]SuggestNode{
|
||||
// "CONTINUOUS QUERY": {},
|
||||
// "DATABASE": {},
|
||||
"MEASUREMENT": {subsuggestFn: c.suggestDropMeasurement},
|
||||
// "RETENTION POLICY": {},
|
||||
// "SERIES": {},
|
||||
// "SHARD": {},
|
||||
// "SUBSCRIPTION": {},
|
||||
// "USER": {},
|
||||
}, rem
|
||||
}},
|
||||
"EXPLAIN": {subsuggestFn: newSugNodeFn("ANALYZE")},
|
||||
// "GRANT": {},
|
||||
// "REVOKE": {},
|
||||
// "ALTER RETENTION POLICY": {},
|
||||
// "SET PASSOWRD FOR": {},
|
||||
// "KILL QUERY": {},
|
||||
}
|
||||
line := d.CurrentLineBeforeCursor()
|
||||
currentSuggestions, _ := getSuggestions(line, suggestions)
|
||||
sort.Slice(currentSuggestions, func(i, j int) bool {
|
||||
return strings.ToLower(currentSuggestions[i].Text) < strings.ToLower(currentSuggestions[j].Text)
|
||||
})
|
||||
return currentSuggestions
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package v1repl
|
||||
package v1shell
|
||||
|
||||
var Gopher string = `
|
||||
.-::-::://:-::- .:/++/'
|
@ -1,4 +1,4 @@
|
||||
package v1repl
|
||||
package v1shell
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
@ -10,13 +10,16 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/influxdata/go-prompt"
|
||||
"github.com/influxdata/influx-cli/v2/api"
|
||||
"github.com/influxdata/influx-cli/v2/clients"
|
||||
)
|
||||
@ -39,11 +42,59 @@ type PersistentQueryParams struct {
|
||||
Format FormatType
|
||||
Pretty bool
|
||||
// Autocompletion Storage
|
||||
historyFilePath string
|
||||
historyLimit int
|
||||
Databases []string
|
||||
RetentionPolicies []string
|
||||
Measurements []string
|
||||
}
|
||||
|
||||
func DefaultPersistentQueryParams() PersistentQueryParams {
|
||||
return PersistentQueryParams{
|
||||
Format: ColumnFormat,
|
||||
Precision: "ns",
|
||||
historyLimit: 1000,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) readHistory() []string {
|
||||
// Attempt to load the history file.
|
||||
if c.historyFilePath != "" {
|
||||
if historyFile, err := os.Open(c.historyFilePath); err == nil {
|
||||
var history []string
|
||||
scanner := bufio.NewScanner(historyFile)
|
||||
for scanner.Scan() {
|
||||
history = append(history, scanner.Text())
|
||||
}
|
||||
historyFile.Close()
|
||||
// Limit to last n elements
|
||||
if len(history) > c.historyLimit {
|
||||
history = history[len(history)-c.historyLimit:]
|
||||
}
|
||||
return history
|
||||
}
|
||||
}
|
||||
return []string{}
|
||||
}
|
||||
|
||||
func (c *Client) rewriteHistoryFile(history []string) {
|
||||
if c.historyFilePath != "" {
|
||||
if historyFile, err := os.Create(c.historyFilePath); err == nil {
|
||||
historyFile.WriteString(strings.Join(history, "\n"))
|
||||
historyFile.Close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) writeCommandToHistory(cmd string) {
|
||||
if c.historyFilePath != "" {
|
||||
if historyFile, err := os.OpenFile(c.historyFilePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0666); err == nil {
|
||||
historyFile.WriteString(cmd + "\n")
|
||||
historyFile.Close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) clear(cmd string) {
|
||||
args := strings.Split(strings.TrimSuffix(strings.TrimSpace(cmd), ";"), " ")
|
||||
v := strings.ToLower(strings.Join(args[1:], " "))
|
||||
@ -73,13 +124,6 @@ func (c *Client) clear(cmd string) {
|
||||
}
|
||||
}
|
||||
|
||||
func DefaultPersistentQueryParams() PersistentQueryParams {
|
||||
return PersistentQueryParams{
|
||||
Format: ColumnFormat,
|
||||
Precision: "ns",
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) Create(ctx context.Context) error {
|
||||
res, err := c.GetPing(ctx).ExecuteWithHttpInfo()
|
||||
if err != nil {
|
||||
@ -90,15 +134,35 @@ func (c *Client) Create(ctx context.Context) error {
|
||||
version := res.Header.Get("X-Influxdb-Version")
|
||||
color.Cyan("Connected to InfluxDB %s %s", build, version)
|
||||
|
||||
c.Databases, _ = c.GetDatabases(ctx)
|
||||
color.Cyan("InfluxQL Shell")
|
||||
|
||||
scanner := bufio.NewScanner(os.Stdin)
|
||||
fmt.Printf("%s", color.GreenString("> "))
|
||||
for scanner.Scan() {
|
||||
c.executor(scanner.Text())
|
||||
fmt.Printf("%s", color.GreenString("> "))
|
||||
// compute historyFilePath at REPL start
|
||||
// Only load/write history if HOME environment variable is set.
|
||||
var historyDir string
|
||||
if runtime.GOOS == "windows" {
|
||||
if userDir := os.Getenv("USERPROFILE"); userDir != "" {
|
||||
historyDir = userDir
|
||||
}
|
||||
}
|
||||
if homeDir := os.Getenv("HOME"); homeDir != "" {
|
||||
historyDir = homeDir
|
||||
}
|
||||
var history []string
|
||||
if historyDir != "" {
|
||||
c.historyFilePath = filepath.Join(historyDir, ".influx_history")
|
||||
history = c.readHistory()
|
||||
// rewriting history now truncates the history file down to c.historyLimit lines of history
|
||||
c.rewriteHistoryFile(history)
|
||||
}
|
||||
|
||||
p := prompt.New(c.executor,
|
||||
c.completer,
|
||||
prompt.OptionTitle("InfluxQL Shell"),
|
||||
prompt.OptionHistory(history),
|
||||
prompt.OptionDescriptionTextColor(prompt.Cyan),
|
||||
prompt.OptionPrefixTextColor(prompt.Green),
|
||||
prompt.OptionCompletionWordSeparator(" ", "."),
|
||||
)
|
||||
c.Databases, _ = c.GetDatabases(ctx)
|
||||
p.Run()
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -111,6 +175,7 @@ func (c *Client) executor(cmd string) {
|
||||
if cmd == "" {
|
||||
return
|
||||
}
|
||||
defer c.writeCommandToHistory(cmd)
|
||||
cmdArgs := strings.Split(cmd, " ")
|
||||
switch strings.ToLower(cmdArgs[0]) {
|
||||
case "quit", "exit":
|
||||
@ -125,7 +190,7 @@ func (c *Client) executor(cmd string) {
|
||||
case "help":
|
||||
c.help()
|
||||
case "history":
|
||||
color.Yellow("The 'history' command is not yet implemented in 2.x")
|
||||
color.HiBlack(strings.Join(c.readHistory(), "\n"))
|
||||
case "format":
|
||||
c.setFormat(cmdArgs)
|
||||
case "precision":
|
||||
@ -225,7 +290,7 @@ func (c Client) insert(cmd string) {
|
||||
|
||||
switch c.Precision {
|
||||
case "h", "m", "rfc3339":
|
||||
color.Red("Current precision %q unsupported for writes. Use [s, ms, ns, us]", c.Precision)
|
||||
color.Red("Current precision %q unsupported for writes. Use precision [s, ms, ns, us]", c.Precision)
|
||||
return
|
||||
}
|
||||
ctx := context.Background()
|
@ -1,9 +1,9 @@
|
||||
package v1repl_test
|
||||
package v1shell_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
v1repl "github.com/influxdata/influx-cli/v2/clients/v1_repl"
|
||||
v1shell "github.com/influxdata/influx-cli/v2/clients/v1_shell"
|
||||
)
|
||||
|
||||
var point = `weather,location=us-midwest temperature=82 1465839830100400200`
|
||||
@ -20,7 +20,7 @@ type InsertTestCase struct {
|
||||
}
|
||||
|
||||
func (it *InsertTestCase) Test(t *testing.T) {
|
||||
db, rp, point, isInsert := v1repl.ParseInsert(it.cmd)
|
||||
db, rp, point, isInsert := v1shell.ParseInsert(it.cmd)
|
||||
if !isInsert {
|
||||
t.Errorf("%q should be a valid INSERT command", it.cmd)
|
||||
} else {
|
||||
@ -135,7 +135,7 @@ func TestParseInsertInto(t *testing.T) {
|
||||
func TestParseInsertInvalid(t *testing.T) {
|
||||
t.Parallel()
|
||||
for _, cmd := range invalidCmds {
|
||||
if _, _, _, isValid := v1repl.ParseInsert(cmd); isValid {
|
||||
if _, _, _, isValid := v1shell.ParseInsert(cmd); isValid {
|
||||
t.Errorf("%q should be an invalid INSERT command", cmd)
|
||||
}
|
||||
}
|
@ -13,7 +13,7 @@ func newV1SubCommand() cli.Command {
|
||||
Subcommands: []cli.Command{
|
||||
newV1DBRPCmd(),
|
||||
newV1AuthCommand(),
|
||||
newV1ReplCmd(),
|
||||
newV1ShellCmd(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import (
|
||||
"github.com/fatih/color"
|
||||
"github.com/influxdata/influx-cli/v2/api"
|
||||
"github.com/influxdata/influx-cli/v2/clients"
|
||||
repl "github.com/influxdata/influx-cli/v2/clients/v1_repl"
|
||||
shell "github.com/influxdata/influx-cli/v2/clients/v1_shell"
|
||||
"github.com/influxdata/influx-cli/v2/pkg/cli/middleware"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
@ -14,13 +14,13 @@ type Client struct {
|
||||
api.LegacyQueryApi
|
||||
}
|
||||
|
||||
func newV1ReplCmd() cli.Command {
|
||||
func newV1ShellCmd() cli.Command {
|
||||
var orgParams clients.OrgParams
|
||||
persistentQueryParams := repl.DefaultPersistentQueryParams()
|
||||
persistentQueryParams := shell.DefaultPersistentQueryParams()
|
||||
return cli.Command{
|
||||
Name: "repl",
|
||||
Usage: "Start an InfluxQL REPL",
|
||||
Description: "Start an InfluxQL REPL",
|
||||
Name: "shell",
|
||||
Usage: "Start an InfluxQL shell",
|
||||
Description: "Start an InfluxQL shell",
|
||||
Before: middleware.WithBeforeFns(withCli(), withApi(true)),
|
||||
Flags: append(commonFlagsNoPrint(), getOrgFlags(&orgParams)...),
|
||||
Action: func(ctx *cli.Context) error {
|
||||
@ -28,7 +28,7 @@ func newV1ReplCmd() cli.Command {
|
||||
return err
|
||||
}
|
||||
api := getAPI(ctx)
|
||||
c := repl.Client{
|
||||
c := shell.Client{
|
||||
CLI: getCLI(ctx),
|
||||
PersistentQueryParams: persistentQueryParams,
|
||||
PingApi: api.PingApi,
|
3
go.mod
3
go.mod
@ -12,6 +12,7 @@ require (
|
||||
github.com/gocarina/gocsv v0.0.0-20210408192840-02d7211d929d
|
||||
github.com/golang/mock v1.5.0
|
||||
github.com/google/go-jsonnet v0.17.0
|
||||
github.com/influxdata/go-prompt v0.2.7
|
||||
github.com/mattn/go-isatty v0.0.14
|
||||
github.com/olekukonko/tablewriter v0.0.5
|
||||
github.com/stretchr/testify v1.7.0
|
||||
@ -30,7 +31,9 @@ require (
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
||||
github.com/mattn/go-colorable v0.1.12 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.13 // indirect
|
||||
github.com/mattn/go-tty v0.0.4 // indirect
|
||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect
|
||||
github.com/pkg/term v1.2.0-beta.2 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/rivo/uniseg v0.2.0 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.0.1 // indirect
|
||||
|
11
go.sum
11
go.sum
@ -33,6 +33,8 @@ github.com/google/go-jsonnet v0.17.0 h1:/9NIEfhK1NQRKl3sP2536b2+x5HnZMdql7x3yK/l
|
||||
github.com/google/go-jsonnet v0.17.0/go.mod h1:sOcuej3UW1vpPTZOr8L7RQimqai1a57bt5j22LzGZCw=
|
||||
github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec h1:qv2VnGeEQHchGaZ/u7lxST/RaJw+cv273q79D81Xbog=
|
||||
github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec/go.mod h1:Q48J4R4DvxnHolD5P8pOtXigYlRuPLGl6moFx3ulM68=
|
||||
github.com/influxdata/go-prompt v0.2.7 h1:LoJCo+imRHw4Md1Y6SWFtLRpuukAHXkQ6pWS+DVTiMM=
|
||||
github.com/influxdata/go-prompt v0.2.7/go.mod h1:sK0TeJSbAWCKVby14Tx85GJE4BZpIZpguBBmFqAqruE=
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
@ -45,16 +47,22 @@ github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVc
|
||||
github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
|
||||
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
||||
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
|
||||
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
|
||||
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mattn/go-tty v0.0.4 h1:NVikla9X8MN0SQAqCYzpGyXv0jY7MNl3HOWD2dkle7E=
|
||||
github.com/mattn/go-tty v0.0.4/go.mod h1:u5GGXBtZU6RQoKV8gY5W6UhMudbR5vXnUe7j3pxse28=
|
||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4=
|
||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
||||
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
||||
github.com/pkg/term v1.2.0-beta.2 h1:L3y/h2jkuBVFdWiJvNfYfKmzcCnILw7mJWm2JQuMppw=
|
||||
github.com/pkg/term v1.2.0-beta.2/go.mod h1:E25nymQcrSllhX42Ok8MRm1+hyBdHY0dCeiKZ9jpNGw=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||
@ -92,7 +100,10 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
Loading…
x
Reference in New Issue
Block a user