add cli draft

content is not there yet
format is very basic
pull/58/head
Simon Let 6 years ago
parent 8e5c4cbe6b
commit ef996545e9
  1. 2
      Makefile
  2. 241
      cmd/cli/main.go
  3. 2
      go.mod
  4. 9
      go.sum
  5. 15
      scripts/reshctl.sh

@ -6,7 +6,7 @@ GOFLAGS=-ldflags "-X main.version=${VERSION} -X main.commit=${REVISION}"
build: submodules bin/resh-session-init bin/resh-collect bin/resh-postcollect bin/resh-daemon\
bin/resh-evaluate bin/resh-sanitize bin/resh-control bin/resh-config bin/resh-inspect
bin/resh-evaluate bin/resh-sanitize bin/resh-control bin/resh-config bin/resh-inspect bin/resh-cli
install: build conf/config-dev.toml
scripts/install.sh

@ -0,0 +1,241 @@
package main
import (
"bytes"
"encoding/json"
"flag"
"fmt"
"io/ioutil"
"log"
"net/http"
"sort"
"strings"
"github.com/BurntSushi/toml"
"github.com/awesome-gocui/gocui"
"github.com/curusarn/resh/pkg/cfg"
"github.com/curusarn/resh/pkg/msg"
"os/user"
"path/filepath"
"strconv"
)
// version from git set during build
var version string
// commit from git set during build
var commit string
func main() {
usr, _ := user.Current()
dir := usr.HomeDir
configPath := filepath.Join(dir, "/.config/resh.toml")
var config cfg.Config
if _, err := toml.DecodeFile(configPath, &config); err != nil {
log.Fatal("Error reading config:", err)
}
sessionID := flag.String("sessionID", "", "resh generated session id")
flag.Parse()
if *sessionID == "" {
fmt.Println("Error: you need to specify sessionId")
}
g, err := gocui.NewGui(gocui.OutputNormal, false)
if err != nil {
log.Panicln(err)
}
defer g.Close()
g.Cursor = true
g.SelFgColor = gocui.ColorGreen
// g.SelBgColor = gocui.ColorGreen
g.Highlight = false
mess := msg.InspectMsg{SessionID: *sessionID, Count: 40}
resp := SendInspectMsg(mess, strconv.Itoa(config.Port))
st := state{
// lock sync.Mutex
dataOriginal: resp.CmdLines,
data: resp.CmdLines,
}
layout := manager{
sessionID: *sessionID,
config: config,
s: &st,
}
g.SetManager(layout)
if err := g.SetKeybinding("", gocui.KeyTab, gocui.ModNone, layout.Next); err != nil {
log.Panicln(err)
}
if err := g.SetKeybinding("", gocui.KeyArrowDown, gocui.ModNone, layout.Next); err != nil {
log.Panicln(err)
}
if err := g.SetKeybinding("", gocui.KeyArrowUp, gocui.ModNone, layout.Prev); err != nil {
log.Panicln(err)
}
if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {
log.Panicln(err)
}
if err := g.SetKeybinding("", gocui.KeyEnter, gocui.ModNone, layout.SelectExecute); err != nil {
log.Panicln(err)
}
err = g.MainLoop()
if err != nil && gocui.IsQuit(err) == false {
log.Panicln(err)
}
layout.Output()
}
// returns the number of hits for query
func queryHits(cmdline string, queryTerms []string) int {
hits := 0
for _, term := range queryTerms {
if strings.Contains(cmdline, term) {
hits++
}
}
return hits
}
type state struct {
dataOriginal []string
data []string
highlightedItem int
outputBuffer string
}
type manager struct {
sessionID string
config cfg.Config
s *state
}
func (m manager) Output() {
if len(m.s.outputBuffer) > 0 {
fmt.Print(m.s.outputBuffer)
}
}
func (m manager) SelectExecute(g *gocui.Gui, v *gocui.View) error {
if m.s.highlightedItem < len(m.s.data) {
m.s.outputBuffer = m.s.data[m.s.highlightedItem]
return gocui.ErrQuit
}
return nil
}
func (m manager) Edit(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) {
gocui.DefaultEditor.Edit(v, key, ch, mod)
query := v.Buffer()
terms := strings.Split(query, " ")
var dataHits []int
m.s.data = nil
for _, entry := range m.s.dataOriginal {
hits := queryHits(entry, terms)
if hits > 0 {
m.s.data = append(m.s.data, entry)
dataHits = append(dataHits, hits)
}
}
sort.SliceStable(m.s.data, func(p, q int) bool {
return dataHits[p] > dataHits[q]
})
m.s.highlightedItem = 0
}
func (m manager) Next(g *gocui.Gui, v *gocui.View) error {
_, y := g.Size()
if m.s.highlightedItem < y {
m.s.highlightedItem++
}
return nil
}
func (m manager) Prev(g *gocui.Gui, v *gocui.View) error {
if m.s.highlightedItem > 0 {
m.s.highlightedItem--
}
return nil
}
// you can have Layout with pointer reciever if you pass the layout function to the setmanger
// I dont think we need that tho
func (m manager) Layout(g *gocui.Gui) error {
var b byte
maxX, maxY := g.Size()
v, err := g.SetView("input", 0, 0, maxX-1, 2, b)
if err != nil && gocui.IsUnknownView(err) == false {
log.Panicln(err.Error())
}
v.Editable = true
// v.Editor = gocui.EditorFunc(m.editor.Edit)
v.Editor = m
v.Title = "resh cli"
g.SetCurrentView("input")
v, err = g.SetView("body", 0, 2, maxX-1, maxY, b)
if err != nil && gocui.IsUnknownView(err) == false {
log.Panicln(err.Error())
}
v.Frame = false
v.Autoscroll = true
v.Clear()
for _, cmdLine := range m.s.data {
entry := strings.Trim(cmdLine, "\n") + "\n"
v.WriteString(entry)
}
if m.s.highlightedItem < len(m.s.data) {
v.SetHighlight(m.s.highlightedItem, true)
}
return nil
}
func quit(g *gocui.Gui, v *gocui.View) error {
return gocui.ErrQuit
}
// SendInspectMsg to daemon
func SendInspectMsg(m msg.InspectMsg, port string) msg.MultiResponse {
recJSON, err := json.Marshal(m)
if err != nil {
log.Fatal("send err 1", err)
}
req, err := http.NewRequest("POST", "http://localhost:"+port+"/inspect",
bytes.NewBuffer(recJSON))
if err != nil {
log.Fatal("send err 2", err)
}
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
log.Fatal("resh-daemon is not running :(")
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatal("read response error")
}
// log.Println(string(body))
response := msg.MultiResponse{}
err = json.Unmarshal(body, &response)
if err != nil {
log.Fatal("unmarshal resp error: ", err)
}
return response
}

@ -4,7 +4,9 @@ go 1.12
require (
github.com/BurntSushi/toml v0.3.1
github.com/awesome-gocui/gocui v0.6.0
github.com/jpillora/longestcommon v0.0.0-20161227235612-adb9d91ee629
github.com/mattn/go-runewidth v0.0.8 // indirect
github.com/mattn/go-shellwords v1.0.6
github.com/mb-14/gomarkov v0.0.0-20190125094512-044dd0dcb5e7
github.com/mitchellh/go-ps v0.0.0-20190716172923-621e5597135b

@ -1,18 +1,27 @@
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/awesome-gocui/gocui v0.6.0 h1:hhDJiQC12tEsJNJ+iZBBVaSSLFYo9llFuYpQlL5JZVI=
github.com/awesome-gocui/gocui v0.6.0/go.mod h1:1QikxFaPhe2frKeKvEwZEIGia3haiOxOUXKinrv17mA=
github.com/awesome-gocui/termbox-go v0.0.0-20190427202837-c0aef3d18bcc h1:wGNpKcHU8Aadr9yOzsT3GEsFLS7HQu8HxQIomnekqf0=
github.com/awesome-gocui/termbox-go v0.0.0-20190427202837-c0aef3d18bcc/go.mod h1:tOy3o5Nf1bA17mnK4W41gD7PS3u4Cv0P0pqFcoWMy8s=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jpillora/longestcommon v0.0.0-20161227235612-adb9d91ee629 h1:1dSBUfGlorLAua2CRx0zFN7kQsTpE2DQSmr7rrTNgY8=
github.com/jpillora/longestcommon v0.0.0-20161227235612-adb9d91ee629/go.mod h1:mb5nS4uRANwOJSZj8rlCWAfAcGi72GGMIXx+xGOjA7M=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.8 h1:3tS41NlGYSmhhe/8fhGRzc+z3AYCw1Fe1WAyLuujKs0=
github.com/mattn/go-runewidth v0.0.8/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-shellwords v1.0.6 h1:9Jok5pILi5S1MnDirGVTufYGtksUs/V2BWUP3ZkeUUI=
github.com/mattn/go-shellwords v1.0.6/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
github.com/mb-14/gomarkov v0.0.0-20190125094512-044dd0dcb5e7 h1:VsJjhYhufMGXICLwLYr8mFVMp8/A+YqmagMHnG/BA/4=

@ -75,6 +75,21 @@ __resh_unbind_all() {
__resh_unbind_control_R
}
# wrapper for resh-cli
# meant to be launched on ctrl+R
resh() {
if resh-cli --sessionID "$__RESH_SESSION_ID" > ~/.resh/cli_last_run_out.txt 2>&1; then
# insert on cmdline
echo "$(cat ~/.resh/cli_last_run_out.txt)"
eval "$(cat ~/.resh/cli_last_run_out.txt)"
# TODO: get rid of eval
else
# print errors
echo "resh-cli ERROR:"
cat ~/.resh/cli_last_run_out.txt
fi
}
reshctl() {
# local log=~/.resh/reshctl.log
# export current shell because resh-control needs to know

Loading…
Cancel
Save