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 }