123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123 |
- package formatter
- import (
- "bytes"
- "fmt"
- "io"
- "strings"
- "text/tabwriter"
- "text/template"
- "github.com/docker/docker/utils/templates"
- )
- // Format keys used to specify certain kinds of output formats
- const (
- TableFormatKey = "table"
- RawFormatKey = "raw"
- PrettyFormatKey = "pretty"
- defaultQuietFormat = "{{.ID}}"
- )
- // Format is the format string rendered using the Context
- type Format string
- // IsTable returns true if the format is a table-type format
- func (f Format) IsTable() bool {
- return strings.HasPrefix(string(f), TableFormatKey)
- }
- // Contains returns true if the format contains the substring
- func (f Format) Contains(sub string) bool {
- return strings.Contains(string(f), sub)
- }
- // Context contains information required by the formatter to print the output as desired.
- type Context struct {
- // Output is the output stream to which the formatted string is written.
- Output io.Writer
- // Format is used to choose raw, table or custom format for the output.
- Format Format
- // Trunc when set to true will truncate the output of certain fields such as Container ID.
- Trunc bool
- // internal element
- finalFormat string
- header string
- buffer *bytes.Buffer
- }
- func (c *Context) preFormat() {
- c.finalFormat = string(c.Format)
- // TODO: handle this in the Format type
- if c.Format.IsTable() {
- c.finalFormat = c.finalFormat[len(TableFormatKey):]
- }
- c.finalFormat = strings.Trim(c.finalFormat, " ")
- r := strings.NewReplacer(`\t`, "\t", `\n`, "\n")
- c.finalFormat = r.Replace(c.finalFormat)
- }
- func (c *Context) parseFormat() (*template.Template, error) {
- tmpl, err := templates.Parse(c.finalFormat)
- if err != nil {
- return tmpl, fmt.Errorf("Template parsing error: %v\n", err)
- }
- return tmpl, err
- }
- func (c *Context) postFormat(tmpl *template.Template, subContext subContext) {
- if c.Format.IsTable() {
- if len(c.header) == 0 {
- // if we still don't have a header, we didn't have any containers so we need to fake it to get the right headers from the template
- tmpl.Execute(bytes.NewBufferString(""), subContext)
- c.header = subContext.FullHeader()
- }
- t := tabwriter.NewWriter(c.Output, 20, 1, 3, ' ', 0)
- t.Write([]byte(c.header))
- t.Write([]byte("\n"))
- c.buffer.WriteTo(t)
- t.Flush()
- } else {
- c.buffer.WriteTo(c.Output)
- }
- }
- func (c *Context) contextFormat(tmpl *template.Template, subContext subContext) error {
- if err := tmpl.Execute(c.buffer, subContext); err != nil {
- return fmt.Errorf("Template parsing error: %v\n", err)
- }
- if c.Format.IsTable() && len(c.header) == 0 {
- c.header = subContext.FullHeader()
- }
- c.buffer.WriteString("\n")
- return nil
- }
- // SubFormat is a function type accepted by Write()
- type SubFormat func(func(subContext) error) error
- // Write the template to the buffer using this Context
- func (c *Context) Write(sub subContext, f SubFormat) error {
- c.buffer = bytes.NewBufferString("")
- c.preFormat()
- tmpl, err := c.parseFormat()
- if err != nil {
- return err
- }
- subFormat := func(subContext subContext) error {
- return c.contextFormat(tmpl, subContext)
- }
- if err := f(subFormat); err != nil {
- return err
- }
- c.postFormat(tmpl, sub)
- return nil
- }
|