Documentation
¶
Overview ¶
Package format provides utilities for handling output formats.
Index ¶
Examples ¶
Constants ¶
const MaxTableColumns = 6
MaxTableColumns is the maximum number of columns shown in horizontal table output.
Variables ¶
var ErrNotJSONAPI = errors.New("not a JSON:API envelope")
ErrNotJSONAPI is the error returned by NewJSONAPIDisplayer when the raw data does not conform to the expected JSON:API shape.
Functions ¶
This section is empty.
Types ¶
type Displayer ¶
type Displayer interface {
// DefaultFormat returns the Format in which to display the payload if the
// user does not specify a Format override.
DefaultFormat() Format
// Payload is the object to display. Payload may return a single object or a
// slice of objects.
Payload() any
// FieldTemplates returns a slice of Fields. Each Field represents an field
// based on the payload to display to the user. It is common that the Field
// is simply a specific field of the payload struct being outputted.
FieldTemplates() []Field
}
Displayer is the interface for displaying a given payload. By implementing this interface, the payload can be outputted in any of the given Formats.
Example ¶
package main
import (
"fmt"
"github.com/hashicorp/tfctl-cli/internal/pkg/format"
"github.com/hashicorp/tfctl-cli/internal/pkg/iostreams"
)
func main() {
// Create the outputter. This is typically passed to the command.
io := iostreams.Test()
outputter := format.New(io)
// Resource is an example resource that we want to display
type Resource struct {
Name string
ID string
Description string
Bytes int
}
// Build our mock resources. Typically this is the response payload from an API
// request.
payload := []Resource{
{
Name: "hello",
ID: "123",
Description: "world",
Bytes: 100,
},
{
Name: "another",
ID: "456",
Description: "example",
Bytes: 1024 * 1024,
},
}
// If you wish to format the values differently, use a Displayer:
// Define the fields that we want to ExampleDisplayer
var fields = []format.Field{
format.NewField("Name", "{{ .Name }}"),
format.NewField("ID", "{{ .ID }}"),
format.NewField("Description", "{{ .Description }}"),
format.NewField("Bytes", "{{ .Bytes }} bytes"),
}
// Build the displayer
d := format.NewDisplayer(payload, format.Pretty, fields)
// Run the displayer
if err := outputter.Display(d); err != nil {
fmt.Printf("error displaying resources: %s\n", err)
}
// Since the IO is a test io, manually print it
fmt.Println(io.Output.String())
}
Output: Name: hello ID: 123 Description: world Bytes: 100 bytes --- Name: another ID: 456 Description: example Bytes: 1048576 bytes
func DisplayFields ¶
DisplayFields displays the given fields about the given payload. If no fields are provided, then all fields are displayed. The fields can be specified using the direct struct field name. If specifying a nested nested field, use a dot to separate (SubStruct.FieldA).
type Field ¶
type Field struct {
// Name is the displayed name of the field to the user.
Name string
// ValueFormat is a text/template that controls how the value will be
// displayed. If the payload is a struct with the following structure:
//
// type Cluster struct {
// Name string
// Description string
// CloudProvider string
// Region string
// CreatedAt time.Time
// }
//
// Example ValueFormat's would be:
// '{{ . Name }}' -> "Example"
// '{{ .CloudProvider }}/{{ . Region }}' -> "aws/us-east-1"
//
// A more advanced example would be using the text/template to invoke a
// function. This can be done by implementing a function on the Payload type
// that can be invoked. Function definitions will shadow fields in the
// returned Payload.
//
// func (c *Cluster) CreatedAt() string {
// return humanize.Time(d.cluster.CreatedAt)
// }
//
// A ValueFormat of '{{ .CreatedAt }}' will now invoke this function. If the
// cluster was recently created an output may display "4s ago".
ValueFormat string
}
Field represents a field to output.
type Format ¶
type Format int
Format captures the output format to use.
const ( // Unset is the default value for Format and indicates that no format has been set. Unset Format = iota // Pretty outputs the payload in vertical records. Pretty Format = iota // Table outputs the payload in a human readable table format. This is the default unless the // output is not a table or is too wide. Table Format = iota // JSON outputs the values in raw JSON. JSON Format = iota // Markdown outputs the payload in markdown format. Markdown Format = iota // Agent outputs as JSON, except edited for relevance. Agent Format = iota )
func FromString ¶
FromString converts a string representation of a format to a Format.
func (Format) IsJSONOrAgent ¶
IsJSONOrAgent returns true if the format is machine-readable output.
type JSONAPIDisplayer ¶
type JSONAPIDisplayer struct {
// contains filtered or unexported fields
}
JSONAPIDisplayer prepares responses within a JSON:API data envelope to be formatted.
func NewJSONAPIDisplayer ¶
func NewJSONAPIDisplayer(raw []byte, logger hclog.Logger) (*JSONAPIDisplayer, error)
NewJSONAPIDisplayer creates a new displayer based on the contents of a JSON:API response body.
func (JSONAPIDisplayer) DefaultFormat ¶
func (d JSONAPIDisplayer) DefaultFormat() Format
DefaultFormat implements the Displayer interface.
func (JSONAPIDisplayer) FieldTemplates ¶
func (d JSONAPIDisplayer) FieldTemplates() []Field
FieldTemplates implements the Displayer interface.
func (JSONAPIDisplayer) Payload ¶
func (d JSONAPIDisplayer) Payload() any
Payload implements the Displayer interface. It returns the full JSON:API envelope for use by the JSON output format.
func (JSONAPIDisplayer) TemplatedPayload ¶
func (d JSONAPIDisplayer) TemplatedPayload() any
TemplatedPayload implements the TemplatedPayload interface. It returns the flattened attribute rows for use by table and pretty output formats.
type Outputter ¶
type Outputter struct {
// contains filtered or unexported fields
}
Outputter is used to output data to users in a consistent manner. The outputter supports outputting data in a number of Formats.
To output data, the Display function should be called with a Displayer. A Displayer has a default format. The outputter will use this format unless a format has previously been set which overrides the default.
Example ¶
package main
import (
"fmt"
"strings"
"github.com/hashicorp/tfctl-cli/internal/pkg/format"
"github.com/hashicorp/tfctl-cli/internal/pkg/iostreams"
)
func main() {
// Create the outputter. This is typically passed to the command.
io := iostreams.Test()
outputter := format.New(io)
// Resource is an example resource that we want to display
type Metadata struct {
Owner string
CreatedAt string
}
type Resource struct {
Name string
ID string
Description string
Bytes int
Metadata Metadata
}
// Build our mock resources. Typically this is the response payload from an API
// request.
payload := []Resource{
{
Name: "hello",
ID: "123",
Description: "world",
Bytes: 100,
Metadata: Metadata{
Owner: "Bob Builder",
CreatedAt: "2021-01-01",
},
},
{
Name: "another",
ID: "456",
Description: "example",
Bytes: 1024 * 1024,
Metadata: Metadata{
Owner: "Jeff Bezos",
CreatedAt: "2023-02-04",
},
},
}
// For displaying a table of the exact values, Show can be used:
_ = outputter.Show(payload, format.Table)
// For displaying a table with a subset of the fields, list the fields as
// such:
// _ = outputter.Show(payload, format.Table, "Name", "ID", "Metadata.Owner")
// Since the IO is a test io, manually print it.
// We trim the lines to make examples testing pass correctly.
lines := strings.Split(io.Output.String(), "\n")
for i, l := range lines {
lines[i] = strings.TrimSpace(l)
}
fmt.Println(strings.Join(lines, "\n"))
}
Output: Name ID Description Bytes Metadata Owner Metadata Created At hello 123 world 100 Bob Builder 2021-01-01 another 456 example 1048576 Jeff Bezos 2023-02-04
func (*Outputter) Display ¶
Display displays the passed Displayer. The format used is the DefaultFormat unless the outputter has had a Format set which overrides the default.
func (*Outputter) SetFormat ¶
SetFormat sets the format to output with regardless of the DefaultFormat returned by the displayer.
func (*Outputter) SetJQFilter ¶
SetJQFilter sets a jq filter expression to apply to JSON output.
func (*Outputter) Show ¶
Show outputs the given val using the DisplayFields function. If fields are specified, only those fields are shown, otherwise all fields are shown. If specifying a nested nested field, use a dot to separate (SubStruct.FieldA).
This is a simplified version of using .Display, which should be used for all more advanced cases that require formatting fields differently.
This function can accept a slice of values as well and formats them correctly. If the value being considered (directly or within in a slice) is not a struct, it is displayed as is under the field named 'Value'.
type StringPayload ¶
StringPayload allows a Displayer to provide pre-formatted string output for pretty and markdown formats instead of using field templates. The displayer receives the active Format so it can tailor the output (e.g. ANSI codes for pretty, markdown syntax for markdown). JSON output is unaffected and still marshals Payload() as usual.
type TableFormatter ¶
type TableFormatter interface {
HeaderFormatter(input string) string
FirstColumnFormatter(input string) string
}
TableFormatter is an optional interface to implement to customize how a table is outputted.
type TemplatedPayload ¶
type TemplatedPayload interface {
TemplatedPayload() any
}
TemplatedPayload allows a Displayer to return a different payload if the output will be templated using the field templates. This can be useful when raw output (e.g. JSON) requires a specific payload but the templated output (e.g. table/pretty) would benefit from a different payload type.