diff --git a/cmd/config.go b/cmd/config.go index 4407be2..767e769 100644 --- a/cmd/config.go +++ b/cmd/config.go @@ -4,11 +4,3 @@ type AppConfig struct { OutputVerbose bool OutputMode string } - -type OutputMode string - -const ( - Go OutputMode = "go" - Json OutputMode = "json" - Yaml OutputMode = "yaml" -) diff --git a/cmd/output.go b/cmd/output.go deleted file mode 100644 index 1d5a0ab..0000000 --- a/cmd/output.go +++ /dev/null @@ -1,5 +0,0 @@ -package cmd - -type OutputProvider interface { - Convert(item any) (string, error) -} diff --git a/cmd/root.go b/cmd/root.go index aca0c6c..9a4b24f 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -31,12 +31,12 @@ func initRootCmd() { var appConfig AppConfig 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) ctx := jlog.ContextWith(context.Background(), logger) logger.Debug("Register verb commands") - rootCmd.AddCommand(getVerbs(ctx)...) + rootCmd.AddCommand(getVerbs(ctx, appConfig)...) logger.Debug("Verb commands registered successfully") } diff --git a/cmd/verbs.go b/cmd/verbs.go index 5f8a107..827c747 100644 --- a/cmd/verbs.go +++ b/cmd/verbs.go @@ -2,8 +2,8 @@ package cmd import ( "context" - "encoding/json" "fmt" + "io" "log/slog" "os" "slices" @@ -11,6 +11,7 @@ import ( "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/output" "git.bissendorf.co/bissendorf/unifood/m/v2/core/services/jlog" "github.com/spf13/cobra" ) @@ -19,32 +20,47 @@ type VerbItem struct { Name interfaces.Verb Aliases []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{ { Name: interfaces.VerbGet, 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) if !ok { return fmt.Errorf("resource does not support GET") } + // Get item item, err := h.Get(ctx, params) if err != nil { 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 }, }, } -func getVerbs(ctx context.Context) (commands []*cobra.Command) { +func getVerbs(ctx context.Context, config AppConfig) (commands []*cobra.Command) { logger := jlog.FromContext(ctx) for _, v := range verbs { @@ -69,7 +85,7 @@ func getVerbs(ctx context.Context) (commands []*cobra.Command) { Run: func(cmd *cobra.Command, args []string) { logger := jlog.New(slog.LevelInfo) ctx := jlog.ContextWith(context.Background(), logger) - err := v.RunFn(ctx, r.Handler, params) + err := v.RunFn(ctx, config, r.Handler, params) if err != nil { logger.ErrorContext(ctx, fmt.Sprintf("%s %s failed", strings.ToUpper(string(v.Name)), r.Name), "error", err.Error()) os.Exit(1) diff --git a/core/interfaces/output.go b/core/interfaces/output.go new file mode 100644 index 0000000..2af3a09 --- /dev/null +++ b/core/interfaces/output.go @@ -0,0 +1,7 @@ +package interfaces + +import "io" + +type Formatter interface { + Format(object any) (io.Reader, error) +} diff --git a/core/output/formatter.go b/core/output/formatter.go new file mode 100644 index 0000000..243caab --- /dev/null +++ b/core/output/formatter.go @@ -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, +} diff --git a/core/output/json.go b/core/output/json.go new file mode 100644 index 0000000..2aa27ec --- /dev/null +++ b/core/output/json.go @@ -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) +} diff --git a/go.mod b/go.mod index c2be15a..3f24465 100644 --- a/go.mod +++ b/go.mod @@ -2,8 +2,9 @@ module git.bissendorf.co/bissendorf/unifood/m/v2 go 1.24.0 +require github.com/spf13/cobra v1.9.1 + require ( github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/spf13/cobra v1.9.1 // indirect github.com/spf13/pflag v1.0.7 // indirect )