func (m ContextPrinter) Print(data *api.Contexts) error {
	for name, c := range data.Contexts {
		if name == data.CurrentContext {
			name = name + " [*]"
		}
		row := []string{name, c.ApiURL, c.IssuerURL}
		m.addShortData(row, c)
	}
	m.shortHeader = []string{"Name", "URL", "DEX"}
	m.render()
	return nil
}
Print a model in yaml format
package output
import (
	"encoding/json"
	"fmt"
	"log"
	"math"
	"net"
	"os"
	"path/filepath"
	"sort"
	"strconv"
	"strings"
	"text/tabwriter"
	"text/template"
	"time"
	"bytes"
	"github.com/dustin/go-humanize"
	"github.com/fatih/color"
	"github.com/metal-stack/metal-go/api/models"
	"github.com/metal-stack/metal-lib/pkg/tag"
	"github.com/metal-stack/metalctl/pkg/api"
	"github.com/olekukonko/tablewriter"
	"github.com/spf13/viper"
	"gopkg.in/yaml.v3"
)
const (
	bark            = "🚧"
	circle          = "↻"
	dot             = "●"
	exclamationMark = "❗"
	lock            = "🔒"
	nbr             = " "
	question        = "❓"
	skull           = "💀"
)
type (
	Printer interface {
		Print(data interface{}) error
	}
	JSONPrinter struct{}
	YAMLPrinter struct{}
	TablePrinter struct {
		table       *tablewriter.Table
		wide        bool
		order       string
		noHeaders   bool
		template    *template.Template
		shortHeader []string
		wideHeader  []string
		shortData   [][]string
		wideData    [][]string
	}
	MetalMachineTablePrinter struct {
		TablePrinter
	}
	MetalMachineLogsPrinter struct {
		TablePrinter
	}
	MetalMachineIssuesTablePrinter struct {
		TablePrinter
	}
	MetalFirewallTablePrinter struct {
		TablePrinter
	}
	MetalMachineAllocationTablePrinter struct {
		TablePrinter
	}
	MetalSizeTablePrinter struct {
		TablePrinter
	}
	MetalSizeMatchingLogTablePrinter struct {
		TablePrinter
	}
	MetalImageTablePrinter struct {
		TablePrinter
	}
	MetalPartitionTablePrinter struct {
		TablePrinter
	}
	MetalPartitionCapacityTablePrinter struct {
		TablePrinter
	}
	MetalSwitchTablePrinter struct {
		TablePrinter
	}
	MetalNetworkTablePrinter struct {
		TablePrinter
	}
	MetalIPTablePrinter struct {
		TablePrinter
	}
	MetalProjectTablePrinter struct {
		TablePrinter
	}
	MachineWithIPMIPrinter struct {
		TablePrinter
	}
	MetalFirmwaresPrinter struct {
		TablePrinter
	}
	FilesystemLayoutPrinter struct {
		TablePrinter
	}
	ContextPrinter struct {
		TablePrinter
	}
)
func New() Printer {
	printer, err := newPrinter(
		viper.GetString("output-format"),
		viper.GetString("order"),
		viper.GetString("template"),
		viper.GetBool("no-headers"),
	)
	if err != nil {
		log.Fatalf("unable to initialize printer:%v", err)
	}
	if viper.IsSet("force-color") {
		enabled := viper.GetBool("force-color")
		if enabled {
			color.NoColor = false
		} else {
			color.NoColor = true
		}
	}
	return printer
}
func (t *TablePrinter) render() {
	if t.template != nil {
		rows := t.shortData
		if t.wide {
			rows = t.wideData
		}
		for _, row := range rows {
			if len(row) < 1 {
				continue
			}
			fmt.Println(row[0])
		}
		return
	}
	if !t.noHeaders {
		if t.wide {
			t.table.SetHeader(t.wideHeader)
		} else {
			t.table.SetHeader(t.shortHeader)
		}
	}
	if t.wide {
		t.table.AppendBulk(t.wideData)
	} else {
		t.table.AppendBulk(t.shortData)
	}
	t.table.Render()
}
func (t *TablePrinter) addShortData(row []string, data interface{}) {
	if t.wide {
		return
	}
	t.shortData = append(t.shortData, t.rowOrTemplate(row, data))
}
func (t *TablePrinter) addWideData(row []string, data interface{}) {
	if !t.wide {
		return
	}
	t.wideData = append(t.wideData, t.rowOrTemplate(row, data))
}
func (t *TablePrinter) rowOrTemplate(row []string, data interface{}) []string {
	tpl := t.template
	if tpl != nil {
		var buf bytes.Buffer
		err := tpl.Execute(&buf, genericObject(data))
		if err != nil {
			fmt.Printf("unable to parse template:%v", err)
			os.Exit(1)
		}
		return []string{buf.String()}
	}
	return row
}
func newPrinter(format, order, tpl string, noHeaders bool) (Printer, error) {
	var printer Printer
	switch format {
	case "yaml":
		printer = &YAMLPrinter{}
	case "json":
		printer = &JSONPrinter{}
	case "table", "wide", "markdown":
		printer = newTablePrinter(format, order, noHeaders, nil)
	case "template":
		tmpl, err := template.New("").Parse(tpl)
		if err != nil {
			return nil, fmt.Errorf("template invalid:%w", err)
		}
		printer = newTablePrinter(format, order, true, tmpl)
	default:
		return nil, fmt.Errorf("unknown format:%s", format)
	}
	return printer, nil
}
func newTablePrinter(format, order string, noHeaders bool, template *template.Template) TablePrinter {
	table := tablewriter.NewWriter(os.Stdout)
	wide := false
	if format == "wide" {
		wide = true
	}
	switch format {
	case "markdown":
		table.SetBorders(tablewriter.Border{Left: true, Top: false, Right: true, Bottom: false})
		table.SetCenterSeparator("|")
	default:
		table.SetHeaderLine(false)
		table.SetAlignment(tablewriter.ALIGN_LEFT)
		table.SetHeaderAlignment(tablewriter.ALIGN_LEFT)
		table.SetBorder(false)
		table.SetCenterSeparator("")
		table.SetColumnSeparator("")
		table.SetRowSeparator("")
		table.SetRowLine(false)
		table.SetTablePadding("\t")  
		table.SetNoWhiteSpace(true)  
	}
	return TablePrinter{
		table:     table,
		wide:      wide,
		order:     order,
		noHeaders: noHeaders,
		template:  template,
	}
}
func (j JSONPrinter) Print(data interface{}) error {
	json, err := json.MarshalIndent(data, "", "    ")
	if err != nil {
		return fmt.Errorf("unable to marshal to json:%w", err)
	}
	fmt.Printf("%s\n", string(json))
	return nil
}
func (y YAMLPrinter) Print(data interface{}) error {
	yml, err := yaml.Marshal(data)
	if err != nil {
		return fmt.Errorf("unable to marshal to yaml:%w", err)
	}
	fmt.Printf("%s", string(yml))
	return nil
}