| package inspect |
| |
| import ( |
| "bytes" |
| "encoding/json" |
| "fmt" |
| "io" |
| "text/template" |
| ) |
| |
| // Inspector defines an interface to implement to process elements |
| type Inspector interface { |
| Inspect(typedElement interface{}, rawElement []byte) error |
| Flush() error |
| } |
| |
| // TemplateInspector uses a text template to inspect elements. |
| type TemplateInspector struct { |
| outputStream io.Writer |
| buffer *bytes.Buffer |
| tmpl *template.Template |
| } |
| |
| // NewTemplateInspector creates a new inspector with a template. |
| func NewTemplateInspector(outputStream io.Writer, tmpl *template.Template) Inspector { |
| return &TemplateInspector{ |
| outputStream: outputStream, |
| buffer: new(bytes.Buffer), |
| tmpl: tmpl, |
| } |
| } |
| |
| // Inspect executes the inspect template. |
| // It decodes the raw element into a map if the initial execution fails. |
| // This allows docker cli to parse inspect structs injected with Swarm fields. |
| func (i *TemplateInspector) Inspect(typedElement interface{}, rawElement []byte) error { |
| buffer := new(bytes.Buffer) |
| if err := i.tmpl.Execute(buffer, typedElement); err != nil { |
| if rawElement == nil { |
| return fmt.Errorf("Template parsing error: %v", err) |
| } |
| return i.tryRawInspectFallback(rawElement, err) |
| } |
| i.buffer.Write(buffer.Bytes()) |
| i.buffer.WriteByte('\n') |
| return nil |
| } |
| |
| // Flush write the result of inspecting all elements into the output stream. |
| func (i *TemplateInspector) Flush() error { |
| if i.buffer.Len() == 0 { |
| _, err := io.WriteString(i.outputStream, "\n") |
| return err |
| } |
| _, err := io.Copy(i.outputStream, i.buffer) |
| return err |
| } |
| |
| // IndentedInspector uses a buffer to stop the indented representation of an element. |
| type IndentedInspector struct { |
| outputStream io.Writer |
| elements []interface{} |
| rawElements [][]byte |
| } |
| |
| // NewIndentedInspector generates a new IndentedInspector. |
| func NewIndentedInspector(outputStream io.Writer) Inspector { |
| return &IndentedInspector{ |
| outputStream: outputStream, |
| } |
| } |
| |
| // Inspect writes the raw element with an indented json format. |
| func (i *IndentedInspector) Inspect(typedElement interface{}, rawElement []byte) error { |
| if rawElement != nil { |
| i.rawElements = append(i.rawElements, rawElement) |
| } else { |
| i.elements = append(i.elements, typedElement) |
| } |
| return nil |
| } |
| |
| // Flush write the result of inspecting all elements into the output stream. |
| func (i *IndentedInspector) Flush() error { |
| if len(i.elements) == 0 && len(i.rawElements) == 0 { |
| _, err := io.WriteString(i.outputStream, "[]\n") |
| return err |
| } |
| |
| var buffer io.Reader |
| if len(i.rawElements) > 0 { |
| bytesBuffer := new(bytes.Buffer) |
| bytesBuffer.WriteString("[") |
| for idx, r := range i.rawElements { |
| bytesBuffer.Write(r) |
| if idx < len(i.rawElements)-1 { |
| bytesBuffer.WriteString(",") |
| } |
| } |
| bytesBuffer.WriteString("]") |
| indented := new(bytes.Buffer) |
| if err := json.Indent(indented, bytesBuffer.Bytes(), "", " "); err != nil { |
| return err |
| } |
| buffer = indented |
| } else { |
| b, err := json.MarshalIndent(i.elements, "", " ") |
| if err != nil { |
| return err |
| } |
| buffer = bytes.NewReader(b) |
| } |
| |
| if _, err := io.Copy(i.outputStream, buffer); err != nil { |
| return err |
| } |
| _, err := io.WriteString(i.outputStream, "\n") |
| return err |
| } |