github.com/sijibomii/docker@v0.0.0-20231230191044-5cf6ca554647/api/client/inspect/inspector.go (about)

     1  package inspect
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"fmt"
     7  	"io"
     8  	"text/template"
     9  )
    10  
    11  // Inspector defines an interface to implement to process elements
    12  type Inspector interface {
    13  	Inspect(typedElement interface{}, rawElement []byte) error
    14  	Flush() error
    15  }
    16  
    17  // TemplateInspector uses a text template to inspect elements.
    18  type TemplateInspector struct {
    19  	outputStream io.Writer
    20  	buffer       *bytes.Buffer
    21  	tmpl         *template.Template
    22  }
    23  
    24  // NewTemplateInspector creates a new inspector with a template.
    25  func NewTemplateInspector(outputStream io.Writer, tmpl *template.Template) Inspector {
    26  	return &TemplateInspector{
    27  		outputStream: outputStream,
    28  		buffer:       new(bytes.Buffer),
    29  		tmpl:         tmpl,
    30  	}
    31  }
    32  
    33  // Inspect executes the inspect template.
    34  // It decodes the raw element into a map if the initial execution fails.
    35  // This allows docker cli to parse inspect structs injected with Swarm fields.
    36  func (i *TemplateInspector) Inspect(typedElement interface{}, rawElement []byte) error {
    37  	buffer := new(bytes.Buffer)
    38  	if err := i.tmpl.Execute(buffer, typedElement); err != nil {
    39  		if rawElement == nil {
    40  			return fmt.Errorf("Template parsing error: %v", err)
    41  		}
    42  		return i.tryRawInspectFallback(rawElement, err)
    43  	}
    44  	i.buffer.Write(buffer.Bytes())
    45  	i.buffer.WriteByte('\n')
    46  	return nil
    47  }
    48  
    49  // Flush write the result of inspecting all elements into the output stream.
    50  func (i *TemplateInspector) Flush() error {
    51  	if i.buffer.Len() == 0 {
    52  		_, err := io.WriteString(i.outputStream, "\n")
    53  		return err
    54  	}
    55  	_, err := io.Copy(i.outputStream, i.buffer)
    56  	return err
    57  }
    58  
    59  // IndentedInspector uses a buffer to stop the indented representation of an element.
    60  type IndentedInspector struct {
    61  	outputStream io.Writer
    62  	elements     []interface{}
    63  	rawElements  [][]byte
    64  }
    65  
    66  // NewIndentedInspector generates a new IndentedInspector.
    67  func NewIndentedInspector(outputStream io.Writer) Inspector {
    68  	return &IndentedInspector{
    69  		outputStream: outputStream,
    70  	}
    71  }
    72  
    73  // Inspect writes the raw element with an indented json format.
    74  func (i *IndentedInspector) Inspect(typedElement interface{}, rawElement []byte) error {
    75  	if rawElement != nil {
    76  		i.rawElements = append(i.rawElements, rawElement)
    77  	} else {
    78  		i.elements = append(i.elements, typedElement)
    79  	}
    80  	return nil
    81  }
    82  
    83  // Flush write the result of inspecting all elements into the output stream.
    84  func (i *IndentedInspector) Flush() error {
    85  	if len(i.elements) == 0 && len(i.rawElements) == 0 {
    86  		_, err := io.WriteString(i.outputStream, "[]\n")
    87  		return err
    88  	}
    89  
    90  	var buffer io.Reader
    91  	if len(i.rawElements) > 0 {
    92  		bytesBuffer := new(bytes.Buffer)
    93  		bytesBuffer.WriteString("[")
    94  		for idx, r := range i.rawElements {
    95  			bytesBuffer.Write(r)
    96  			if idx < len(i.rawElements)-1 {
    97  				bytesBuffer.WriteString(",")
    98  			}
    99  		}
   100  		bytesBuffer.WriteString("]")
   101  		indented := new(bytes.Buffer)
   102  		if err := json.Indent(indented, bytesBuffer.Bytes(), "", "    "); err != nil {
   103  			return err
   104  		}
   105  		buffer = indented
   106  	} else {
   107  		b, err := json.MarshalIndent(i.elements, "", "    ")
   108  		if err != nil {
   109  			return err
   110  		}
   111  		buffer = bytes.NewReader(b)
   112  	}
   113  
   114  	if _, err := io.Copy(i.outputStream, buffer); err != nil {
   115  		return err
   116  	}
   117  	_, err := io.WriteString(i.outputStream, "\n")
   118  	return err
   119  }