Skip to content

Commit

Permalink
Merge pull request #1675 from ripienaar/1665.6
Browse files Browse the repository at this point in the history
(#1665) support rendering json in kv history and get
  • Loading branch information
ripienaar authored May 16, 2022
2 parents e710062 + 7f4b9c6 commit df4f632
Show file tree
Hide file tree
Showing 2 changed files with 134 additions and 52 deletions.
5 changes: 5 additions & 0 deletions internal/fs/schemas/builder.json
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,11 @@
"type": "string",
"description": "The action to perform against the bucket and key",
"enum": ["get","put","del", "history"]
},
"json": {
"type": "boolean",
"description": "Renders the result in JSON format for get and history actions",
"default": false
}
}
}
Expand Down
181 changes: 129 additions & 52 deletions providers/appbuilder/kv.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@ import (
)

type KVCommand struct {
Action string `json:"action"`
Bucket string `json:"bucket"`
Key string `json:"key"`
Value string `json:"value"`
Action string `json:"action"`
Bucket string `json:"bucket"`
Key string `json:"key"`
Value string `json:"value"`
RenderJSON bool `json:"json"`

StandardSubCommands
StandardCommand
Expand Down Expand Up @@ -74,6 +75,10 @@ func (r *KV) CreateCommand(app inter.FlagApp) (*kingpin.CmdClause, error) {
r.Arguments[a.Name] = arg.String()
}

if r.def.Action == "get" || r.def.Action == "history" && !r.def.RenderJSON {
r.cmd.Flag("json", "Renders results in JSON format").BoolVar(&r.def.RenderJSON)
}

for _, f := range r.def.Flags {
flag := r.cmd.Flag(f.Name, f.Description)
if f.Required {
Expand All @@ -88,76 +93,148 @@ func (r *KV) CreateCommand(app inter.FlagApp) (*kingpin.CmdClause, error) {
return r.cmd, nil
}

func (r *KV) runCommand(_ *kingpin.ParseContext) error {
fw, err := choria.New(choria.UserConfig())
func (r *KV) getAction(kv nats.KeyValue) error {
entry, err := kv.Get(r.def.Key)
if err != nil {
return err
}

kv, err := fw.KV(r.ctx, nil, r.def.Bucket, false)
if err != nil {
return err
}

switch r.def.Action {
case "get":
entry, err := kv.Get(r.def.Key)
if r.def.RenderJSON {
ej, err := json.MarshalIndent(r.entryMap(entry), "", " ")
if err != nil {
return err
}

fmt.Println(string(ej))
} else {
fmt.Println(string(entry.Value()))
}

case "put":
v, err := parseStateTemplate(r.def.Value, r.Arguments, r.Flags, r.cfg)
if err != nil {
return err
}
return nil
}

rev, err := kv.PutString(r.def.Key, v)
if err != nil {
return err
}
func (r *KV) putAction(kv nats.KeyValue) error {
v, err := parseStateTemplate(r.def.Value, r.Arguments, r.Flags, r.cfg)
if err != nil {
return err
}

fmt.Printf("Wrote revision %d\n", rev)
rev, err := kv.PutString(r.def.Key, v)
if err != nil {
return err
}

case "del":
err = kv.Delete(r.def.Key)
if err != nil {
return err
fmt.Printf("Wrote revision %d\n", rev)

return nil
}

func (r *KV) delAction(kv nats.KeyValue) error {
err := kv.Delete(r.def.Key)
if err != nil {
return err
}
fmt.Printf("Deleted key %s\n", r.def.Key)

return nil
}

func (r *KV) opStringForOp(kvop nats.KeyValueOp) string {
var op string

switch kvop {
case nats.KeyValuePurge:
op = "PURGE"
case nats.KeyValueDelete:
op = "DELETE"
case nats.KeyValuePut:
op = "PUT"
default:
op = kvop.String()
}

return op
}

func (r *KV) entryMap(e nats.KeyValueEntry) map[string]interface{} {
if e == nil {
return nil
}

res := map[string]interface{}{
"operation": r.opStringForOp(e.Operation()),
"revision": e.Revision(),
"value": util.Base64IfNotPrintable(e.Value()),
"created": e.Created().Unix(),
}

return res
}

func (r *KV) historyAction(kv nats.KeyValue) error {
history, err := kv.History(r.def.Key)
if err != nil {
return err
}

if r.def.RenderJSON {
hist := map[string]map[string]map[string]interface{}{}
for _, e := range history {
if _, ok := hist[e.Bucket()]; !ok {
hist[e.Bucket()] = map[string]map[string]interface{}{}
}

hist[e.Bucket()][e.Key()] = r.entryMap(e)
}
fmt.Printf("Deleted key %s\n", r.def.Key)

case "history":
history, err := kv.History(r.def.Key)
j, err := json.MarshalIndent(hist, "", " ")
if err != nil {
return err
}

table := util.NewUTF8Table("Seq", "Operation", "Time", "Length", "Value")
for _, r := range history {
val := util.Base64IfNotPrintable(r.Value())
if len(val) > 40 {
val = fmt.Sprintf("%s...%s", val[0:15], val[len(val)-15:])
}

var op string

switch r.Operation() {
case nats.KeyValuePurge:
op = "PURGE"
case nats.KeyValueDelete:
op = "DELETE"
case nats.KeyValuePut:
op = "PUT"
default:
op = r.Operation().String()
}
fmt.Println(string(j))
return nil
}

table.AddRow(r.Revision(), op, r.Created().Format(time.RFC822), len(r.Value()), val)
table := util.NewUTF8Table("Seq", "Operation", "Time", "Length", "Value")
for _, e := range history {
val := util.Base64IfNotPrintable(e.Value())
if len(val) > 40 {
val = fmt.Sprintf("%s...%s", val[0:15], val[len(val)-15:])
}

fmt.Println(table.Render())
table.AddRow(e.Revision(), r.opStringForOp(e.Operation()), e.Created().Format(time.RFC822), len(e.Value()), val)
}

fmt.Println(table.Render())

return nil
}

func (r *KV) runCommand(_ *kingpin.ParseContext) error {
fw, err := choria.New(choria.UserConfig())
if err != nil {
return err
}

kv, err := fw.KV(r.ctx, nil, r.def.Bucket, false)
if err != nil {
return err
}

switch r.def.Action {
case "get":
err = r.getAction(kv)

case "put":
err = r.putAction(kv)

case "del":
err = r.delAction(kv)

case "history":
err = r.historyAction(kv)
}

return err
}

0 comments on commit df4f632

Please sign in to comment.