Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add --output=jsonpointer #644

Merged
merged 1 commit into from Dec 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
52 changes: 43 additions & 9 deletions cmdx/printing.go
Expand Up @@ -12,6 +12,7 @@ import (
"strings"
"text/tabwriter"

"github.com/go-openapi/jsonpointer"
"github.com/goccy/go-yaml"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
Expand Down Expand Up @@ -39,13 +40,14 @@ type (
)

const (
FormatQuiet format = "quiet"
FormatTable format = "table"
FormatJSON format = "json"
FormatJSONPath format = "jsonpath"
FormatJSONPretty format = "json-pretty"
FormatYAML format = "yaml"
FormatDefault format = "default"
FormatQuiet format = "quiet"
FormatTable format = "table"
FormatJSON format = "json"
FormatJSONPath format = "jsonpath"
FormatJSONPointer format = "jsonpointer"
FormatJSONPretty format = "json-pretty"
FormatYAML format = "yaml"
FormatDefault format = "default"

FlagFormat = "format"

Expand Down Expand Up @@ -84,6 +86,8 @@ func PrintRow(cmd *cobra.Command, row TableRow) {
printJSON(cmd.OutOrStdout(), row.Interface(), true, "")
case FormatJSONPath:
printJSON(cmd.OutOrStdout(), row.Interface(), true, getPath(cmd))
case FormatJSONPointer:
printJSON(cmd.OutOrStdout(), filterJSONPointer(cmd, row.Interface()), true, "")
case FormatTable, FormatDefault:
w := tabwriter.NewWriter(cmd.OutOrStdout(), 0, 8, 1, '\t', 0)

Expand All @@ -96,6 +100,26 @@ func PrintRow(cmd *cobra.Command, row TableRow) {
}
}

func filterJSONPointer(cmd *cobra.Command, data any) any {
f, err := cmd.Flags().GetString(FlagFormat)
// unexpected error
Must(err, "flag access error: %s", err)
_, jsonptr, found := strings.Cut(f, "=")
if !found {
_, _ = fmt.Fprintf(os.Stderr,
"Format %s is missing a JSON pointer, e.g., --%s=%s=<jsonpointer>. The path syntax is described at https://datatracker.ietf.org/doc/html/draft-ietf-appsawg-json-pointer-07.",
f, FlagFormat, f)
os.Exit(1)
}
ptr, err := jsonpointer.New(jsonptr)
Must(err, "invalid JSON pointer: %s", err)

result, _, err := ptr.Get(data)
Must(err, "failed to apply JSON pointer: %s", err)

return result
}

func PrintTable(cmd *cobra.Command, table Table) {
f := getFormat(cmd)

Expand All @@ -121,6 +145,8 @@ func PrintTable(cmd *cobra.Command, table Table) {
printJSON(cmd.OutOrStdout(), table.Interface(), true, "")
case FormatJSONPath:
printJSON(cmd.OutOrStdout(), table.Interface(), true, getPath(cmd))
case FormatJSONPointer:
printJSON(cmd.OutOrStdout(), filterJSONPointer(cmd, table.Interface()), true, "")
case FormatYAML:
printYAML(cmd.OutOrStdout(), table.Interface())
default:
Expand Down Expand Up @@ -164,6 +190,12 @@ func PrintJSONAble(cmd *cobra.Command, d interface{ String() string }) {
v = i
}
printJSON(cmd.OutOrStdout(), v, true, path)
case FormatJSONPointer:
var v interface{} = d
if i, ok := d.(interfacer); ok {
v = i
}
printJSON(cmd.OutOrStdout(), filterJSONPointer(cmd, v), true, "")
case FormatYAML:
var v interface{} = d
if i, ok := d.(interfacer); ok {
Expand Down Expand Up @@ -200,6 +232,8 @@ func getFormat(cmd *cobra.Command) format {
return FormatJSON
case strings.HasPrefix(f, string(FormatJSONPath)):
return FormatJSONPath
case strings.HasPrefix(f, string(FormatJSONPointer)):
return FormatJSONPointer
case f == string(FormatJSONPretty):
return FormatJSONPretty
case f == string(FormatYAML):
Expand Down Expand Up @@ -249,12 +283,12 @@ func printYAML(w io.Writer, v interface{}) {
}

func RegisterJSONFormatFlags(flags *pflag.FlagSet) {
flags.String(FlagFormat, string(FormatDefault), fmt.Sprintf("Set the output format. One of %s, %s, %s, %s and %s.", FormatDefault, FormatJSON, FormatYAML, FormatJSONPretty, FormatJSONPath))
flags.String(FlagFormat, string(FormatDefault), fmt.Sprintf("Set the output format. One of %s, %s, %s, %s, %s and %s.", FormatDefault, FormatJSON, FormatYAML, FormatJSONPretty, FormatJSONPath, FormatJSONPointer))
}

func RegisterFormatFlags(flags *pflag.FlagSet) {
RegisterNoiseFlags(flags)
flags.String(FlagFormat, string(FormatDefault), fmt.Sprintf("Set the output format. One of %s, %s, %s, %s, and %s.", FormatTable, FormatJSON, FormatYAML, FormatJSONPretty, FormatJSONPath))
flags.String(FlagFormat, string(FormatDefault), fmt.Sprintf("Set the output format. One of %s, %s, %s, %s, %s and %s.", FormatTable, FormatJSON, FormatYAML, FormatJSONPretty, FormatJSONPath, FormatJSONPointer))
}

type bodyer interface {
Expand Down
18 changes: 17 additions & 1 deletion cmdx/printing_test.go
Expand Up @@ -128,6 +128,18 @@ func TestPrinting(t *testing.T) {
fArgs: []string{"--" + FlagFormat, string(FormatJSONPretty)},
contained: tr,
},
{
fArgs: []string{"--" + FlagFormat, string(FormatJSONPointer) + "=/0"},
contained: []string{"AAA"},
},
{
fArgs: []string{"--" + FlagFormat, string(FormatJSONPointer) + "=/2"},
contained: []string{"CCC"},
},
{
fArgs: []string{"--" + FlagFormat, string(FormatJSONPointer) + "=/1"},
contained: []string{"BBB"},
},
{
fArgs: []string{"--" + FlagFormat, string(FormatJSONPath) + "=0"},
contained: []string{"AAA"},
Expand Down Expand Up @@ -224,6 +236,10 @@ func TestPrinting(t *testing.T) {
fArgs: []string{"--" + FlagFormat, string(FormatJSONPath) + "=1.1"},
contained: []string{tb.t[1][1]},
},
{
fArgs: []string{"--" + FlagFormat, string(FormatJSONPointer) + "=/1/1"},
contained: []string{tb.t[1][1]},
},
{
fArgs: []string{"--" + FlagFormat, string(FormatYAML)},
contained: append(tb.t[0], tb.t[1]...),
Expand Down Expand Up @@ -330,7 +346,7 @@ func TestPrinting(t *testing.T) {

t.Run("method=jsonable", func(t *testing.T) {
t.Run("case=nil", func(t *testing.T) {
for _, f := range []format{FormatDefault, FormatJSON, FormatJSONPretty, FormatJSONPath, FormatYAML} {
for _, f := range []format{FormatDefault, FormatJSON, FormatJSONPretty, FormatJSONPath, FormatJSONPointer, FormatYAML} {
t.Run("format="+string(f), func(t *testing.T) {
out := &bytes.Buffer{}
cmd := &cobra.Command{}
Expand Down
1 change: 1 addition & 0 deletions go.mod
Expand Up @@ -133,6 +133,7 @@ require (
github.com/go-logr/logr v1.2.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-openapi/errors v0.20.3 // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect
github.com/go-openapi/strfmt v0.21.3 // indirect
github.com/go-openapi/swag v0.22.3 // indirect
github.com/go-pdf/fpdf v0.6.0 // indirect
Expand Down