Skip to content

Commit

Permalink
add support for jsonpath format (#52)
Browse files Browse the repository at this point in the history
* add support for `jsonpath` format

* revert change

* use go 1.13
  • Loading branch information
0x4c6565 authored May 15, 2020
1 parent 47a049b commit 00e77d1
Show file tree
Hide file tree
Showing 9 changed files with 97 additions and 32 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
language: go
go:
- "1.12"
- "1.13"
env:
- GO111MODULE=on
script:
Expand Down
13 changes: 0 additions & 13 deletions cmd/output.go

This file was deleted.

4 changes: 3 additions & 1 deletion cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
var flagConfig string
var flagFormat string
var flagOutputTemplate string
var flagJSONPath string
var flagSort string
var flagProperty []string
var flagFilter []string
Expand All @@ -48,8 +49,9 @@ func Execute(build build.BuildInfo) {

// Global flags
rootCmd.PersistentFlags().StringVar(&flagConfig, "config", "", "config file (default is $HOME/.ukfast.yml)")
rootCmd.PersistentFlags().StringVarP(&flagFormat, "format", "f", "", "output format {table, json, template, value, csv, list}")
rootCmd.PersistentFlags().StringVarP(&flagFormat, "format", "f", "", "output format {table, json, jsonpath, template, value, csv, list}")
rootCmd.PersistentFlags().StringVar(&flagOutputTemplate, "outputtemplate", "", "output Go template (used with 'template' format), e.g. 'Name: {{ .Name }}'")
rootCmd.PersistentFlags().StringVar(&flagJSONPath, "jsonpath", "", "JSON path query (used with 'jsonpath' format)")
rootCmd.PersistentFlags().StringVar(&flagSort, "sort", "", "output sorting, e.g. 'name', 'name:asc', 'name:desc'")
rootCmd.PersistentFlags().StringSliceVar(&flagProperty, "property", []string{}, "property to output (used with several formats), can be repeated")
rootCmd.PersistentFlags().StringArrayVar(&flagFilter, "filter", []string{}, "filter for list commands, can be repeated, e.g. 'property=somevalue', 'property:gt=3', 'property=valu*'")
Expand Down
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ require (
github.com/spf13/cobra v0.0.5
github.com/spf13/viper v1.3.2
github.com/stretchr/testify v1.3.0
github.com/ukfast/sdk-go v1.3.7
github.com/ukfast/sdk-go v1.3.8
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b // indirect
gopkg.in/go-playground/assert.v1 v1.2.1
k8s.io/client-go v11.0.0+incompatible
)

go 1.13
10 changes: 4 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,8 @@ github.com/tcnksm/go-gitconfig v0.1.2/go.mod h1:/8EhP4H7oJZdIPyT+/UIsG87kTzrzM4U
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/ukfast/go-durationstring v1.0.0 h1:kgPuA7XjLjgLDfkG8j0MpolxcZh/eMdiVoOIFD/uc5I=
github.com/ukfast/go-durationstring v1.0.0/go.mod h1:Ci81n51kfxlKUIaLY9cINIKRO94VTqV+iCGbOMTb0V8=
github.com/ukfast/sdk-go v1.3.4 h1:3L+wBtJ4Gk0hie9BzWSeFhQ8cyCRJzwCHDVh88LSbRA=
github.com/ukfast/sdk-go v1.3.4/go.mod h1:VHQi+BbNxVKPu131MHaMFe0UrMoFWbe4LjUqSCt64yg=
github.com/ukfast/sdk-go v1.3.6 h1:T1wQiy3Us4zbJWJrHCPk7TQN6uL1VruU7AJ3/0aSmkQ=
github.com/ukfast/sdk-go v1.3.6/go.mod h1:VHQi+BbNxVKPu131MHaMFe0UrMoFWbe4LjUqSCt64yg=
github.com/ukfast/sdk-go v1.3.7 h1:iY08lE8WcnwI7ZGcLRYUW6JWWf0aX20a+VZ0fm9tsZg=
github.com/ukfast/sdk-go v1.3.7/go.mod h1:VHQi+BbNxVKPu131MHaMFe0UrMoFWbe4LjUqSCt64yg=
github.com/ukfast/sdk-go v1.3.8 h1:UUKtNxHeKWN53pdcAZNYhi/d+XQCqsl9/9wDacbRyo4=
github.com/ukfast/sdk-go v1.3.8/go.mod h1:VHQi+BbNxVKPu131MHaMFe0UrMoFWbe4LjUqSCt64yg=
github.com/ulikunitz/xz v0.5.5 h1:pFrO0lVpTBXLpYw+pnLj6TbvHuyjXMfjGeCwSqCVwok=
github.com/ulikunitz/xz v0.5.5/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
Expand Down Expand Up @@ -137,3 +133,5 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWD
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
k8s.io/client-go v11.0.0+incompatible h1:LBbX2+lOwY9flffWlJM7f1Ct8V2SRNiMRDFeiwnJo9o=
k8s.io/client-go v11.0.0+incompatible/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s=
28 changes: 26 additions & 2 deletions internal/pkg/output/output.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/olekukonko/tablewriter"
"github.com/ryanuber/go-glob"
"github.com/spf13/cobra"
"k8s.io/client-go/util/jsonpath"
)

var outputExit func(code int) = os.Exit
Expand Down Expand Up @@ -128,6 +129,22 @@ func JSON(v interface{}) error {
return err
}

// JSONPath marshals and outputs value v to stdout
func JSONPath(jsonPathTemplate string, v interface{}) error {
j := jsonpath.New("clioutput")
err := j.Parse(jsonPathTemplate)
if err != nil {
return fmt.Errorf("Failed to parse jsonpath template: %w", err)
}

err = j.Execute(os.Stdout, v)
if err != nil {
return fmt.Errorf("Failed to execute jsonpath: %w", err)
}

return nil
}

// Table takes an array of mapped fields (key being lowercased name), and outputs a table
// Included properties can be overriden by populating includeProperties parameter
func Table(includeProperties []string, rows []*OrderedFields) error {
Expand Down Expand Up @@ -356,8 +373,15 @@ func NewFieldValue(value string, def bool) FieldValue {
func CommandOutput(cmd *cobra.Command, out OutputHandlerProvider) error {
format, _ := cmd.Flags().GetString("format")
handler := NewOutputHandler(out, format)
handler.Properties, _ = cmd.Flags().GetStringSlice("property")
handler.Template, _ = cmd.Flags().GetString("outputtemplate")

properties, _ := cmd.Flags().GetStringSlice("property")
handler.WithOption("Properties", properties)

template, _ := cmd.Flags().GetString("outputtemplate")
handler.WithOption("Template", template)

jsonPath, _ := cmd.Flags().GetString("jsonpath")
handler.WithOption("JSONPath", jsonPath)

return handler.Handle()
}
39 changes: 32 additions & 7 deletions internal/pkg/output/output_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@ import (

type UnsupportedFormatHandler func() error

type OutputHandlerOpts map[string]interface{}

type OutputHandler struct {
Format string
Provider OutputHandlerProvider
Properties []string
Template string
Options OutputHandlerOpts
UnsupportedFormatHandler UnsupportedFormatHandler
}

Expand All @@ -23,9 +24,15 @@ func NewOutputHandler(out OutputHandlerProvider, format string) *OutputHandler {
return &OutputHandler{
Provider: out,
Format: format,
Options: make(map[string]interface{}),
}
}

func (o *OutputHandler) WithOption(name string, value interface{}) *OutputHandler {
o.Options[name] = value
return o
}

// Handle calls the relevant OutputProvider data retrieval methods for given value
// in struct property 'Format'
func (o *OutputHandler) Handle() error {
Expand All @@ -40,26 +47,28 @@ func (o *OutputHandler) Handle() error {
switch o.Format {
case "json":
return JSON(o.Provider.GetData())
case "jsonpath":
return JSONPath(o.getStringOpt("JSONPath"), o.Provider.GetData())
case "template":
return Template(o.Template, o.Provider.GetData())
return Template(o.getStringOpt("Template"), o.Provider.GetData())
case "value":
d, err := o.Provider.GetFieldData()
if err != nil {
return err
}
return Value(o.Properties, d)
return Value(o.getStringSliceOpt("Properties"), d)
case "csv":
d, err := o.Provider.GetFieldData()
if err != nil {
return err
}
return CSV(o.Properties, d)
return CSV(o.getStringSliceOpt("Properties"), d)
case "list":
d, err := o.Provider.GetFieldData()
if err != nil {
return err
}
return List(o.Properties, d)
return List(o.getStringSliceOpt("Properties"), d)
default:
Errorf("Invalid output format [%s], defaulting to 'table'", o.Format)
fallthrough
Expand All @@ -68,7 +77,7 @@ func (o *OutputHandler) Handle() error {
if err != nil {
return err
}
return Table(o.Properties, d)
return Table(o.getStringSliceOpt("Properties"), d)
}
}

Expand All @@ -85,3 +94,19 @@ func (o *OutputHandler) supportedFormat() bool {

return false
}

func (o *OutputHandler) getStringOpt(name string) string {
if o.Options[name] != nil {
return o.Options[name].(string)
}

return ""
}

func (o *OutputHandler) getStringSliceOpt(name string) []string {
if o.Options[name] != nil {
return o.Options[name].([]string)
}

return []string{}
}
2 changes: 1 addition & 1 deletion internal/pkg/output/output_handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ func TestOutputHandler_Handle(t *testing.T) {

t.Run("TemplateFormat_ExpectedOutput", func(t *testing.T) {
handler := NewOutputHandler(testOutputHandlerProvider, "template")
handler.Template = "{{ .TestProperty1 }}"
handler.WithOption("Template", "{{ .TestProperty1 }}")

output := test.CatchStdOut(t, func() {
handler.Handle()
Expand Down
28 changes: 28 additions & 0 deletions internal/pkg/output/output_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,34 @@ func TestOutput_JSON_ExpectedStdout(t *testing.T) {
})
}

func TestOutput_JSONPath_ExpectedStdout(t *testing.T) {
t.Run("WithJSONPathTemplate_ExpectedStdOut", func(t *testing.T) {
zone := safedns.Zone{Name: "testzone.com", Description: "testdescription"}

output := test.CatchStdOut(t, func() {
JSONPath("{.name}", zone)
})

assert.Equal(t, "testzone.com", output)
})

t.Run("WithJSONPathParseError_ReturnsError", func(t *testing.T) {
zone := safedns.Zone{Name: "testzone.com", Description: "testdescription"}

err := JSONPath("{.name", zone)

assert.NotNil(t, err)
})

t.Run("WithJSONPathExecuteError_ReturnsError", func(t *testing.T) {
zone := safedns.Zone{Name: "testzone.com", Description: "testdescription"}

err := JSONPath("{.invalid}", zone)

assert.NotNil(t, err)
})
}

func TestTable_ExpectedStdout(t *testing.T) {
t.Run("SingleRowDefaultFields", func(t *testing.T) {
var rows []*OrderedFields
Expand Down

0 comments on commit 00e77d1

Please sign in to comment.