mirror of
https://codeberg.org/scip/esctl.git
synced 2026-08-24 11:44:18 +02:00
add external pager support via ES_JSON_PAGER (#65)
This commit is contained in:
@@ -23,6 +23,8 @@ Features:
|
|||||||
- Shell completion support (bash, zsh and fish). Put this into your
|
- Shell completion support (bash, zsh and fish). Put this into your
|
||||||
rc: `source <(esctl completion bash)`.
|
rc: `source <(esctl completion bash)`.
|
||||||
- Cluster settings can be viewed and modified.
|
- Cluster settings can be viewed and modified.
|
||||||
|
- Comprehensive cluster status.
|
||||||
|
- Cluster reroute support.
|
||||||
- Search: you can search indices using full text or by fields, select
|
- Search: you can search indices using full text or by fields, select
|
||||||
logical condition (OR, AND), use PIT, limit datetime (ES date math
|
logical condition (OR, AND), use PIT, limit datetime (ES date math
|
||||||
can be used), etc. It is however not yet possible to create
|
can be used), etc. It is however not yet possible to create
|
||||||
@@ -47,7 +49,9 @@ Features:
|
|||||||
elasticsearch API. You can run API calls on the current selected
|
elasticsearch API. You can run API calls on the current selected
|
||||||
cluster w/o the hassle to specify the whole url, credentials etc. It
|
cluster w/o the hassle to specify the whole url, credentials etc. It
|
||||||
has line editing and history support. If `jq` is installed output
|
has line editing and history support. If `jq` is installed output
|
||||||
JSON will be syntax highlighted.
|
JSON will be syntax highlighted. A simple internal pager will be
|
||||||
|
used if output exceeds the terminal height. You can tweak this using
|
||||||
|
the `$ES_JSON_PAGER` environment variable (I'd recommend [fx](https://fx.wtf/)).
|
||||||
- Doc support. You can put, delete and show docs for an index. Very
|
- Doc support. You can put, delete and show docs for an index. Very
|
||||||
handy if you want to play with it. Just create a new index:
|
handy if you want to play with it. Just create a new index:
|
||||||
`esctl index create foo` and then insert docs into it for search
|
`esctl index create foo` and then insert docs into it for search
|
||||||
|
|||||||
10
cmd/api.go
10
cmd/api.go
@@ -83,6 +83,16 @@ func ApiRepl(conf *cfg.Config) *cli.Command {
|
|||||||
Aliases: []string{"shell"},
|
Aliases: []string{"shell"},
|
||||||
Usage: "interactive API repl",
|
Usage: "interactive API repl",
|
||||||
|
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "pager",
|
||||||
|
Usage: "external viewer program (default:internal)",
|
||||||
|
Destination: &conf.Pager,
|
||||||
|
Aliases: []string{"p"},
|
||||||
|
Sources: cli.EnvVars("PAGER", "ES_JSON_PAGER"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||||
return es.ApiRepl(conf)
|
return es.ApiRepl(conf)
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -106,6 +106,8 @@ type Config struct {
|
|||||||
|
|
||||||
FromNode, ToNode string // cluster reroute move: -f + -t
|
FromNode, ToNode string // cluster reroute move: -f + -t
|
||||||
AllowPrimary, AcceptDataLoss bool // cluster reroute cancel: -p,-a
|
AllowPrimary, AcceptDataLoss bool // cluster reroute cancel: -p,-a
|
||||||
|
|
||||||
|
Pager string // api repl: -p || PAGER
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewConfig() *Config {
|
func NewConfig() *Config {
|
||||||
|
|||||||
@@ -36,3 +36,14 @@ func GetTermWidth() int {
|
|||||||
|
|
||||||
return 80
|
return 80
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetTermHeight() int {
|
||||||
|
if term.IsTerminal(int(os.Stdout.Fd())) {
|
||||||
|
_, height, err := term.GetSize(int(os.Stdout.Fd()))
|
||||||
|
if err == nil {
|
||||||
|
return height
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 25
|
||||||
|
}
|
||||||
|
|||||||
@@ -141,14 +141,50 @@ func ApiRepl(conf *cfg.Config) error {
|
|||||||
fmt.Printf("failed to call API: %s\n", esErrorString(err))
|
fmt.Printf("failed to call API: %s\n", esErrorString(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := prettyfiJson(conf, raw); err != nil {
|
pageJsonOutput(conf, raw)
|
||||||
fmt.Println(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func pageJsonOutput(conf *cfg.Config, raw []byte) {
|
||||||
|
tmpconf := &cfg.Config{HaveJQ: conf.HaveJQ}
|
||||||
|
|
||||||
|
if conf.Pager != "" {
|
||||||
|
tmpconf.HaveJQ = false
|
||||||
|
}
|
||||||
|
|
||||||
|
output, err := prettyfiJson(tmpconf, raw)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
lines := len(strings.Split(output, "\n"))
|
||||||
|
height := cfg.GetTermHeight()
|
||||||
|
|
||||||
|
if lines > height {
|
||||||
|
if conf.Pager != "" {
|
||||||
|
cmd := strings.Split(conf.Pager, " ")
|
||||||
|
pager := exec.Command(cmd[0], cmd[1:]...)
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
buf.WriteString(output)
|
||||||
|
|
||||||
|
pager.Stdout = os.Stdout
|
||||||
|
pager.Stdin = &buf
|
||||||
|
pager.Stderr = os.Stderr
|
||||||
|
|
||||||
|
err := pager.Run()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("failed to execute pager '%s': %s", conf.Pager, err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
printer.Pager("json output", output)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func encodeAuth(username, password string) string {
|
func encodeAuth(username, password string) string {
|
||||||
return base64.StdEncoding.EncodeToString([]byte(username + ":" + password))
|
return base64.StdEncoding.EncodeToString([]byte(username + ":" + password))
|
||||||
}
|
}
|
||||||
@@ -197,7 +233,7 @@ func CallAPI(conf *cfg.Config, verb, path, data string) ([]byte, error) {
|
|||||||
return body, nil
|
return body, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func prettyfiJson(conf *cfg.Config, raw []byte) error {
|
func prettyfiJson(conf *cfg.Config, raw []byte) (string, error) {
|
||||||
if conf.HaveJQ {
|
if conf.HaveJQ {
|
||||||
cmd := exec.CommandContext(context.Background(), "jq", "-C")
|
cmd := exec.CommandContext(context.Background(), "jq", "-C")
|
||||||
cmd.Stdin = bytes.NewReader(raw)
|
cmd.Stdin = bytes.NewReader(raw)
|
||||||
@@ -207,23 +243,18 @@ func prettyfiJson(conf *cfg.Config, raw []byte) error {
|
|||||||
|
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println(out.String())
|
return out.String(), nil
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var pretty bytes.Buffer
|
var pretty bytes.Buffer
|
||||||
err := json.Indent(&pretty, raw, "", "\t")
|
err := json.Indent(&pretty, raw, "", "\t")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("json parse error: %s", err)
|
return "", fmt.Errorf("json parse error: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println(pretty.String())
|
return pretty.String(), nil
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// interactively read arbitrary JSON data from STDIN, which is
|
// interactively read arbitrary JSON data from STDIN, which is
|
||||||
|
|||||||
@@ -39,9 +39,11 @@ func getIndexTemplateSettings(conf *cfg.Config, tplname string, table *printer.T
|
|||||||
}
|
}
|
||||||
|
|
||||||
if conf.Debug {
|
if conf.Debug {
|
||||||
if err := prettyfiJson(conf, raw); err != nil {
|
output, err := prettyfiJson(conf, raw)
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
fmt.Println(output)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(data.IndexTemplates) == 0 {
|
if len(data.IndexTemplates) == 0 {
|
||||||
|
|||||||
Reference in New Issue
Block a user