Skip to content

Wire it to a cobra CLI

The core output package takes an io.Writer and a Format — it knows nothing about cobra. The opt-in output/cobra subpackage is the thin bridge: it reads the --output flag and the command's writer off a *cobra.Command and hands them to a core Renderer.

Importing the core never pulls cobra into your dependency graph; only importing this subpackage does.

import (
    "gitlab.com/phpboyscout/go/output"
    ocobra "gitlab.com/phpboyscout/go/output/cobra"
)

Register the flag once

On your root command, so every subcommand inherits a consistently-defined flag:

ocobra.RegisterOutputFlag(rootCmd)
// adds: --output  (default "text", values: text, json, yaml, csv, tsv, markdown)

Build a Renderer from the command

Inside a RunE, NewRenderer wires the writer (cmd.OutOrStdout()) and the format (the --output value):

RunE: func(cmd *cobra.Command, args []string) error {
    r := ocobra.NewRenderer(cmd)

    result, err := doWork()
    if err != nil {
        _ = r.EmitError("update", err) // JSON envelope in json mode; no-op otherwise
        return err
    }

    if r.IsJSON() {
        return r.Emit(output.Response{
            Status: output.StatusSuccess, Command: "update", Data: result,
        })
    }
    fmt.Fprintf(cmd.OutOrStdout(), "Updated to %s\n", result.Version)
    return nil
},

You can pass extra core options after the command — they apply last, so a theme or an explicit writer override composes cleanly:

r := ocobra.NewRenderer(cmd, output.WithTheme(myTheme))

The whole surface

Function Purpose
RegisterOutputFlag(cmd) define the persistent --output flag
Format(cmd) output.Format read the flag (default text)
IsJSONOutput(cmd) bool is --output json?
NewRenderer(cmd, opts...) *output.Renderer build a Renderer from the command
Emit(cmd, resp) / EmitError(cmd, command, err) envelope sugar

Not using cobra? Skip the subpackage and call output.New(...) directly with your own writer and format — the same Renderer, from a urfave/cli app, an HTTP handler, or a test.