feat: json output formatter
This commit is contained in:
@ -4,11 +4,3 @@ type AppConfig struct {
|
|||||||
OutputVerbose bool
|
OutputVerbose bool
|
||||||
OutputMode string
|
OutputMode string
|
||||||
}
|
}
|
||||||
|
|
||||||
type OutputMode string
|
|
||||||
|
|
||||||
const (
|
|
||||||
Go OutputMode = "go"
|
|
||||||
Json OutputMode = "json"
|
|
||||||
Yaml OutputMode = "yaml"
|
|
||||||
)
|
|
||||||
|
|||||||
@ -1,5 +0,0 @@
|
|||||||
package cmd
|
|
||||||
|
|
||||||
type OutputProvider interface {
|
|
||||||
Convert(item any) (string, error)
|
|
||||||
}
|
|
||||||
@ -31,12 +31,12 @@ func initRootCmd() {
|
|||||||
var appConfig AppConfig
|
var appConfig AppConfig
|
||||||
|
|
||||||
rootCmd.PersistentFlags().BoolVarP(&appConfig.OutputVerbose, "verbose", "v", false, "Enable verbose output")
|
rootCmd.PersistentFlags().BoolVarP(&appConfig.OutputVerbose, "verbose", "v", false, "Enable verbose output")
|
||||||
rootCmd.PersistentFlags().StringVarP(&appConfig.OutputMode, "output", "o", string(Json), "Set output format")
|
rootCmd.PersistentFlags().StringVarP(&appConfig.OutputMode, "output", "o", "json", "Set output format")
|
||||||
|
|
||||||
logger := jlog.New(slog.LevelDebug)
|
logger := jlog.New(slog.LevelDebug)
|
||||||
ctx := jlog.ContextWith(context.Background(), logger)
|
ctx := jlog.ContextWith(context.Background(), logger)
|
||||||
|
|
||||||
logger.Debug("Register verb commands")
|
logger.Debug("Register verb commands")
|
||||||
rootCmd.AddCommand(getVerbs(ctx)...)
|
rootCmd.AddCommand(getVerbs(ctx, appConfig)...)
|
||||||
logger.Debug("Verb commands registered successfully")
|
logger.Debug("Verb commands registered successfully")
|
||||||
}
|
}
|
||||||
|
|||||||
28
cmd/verbs.go
28
cmd/verbs.go
@ -2,8 +2,8 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"os"
|
"os"
|
||||||
"slices"
|
"slices"
|
||||||
@ -11,6 +11,7 @@ import (
|
|||||||
|
|
||||||
"git.bissendorf.co/bissendorf/unifood/m/v2/core/interfaces"
|
"git.bissendorf.co/bissendorf/unifood/m/v2/core/interfaces"
|
||||||
"git.bissendorf.co/bissendorf/unifood/m/v2/core/interfaces/params"
|
"git.bissendorf.co/bissendorf/unifood/m/v2/core/interfaces/params"
|
||||||
|
"git.bissendorf.co/bissendorf/unifood/m/v2/core/output"
|
||||||
"git.bissendorf.co/bissendorf/unifood/m/v2/core/services/jlog"
|
"git.bissendorf.co/bissendorf/unifood/m/v2/core/services/jlog"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
@ -19,32 +20,47 @@ type VerbItem struct {
|
|||||||
Name interfaces.Verb
|
Name interfaces.Verb
|
||||||
Aliases []string
|
Aliases []string
|
||||||
Description string
|
Description string
|
||||||
RunFn func(ctx context.Context, handler interfaces.ResourceHandler, params params.Container) error
|
RunFn func(ctx context.Context, config AppConfig, handler interfaces.ResourceHandler, params params.Container) error
|
||||||
}
|
}
|
||||||
|
|
||||||
var verbs = []VerbItem{
|
var verbs = []VerbItem{
|
||||||
{
|
{
|
||||||
Name: interfaces.VerbGet,
|
Name: interfaces.VerbGet,
|
||||||
Description: "Retrieve resource information",
|
Description: "Retrieve resource information",
|
||||||
RunFn: func(ctx context.Context, handler interfaces.ResourceHandler, params params.Container) error {
|
RunFn: func(ctx context.Context, config AppConfig, handler interfaces.ResourceHandler, params params.Container) error {
|
||||||
h, ok := handler.(interfaces.GetHandler)
|
h, ok := handler.(interfaces.GetHandler)
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("resource does not support GET")
|
return fmt.Errorf("resource does not support GET")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get item
|
||||||
item, err := h.Get(ctx, params)
|
item, err := h.Get(ctx, params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("retrieving item failed: %w", err)
|
return fmt.Errorf("retrieving item failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
json.NewEncoder(os.Stdout).Encode(item)
|
formatterName := strings.ToLower(config.OutputMode)
|
||||||
|
formatter, exists := output.Formatters[formatterName]
|
||||||
|
if !exists {
|
||||||
|
return fmt.Errorf("could not find output formatter '%s'", formatterName)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format and output
|
||||||
|
formatted, err := formatter.Format(item)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to format output: %w", err)
|
||||||
|
}
|
||||||
|
_, err = io.Copy(os.Stdout, formatted)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to write output: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func getVerbs(ctx context.Context) (commands []*cobra.Command) {
|
func getVerbs(ctx context.Context, config AppConfig) (commands []*cobra.Command) {
|
||||||
logger := jlog.FromContext(ctx)
|
logger := jlog.FromContext(ctx)
|
||||||
|
|
||||||
for _, v := range verbs {
|
for _, v := range verbs {
|
||||||
@ -69,7 +85,7 @@ func getVerbs(ctx context.Context) (commands []*cobra.Command) {
|
|||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
logger := jlog.New(slog.LevelInfo)
|
logger := jlog.New(slog.LevelInfo)
|
||||||
ctx := jlog.ContextWith(context.Background(), logger)
|
ctx := jlog.ContextWith(context.Background(), logger)
|
||||||
err := v.RunFn(ctx, r.Handler, params)
|
err := v.RunFn(ctx, config, r.Handler, params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.ErrorContext(ctx, fmt.Sprintf("%s %s failed", strings.ToUpper(string(v.Name)), r.Name), "error", err.Error())
|
logger.ErrorContext(ctx, fmt.Sprintf("%s %s failed", strings.ToUpper(string(v.Name)), r.Name), "error", err.Error())
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
|||||||
7
core/interfaces/output.go
Normal file
7
core/interfaces/output.go
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package interfaces
|
||||||
|
|
||||||
|
import "io"
|
||||||
|
|
||||||
|
type Formatter interface {
|
||||||
|
Format(object any) (io.Reader, error)
|
||||||
|
}
|
||||||
12
core/output/formatter.go
Normal file
12
core/output/formatter.go
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package output
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.bissendorf.co/bissendorf/unifood/m/v2/core/interfaces"
|
||||||
|
)
|
||||||
|
|
||||||
|
var Formatters = map[string]interfaces.Formatter{
|
||||||
|
"json": &JsonFormatter{},
|
||||||
|
"go": nil,
|
||||||
|
"table": nil,
|
||||||
|
"xml": nil,
|
||||||
|
}
|
||||||
15
core/output/json.go
Normal file
15
core/output/json.go
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package output
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
type JsonFormatter struct{}
|
||||||
|
|
||||||
|
func (f *JsonFormatter) Format(object any) (io.Reader, error) {
|
||||||
|
var buffer = make([]byte, 0, 1024)
|
||||||
|
outputBuffer := bytes.NewBuffer(buffer)
|
||||||
|
return outputBuffer, json.NewEncoder(outputBuffer).Encode(object)
|
||||||
|
}
|
||||||
3
go.mod
3
go.mod
@ -2,8 +2,9 @@ module git.bissendorf.co/bissendorf/unifood/m/v2
|
|||||||
|
|
||||||
go 1.24.0
|
go 1.24.0
|
||||||
|
|
||||||
|
require github.com/spf13/cobra v1.9.1
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||||
github.com/spf13/cobra v1.9.1 // indirect
|
|
||||||
github.com/spf13/pflag v1.0.7 // indirect
|
github.com/spf13/pflag v1.0.7 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user