Initial commit
This commit is contained in:
119
vendor/github.com/hyperhq/hypercli/api/client/inspect/inspector.go
generated
vendored
Normal file
119
vendor/github.com/hyperhq/hypercli/api/client/inspect/inspector.go
generated
vendored
Normal file
@@ -0,0 +1,119 @@
|
||||
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
|
||||
}
|
||||
40
vendor/github.com/hyperhq/hypercli/api/client/inspect/inspector_go14.go
generated
vendored
Normal file
40
vendor/github.com/hyperhq/hypercli/api/client/inspect/inspector_go14.go
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
// +build !go1.5
|
||||
|
||||
package inspect
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// tryeRawInspectFallback executes the inspect template with a raw interface.
|
||||
// This allows docker cli to parse inspect structs injected with Swarm fields.
|
||||
// Unfortunately, go 1.4 doesn't fail executing invalid templates when the input is an interface.
|
||||
// It doesn't allow to modify this behavior either, sending <no value> messages to the output.
|
||||
// We assume that the template is invalid when there is a <no value>, if the template was valid
|
||||
// we'd get <nil> or "" values. In that case we fail with the original error raised executing the
|
||||
// template with the typed input.
|
||||
func (i *TemplateInspector) tryRawInspectFallback(rawElement []byte, originalErr error) error {
|
||||
var raw interface{}
|
||||
buffer := new(bytes.Buffer)
|
||||
rdr := bytes.NewReader(rawElement)
|
||||
dec := json.NewDecoder(rdr)
|
||||
|
||||
if rawErr := dec.Decode(&raw); rawErr != nil {
|
||||
return fmt.Errorf("unable to read inspect data: %v", rawErr)
|
||||
}
|
||||
|
||||
if rawErr := i.tmpl.Execute(buffer, raw); rawErr != nil {
|
||||
return fmt.Errorf("Template parsing error: %v", rawErr)
|
||||
}
|
||||
|
||||
if strings.Contains(buffer.String(), "<no value>") {
|
||||
return fmt.Errorf("Template parsing error: %v", originalErr)
|
||||
}
|
||||
|
||||
i.buffer.Write(buffer.Bytes())
|
||||
i.buffer.WriteByte('\n')
|
||||
return nil
|
||||
}
|
||||
29
vendor/github.com/hyperhq/hypercli/api/client/inspect/inspector_go15.go
generated
vendored
Normal file
29
vendor/github.com/hyperhq/hypercli/api/client/inspect/inspector_go15.go
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
// +build go1.5
|
||||
|
||||
package inspect
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func (i *TemplateInspector) tryRawInspectFallback(rawElement []byte, _ error) error {
|
||||
var raw interface{}
|
||||
buffer := new(bytes.Buffer)
|
||||
rdr := bytes.NewReader(rawElement)
|
||||
dec := json.NewDecoder(rdr)
|
||||
|
||||
if rawErr := dec.Decode(&raw); rawErr != nil {
|
||||
return fmt.Errorf("unable to read inspect data: %v", rawErr)
|
||||
}
|
||||
|
||||
tmplMissingKey := i.tmpl.Option("missingkey=error")
|
||||
if rawErr := tmplMissingKey.Execute(buffer, raw); rawErr != nil {
|
||||
return fmt.Errorf("Template parsing error: %v", rawErr)
|
||||
}
|
||||
|
||||
i.buffer.Write(buffer.Bytes())
|
||||
i.buffer.WriteByte('\n')
|
||||
return nil
|
||||
}
|
||||
220
vendor/github.com/hyperhq/hypercli/api/client/inspect/inspector_test.go
generated
vendored
Normal file
220
vendor/github.com/hyperhq/hypercli/api/client/inspect/inspector_test.go
generated
vendored
Normal file
@@ -0,0 +1,220 @@
|
||||
package inspect
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
"testing"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
type testElement struct {
|
||||
DNS string `json:"Dns"`
|
||||
}
|
||||
|
||||
func TestTemplateInspectorDefault(t *testing.T) {
|
||||
b := new(bytes.Buffer)
|
||||
tmpl, err := template.New("test").Parse("{{.DNS}}")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
i := NewTemplateInspector(b, tmpl)
|
||||
if err := i.Inspect(testElement{"0.0.0.0"}, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := i.Flush(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if b.String() != "0.0.0.0\n" {
|
||||
t.Fatalf("Expected `0.0.0.0\\n`, got `%s`", b.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestTemplateInspectorEmpty(t *testing.T) {
|
||||
b := new(bytes.Buffer)
|
||||
tmpl, err := template.New("test").Parse("{{.DNS}}")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
i := NewTemplateInspector(b, tmpl)
|
||||
|
||||
if err := i.Flush(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if b.String() != "\n" {
|
||||
t.Fatalf("Expected `\\n`, got `%s`", b.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestTemplateInspectorTemplateError(t *testing.T) {
|
||||
b := new(bytes.Buffer)
|
||||
tmpl, err := template.New("test").Parse("{{.Foo}}")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
i := NewTemplateInspector(b, tmpl)
|
||||
|
||||
err = i.Inspect(testElement{"0.0.0.0"}, nil)
|
||||
if err == nil {
|
||||
t.Fatal("Expected error got nil")
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(err.Error(), "Template parsing error") {
|
||||
t.Fatalf("Expected template error, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTemplateInspectorRawFallback(t *testing.T) {
|
||||
b := new(bytes.Buffer)
|
||||
tmpl, err := template.New("test").Parse("{{.Dns}}")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
i := NewTemplateInspector(b, tmpl)
|
||||
if err := i.Inspect(testElement{"0.0.0.0"}, []byte(`{"Dns": "0.0.0.0"}`)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := i.Flush(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if b.String() != "0.0.0.0\n" {
|
||||
t.Fatalf("Expected `0.0.0.0\\n`, got `%s`", b.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestTemplateInspectorRawFallbackError(t *testing.T) {
|
||||
b := new(bytes.Buffer)
|
||||
tmpl, err := template.New("test").Parse("{{.Dns}}")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
i := NewTemplateInspector(b, tmpl)
|
||||
err = i.Inspect(testElement{"0.0.0.0"}, []byte(`{"Foo": "0.0.0.0"}`))
|
||||
if err == nil {
|
||||
t.Fatal("Expected error got nil")
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(err.Error(), "Template parsing error") {
|
||||
t.Fatalf("Expected template error, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTemplateInspectorMultiple(t *testing.T) {
|
||||
b := new(bytes.Buffer)
|
||||
tmpl, err := template.New("test").Parse("{{.DNS}}")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
i := NewTemplateInspector(b, tmpl)
|
||||
|
||||
if err := i.Inspect(testElement{"0.0.0.0"}, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := i.Inspect(testElement{"1.1.1.1"}, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := i.Flush(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if b.String() != "0.0.0.0\n1.1.1.1\n" {
|
||||
t.Fatalf("Expected `0.0.0.0\\n1.1.1.1\\n`, got `%s`", b.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestIndentedInspectorDefault(t *testing.T) {
|
||||
b := new(bytes.Buffer)
|
||||
i := NewIndentedInspector(b)
|
||||
if err := i.Inspect(testElement{"0.0.0.0"}, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := i.Flush(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
expected := `[
|
||||
{
|
||||
"Dns": "0.0.0.0"
|
||||
}
|
||||
]
|
||||
`
|
||||
if b.String() != expected {
|
||||
t.Fatalf("Expected `%s`, got `%s`", expected, b.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestIndentedInspectorMultiple(t *testing.T) {
|
||||
b := new(bytes.Buffer)
|
||||
i := NewIndentedInspector(b)
|
||||
if err := i.Inspect(testElement{"0.0.0.0"}, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := i.Inspect(testElement{"1.1.1.1"}, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := i.Flush(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
expected := `[
|
||||
{
|
||||
"Dns": "0.0.0.0"
|
||||
},
|
||||
{
|
||||
"Dns": "1.1.1.1"
|
||||
}
|
||||
]
|
||||
`
|
||||
if b.String() != expected {
|
||||
t.Fatalf("Expected `%s`, got `%s`", expected, b.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestIndentedInspectorEmpty(t *testing.T) {
|
||||
b := new(bytes.Buffer)
|
||||
i := NewIndentedInspector(b)
|
||||
|
||||
if err := i.Flush(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
expected := "[]\n"
|
||||
if b.String() != expected {
|
||||
t.Fatalf("Expected `%s`, got `%s`", expected, b.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestIndentedInspectorRawElements(t *testing.T) {
|
||||
b := new(bytes.Buffer)
|
||||
i := NewIndentedInspector(b)
|
||||
if err := i.Inspect(testElement{"0.0.0.0"}, []byte(`{"Dns": "0.0.0.0", "Node": "0"}`)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := i.Inspect(testElement{"1.1.1.1"}, []byte(`{"Dns": "1.1.1.1", "Node": "1"}`)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := i.Flush(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
expected := `[
|
||||
{
|
||||
"Dns": "0.0.0.0",
|
||||
"Node": "0"
|
||||
},
|
||||
{
|
||||
"Dns": "1.1.1.1",
|
||||
"Node": "1"
|
||||
}
|
||||
]
|
||||
`
|
||||
if b.String() != expected {
|
||||
t.Fatalf("Expected `%s`, got `%s`", expected, b.String())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user