Skip to content

Commit

Permalink
Anthony/json output issue (#92)
Browse files Browse the repository at this point in the history
* JSON errors

* Fixed ish

* Fixed errors

* Linting

* lint
  • Loading branch information
notanthony authored Dec 26, 2023
1 parent d9440ed commit 1a8c274
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 27 deletions.
4 changes: 3 additions & 1 deletion cmd/cone/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"os/signal"
"syscall"

"github.com/conductorone/cone/pkg/output"
"github.com/spf13/cobra"
)

Expand Down Expand Up @@ -72,7 +73,8 @@ func runCli(ctx context.Context) int {

err = cliCmd.ExecuteContext(ctx)
if err != nil {
fmt.Fprintln(os.Stderr, err.Error())
_, _, v, _ := cmdContext(cliCmd)
fmt.Fprintln(os.Stderr, output.HandleErrors(ctx, v, err))
return 1
}

Expand Down
28 changes: 28 additions & 0 deletions pkg/output/error.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package output

import (
"context"
"fmt"

"github.com/spf13/viper"
)

const defaultJSONError = `{"error": "unable to marshal error to JSON %s"}`

type JSONError struct {
Error string `json:"error"`
}

func HandleErrors(ctx context.Context, v *viper.Viper, input error) error {
outputType := v.GetString("output")
if outputType != "json" && outputType != JSONPretty {
return input
}
// TODO: @anthony - handle errors better, for example, HTTP errors could be better, see client.go
jsonError, err := MakeJSONFromInterface(ctx, JSONError{Error: input.Error()}, outputType == JSONPretty)
if err != nil {
return fmt.Errorf(defaultJSONError, input.Error())
}

return fmt.Errorf(string(jsonError))
}
51 changes: 26 additions & 25 deletions pkg/output/json.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,56 +15,57 @@ type jsonManager struct {
}

func (j *jsonManager) Output(ctx context.Context, out interface{}, opts ...outputOption) error {
outBytes, err := MakeJSON(ctx, out, j.pretty)
if err != nil {
return err
}

_, err = fmt.Fprint(os.Stdout, string(outBytes))
if err != nil {
return err
}

return nil
}

func MakeJSON(ctx context.Context, out interface{}, pretty bool) ([]byte, error) {
if m, ok := out.(proto.Message); ok {
return j.printProto(ctx, m)
return MakeJSONFromProto(ctx, m, pretty)
}

return j.printInterface(ctx, out)
return MakeJSONFromInterface(ctx, out, pretty)
}

func (j *jsonManager) printProto(ctx context.Context, m proto.Message) error {
func MakeJSONFromProto(ctx context.Context, m proto.Message, pretty bool) ([]byte, error) {
opts := protojson.MarshalOptions{
EmitUnpopulated: true,
}
if j.pretty {
if pretty {
opts.Multiline = true
opts.Indent = " "
}

outBytes, err := opts.Marshal(m)
if err != nil {
return err
}

_, err = fmt.Fprint(os.Stdout, string(outBytes))
if err != nil {
return err
return nil, err
}

return nil
return outBytes, nil
}

func (j *jsonManager) printInterface(ctx context.Context, data interface{}) error {
if j.pretty {
func MakeJSONFromInterface(ctx context.Context, data interface{}, pretty bool) ([]byte, error) {
if pretty {
prettyJSON, err := json.MarshalIndent(data, "", " ")
if err != nil {
return err
return nil, err
}
_, err = fmt.Fprint(os.Stdout, string(prettyJSON))
if err != nil {
return err
}
return nil
return prettyJSON, nil
}

plainJSON, err := json.Marshal(data)
if err != nil {
return err
}
_, err = fmt.Fprint(os.Stdout, string(plainJSON))
if err != nil {
return err
return nil, err
}

return nil
return plainJSON, nil
}
4 changes: 3 additions & 1 deletion pkg/output/output.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ type Manager interface {
Output(ctx context.Context, out interface{}, opts ...outputOption) error
}

const JSONPretty = "json-pretty"

func NewManager(ctx context.Context, v *viper.Viper) Manager {
var area *pterm.AreaPrinter
if v.GetBool("wait") {
Expand All @@ -22,7 +24,7 @@ func NewManager(ctx context.Context, v *viper.Viper) Manager {
return &tableManager{area: area, isWide: false}
case "json":
return &jsonManager{}
case "json-pretty":
case JSONPretty:
return &jsonManager{pretty: true}
case "wide":
return &tableManager{area: area, isWide: true}
Expand Down

0 comments on commit 1a8c274

Please sign in to comment.