diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 09dd3c8617a..64e4876dbcc 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -44,6 +44,10 @@ "Comment": "v0.2.0-rc1-120-g23142f6", "Rev": "23142f6773a676cc2cae8dd0cb90b2ea761c853f" }, + { + "ImportPath": "github.com/davecgh/go-spew/spew", + "Rev": "83f84dc933714d51504ceed59f43ead21d096fe7" + }, { "ImportPath": "github.com/elazarl/go-bindata-assetfs", "Rev": "ae4665cf2d188c65764c73fe4af5378acc549510" @@ -58,6 +62,10 @@ "Comment": "0.2.1-267-g15d2c6e", "Rev": "15d2c6e3eb670c545d0af0604d7f9aff3871af04" }, + { + "ImportPath": "github.com/ghodss/yaml", + "Rev": "a4ad25344bbdf7fec4f4675f866b0091fb00e00e" + }, { "ImportPath": "github.com/golang/glog", "Rev": "44145f04b68cf362d9c4df2182967c2275eaefed" @@ -151,8 +159,8 @@ "Rev": "c043f0dc72e4cdd23ae039470ea9d63e6680a1b2" }, { - "ImportPath": "gopkg.in/v1/yaml", - "Rev": "1b9791953ba4027efaeb728c7355e542a203be5e" + "ImportPath": "gopkg.in/v2/yaml", + "Rev": "8fac37523b5c7a1128bf0217f6bd07be1ad266b2" } ] } diff --git a/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/common.go b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/common.go new file mode 100644 index 00000000000..0ce0df12962 --- /dev/null +++ b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/common.go @@ -0,0 +1,371 @@ +/* + * Copyright (c) 2013 Dave Collins + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package spew + +import ( + "fmt" + "io" + "reflect" + "sort" + "strconv" + "unsafe" +) + +const ( + // ptrSize is the size of a pointer on the current arch. + ptrSize = unsafe.Sizeof((*byte)(nil)) +) + +var ( + // offsetPtr, offsetScalar, and offsetFlag are the offsets for the + // internal reflect.Value fields. These values are valid before golang + // commit ecccf07e7f9d which changed the format. The are also valid + // after commit 82f48826c6c7 which changed the format again to mirror + // the original format. Code in the init function updates these offsets + // as necessary. + offsetPtr = uintptr(ptrSize) + offsetScalar = uintptr(0) + offsetFlag = uintptr(ptrSize * 2) + + // flagKindWidth and flagKindShift indicate various bits that the + // reflect package uses internally to track kind information. + // + // flagRO indicates whether or not the value field of a reflect.Value is + // read-only. + // + // flagIndir indicates whether the value field of a reflect.Value is + // the actual data or a pointer to the data. + // + // These values are valid before golang commit 90a7c3c86944 which + // changed their positions. Code in the init function updates these + // flags as necessary. + flagKindWidth = uintptr(5) + flagKindShift = uintptr(flagKindWidth - 1) + flagRO = uintptr(1 << 0) + flagIndir = uintptr(1 << 1) +) + +func init() { + // Older versions of reflect.Value stored small integers directly in the + // ptr field (which is named val in the older versions). Versions + // between commits ecccf07e7f9d and 82f48826c6c7 added a new field named + // scalar for this purpose which unfortunately came before the flag + // field, so the offset of the flag field is different for those + // versions. + // + // This code constructs a new reflect.Value from a known small integer + // and checks if the size of the reflect.Value struct indicates it has + // the scalar field. When it does, the offsets are updated accordingly. + vv := reflect.ValueOf(0xf00) + if unsafe.Sizeof(vv) == (ptrSize * 4) { + offsetScalar = ptrSize * 2 + offsetFlag = ptrSize * 3 + } + + // Commit 90a7c3c86944 changed the flag positions such that the low + // order bits are the kind. This code extracts the kind from the flags + // field and ensures it's the correct type. When it's not, the flag + // order has been changed to the newer format, so the flags are updated + // accordingly. + upf := unsafe.Pointer(uintptr(unsafe.Pointer(&vv)) + offsetFlag) + upfv := *(*uintptr)(upf) + flagKindMask := uintptr((1<>flagKindShift != uintptr(reflect.Int) { + flagKindShift = 0 + flagRO = 1 << 5 + flagIndir = 1 << 6 + } +} + +// unsafeReflectValue converts the passed reflect.Value into a one that bypasses +// the typical safety restrictions preventing access to unaddressable and +// unexported data. It works by digging the raw pointer to the underlying +// value out of the protected value and generating a new unprotected (unsafe) +// reflect.Value to it. +// +// This allows us to check for implementations of the Stringer and error +// interfaces to be used for pretty printing ordinarily unaddressable and +// inaccessible values such as unexported struct fields. +func unsafeReflectValue(v reflect.Value) (rv reflect.Value) { + indirects := 1 + vt := v.Type() + upv := unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetPtr) + rvf := *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetFlag)) + if rvf&flagIndir != 0 { + vt = reflect.PtrTo(v.Type()) + indirects++ + } else if offsetScalar != 0 { + // The value is in the scalar field when it's not one of the + // reference types. + switch vt.Kind() { + case reflect.Uintptr: + case reflect.Chan: + case reflect.Func: + case reflect.Map: + case reflect.Ptr: + case reflect.UnsafePointer: + default: + upv = unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + + offsetScalar) + } + } + + pv := reflect.NewAt(vt, upv) + rv = pv + for i := 0; i < indirects; i++ { + rv = rv.Elem() + } + return rv +} + +// Some constants in the form of bytes to avoid string overhead. This mirrors +// the technique used in the fmt package. +var ( + panicBytes = []byte("(PANIC=") + plusBytes = []byte("+") + iBytes = []byte("i") + trueBytes = []byte("true") + falseBytes = []byte("false") + interfaceBytes = []byte("(interface {})") + commaNewlineBytes = []byte(",\n") + newlineBytes = []byte("\n") + openBraceBytes = []byte("{") + openBraceNewlineBytes = []byte("{\n") + closeBraceBytes = []byte("}") + asteriskBytes = []byte("*") + colonBytes = []byte(":") + colonSpaceBytes = []byte(": ") + openParenBytes = []byte("(") + closeParenBytes = []byte(")") + spaceBytes = []byte(" ") + pointerChainBytes = []byte("->") + nilAngleBytes = []byte("") + maxNewlineBytes = []byte("\n") + maxShortBytes = []byte("") + circularBytes = []byte("") + circularShortBytes = []byte("") + invalidAngleBytes = []byte("") + openBracketBytes = []byte("[") + closeBracketBytes = []byte("]") + percentBytes = []byte("%") + precisionBytes = []byte(".") + openAngleBytes = []byte("<") + closeAngleBytes = []byte(">") + openMapBytes = []byte("map[") + closeMapBytes = []byte("]") + lenEqualsBytes = []byte("len=") + capEqualsBytes = []byte("cap=") +) + +// hexDigits is used to map a decimal value to a hex digit. +var hexDigits = "0123456789abcdef" + +// catchPanic handles any panics that might occur during the handleMethods +// calls. +func catchPanic(w io.Writer, v reflect.Value) { + if err := recover(); err != nil { + w.Write(panicBytes) + fmt.Fprintf(w, "%v", err) + w.Write(closeParenBytes) + } +} + +// handleMethods attempts to call the Error and String methods on the underlying +// type the passed reflect.Value represents and outputes the result to Writer w. +// +// It handles panics in any called methods by catching and displaying the error +// as the formatted value. +func handleMethods(cs *ConfigState, w io.Writer, v reflect.Value) (handled bool) { + // We need an interface to check if the type implements the error or + // Stringer interface. However, the reflect package won't give us an + // interface on certain things like unexported struct fields in order + // to enforce visibility rules. We use unsafe to bypass these restrictions + // since this package does not mutate the values. + if !v.CanInterface() { + v = unsafeReflectValue(v) + } + + // Choose whether or not to do error and Stringer interface lookups against + // the base type or a pointer to the base type depending on settings. + // Technically calling one of these methods with a pointer receiver can + // mutate the value, however, types which choose to satisify an error or + // Stringer interface with a pointer receiver should not be mutating their + // state inside these interface methods. + var viface interface{} + if !cs.DisablePointerMethods { + if !v.CanAddr() { + v = unsafeReflectValue(v) + } + viface = v.Addr().Interface() + } else { + if v.CanAddr() { + v = v.Addr() + } + viface = v.Interface() + } + + // Is it an error or Stringer? + switch iface := viface.(type) { + case error: + defer catchPanic(w, v) + if cs.ContinueOnMethod { + w.Write(openParenBytes) + w.Write([]byte(iface.Error())) + w.Write(closeParenBytes) + w.Write(spaceBytes) + return false + } + + w.Write([]byte(iface.Error())) + return true + + case fmt.Stringer: + defer catchPanic(w, v) + if cs.ContinueOnMethod { + w.Write(openParenBytes) + w.Write([]byte(iface.String())) + w.Write(closeParenBytes) + w.Write(spaceBytes) + return false + } + w.Write([]byte(iface.String())) + return true + } + return false +} + +// printBool outputs a boolean value as true or false to Writer w. +func printBool(w io.Writer, val bool) { + if val { + w.Write(trueBytes) + } else { + w.Write(falseBytes) + } +} + +// printInt outputs a signed integer value to Writer w. +func printInt(w io.Writer, val int64, base int) { + w.Write([]byte(strconv.FormatInt(val, base))) +} + +// printUint outputs an unsigned integer value to Writer w. +func printUint(w io.Writer, val uint64, base int) { + w.Write([]byte(strconv.FormatUint(val, base))) +} + +// printFloat outputs a floating point value using the specified precision, +// which is expected to be 32 or 64bit, to Writer w. +func printFloat(w io.Writer, val float64, precision int) { + w.Write([]byte(strconv.FormatFloat(val, 'g', -1, precision))) +} + +// printComplex outputs a complex value using the specified float precision +// for the real and imaginary parts to Writer w. +func printComplex(w io.Writer, c complex128, floatPrecision int) { + r := real(c) + w.Write(openParenBytes) + w.Write([]byte(strconv.FormatFloat(r, 'g', -1, floatPrecision))) + i := imag(c) + if i >= 0 { + w.Write(plusBytes) + } + w.Write([]byte(strconv.FormatFloat(i, 'g', -1, floatPrecision))) + w.Write(iBytes) + w.Write(closeParenBytes) +} + +// printHexPtr outputs a uintptr formatted as hexidecimal with a leading '0x' +// prefix to Writer w. +func printHexPtr(w io.Writer, p uintptr) { + // Null pointer. + num := uint64(p) + if num == 0 { + w.Write(nilAngleBytes) + return + } + + // Max uint64 is 16 bytes in hex + 2 bytes for '0x' prefix + buf := make([]byte, 18) + + // It's simpler to construct the hex string right to left. + base := uint64(16) + i := len(buf) - 1 + for num >= base { + buf[i] = hexDigits[num%base] + num /= base + i-- + } + buf[i] = hexDigits[num] + + // Add '0x' prefix. + i-- + buf[i] = 'x' + i-- + buf[i] = '0' + + // Strip unused leading bytes. + buf = buf[i:] + w.Write(buf) +} + +// valuesSorter implements sort.Interface to allow a slice of reflect.Value +// elements to be sorted. +type valuesSorter struct { + values []reflect.Value +} + +// Len returns the number of values in the slice. It is part of the +// sort.Interface implementation. +func (s *valuesSorter) Len() int { + return len(s.values) +} + +// Swap swaps the values at the passed indices. It is part of the +// sort.Interface implementation. +func (s *valuesSorter) Swap(i, j int) { + s.values[i], s.values[j] = s.values[j], s.values[i] +} + +// Less returns whether the value at index i should sort before the +// value at index j. It is part of the sort.Interface implementation. +func (s *valuesSorter) Less(i, j int) bool { + switch s.values[i].Kind() { + case reflect.Bool: + return !s.values[i].Bool() && s.values[j].Bool() + case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: + return s.values[i].Int() < s.values[j].Int() + case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: + return s.values[i].Uint() < s.values[j].Uint() + case reflect.Float32, reflect.Float64: + return s.values[i].Float() < s.values[j].Float() + case reflect.String: + return s.values[i].String() < s.values[j].String() + case reflect.Uintptr: + return s.values[i].Uint() < s.values[j].Uint() + } + return s.values[i].String() < s.values[j].String() +} + +// sortValues is a generic sort function for native types: int, uint, bool, +// string and uintptr. Other inputs are sorted according to their +// Value.String() value to ensure display stability. +func sortValues(values []reflect.Value) { + if len(values) == 0 { + return + } + sort.Sort(&valuesSorter{values}) +} diff --git a/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/common_test.go b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/common_test.go new file mode 100644 index 00000000000..3bea81f230d --- /dev/null +++ b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/common_test.go @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2013 Dave Collins + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package spew_test + +import ( + "fmt" + "github.com/davecgh/go-spew/spew" + "reflect" + "testing" +) + +// custom type to test Stinger interface on non-pointer receiver. +type stringer string + +// String implements the Stringer interface for testing invocation of custom +// stringers on types with non-pointer receivers. +func (s stringer) String() string { + return "stringer " + string(s) +} + +// custom type to test Stinger interface on pointer receiver. +type pstringer string + +// String implements the Stringer interface for testing invocation of custom +// stringers on types with only pointer receivers. +func (s *pstringer) String() string { + return "stringer " + string(*s) +} + +// xref1 and xref2 are cross referencing structs for testing circular reference +// detection. +type xref1 struct { + ps2 *xref2 +} +type xref2 struct { + ps1 *xref1 +} + +// indirCir1, indirCir2, and indirCir3 are used to generate an indirect circular +// reference for testing detection. +type indirCir1 struct { + ps2 *indirCir2 +} +type indirCir2 struct { + ps3 *indirCir3 +} +type indirCir3 struct { + ps1 *indirCir1 +} + +// embed is used to test embedded structures. +type embed struct { + a string +} + +// embedwrap is used to test embedded structures. +type embedwrap struct { + *embed + e *embed +} + +// panicer is used to intentionally cause a panic for testing spew properly +// handles them +type panicer int + +func (p panicer) String() string { + panic("test panic") +} + +// customError is used to test custom error interface invocation. +type customError int + +func (e customError) Error() string { + return fmt.Sprintf("error: %d", int(e)) +} + +// stringizeWants converts a slice of wanted test output into a format suitable +// for a test error message. +func stringizeWants(wants []string) string { + s := "" + for i, want := range wants { + if i > 0 { + s += fmt.Sprintf("want%d: %s", i+1, want) + } else { + s += "want: " + want + } + } + return s +} + +// testFailed returns whether or not a test failed by checking if the result +// of the test is in the slice of wanted strings. +func testFailed(result string, wants []string) bool { + for _, want := range wants { + if result == want { + return false + } + } + return true +} + +// TestSortValues ensures the sort functionality for relect.Value based sorting +// works as intended. +func TestSortValues(t *testing.T) { + getInterfaces := func(values []reflect.Value) []interface{} { + interfaces := []interface{}{} + for _, v := range values { + interfaces = append(interfaces, v.Interface()) + } + return interfaces + } + + v := reflect.ValueOf + + a := v("a") + b := v("b") + c := v("c") + embedA := v(embed{"a"}) + embedB := v(embed{"b"}) + embedC := v(embed{"c"}) + tests := []struct { + input []reflect.Value + expected []reflect.Value + }{ + // No values. + { + []reflect.Value{}, + []reflect.Value{}, + }, + // Bools. + { + []reflect.Value{v(false), v(true), v(false)}, + []reflect.Value{v(false), v(false), v(true)}, + }, + // Ints. + { + []reflect.Value{v(2), v(1), v(3)}, + []reflect.Value{v(1), v(2), v(3)}, + }, + // Uints. + { + []reflect.Value{v(uint8(2)), v(uint8(1)), v(uint8(3))}, + []reflect.Value{v(uint8(1)), v(uint8(2)), v(uint8(3))}, + }, + // Floats. + { + []reflect.Value{v(2.0), v(1.0), v(3.0)}, + []reflect.Value{v(1.0), v(2.0), v(3.0)}, + }, + // Strings. + { + []reflect.Value{b, a, c}, + []reflect.Value{a, b, c}, + }, + // Uintptrs. + { + []reflect.Value{v(uintptr(2)), v(uintptr(1)), v(uintptr(3))}, + []reflect.Value{v(uintptr(1)), v(uintptr(2)), v(uintptr(3))}, + }, + // Invalid. + { + []reflect.Value{embedB, embedA, embedC}, + []reflect.Value{embedB, embedA, embedC}, + }, + } + for _, test := range tests { + spew.SortValues(test.input) + // reflect.DeepEqual cannot really make sense of reflect.Value, + // probably because of all the pointer tricks. For instance, + // v(2.0) != v(2.0) on a 32-bits system. Turn them into interface{} + // instead. + input := getInterfaces(test.input) + expected := getInterfaces(test.expected) + if !reflect.DeepEqual(input, expected) { + t.Errorf("Sort mismatch:\n %v != %v", input, expected) + } + } +} diff --git a/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/config.go b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/config.go new file mode 100644 index 00000000000..e516675d288 --- /dev/null +++ b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/config.go @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2013 Dave Collins + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package spew + +import ( + "bytes" + "fmt" + "io" + "os" +) + +// ConfigState houses the configuration options used by spew to format and +// display values. There is a global instance, Config, that is used to control +// all top-level Formatter and Dump functionality. Each ConfigState instance +// provides methods equivalent to the top-level functions. +// +// The zero value for ConfigState provides no indentation. You would typically +// want to set it to a space or a tab. +// +// Alternatively, you can use NewDefaultConfig to get a ConfigState instance +// with default settings. See the documentation of NewDefaultConfig for default +// values. +type ConfigState struct { + // Indent specifies the string to use for each indentation level. The + // global config instance that all top-level functions use set this to a + // single space by default. If you would like more indentation, you might + // set this to a tab with "\t" or perhaps two spaces with " ". + Indent string + + // MaxDepth controls the maximum number of levels to descend into nested + // data structures. The default, 0, means there is no limit. + // + // NOTE: Circular data structures are properly detected, so it is not + // necessary to set this value unless you specifically want to limit deeply + // nested data structures. + MaxDepth int + + // DisableMethods specifies whether or not error and Stringer interfaces are + // invoked for types that implement them. + DisableMethods bool + + // DisablePointerMethods specifies whether or not to check for and invoke + // error and Stringer interfaces on types which only accept a pointer + // receiver when the current type is not a pointer. + // + // NOTE: This might be an unsafe action since calling one of these methods + // with a pointer receiver could technically mutate the value, however, + // in practice, types which choose to satisify an error or Stringer + // interface with a pointer receiver should not be mutating their state + // inside these interface methods. + DisablePointerMethods bool + + // ContinueOnMethod specifies whether or not recursion should continue once + // a custom error or Stringer interface is invoked. The default, false, + // means it will print the results of invoking the custom error or Stringer + // interface and return immediately instead of continuing to recurse into + // the internals of the data type. + // + // NOTE: This flag does not have any effect if method invocation is disabled + // via the DisableMethods or DisablePointerMethods options. + ContinueOnMethod bool + + // SortKeys specifies map keys should be sorted before being printed. Use + // this to have a more deterministic, diffable output. Note that only + // native types (bool, int, uint, floats, uintptr and string) are supported + // with other types sorted according to the reflect.Value.String() output + // which guarantees display stability. + SortKeys bool +} + +// Config is the active configuration of the top-level functions. +// The configuration can be changed by modifying the contents of spew.Config. +var Config = ConfigState{Indent: " "} + +// Errorf is a wrapper for fmt.Errorf that treats each argument as if it were +// passed with a Formatter interface returned by c.NewFormatter. It returns +// the formatted string as a value that satisfies error. See NewFormatter +// for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Errorf(format, c.NewFormatter(a), c.NewFormatter(b)) +func (c *ConfigState) Errorf(format string, a ...interface{}) (err error) { + return fmt.Errorf(format, c.convertArgs(a)...) +} + +// Fprint is a wrapper for fmt.Fprint that treats each argument as if it were +// passed with a Formatter interface returned by c.NewFormatter. It returns +// the number of bytes written and any write error encountered. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Fprint(w, c.NewFormatter(a), c.NewFormatter(b)) +func (c *ConfigState) Fprint(w io.Writer, a ...interface{}) (n int, err error) { + return fmt.Fprint(w, c.convertArgs(a)...) +} + +// Fprintf is a wrapper for fmt.Fprintf that treats each argument as if it were +// passed with a Formatter interface returned by c.NewFormatter. It returns +// the number of bytes written and any write error encountered. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Fprintf(w, format, c.NewFormatter(a), c.NewFormatter(b)) +func (c *ConfigState) Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) { + return fmt.Fprintf(w, format, c.convertArgs(a)...) +} + +// Fprintln is a wrapper for fmt.Fprintln that treats each argument as if it +// passed with a Formatter interface returned by c.NewFormatter. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Fprintln(w, c.NewFormatter(a), c.NewFormatter(b)) +func (c *ConfigState) Fprintln(w io.Writer, a ...interface{}) (n int, err error) { + return fmt.Fprintln(w, c.convertArgs(a)...) +} + +// Print is a wrapper for fmt.Print that treats each argument as if it were +// passed with a Formatter interface returned by c.NewFormatter. It returns +// the number of bytes written and any write error encountered. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Print(c.NewFormatter(a), c.NewFormatter(b)) +func (c *ConfigState) Print(a ...interface{}) (n int, err error) { + return fmt.Print(c.convertArgs(a)...) +} + +// Printf is a wrapper for fmt.Printf that treats each argument as if it were +// passed with a Formatter interface returned by c.NewFormatter. It returns +// the number of bytes written and any write error encountered. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Printf(format, c.NewFormatter(a), c.NewFormatter(b)) +func (c *ConfigState) Printf(format string, a ...interface{}) (n int, err error) { + return fmt.Printf(format, c.convertArgs(a)...) +} + +// Println is a wrapper for fmt.Println that treats each argument as if it were +// passed with a Formatter interface returned by c.NewFormatter. It returns +// the number of bytes written and any write error encountered. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Println(c.NewFormatter(a), c.NewFormatter(b)) +func (c *ConfigState) Println(a ...interface{}) (n int, err error) { + return fmt.Println(c.convertArgs(a)...) +} + +// Sprint is a wrapper for fmt.Sprint that treats each argument as if it were +// passed with a Formatter interface returned by c.NewFormatter. It returns +// the resulting string. See NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Sprint(c.NewFormatter(a), c.NewFormatter(b)) +func (c *ConfigState) Sprint(a ...interface{}) string { + return fmt.Sprint(c.convertArgs(a)...) +} + +// Sprintf is a wrapper for fmt.Sprintf that treats each argument as if it were +// passed with a Formatter interface returned by c.NewFormatter. It returns +// the resulting string. See NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Sprintf(format, c.NewFormatter(a), c.NewFormatter(b)) +func (c *ConfigState) Sprintf(format string, a ...interface{}) string { + return fmt.Sprintf(format, c.convertArgs(a)...) +} + +// Sprintln is a wrapper for fmt.Sprintln that treats each argument as if it +// were passed with a Formatter interface returned by c.NewFormatter. It +// returns the resulting string. See NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Sprintln(c.NewFormatter(a), c.NewFormatter(b)) +func (c *ConfigState) Sprintln(a ...interface{}) string { + return fmt.Sprintln(c.convertArgs(a)...) +} + +/* +NewFormatter returns a custom formatter that satisfies the fmt.Formatter +interface. As a result, it integrates cleanly with standard fmt package +printing functions. The formatter is useful for inline printing of smaller data +types similar to the standard %v format specifier. + +The custom formatter only responds to the %v (most compact), %+v (adds pointer +addresses), %#v (adds types), and %#+v (adds types and pointer addresses) verb +combinations. Any other verbs such as %x and %q will be sent to the the +standard fmt package for formatting. In addition, the custom formatter ignores +the width and precision arguments (however they will still work on the format +specifiers not handled by the custom formatter). + +Typically this function shouldn't be called directly. It is much easier to make +use of the custom formatter by calling one of the convenience functions such as +c.Printf, c.Println, or c.Printf. +*/ +func (c *ConfigState) NewFormatter(v interface{}) fmt.Formatter { + return newFormatter(c, v) +} + +// Fdump formats and displays the passed arguments to io.Writer w. It formats +// exactly the same as Dump. +func (c *ConfigState) Fdump(w io.Writer, a ...interface{}) { + fdump(c, w, a...) +} + +/* +Dump displays the passed parameters to standard out with newlines, customizable +indentation, and additional debug information such as complete types and all +pointer addresses used to indirect to the final value. It provides the +following features over the built-in printing facilities provided by the fmt +package: + + * Pointers are dereferenced and followed + * Circular data structures are detected and handled properly + * Custom Stringer/error interfaces are optionally invoked, including + on unexported types + * Custom types which only implement the Stringer/error interfaces via + a pointer receiver are optionally invoked when passing non-pointer + variables + * Byte arrays and slices are dumped like the hexdump -C command which + includes offsets, byte values in hex, and ASCII output + +The configuration options are controlled by modifying the public members +of c. See ConfigState for options documentation. + +See Fdump if you would prefer dumping to an arbitrary io.Writer or Sdump to +get the formatted result as a string. +*/ +func (c *ConfigState) Dump(a ...interface{}) { + fdump(c, os.Stdout, a...) +} + +// Sdump returns a string with the passed arguments formatted exactly the same +// as Dump. +func (c *ConfigState) Sdump(a ...interface{}) string { + var buf bytes.Buffer + fdump(c, &buf, a...) + return buf.String() +} + +// convertArgs accepts a slice of arguments and returns a slice of the same +// length with each argument converted to a spew Formatter interface using +// the ConfigState associated with s. +func (c *ConfigState) convertArgs(args []interface{}) (formatters []interface{}) { + formatters = make([]interface{}, len(args)) + for index, arg := range args { + formatters[index] = newFormatter(c, arg) + } + return formatters +} + +// NewDefaultConfig returns a ConfigState with the following default settings. +// +// Indent: " " +// MaxDepth: 0 +// DisableMethods: false +// DisablePointerMethods: false +// ContinueOnMethod: false +// SortKeys: false +func NewDefaultConfig() *ConfigState { + return &ConfigState{Indent: " "} +} diff --git a/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/doc.go b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/doc.go new file mode 100644 index 00000000000..a0d73acd9c0 --- /dev/null +++ b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/doc.go @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2013 Dave Collins + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* +Package spew implements a deep pretty printer for Go data structures to aid in +debugging. + +A quick overview of the additional features spew provides over the built-in +printing facilities for Go data types are as follows: + + * Pointers are dereferenced and followed + * Circular data structures are detected and handled properly + * Custom Stringer/error interfaces are optionally invoked, including + on unexported types + * Custom types which only implement the Stringer/error interfaces via + a pointer receiver are optionally invoked when passing non-pointer + variables + * Byte arrays and slices are dumped like the hexdump -C command which + includes offsets, byte values in hex, and ASCII output (only when using + Dump style) + +There are two different approaches spew allows for dumping Go data structures: + + * Dump style which prints with newlines, customizable indentation, + and additional debug information such as types and all pointer addresses + used to indirect to the final value + * A custom Formatter interface that integrates cleanly with the standard fmt + package and replaces %v, %+v, %#v, and %#+v to provide inline printing + similar to the default %v while providing the additional functionality + outlined above and passing unsupported format verbs such as %x and %q + along to fmt + +Quick Start + +This section demonstrates how to quickly get started with spew. See the +sections below for further details on formatting and configuration options. + +To dump a variable with full newlines, indentation, type, and pointer +information use Dump, Fdump, or Sdump: + spew.Dump(myVar1, myVar2, ...) + spew.Fdump(someWriter, myVar1, myVar2, ...) + str := spew.Sdump(myVar1, myVar2, ...) + +Alternatively, if you would prefer to use format strings with a compacted inline +printing style, use the convenience wrappers Printf, Fprintf, etc with +%v (most compact), %+v (adds pointer addresses), %#v (adds types), or +%#+v (adds types and pointer addresses): + spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2) + spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) + spew.Fprintf(someWriter, "myVar1: %v -- myVar2: %+v", myVar1, myVar2) + spew.Fprintf(someWriter, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) + +Configuration Options + +Configuration of spew is handled by fields in the ConfigState type. For +convenience, all of the top-level functions use a global state available +via the spew.Config global. + +It is also possible to create a ConfigState instance that provides methods +equivalent to the top-level functions. This allows concurrent configuration +options. See the ConfigState documentation for more details. + +The following configuration options are available: + * Indent + String to use for each indentation level for Dump functions. + It is a single space by default. A popular alternative is "\t". + + * MaxDepth + Maximum number of levels to descend into nested data structures. + There is no limit by default. + + * DisableMethods + Disables invocation of error and Stringer interface methods. + Method invocation is enabled by default. + + * DisablePointerMethods + Disables invocation of error and Stringer interface methods on types + which only accept pointer receivers from non-pointer variables. + Pointer method invocation is enabled by default. + + * ContinueOnMethod + Enables recursion into types after invoking error and Stringer interface + methods. Recursion after method invocation is disabled by default. + + * SortKeys + Specifies map keys should be sorted before being printed. Use + this to have a more deterministic, diffable output. Note that + only native types (bool, int, uint, floats, uintptr and string) + are supported with other types sorted according to the + reflect.Value.String() output which guarantees display stability. + Natural map order is used by default. + +Dump Usage + +Simply call spew.Dump with a list of variables you want to dump: + + spew.Dump(myVar1, myVar2, ...) + +You may also call spew.Fdump if you would prefer to output to an arbitrary +io.Writer. For example, to dump to standard error: + + spew.Fdump(os.Stderr, myVar1, myVar2, ...) + +A third option is to call spew.Sdump to get the formatted output as a string: + + str := spew.Sdump(myVar1, myVar2, ...) + +Sample Dump Output + +See the Dump example for details on the setup of the types and variables being +shown here. + + (main.Foo) { + unexportedField: (*main.Bar)(0xf84002e210)({ + flag: (main.Flag) flagTwo, + data: (uintptr) + }), + ExportedField: (map[interface {}]interface {}) (len=1) { + (string) (len=3) "one": (bool) true + } + } + +Byte (and uint8) arrays and slices are displayed uniquely like the hexdump -C +command as shown. + ([]uint8) (len=32 cap=32) { + 00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 |............... | + 00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 |!"#$%&'()*+,-./0| + 00000020 31 32 |12| + } + +Custom Formatter + +Spew provides a custom formatter that implements the fmt.Formatter interface +so that it integrates cleanly with standard fmt package printing functions. The +formatter is useful for inline printing of smaller data types similar to the +standard %v format specifier. + +The custom formatter only responds to the %v (most compact), %+v (adds pointer +addresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb +combinations. Any other verbs such as %x and %q will be sent to the the +standard fmt package for formatting. In addition, the custom formatter ignores +the width and precision arguments (however they will still work on the format +specifiers not handled by the custom formatter). + +Custom Formatter Usage + +The simplest way to make use of the spew custom formatter is to call one of the +convenience functions such as spew.Printf, spew.Println, or spew.Printf. The +functions have syntax you are most likely already familiar with: + + spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2) + spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) + spew.Println(myVar, myVar2) + spew.Fprintf(os.Stderr, "myVar1: %v -- myVar2: %+v", myVar1, myVar2) + spew.Fprintf(os.Stderr, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) + +See the Index for the full list convenience functions. + +Sample Formatter Output + +Double pointer to a uint8: + %v: <**>5 + %+v: <**>(0xf8400420d0->0xf8400420c8)5 + %#v: (**uint8)5 + %#+v: (**uint8)(0xf8400420d0->0xf8400420c8)5 + +Pointer to circular struct with a uint8 field and a pointer to itself: + %v: <*>{1 <*>} + %+v: <*>(0xf84003e260){ui8:1 c:<*>(0xf84003e260)} + %#v: (*main.circular){ui8:(uint8)1 c:(*main.circular)} + %#+v: (*main.circular)(0xf84003e260){ui8:(uint8)1 c:(*main.circular)(0xf84003e260)} + +See the Printf example for details on the setup of variables being shown +here. + +Errors + +Since it is possible for custom Stringer/error interfaces to panic, spew +detects them and handles them internally by printing the panic information +inline with the output. Since spew is intended to provide deep pretty printing +capabilities on structures, it intentionally does not return any errors. +*/ +package spew diff --git a/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/dump.go b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/dump.go new file mode 100644 index 00000000000..02d4c9d3996 --- /dev/null +++ b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/dump.go @@ -0,0 +1,500 @@ +/* + * Copyright (c) 2013 Dave Collins + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package spew + +import ( + "bytes" + "encoding/hex" + "fmt" + "io" + "os" + "reflect" + "regexp" + "strconv" + "strings" +) + +var ( + // uint8Type is a reflect.Type representing a uint8. It is used to + // convert cgo types to uint8 slices for hexdumping. + uint8Type = reflect.TypeOf(uint8(0)) + + // cCharRE is a regular expression that matches a cgo char. + // It is used to detect character arrays to hexdump them. + cCharRE = regexp.MustCompile("^.*\\._Ctype_char$") + + // cUnsignedCharRE is a regular expression that matches a cgo unsigned + // char. It is used to detect unsigned character arrays to hexdump + // them. + cUnsignedCharRE = regexp.MustCompile("^.*\\._Ctype_unsignedchar$") + + // cUint8tCharRE is a regular expression that matches a cgo uint8_t. + // It is used to detect uint8_t arrays to hexdump them. + cUint8tCharRE = regexp.MustCompile("^.*\\._Ctype_uint8_t$") +) + +// dumpState contains information about the state of a dump operation. +type dumpState struct { + w io.Writer + depth int + pointers map[uintptr]int + ignoreNextType bool + ignoreNextIndent bool + cs *ConfigState +} + +// indent performs indentation according to the depth level and cs.Indent +// option. +func (d *dumpState) indent() { + if d.ignoreNextIndent { + d.ignoreNextIndent = false + return + } + d.w.Write(bytes.Repeat([]byte(d.cs.Indent), d.depth)) +} + +// unpackValue returns values inside of non-nil interfaces when possible. +// This is useful for data types like structs, arrays, slices, and maps which +// can contain varying types packed inside an interface. +func (d *dumpState) unpackValue(v reflect.Value) reflect.Value { + if v.Kind() == reflect.Interface && !v.IsNil() { + v = v.Elem() + } + return v +} + +// dumpPtr handles formatting of pointers by indirecting them as necessary. +func (d *dumpState) dumpPtr(v reflect.Value) { + // Remove pointers at or below the current depth from map used to detect + // circular refs. + for k, depth := range d.pointers { + if depth >= d.depth { + delete(d.pointers, k) + } + } + + // Keep list of all dereferenced pointers to show later. + pointerChain := make([]uintptr, 0) + + // Figure out how many levels of indirection there are by dereferencing + // pointers and unpacking interfaces down the chain while detecting circular + // references. + nilFound := false + cycleFound := false + indirects := 0 + ve := v + for ve.Kind() == reflect.Ptr { + if ve.IsNil() { + nilFound = true + break + } + indirects++ + addr := ve.Pointer() + pointerChain = append(pointerChain, addr) + if pd, ok := d.pointers[addr]; ok && pd < d.depth { + cycleFound = true + indirects-- + break + } + d.pointers[addr] = d.depth + + ve = ve.Elem() + if ve.Kind() == reflect.Interface { + if ve.IsNil() { + nilFound = true + break + } + ve = ve.Elem() + } + } + + // Display type information. + d.w.Write(openParenBytes) + d.w.Write(bytes.Repeat(asteriskBytes, indirects)) + d.w.Write([]byte(ve.Type().String())) + d.w.Write(closeParenBytes) + + // Display pointer information. + if len(pointerChain) > 0 { + d.w.Write(openParenBytes) + for i, addr := range pointerChain { + if i > 0 { + d.w.Write(pointerChainBytes) + } + printHexPtr(d.w, addr) + } + d.w.Write(closeParenBytes) + } + + // Display dereferenced value. + d.w.Write(openParenBytes) + switch { + case nilFound == true: + d.w.Write(nilAngleBytes) + + case cycleFound == true: + d.w.Write(circularBytes) + + default: + d.ignoreNextType = true + d.dump(ve) + } + d.w.Write(closeParenBytes) +} + +// dumpSlice handles formatting of arrays and slices. Byte (uint8 under +// reflection) arrays and slices are dumped in hexdump -C fashion. +func (d *dumpState) dumpSlice(v reflect.Value) { + // Determine whether this type should be hex dumped or not. Also, + // for types which should be hexdumped, try to use the underlying data + // first, then fall back to trying to convert them to a uint8 slice. + var buf []uint8 + doConvert := false + doHexDump := false + numEntries := v.Len() + if numEntries > 0 { + vt := v.Index(0).Type() + vts := vt.String() + switch { + // C types that need to be converted. + case cCharRE.MatchString(vts): + fallthrough + case cUnsignedCharRE.MatchString(vts): + fallthrough + case cUint8tCharRE.MatchString(vts): + doConvert = true + + // Try to use existing uint8 slices and fall back to converting + // and copying if that fails. + case vt.Kind() == reflect.Uint8: + // We need an addressable interface to convert the type back + // into a byte slice. However, the reflect package won't give + // us an interface on certain things like unexported struct + // fields in order to enforce visibility rules. We use unsafe + // to bypass these restrictions since this package does not + // mutate the values. + vs := v + if !vs.CanInterface() || !vs.CanAddr() { + vs = unsafeReflectValue(vs) + } + vs = vs.Slice(0, numEntries) + + // Use the existing uint8 slice if it can be type + // asserted. + iface := vs.Interface() + if slice, ok := iface.([]uint8); ok { + buf = slice + doHexDump = true + break + } + + // The underlying data needs to be converted if it can't + // be type asserted to a uint8 slice. + doConvert = true + } + + // Copy and convert the underlying type if needed. + if doConvert && vt.ConvertibleTo(uint8Type) { + // Convert and copy each element into a uint8 byte + // slice. + buf = make([]uint8, numEntries) + for i := 0; i < numEntries; i++ { + vv := v.Index(i) + buf[i] = uint8(vv.Convert(uint8Type).Uint()) + } + doHexDump = true + } + } + + // Hexdump the entire slice as needed. + if doHexDump { + indent := strings.Repeat(d.cs.Indent, d.depth) + str := indent + hex.Dump(buf) + str = strings.Replace(str, "\n", "\n"+indent, -1) + str = strings.TrimRight(str, d.cs.Indent) + d.w.Write([]byte(str)) + return + } + + // Recursively call dump for each item. + for i := 0; i < numEntries; i++ { + d.dump(d.unpackValue(v.Index(i))) + if i < (numEntries - 1) { + d.w.Write(commaNewlineBytes) + } else { + d.w.Write(newlineBytes) + } + } +} + +// dump is the main workhorse for dumping a value. It uses the passed reflect +// value to figure out what kind of object we are dealing with and formats it +// appropriately. It is a recursive function, however circular data structures +// are detected and handled properly. +func (d *dumpState) dump(v reflect.Value) { + // Handle invalid reflect values immediately. + kind := v.Kind() + if kind == reflect.Invalid { + d.w.Write(invalidAngleBytes) + return + } + + // Handle pointers specially. + if kind == reflect.Ptr { + d.indent() + d.dumpPtr(v) + return + } + + // Print type information unless already handled elsewhere. + if !d.ignoreNextType { + d.indent() + d.w.Write(openParenBytes) + d.w.Write([]byte(v.Type().String())) + d.w.Write(closeParenBytes) + d.w.Write(spaceBytes) + } + d.ignoreNextType = false + + // Display length and capacity if the built-in len and cap functions + // work with the value's kind and the len/cap itself is non-zero. + valueLen, valueCap := 0, 0 + switch v.Kind() { + case reflect.Array, reflect.Slice, reflect.Chan: + valueLen, valueCap = v.Len(), v.Cap() + case reflect.Map, reflect.String: + valueLen = v.Len() + } + if valueLen != 0 || valueCap != 0 { + d.w.Write(openParenBytes) + if valueLen != 0 { + d.w.Write(lenEqualsBytes) + printInt(d.w, int64(valueLen), 10) + } + if valueCap != 0 { + if valueLen != 0 { + d.w.Write(spaceBytes) + } + d.w.Write(capEqualsBytes) + printInt(d.w, int64(valueCap), 10) + } + d.w.Write(closeParenBytes) + d.w.Write(spaceBytes) + } + + // Call Stringer/error interfaces if they exist and the handle methods flag + // is enabled + if !d.cs.DisableMethods { + if (kind != reflect.Invalid) && (kind != reflect.Interface) { + if handled := handleMethods(d.cs, d.w, v); handled { + return + } + } + } + + switch kind { + case reflect.Invalid: + // Do nothing. We should never get here since invalid has already + // been handled above. + + case reflect.Bool: + printBool(d.w, v.Bool()) + + case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: + printInt(d.w, v.Int(), 10) + + case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: + printUint(d.w, v.Uint(), 10) + + case reflect.Float32: + printFloat(d.w, v.Float(), 32) + + case reflect.Float64: + printFloat(d.w, v.Float(), 64) + + case reflect.Complex64: + printComplex(d.w, v.Complex(), 32) + + case reflect.Complex128: + printComplex(d.w, v.Complex(), 64) + + case reflect.Slice: + if v.IsNil() { + d.w.Write(nilAngleBytes) + break + } + fallthrough + + case reflect.Array: + d.w.Write(openBraceNewlineBytes) + d.depth++ + if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) { + d.indent() + d.w.Write(maxNewlineBytes) + } else { + d.dumpSlice(v) + } + d.depth-- + d.indent() + d.w.Write(closeBraceBytes) + + case reflect.String: + d.w.Write([]byte(strconv.Quote(v.String()))) + + case reflect.Interface: + // The only time we should get here is for nil interfaces due to + // unpackValue calls. + if v.IsNil() { + d.w.Write(nilAngleBytes) + } + + case reflect.Ptr: + // Do nothing. We should never get here since pointers have already + // been handled above. + + case reflect.Map: + d.w.Write(openBraceNewlineBytes) + d.depth++ + if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) { + d.indent() + d.w.Write(maxNewlineBytes) + } else { + numEntries := v.Len() + keys := v.MapKeys() + if d.cs.SortKeys { + sortValues(keys) + } + for i, key := range keys { + d.dump(d.unpackValue(key)) + d.w.Write(colonSpaceBytes) + d.ignoreNextIndent = true + d.dump(d.unpackValue(v.MapIndex(key))) + if i < (numEntries - 1) { + d.w.Write(commaNewlineBytes) + } else { + d.w.Write(newlineBytes) + } + } + } + d.depth-- + d.indent() + d.w.Write(closeBraceBytes) + + case reflect.Struct: + d.w.Write(openBraceNewlineBytes) + d.depth++ + if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) { + d.indent() + d.w.Write(maxNewlineBytes) + } else { + vt := v.Type() + numFields := v.NumField() + for i := 0; i < numFields; i++ { + d.indent() + vtf := vt.Field(i) + d.w.Write([]byte(vtf.Name)) + d.w.Write(colonSpaceBytes) + d.ignoreNextIndent = true + d.dump(d.unpackValue(v.Field(i))) + if i < (numFields - 1) { + d.w.Write(commaNewlineBytes) + } else { + d.w.Write(newlineBytes) + } + } + } + d.depth-- + d.indent() + d.w.Write(closeBraceBytes) + + case reflect.Uintptr: + printHexPtr(d.w, uintptr(v.Uint())) + + case reflect.UnsafePointer, reflect.Chan, reflect.Func: + printHexPtr(d.w, v.Pointer()) + + // There were not any other types at the time this code was written, but + // fall back to letting the default fmt package handle it in case any new + // types are added. + default: + if v.CanInterface() { + fmt.Fprintf(d.w, "%v", v.Interface()) + } else { + fmt.Fprintf(d.w, "%v", v.String()) + } + } +} + +// fdump is a helper function to consolidate the logic from the various public +// methods which take varying writers and config states. +func fdump(cs *ConfigState, w io.Writer, a ...interface{}) { + for _, arg := range a { + if arg == nil { + w.Write(interfaceBytes) + w.Write(spaceBytes) + w.Write(nilAngleBytes) + w.Write(newlineBytes) + continue + } + + d := dumpState{w: w, cs: cs} + d.pointers = make(map[uintptr]int) + d.dump(reflect.ValueOf(arg)) + d.w.Write(newlineBytes) + } +} + +// Fdump formats and displays the passed arguments to io.Writer w. It formats +// exactly the same as Dump. +func Fdump(w io.Writer, a ...interface{}) { + fdump(&Config, w, a...) +} + +// Sdump returns a string with the passed arguments formatted exactly the same +// as Dump. +func Sdump(a ...interface{}) string { + var buf bytes.Buffer + fdump(&Config, &buf, a...) + return buf.String() +} + +/* +Dump displays the passed parameters to standard out with newlines, customizable +indentation, and additional debug information such as complete types and all +pointer addresses used to indirect to the final value. It provides the +following features over the built-in printing facilities provided by the fmt +package: + + * Pointers are dereferenced and followed + * Circular data structures are detected and handled properly + * Custom Stringer/error interfaces are optionally invoked, including + on unexported types + * Custom types which only implement the Stringer/error interfaces via + a pointer receiver are optionally invoked when passing non-pointer + variables + * Byte arrays and slices are dumped like the hexdump -C command which + includes offsets, byte values in hex, and ASCII output + +The configuration options are controlled by an exported package global, +spew.Config. See ConfigState for options documentation. + +See Fdump if you would prefer dumping to an arbitrary io.Writer or Sdump to +get the formatted result as a string. +*/ +func Dump(a ...interface{}) { + fdump(&Config, os.Stdout, a...) +} diff --git a/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/dump_test.go b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/dump_test.go new file mode 100644 index 00000000000..f1a5644f358 --- /dev/null +++ b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/dump_test.go @@ -0,0 +1,978 @@ +/* + * Copyright (c) 2013 Dave Collins + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* +Test Summary: +NOTE: For each test, a nil pointer, a single pointer and double pointer to the +base test element are also tested to ensure proper indirection across all types. + +- Max int8, int16, int32, int64, int +- Max uint8, uint16, uint32, uint64, uint +- Boolean true and false +- Standard complex64 and complex128 +- Array containing standard ints +- Array containing type with custom formatter on pointer receiver only +- Array containing interfaces +- Array containing bytes +- Slice containing standard float32 values +- Slice containing type with custom formatter on pointer receiver only +- Slice containing interfaces +- Slice containing bytes +- Nil slice +- Standard string +- Nil interface +- Sub-interface +- Map with string keys and int vals +- Map with custom formatter type on pointer receiver only keys and vals +- Map with interface keys and values +- Map with nil interface value +- Struct with primitives +- Struct that contains another struct +- Struct that contains custom type with Stringer pointer interface via both + exported and unexported fields +- Struct that contains embedded struct and field to same struct +- Uintptr to 0 (null pointer) +- Uintptr address of real variable +- Unsafe.Pointer to 0 (null pointer) +- Unsafe.Pointer to address of real variable +- Nil channel +- Standard int channel +- Function with no params and no returns +- Function with param and no returns +- Function with multiple params and multiple returns +- Struct that is circular through self referencing +- Structs that are circular through cross referencing +- Structs that are indirectly circular +- Type that panics in its Stringer interface +*/ + +package spew_test + +import ( + "bytes" + "fmt" + "github.com/davecgh/go-spew/spew" + "testing" + "unsafe" +) + +// dumpTest is used to describe a test to be perfomed against the Dump method. +type dumpTest struct { + in interface{} + wants []string +} + +// dumpTests houses all of the tests to be performed against the Dump method. +var dumpTests = make([]dumpTest, 0) + +// addDumpTest is a helper method to append the passed input and desired result +// to dumpTests +func addDumpTest(in interface{}, wants ...string) { + test := dumpTest{in, wants} + dumpTests = append(dumpTests, test) +} + +func addIntDumpTests() { + // Max int8. + v := int8(127) + nv := (*int8)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "int8" + vs := "127" + addDumpTest(v, "("+vt+") "+vs+"\n") + addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") + addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") + addDumpTest(nv, "(*"+vt+")()\n") + + // Max int16. + v2 := int16(32767) + nv2 := (*int16)(nil) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "int16" + v2s := "32767" + addDumpTest(v2, "("+v2t+") "+v2s+"\n") + addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") + addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") + addDumpTest(nv2, "(*"+v2t+")()\n") + + // Max int32. + v3 := int32(2147483647) + nv3 := (*int32)(nil) + pv3 := &v3 + v3Addr := fmt.Sprintf("%p", pv3) + pv3Addr := fmt.Sprintf("%p", &pv3) + v3t := "int32" + v3s := "2147483647" + addDumpTest(v3, "("+v3t+") "+v3s+"\n") + addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n") + addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n") + addDumpTest(nv3, "(*"+v3t+")()\n") + + // Max int64. + v4 := int64(9223372036854775807) + nv4 := (*int64)(nil) + pv4 := &v4 + v4Addr := fmt.Sprintf("%p", pv4) + pv4Addr := fmt.Sprintf("%p", &pv4) + v4t := "int64" + v4s := "9223372036854775807" + addDumpTest(v4, "("+v4t+") "+v4s+"\n") + addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n") + addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n") + addDumpTest(nv4, "(*"+v4t+")()\n") + + // Max int. + v5 := int(2147483647) + nv5 := (*int)(nil) + pv5 := &v5 + v5Addr := fmt.Sprintf("%p", pv5) + pv5Addr := fmt.Sprintf("%p", &pv5) + v5t := "int" + v5s := "2147483647" + addDumpTest(v5, "("+v5t+") "+v5s+"\n") + addDumpTest(pv5, "(*"+v5t+")("+v5Addr+")("+v5s+")\n") + addDumpTest(&pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")("+v5s+")\n") + addDumpTest(nv5, "(*"+v5t+")()\n") +} + +func addUintDumpTests() { + // Max uint8. + v := uint8(255) + nv := (*uint8)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "uint8" + vs := "255" + addDumpTest(v, "("+vt+") "+vs+"\n") + addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") + addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") + addDumpTest(nv, "(*"+vt+")()\n") + + // Max uint16. + v2 := uint16(65535) + nv2 := (*uint16)(nil) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "uint16" + v2s := "65535" + addDumpTest(v2, "("+v2t+") "+v2s+"\n") + addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") + addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") + addDumpTest(nv2, "(*"+v2t+")()\n") + + // Max uint32. + v3 := uint32(4294967295) + nv3 := (*uint32)(nil) + pv3 := &v3 + v3Addr := fmt.Sprintf("%p", pv3) + pv3Addr := fmt.Sprintf("%p", &pv3) + v3t := "uint32" + v3s := "4294967295" + addDumpTest(v3, "("+v3t+") "+v3s+"\n") + addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n") + addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n") + addDumpTest(nv3, "(*"+v3t+")()\n") + + // Max uint64. + v4 := uint64(18446744073709551615) + nv4 := (*uint64)(nil) + pv4 := &v4 + v4Addr := fmt.Sprintf("%p", pv4) + pv4Addr := fmt.Sprintf("%p", &pv4) + v4t := "uint64" + v4s := "18446744073709551615" + addDumpTest(v4, "("+v4t+") "+v4s+"\n") + addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n") + addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n") + addDumpTest(nv4, "(*"+v4t+")()\n") + + // Max uint. + v5 := uint(4294967295) + nv5 := (*uint)(nil) + pv5 := &v5 + v5Addr := fmt.Sprintf("%p", pv5) + pv5Addr := fmt.Sprintf("%p", &pv5) + v5t := "uint" + v5s := "4294967295" + addDumpTest(v5, "("+v5t+") "+v5s+"\n") + addDumpTest(pv5, "(*"+v5t+")("+v5Addr+")("+v5s+")\n") + addDumpTest(&pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")("+v5s+")\n") + addDumpTest(nv5, "(*"+v5t+")()\n") +} + +func addBoolDumpTests() { + // Boolean true. + v := bool(true) + nv := (*bool)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "bool" + vs := "true" + addDumpTest(v, "("+vt+") "+vs+"\n") + addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") + addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") + addDumpTest(nv, "(*"+vt+")()\n") + + // Boolean false. + v2 := bool(false) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "bool" + v2s := "false" + addDumpTest(v2, "("+v2t+") "+v2s+"\n") + addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") + addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") +} + +func addFloatDumpTests() { + // Standard float32. + v := float32(3.1415) + nv := (*float32)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "float32" + vs := "3.1415" + addDumpTest(v, "("+vt+") "+vs+"\n") + addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") + addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") + addDumpTest(nv, "(*"+vt+")()\n") + + // Standard float64. + v2 := float64(3.1415926) + nv2 := (*float64)(nil) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "float64" + v2s := "3.1415926" + addDumpTest(v2, "("+v2t+") "+v2s+"\n") + addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") + addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") + addDumpTest(nv2, "(*"+v2t+")()\n") +} + +func addComplexDumpTests() { + // Standard complex64. + v := complex(float32(6), -2) + nv := (*complex64)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "complex64" + vs := "(6-2i)" + addDumpTest(v, "("+vt+") "+vs+"\n") + addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") + addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") + addDumpTest(nv, "(*"+vt+")()\n") + + // Standard complex128. + v2 := complex(float64(-6), 2) + nv2 := (*complex128)(nil) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "complex128" + v2s := "(-6+2i)" + addDumpTest(v2, "("+v2t+") "+v2s+"\n") + addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") + addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") + addDumpTest(nv2, "(*"+v2t+")()\n") +} + +func addArrayDumpTests() { + // Array containing standard ints. + v := [3]int{1, 2, 3} + vLen := fmt.Sprintf("%d", len(v)) + vCap := fmt.Sprintf("%d", cap(v)) + nv := (*[3]int)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "int" + vs := "(len=" + vLen + " cap=" + vCap + ") {\n (" + vt + ") 1,\n (" + + vt + ") 2,\n (" + vt + ") 3\n}" + addDumpTest(v, "([3]"+vt+") "+vs+"\n") + addDumpTest(pv, "(*[3]"+vt+")("+vAddr+")("+vs+")\n") + addDumpTest(&pv, "(**[3]"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") + addDumpTest(nv, "(*[3]"+vt+")()\n") + + // Array containing type with custom formatter on pointer receiver only. + v2i0 := pstringer("1") + v2i1 := pstringer("2") + v2i2 := pstringer("3") + v2 := [3]pstringer{v2i0, v2i1, v2i2} + v2i0Len := fmt.Sprintf("%d", len(v2i0)) + v2i1Len := fmt.Sprintf("%d", len(v2i1)) + v2i2Len := fmt.Sprintf("%d", len(v2i2)) + v2Len := fmt.Sprintf("%d", len(v2)) + v2Cap := fmt.Sprintf("%d", cap(v2)) + nv2 := (*[3]pstringer)(nil) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "spew_test.pstringer" + v2s := "(len=" + v2Len + " cap=" + v2Cap + ") {\n (" + v2t + ") (len=" + + v2i0Len + ") stringer 1,\n (" + v2t + ") (len=" + v2i1Len + + ") stringer 2,\n (" + v2t + ") (len=" + v2i2Len + ") " + + "stringer 3\n}" + addDumpTest(v2, "([3]"+v2t+") "+v2s+"\n") + addDumpTest(pv2, "(*[3]"+v2t+")("+v2Addr+")("+v2s+")\n") + addDumpTest(&pv2, "(**[3]"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") + addDumpTest(nv2, "(*[3]"+v2t+")()\n") + + // Array containing interfaces. + v3i0 := "one" + v3 := [3]interface{}{v3i0, int(2), uint(3)} + v3i0Len := fmt.Sprintf("%d", len(v3i0)) + v3Len := fmt.Sprintf("%d", len(v3)) + v3Cap := fmt.Sprintf("%d", cap(v3)) + nv3 := (*[3]interface{})(nil) + pv3 := &v3 + v3Addr := fmt.Sprintf("%p", pv3) + pv3Addr := fmt.Sprintf("%p", &pv3) + v3t := "[3]interface {}" + v3t2 := "string" + v3t3 := "int" + v3t4 := "uint" + v3s := "(len=" + v3Len + " cap=" + v3Cap + ") {\n (" + v3t2 + ") " + + "(len=" + v3i0Len + ") \"one\",\n (" + v3t3 + ") 2,\n (" + + v3t4 + ") 3\n}" + addDumpTest(v3, "("+v3t+") "+v3s+"\n") + addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n") + addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n") + addDumpTest(nv3, "(*"+v3t+")()\n") + + // Array containing bytes. + v4 := [34]byte{ + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, + 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, + 0x31, 0x32, + } + v4Len := fmt.Sprintf("%d", len(v4)) + v4Cap := fmt.Sprintf("%d", cap(v4)) + nv4 := (*[34]byte)(nil) + pv4 := &v4 + v4Addr := fmt.Sprintf("%p", pv4) + pv4Addr := fmt.Sprintf("%p", &pv4) + v4t := "[34]uint8" + v4s := "(len=" + v4Len + " cap=" + v4Cap + ") " + + "{\n 00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20" + + " |............... |\n" + + " 00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30" + + " |!\"#$%&'()*+,-./0|\n" + + " 00000020 31 32 " + + " |12|\n}" + addDumpTest(v4, "("+v4t+") "+v4s+"\n") + addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n") + addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n") + addDumpTest(nv4, "(*"+v4t+")()\n") +} + +func addSliceDumpTests() { + // Slice containing standard float32 values. + v := []float32{3.14, 6.28, 12.56} + vLen := fmt.Sprintf("%d", len(v)) + vCap := fmt.Sprintf("%d", cap(v)) + nv := (*[]float32)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "float32" + vs := "(len=" + vLen + " cap=" + vCap + ") {\n (" + vt + ") 3.14,\n (" + + vt + ") 6.28,\n (" + vt + ") 12.56\n}" + addDumpTest(v, "([]"+vt+") "+vs+"\n") + addDumpTest(pv, "(*[]"+vt+")("+vAddr+")("+vs+")\n") + addDumpTest(&pv, "(**[]"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") + addDumpTest(nv, "(*[]"+vt+")()\n") + + // Slice containing type with custom formatter on pointer receiver only. + v2i0 := pstringer("1") + v2i1 := pstringer("2") + v2i2 := pstringer("3") + v2 := []pstringer{v2i0, v2i1, v2i2} + v2i0Len := fmt.Sprintf("%d", len(v2i0)) + v2i1Len := fmt.Sprintf("%d", len(v2i1)) + v2i2Len := fmt.Sprintf("%d", len(v2i2)) + v2Len := fmt.Sprintf("%d", len(v2)) + v2Cap := fmt.Sprintf("%d", cap(v2)) + nv2 := (*[]pstringer)(nil) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "spew_test.pstringer" + v2s := "(len=" + v2Len + " cap=" + v2Cap + ") {\n (" + v2t + ") (len=" + + v2i0Len + ") stringer 1,\n (" + v2t + ") (len=" + v2i1Len + + ") stringer 2,\n (" + v2t + ") (len=" + v2i2Len + ") " + + "stringer 3\n}" + addDumpTest(v2, "([]"+v2t+") "+v2s+"\n") + addDumpTest(pv2, "(*[]"+v2t+")("+v2Addr+")("+v2s+")\n") + addDumpTest(&pv2, "(**[]"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") + addDumpTest(nv2, "(*[]"+v2t+")()\n") + + // Slice containing interfaces. + v3i0 := "one" + v3 := []interface{}{v3i0, int(2), uint(3), nil} + v3i0Len := fmt.Sprintf("%d", len(v3i0)) + v3Len := fmt.Sprintf("%d", len(v3)) + v3Cap := fmt.Sprintf("%d", cap(v3)) + nv3 := (*[]interface{})(nil) + pv3 := &v3 + v3Addr := fmt.Sprintf("%p", pv3) + pv3Addr := fmt.Sprintf("%p", &pv3) + v3t := "[]interface {}" + v3t2 := "string" + v3t3 := "int" + v3t4 := "uint" + v3t5 := "interface {}" + v3s := "(len=" + v3Len + " cap=" + v3Cap + ") {\n (" + v3t2 + ") " + + "(len=" + v3i0Len + ") \"one\",\n (" + v3t3 + ") 2,\n (" + + v3t4 + ") 3,\n (" + v3t5 + ") \n}" + addDumpTest(v3, "("+v3t+") "+v3s+"\n") + addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n") + addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n") + addDumpTest(nv3, "(*"+v3t+")()\n") + + // Slice containing bytes. + v4 := []byte{ + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, + 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, + 0x31, 0x32, + } + v4Len := fmt.Sprintf("%d", len(v4)) + v4Cap := fmt.Sprintf("%d", cap(v4)) + nv4 := (*[]byte)(nil) + pv4 := &v4 + v4Addr := fmt.Sprintf("%p", pv4) + pv4Addr := fmt.Sprintf("%p", &pv4) + v4t := "[]uint8" + v4s := "(len=" + v4Len + " cap=" + v4Cap + ") " + + "{\n 00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20" + + " |............... |\n" + + " 00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30" + + " |!\"#$%&'()*+,-./0|\n" + + " 00000020 31 32 " + + " |12|\n}" + addDumpTest(v4, "("+v4t+") "+v4s+"\n") + addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n") + addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n") + addDumpTest(nv4, "(*"+v4t+")()\n") + + // Nil slice. + v5 := []int(nil) + nv5 := (*[]int)(nil) + pv5 := &v5 + v5Addr := fmt.Sprintf("%p", pv5) + pv5Addr := fmt.Sprintf("%p", &pv5) + v5t := "[]int" + v5s := "" + addDumpTest(v5, "("+v5t+") "+v5s+"\n") + addDumpTest(pv5, "(*"+v5t+")("+v5Addr+")("+v5s+")\n") + addDumpTest(&pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")("+v5s+")\n") + addDumpTest(nv5, "(*"+v5t+")()\n") +} + +func addStringDumpTests() { + // Standard string. + v := "test" + vLen := fmt.Sprintf("%d", len(v)) + nv := (*string)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "string" + vs := "(len=" + vLen + ") \"test\"" + addDumpTest(v, "("+vt+") "+vs+"\n") + addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") + addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") + addDumpTest(nv, "(*"+vt+")()\n") +} + +func addInterfaceDumpTests() { + // Nil interface. + var v interface{} + nv := (*interface{})(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "interface {}" + vs := "" + addDumpTest(v, "("+vt+") "+vs+"\n") + addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") + addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") + addDumpTest(nv, "(*"+vt+")()\n") + + // Sub-interface. + v2 := interface{}(uint16(65535)) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "uint16" + v2s := "65535" + addDumpTest(v2, "("+v2t+") "+v2s+"\n") + addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") + addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") +} + +func addMapDumpTests() { + // Map with string keys and int vals. + k := "one" + kk := "two" + m := map[string]int{k: 1, kk: 2} + klen := fmt.Sprintf("%d", len(k)) // not kLen to shut golint up + kkLen := fmt.Sprintf("%d", len(kk)) + mLen := fmt.Sprintf("%d", len(m)) + nm := (*map[string]int)(nil) + pm := &m + mAddr := fmt.Sprintf("%p", pm) + pmAddr := fmt.Sprintf("%p", &pm) + mt := "map[string]int" + mt1 := "string" + mt2 := "int" + ms := "(len=" + mLen + ") {\n (" + mt1 + ") (len=" + klen + ") " + + "\"one\": (" + mt2 + ") 1,\n (" + mt1 + ") (len=" + kkLen + + ") \"two\": (" + mt2 + ") 2\n}" + ms2 := "(len=" + mLen + ") {\n (" + mt1 + ") (len=" + kkLen + ") " + + "\"two\": (" + mt2 + ") 2,\n (" + mt1 + ") (len=" + klen + + ") \"one\": (" + mt2 + ") 1\n}" + addDumpTest(m, "("+mt+") "+ms+"\n", "("+mt+") "+ms2+"\n") + addDumpTest(pm, "(*"+mt+")("+mAddr+")("+ms+")\n", + "(*"+mt+")("+mAddr+")("+ms2+")\n") + addDumpTest(&pm, "(**"+mt+")("+pmAddr+"->"+mAddr+")("+ms+")\n", + "(**"+mt+")("+pmAddr+"->"+mAddr+")("+ms2+")\n") + addDumpTest(nm, "(*"+mt+")()\n") + + // Map with custom formatter type on pointer receiver only keys and vals. + k2 := pstringer("one") + v2 := pstringer("1") + m2 := map[pstringer]pstringer{k2: v2} + k2Len := fmt.Sprintf("%d", len(k2)) + v2Len := fmt.Sprintf("%d", len(v2)) + m2Len := fmt.Sprintf("%d", len(m2)) + nm2 := (*map[pstringer]pstringer)(nil) + pm2 := &m2 + m2Addr := fmt.Sprintf("%p", pm2) + pm2Addr := fmt.Sprintf("%p", &pm2) + m2t := "map[spew_test.pstringer]spew_test.pstringer" + m2t1 := "spew_test.pstringer" + m2t2 := "spew_test.pstringer" + m2s := "(len=" + m2Len + ") {\n (" + m2t1 + ") (len=" + k2Len + ") " + + "stringer one: (" + m2t2 + ") (len=" + v2Len + ") stringer 1\n}" + addDumpTest(m2, "("+m2t+") "+m2s+"\n") + addDumpTest(pm2, "(*"+m2t+")("+m2Addr+")("+m2s+")\n") + addDumpTest(&pm2, "(**"+m2t+")("+pm2Addr+"->"+m2Addr+")("+m2s+")\n") + addDumpTest(nm2, "(*"+m2t+")()\n") + + // Map with interface keys and values. + k3 := "one" + k3Len := fmt.Sprintf("%d", len(k3)) + m3 := map[interface{}]interface{}{k3: 1} + m3Len := fmt.Sprintf("%d", len(m3)) + nm3 := (*map[interface{}]interface{})(nil) + pm3 := &m3 + m3Addr := fmt.Sprintf("%p", pm3) + pm3Addr := fmt.Sprintf("%p", &pm3) + m3t := "map[interface {}]interface {}" + m3t1 := "string" + m3t2 := "int" + m3s := "(len=" + m3Len + ") {\n (" + m3t1 + ") (len=" + k3Len + ") " + + "\"one\": (" + m3t2 + ") 1\n}" + addDumpTest(m3, "("+m3t+") "+m3s+"\n") + addDumpTest(pm3, "(*"+m3t+")("+m3Addr+")("+m3s+")\n") + addDumpTest(&pm3, "(**"+m3t+")("+pm3Addr+"->"+m3Addr+")("+m3s+")\n") + addDumpTest(nm3, "(*"+m3t+")()\n") + + // Map with nil interface value. + k4 := "nil" + k4Len := fmt.Sprintf("%d", len(k4)) + m4 := map[string]interface{}{k4: nil} + m4Len := fmt.Sprintf("%d", len(m4)) + nm4 := (*map[string]interface{})(nil) + pm4 := &m4 + m4Addr := fmt.Sprintf("%p", pm4) + pm4Addr := fmt.Sprintf("%p", &pm4) + m4t := "map[string]interface {}" + m4t1 := "string" + m4t2 := "interface {}" + m4s := "(len=" + m4Len + ") {\n (" + m4t1 + ") (len=" + k4Len + ")" + + " \"nil\": (" + m4t2 + ") \n}" + addDumpTest(m4, "("+m4t+") "+m4s+"\n") + addDumpTest(pm4, "(*"+m4t+")("+m4Addr+")("+m4s+")\n") + addDumpTest(&pm4, "(**"+m4t+")("+pm4Addr+"->"+m4Addr+")("+m4s+")\n") + addDumpTest(nm4, "(*"+m4t+")()\n") +} + +func addStructDumpTests() { + // Struct with primitives. + type s1 struct { + a int8 + b uint8 + } + v := s1{127, 255} + nv := (*s1)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "spew_test.s1" + vt2 := "int8" + vt3 := "uint8" + vs := "{\n a: (" + vt2 + ") 127,\n b: (" + vt3 + ") 255\n}" + addDumpTest(v, "("+vt+") "+vs+"\n") + addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") + addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") + addDumpTest(nv, "(*"+vt+")()\n") + + // Struct that contains another struct. + type s2 struct { + s1 s1 + b bool + } + v2 := s2{s1{127, 255}, true} + nv2 := (*s2)(nil) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "spew_test.s2" + v2t2 := "spew_test.s1" + v2t3 := "int8" + v2t4 := "uint8" + v2t5 := "bool" + v2s := "{\n s1: (" + v2t2 + ") {\n a: (" + v2t3 + ") 127,\n b: (" + + v2t4 + ") 255\n },\n b: (" + v2t5 + ") true\n}" + addDumpTest(v2, "("+v2t+") "+v2s+"\n") + addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") + addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") + addDumpTest(nv2, "(*"+v2t+")()\n") + + // Struct that contains custom type with Stringer pointer interface via both + // exported and unexported fields. + type s3 struct { + s pstringer + S pstringer + } + v3 := s3{"test", "test2"} + nv3 := (*s3)(nil) + pv3 := &v3 + v3Addr := fmt.Sprintf("%p", pv3) + pv3Addr := fmt.Sprintf("%p", &pv3) + v3t := "spew_test.s3" + v3t2 := "spew_test.pstringer" + v3s := "{\n s: (" + v3t2 + ") (len=4) stringer test,\n S: (" + v3t2 + + ") (len=5) stringer test2\n}" + addDumpTest(v3, "("+v3t+") "+v3s+"\n") + addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n") + addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n") + addDumpTest(nv3, "(*"+v3t+")()\n") + + // Struct that contains embedded struct and field to same struct. + e := embed{"embedstr"} + eLen := fmt.Sprintf("%d", len("embedstr")) + v4 := embedwrap{embed: &e, e: &e} + nv4 := (*embedwrap)(nil) + pv4 := &v4 + eAddr := fmt.Sprintf("%p", &e) + v4Addr := fmt.Sprintf("%p", pv4) + pv4Addr := fmt.Sprintf("%p", &pv4) + v4t := "spew_test.embedwrap" + v4t2 := "spew_test.embed" + v4t3 := "string" + v4s := "{\n embed: (*" + v4t2 + ")(" + eAddr + ")({\n a: (" + v4t3 + + ") (len=" + eLen + ") \"embedstr\"\n }),\n e: (*" + v4t2 + + ")(" + eAddr + ")({\n a: (" + v4t3 + ") (len=" + eLen + ")" + + " \"embedstr\"\n })\n}" + addDumpTest(v4, "("+v4t+") "+v4s+"\n") + addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n") + addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n") + addDumpTest(nv4, "(*"+v4t+")()\n") +} + +func addUintptrDumpTests() { + // Null pointer. + v := uintptr(0) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "uintptr" + vs := "" + addDumpTest(v, "("+vt+") "+vs+"\n") + addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") + addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") + + // Address of real variable. + i := 1 + v2 := uintptr(unsafe.Pointer(&i)) + nv2 := (*uintptr)(nil) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "uintptr" + v2s := fmt.Sprintf("%p", &i) + addDumpTest(v2, "("+v2t+") "+v2s+"\n") + addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") + addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") + addDumpTest(nv2, "(*"+v2t+")()\n") +} + +func addUnsafePointerDumpTests() { + // Null pointer. + v := unsafe.Pointer(uintptr(0)) + nv := (*unsafe.Pointer)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "unsafe.Pointer" + vs := "" + addDumpTest(v, "("+vt+") "+vs+"\n") + addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") + addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") + addDumpTest(nv, "(*"+vt+")()\n") + + // Address of real variable. + i := 1 + v2 := unsafe.Pointer(&i) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "unsafe.Pointer" + v2s := fmt.Sprintf("%p", &i) + addDumpTest(v2, "("+v2t+") "+v2s+"\n") + addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") + addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") + addDumpTest(nv, "(*"+vt+")()\n") +} + +func addChanDumpTests() { + // Nil channel. + var v chan int + pv := &v + nv := (*chan int)(nil) + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "chan int" + vs := "" + addDumpTest(v, "("+vt+") "+vs+"\n") + addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") + addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") + addDumpTest(nv, "(*"+vt+")()\n") + + // Real channel. + v2 := make(chan int) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "chan int" + v2s := fmt.Sprintf("%p", v2) + addDumpTest(v2, "("+v2t+") "+v2s+"\n") + addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") + addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") +} + +func addFuncDumpTests() { + // Function with no params and no returns. + v := addIntDumpTests + nv := (*func())(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "func()" + vs := fmt.Sprintf("%p", v) + addDumpTest(v, "("+vt+") "+vs+"\n") + addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") + addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") + addDumpTest(nv, "(*"+vt+")()\n") + + // Function with param and no returns. + v2 := TestDump + nv2 := (*func(*testing.T))(nil) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "func(*testing.T)" + v2s := fmt.Sprintf("%p", v2) + addDumpTest(v2, "("+v2t+") "+v2s+"\n") + addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") + addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") + addDumpTest(nv2, "(*"+v2t+")()\n") + + // Function with multiple params and multiple returns. + var v3 = func(i int, s string) (b bool, err error) { + return true, nil + } + nv3 := (*func(int, string) (bool, error))(nil) + pv3 := &v3 + v3Addr := fmt.Sprintf("%p", pv3) + pv3Addr := fmt.Sprintf("%p", &pv3) + v3t := "func(int, string) (bool, error)" + v3s := fmt.Sprintf("%p", v3) + addDumpTest(v3, "("+v3t+") "+v3s+"\n") + addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n") + addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n") + addDumpTest(nv3, "(*"+v3t+")()\n") +} + +func addCircularDumpTests() { + // Struct that is circular through self referencing. + type circular struct { + c *circular + } + v := circular{nil} + v.c = &v + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "spew_test.circular" + vs := "{\n c: (*" + vt + ")(" + vAddr + ")({\n c: (*" + vt + ")(" + + vAddr + ")()\n })\n}" + vs2 := "{\n c: (*" + vt + ")(" + vAddr + ")()\n}" + addDumpTest(v, "("+vt+") "+vs+"\n") + addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs2+")\n") + addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs2+")\n") + + // Structs that are circular through cross referencing. + v2 := xref1{nil} + ts2 := xref2{&v2} + v2.ps2 = &ts2 + pv2 := &v2 + ts2Addr := fmt.Sprintf("%p", &ts2) + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "spew_test.xref1" + v2t2 := "spew_test.xref2" + v2s := "{\n ps2: (*" + v2t2 + ")(" + ts2Addr + ")({\n ps1: (*" + v2t + + ")(" + v2Addr + ")({\n ps2: (*" + v2t2 + ")(" + ts2Addr + + ")()\n })\n })\n}" + v2s2 := "{\n ps2: (*" + v2t2 + ")(" + ts2Addr + ")({\n ps1: (*" + v2t + + ")(" + v2Addr + ")()\n })\n}" + addDumpTest(v2, "("+v2t+") "+v2s+"\n") + addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s2+")\n") + addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s2+")\n") + + // Structs that are indirectly circular. + v3 := indirCir1{nil} + tic2 := indirCir2{nil} + tic3 := indirCir3{&v3} + tic2.ps3 = &tic3 + v3.ps2 = &tic2 + pv3 := &v3 + tic2Addr := fmt.Sprintf("%p", &tic2) + tic3Addr := fmt.Sprintf("%p", &tic3) + v3Addr := fmt.Sprintf("%p", pv3) + pv3Addr := fmt.Sprintf("%p", &pv3) + v3t := "spew_test.indirCir1" + v3t2 := "spew_test.indirCir2" + v3t3 := "spew_test.indirCir3" + v3s := "{\n ps2: (*" + v3t2 + ")(" + tic2Addr + ")({\n ps3: (*" + v3t3 + + ")(" + tic3Addr + ")({\n ps1: (*" + v3t + ")(" + v3Addr + + ")({\n ps2: (*" + v3t2 + ")(" + tic2Addr + + ")()\n })\n })\n })\n}" + v3s2 := "{\n ps2: (*" + v3t2 + ")(" + tic2Addr + ")({\n ps3: (*" + v3t3 + + ")(" + tic3Addr + ")({\n ps1: (*" + v3t + ")(" + v3Addr + + ")()\n })\n })\n}" + addDumpTest(v3, "("+v3t+") "+v3s+"\n") + addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s2+")\n") + addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s2+")\n") +} + +func addPanicDumpTests() { + // Type that panics in its Stringer interface. + v := panicer(127) + nv := (*panicer)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "spew_test.panicer" + vs := "(PANIC=test panic)127" + addDumpTest(v, "("+vt+") "+vs+"\n") + addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") + addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") + addDumpTest(nv, "(*"+vt+")()\n") +} + +func addErrorDumpTests() { + // Type that has a custom Error interface. + v := customError(127) + nv := (*customError)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "spew_test.customError" + vs := "error: 127" + addDumpTest(v, "("+vt+") "+vs+"\n") + addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") + addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") + addDumpTest(nv, "(*"+vt+")()\n") +} + +// TestDump executes all of the tests described by dumpTests. +func TestDump(t *testing.T) { + // Setup tests. + addIntDumpTests() + addUintDumpTests() + addBoolDumpTests() + addFloatDumpTests() + addComplexDumpTests() + addArrayDumpTests() + addSliceDumpTests() + addStringDumpTests() + addInterfaceDumpTests() + addMapDumpTests() + addStructDumpTests() + addUintptrDumpTests() + addUnsafePointerDumpTests() + addChanDumpTests() + addFuncDumpTests() + addCircularDumpTests() + addPanicDumpTests() + addErrorDumpTests() + addCgoDumpTests() + + t.Logf("Running %d tests", len(dumpTests)) + for i, test := range dumpTests { + buf := new(bytes.Buffer) + spew.Fdump(buf, test.in) + s := buf.String() + if testFailed(s, test.wants) { + t.Errorf("Dump #%d\n got: %s %s", i, s, stringizeWants(test.wants)) + continue + } + } +} + +func TestDumpSortedKeys(t *testing.T) { + cfg := spew.ConfigState{SortKeys: true} + s := cfg.Sdump(map[int]string{1: "1", 3: "3", 2: "2"}) + expected := `(map[int]string) (len=3) { +(int) 1: (string) (len=1) "1", +(int) 2: (string) (len=1) "2", +(int) 3: (string) (len=1) "3" +} +` + if s != expected { + t.Errorf("Sorted keys mismatch:\n %v %v", s, expected) + } +} diff --git a/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/dumpcgo_test.go b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/dumpcgo_test.go new file mode 100644 index 00000000000..9b8a358ec8d --- /dev/null +++ b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/dumpcgo_test.go @@ -0,0 +1,97 @@ +// Copyright (c) 2013 Dave Collins +// +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +// NOTE: Due to the following build constraints, this file will only be compiled +// when both cgo is supported and "-tags testcgo" is added to the go test +// command line. This means the cgo tests are only added (and hence run) when +// specifially requested. This configuration is used because spew itself +// does not require cgo to run even though it does handle certain cgo types +// specially. Rather than forcing all clients to require cgo and an external +// C compiler just to run the tests, this scheme makes them optional. +// +build cgo,testcgo + +package spew_test + +import ( + "fmt" + "github.com/davecgh/go-spew/spew/testdata" +) + +func addCgoDumpTests() { + // C char pointer. + v := testdata.GetCgoCharPointer() + nv := testdata.GetCgoNullCharPointer() + pv := &v + vcAddr := fmt.Sprintf("%p", v) + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "*testdata._Ctype_char" + vs := "116" + addDumpTest(v, "("+vt+")("+vcAddr+")("+vs+")\n") + addDumpTest(pv, "(*"+vt+")("+vAddr+"->"+vcAddr+")("+vs+")\n") + addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+"->"+vcAddr+")("+vs+")\n") + addDumpTest(nv, "("+vt+")()\n") + + // C char array. + v2, v2l, v2c := testdata.GetCgoCharArray() + v2Len := fmt.Sprintf("%d", v2l) + v2Cap := fmt.Sprintf("%d", v2c) + v2t := "[6]testdata._Ctype_char" + v2s := "(len=" + v2Len + " cap=" + v2Cap + ") " + + "{\n 00000000 74 65 73 74 32 00 " + + " |test2.|\n}" + addDumpTest(v2, "("+v2t+") "+v2s+"\n") + + // C unsigned char array. + v3, v3l, v3c := testdata.GetCgoUnsignedCharArray() + v3Len := fmt.Sprintf("%d", v3l) + v3Cap := fmt.Sprintf("%d", v3c) + v3t := "[6]testdata._Ctype_unsignedchar" + v3s := "(len=" + v3Len + " cap=" + v3Cap + ") " + + "{\n 00000000 74 65 73 74 33 00 " + + " |test3.|\n}" + addDumpTest(v3, "("+v3t+") "+v3s+"\n") + + // C signed char array. + v4, v4l, v4c := testdata.GetCgoSignedCharArray() + v4Len := fmt.Sprintf("%d", v4l) + v4Cap := fmt.Sprintf("%d", v4c) + v4t := "[6]testdata._Ctype_schar" + v4t2 := "testdata._Ctype_schar" + v4s := "(len=" + v4Len + " cap=" + v4Cap + ") " + + "{\n (" + v4t2 + ") 116,\n (" + v4t2 + ") 101,\n (" + v4t2 + + ") 115,\n (" + v4t2 + ") 116,\n (" + v4t2 + ") 52,\n (" + v4t2 + + ") 0\n}" + addDumpTest(v4, "("+v4t+") "+v4s+"\n") + + // C uint8_t array. + v5, v5l, v5c := testdata.GetCgoUint8tArray() + v5Len := fmt.Sprintf("%d", v5l) + v5Cap := fmt.Sprintf("%d", v5c) + v5t := "[6]testdata._Ctype_uint8_t" + v5s := "(len=" + v5Len + " cap=" + v5Cap + ") " + + "{\n 00000000 74 65 73 74 35 00 " + + " |test5.|\n}" + addDumpTest(v5, "("+v5t+") "+v5s+"\n") + + // C typedefed unsigned char array. + v6, v6l, v6c := testdata.GetCgoTypdefedUnsignedCharArray() + v6Len := fmt.Sprintf("%d", v6l) + v6Cap := fmt.Sprintf("%d", v6c) + v6t := "[6]testdata._Ctype_custom_uchar_t" + v6s := "(len=" + v6Len + " cap=" + v6Cap + ") " + + "{\n 00000000 74 65 73 74 36 00 " + + " |test6.|\n}" + addDumpTest(v6, "("+v6t+") "+v6s+"\n") +} diff --git a/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/dumpnocgo_test.go b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/dumpnocgo_test.go new file mode 100644 index 00000000000..52a0971fb3f --- /dev/null +++ b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/dumpnocgo_test.go @@ -0,0 +1,26 @@ +// Copyright (c) 2013 Dave Collins +// +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +// NOTE: Due to the following build constraints, this file will only be compiled +// when either cgo is not supported or "-tags testcgo" is not added to the go +// test command line. This file intentionally does not setup any cgo tests in +// this scenario. +// +build !cgo !testcgo + +package spew_test + +func addCgoDumpTests() { + // Don't add any tests for cgo since this file is only compiled when + // there should not be any cgo tests. +} diff --git a/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/example_test.go b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/example_test.go new file mode 100644 index 00000000000..a7acd141257 --- /dev/null +++ b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/example_test.go @@ -0,0 +1,230 @@ +/* + * Copyright (c) 2013 Dave Collins + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package spew_test + +import ( + "fmt" + "github.com/davecgh/go-spew/spew" +) + +type Flag int + +const ( + flagOne Flag = iota + flagTwo +) + +var flagStrings = map[Flag]string{ + flagOne: "flagOne", + flagTwo: "flagTwo", +} + +func (f Flag) String() string { + if s, ok := flagStrings[f]; ok { + return s + } + return fmt.Sprintf("Unknown flag (%d)", int(f)) +} + +type Bar struct { + flag Flag + data uintptr +} + +type Foo struct { + unexportedField Bar + ExportedField map[interface{}]interface{} +} + +// This example demonstrates how to use Dump to dump variables to stdout. +func ExampleDump() { + // The following package level declarations are assumed for this example: + /* + type Flag int + + const ( + flagOne Flag = iota + flagTwo + ) + + var flagStrings = map[Flag]string{ + flagOne: "flagOne", + flagTwo: "flagTwo", + } + + func (f Flag) String() string { + if s, ok := flagStrings[f]; ok { + return s + } + return fmt.Sprintf("Unknown flag (%d)", int(f)) + } + + type Bar struct { + flag Flag + data uintptr + } + + type Foo struct { + unexportedField Bar + ExportedField map[interface{}]interface{} + } + */ + + // Setup some sample data structures for the example. + bar := Bar{Flag(flagTwo), uintptr(0)} + s1 := Foo{bar, map[interface{}]interface{}{"one": true}} + f := Flag(5) + b := []byte{ + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, + 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, + 0x31, 0x32, + } + + // Dump! + spew.Dump(s1, f, b) + + // Output: + // (spew_test.Foo) { + // unexportedField: (spew_test.Bar) { + // flag: (spew_test.Flag) flagTwo, + // data: (uintptr) + // }, + // ExportedField: (map[interface {}]interface {}) (len=1) { + // (string) (len=3) "one": (bool) true + // } + // } + // (spew_test.Flag) Unknown flag (5) + // ([]uint8) (len=34 cap=34) { + // 00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 |............... | + // 00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 |!"#$%&'()*+,-./0| + // 00000020 31 32 |12| + // } + // +} + +// This example demonstrates how to use Printf to display a variable with a +// format string and inline formatting. +func ExamplePrintf() { + // Create a double pointer to a uint 8. + ui8 := uint8(5) + pui8 := &ui8 + ppui8 := &pui8 + + // Create a circular data type. + type circular struct { + ui8 uint8 + c *circular + } + c := circular{ui8: 1} + c.c = &c + + // Print! + spew.Printf("ppui8: %v\n", ppui8) + spew.Printf("circular: %v\n", c) + + // Output: + // ppui8: <**>5 + // circular: {1 <*>{1 <*>}} +} + +// This example demonstrates how to use a ConfigState. +func ExampleConfigState() { + // Modify the indent level of the ConfigState only. The global + // configuration is not modified. + scs := spew.ConfigState{Indent: "\t"} + + // Output using the ConfigState instance. + v := map[string]int{"one": 1} + scs.Printf("v: %v\n", v) + scs.Dump(v) + + // Output: + // v: map[one:1] + // (map[string]int) (len=1) { + // (string) (len=3) "one": (int) 1 + // } +} + +// This example demonstrates how to use ConfigState.Dump to dump variables to +// stdout +func ExampleConfigState_Dump() { + // See the top-level Dump example for details on the types used in this + // example. + + // Create two ConfigState instances with different indentation. + scs := spew.ConfigState{Indent: "\t"} + scs2 := spew.ConfigState{Indent: " "} + + // Setup some sample data structures for the example. + bar := Bar{Flag(flagTwo), uintptr(0)} + s1 := Foo{bar, map[interface{}]interface{}{"one": true}} + + // Dump using the ConfigState instances. + scs.Dump(s1) + scs2.Dump(s1) + + // Output: + // (spew_test.Foo) { + // unexportedField: (spew_test.Bar) { + // flag: (spew_test.Flag) flagTwo, + // data: (uintptr) + // }, + // ExportedField: (map[interface {}]interface {}) (len=1) { + // (string) (len=3) "one": (bool) true + // } + // } + // (spew_test.Foo) { + // unexportedField: (spew_test.Bar) { + // flag: (spew_test.Flag) flagTwo, + // data: (uintptr) + // }, + // ExportedField: (map[interface {}]interface {}) (len=1) { + // (string) (len=3) "one": (bool) true + // } + // } + // +} + +// This example demonstrates how to use ConfigState.Printf to display a variable +// with a format string and inline formatting. +func ExampleConfigState_Printf() { + // See the top-level Dump example for details on the types used in this + // example. + + // Create two ConfigState instances and modify the method handling of the + // first ConfigState only. + scs := spew.NewDefaultConfig() + scs2 := spew.NewDefaultConfig() + scs.DisableMethods = true + + // Alternatively + // scs := spew.ConfigState{Indent: " ", DisableMethods: true} + // scs2 := spew.ConfigState{Indent: " "} + + // This is of type Flag which implements a Stringer and has raw value 1. + f := flagTwo + + // Dump using the ConfigState instances. + scs.Printf("f: %v\n", f) + scs2.Printf("f: %v\n", f) + + // Output: + // f: 1 + // f: flagTwo +} diff --git a/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/format.go b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/format.go new file mode 100644 index 00000000000..b6b1fb0d0fd --- /dev/null +++ b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/format.go @@ -0,0 +1,413 @@ +/* + * Copyright (c) 2013 Dave Collins + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package spew + +import ( + "bytes" + "fmt" + "reflect" + "strconv" + "strings" +) + +// supportedFlags is a list of all the character flags supported by fmt package. +const supportedFlags = "0-+# " + +// formatState implements the fmt.Formatter interface and contains information +// about the state of a formatting operation. The NewFormatter function can +// be used to get a new Formatter which can be used directly as arguments +// in standard fmt package printing calls. +type formatState struct { + value interface{} + fs fmt.State + depth int + pointers map[uintptr]int + ignoreNextType bool + cs *ConfigState +} + +// buildDefaultFormat recreates the original format string without precision +// and width information to pass in to fmt.Sprintf in the case of an +// unrecognized type. Unless new types are added to the language, this +// function won't ever be called. +func (f *formatState) buildDefaultFormat() (format string) { + buf := bytes.NewBuffer(percentBytes) + + for _, flag := range supportedFlags { + if f.fs.Flag(int(flag)) { + buf.WriteRune(flag) + } + } + + buf.WriteRune('v') + + format = buf.String() + return format +} + +// constructOrigFormat recreates the original format string including precision +// and width information to pass along to the standard fmt package. This allows +// automatic deferral of all format strings this package doesn't support. +func (f *formatState) constructOrigFormat(verb rune) (format string) { + buf := bytes.NewBuffer(percentBytes) + + for _, flag := range supportedFlags { + if f.fs.Flag(int(flag)) { + buf.WriteRune(flag) + } + } + + if width, ok := f.fs.Width(); ok { + buf.WriteString(strconv.Itoa(width)) + } + + if precision, ok := f.fs.Precision(); ok { + buf.Write(precisionBytes) + buf.WriteString(strconv.Itoa(precision)) + } + + buf.WriteRune(verb) + + format = buf.String() + return format +} + +// unpackValue returns values inside of non-nil interfaces when possible and +// ensures that types for values which have been unpacked from an interface +// are displayed when the show types flag is also set. +// This is useful for data types like structs, arrays, slices, and maps which +// can contain varying types packed inside an interface. +func (f *formatState) unpackValue(v reflect.Value) reflect.Value { + if v.Kind() == reflect.Interface { + f.ignoreNextType = false + if !v.IsNil() { + v = v.Elem() + } + } + return v +} + +// formatPtr handles formatting of pointers by indirecting them as necessary. +func (f *formatState) formatPtr(v reflect.Value) { + // Display nil if top level pointer is nil. + showTypes := f.fs.Flag('#') + if v.IsNil() && (!showTypes || f.ignoreNextType) { + f.fs.Write(nilAngleBytes) + return + } + + // Remove pointers at or below the current depth from map used to detect + // circular refs. + for k, depth := range f.pointers { + if depth >= f.depth { + delete(f.pointers, k) + } + } + + // Keep list of all dereferenced pointers to possibly show later. + pointerChain := make([]uintptr, 0) + + // Figure out how many levels of indirection there are by derferencing + // pointers and unpacking interfaces down the chain while detecting circular + // references. + nilFound := false + cycleFound := false + indirects := 0 + ve := v + for ve.Kind() == reflect.Ptr { + if ve.IsNil() { + nilFound = true + break + } + indirects++ + addr := ve.Pointer() + pointerChain = append(pointerChain, addr) + if pd, ok := f.pointers[addr]; ok && pd < f.depth { + cycleFound = true + indirects-- + break + } + f.pointers[addr] = f.depth + + ve = ve.Elem() + if ve.Kind() == reflect.Interface { + if ve.IsNil() { + nilFound = true + break + } + ve = ve.Elem() + } + } + + // Display type or indirection level depending on flags. + if showTypes && !f.ignoreNextType { + f.fs.Write(openParenBytes) + f.fs.Write(bytes.Repeat(asteriskBytes, indirects)) + f.fs.Write([]byte(ve.Type().String())) + f.fs.Write(closeParenBytes) + } else { + if nilFound || cycleFound { + indirects += strings.Count(ve.Type().String(), "*") + } + f.fs.Write(openAngleBytes) + f.fs.Write([]byte(strings.Repeat("*", indirects))) + f.fs.Write(closeAngleBytes) + } + + // Display pointer information depending on flags. + if f.fs.Flag('+') && (len(pointerChain) > 0) { + f.fs.Write(openParenBytes) + for i, addr := range pointerChain { + if i > 0 { + f.fs.Write(pointerChainBytes) + } + printHexPtr(f.fs, addr) + } + f.fs.Write(closeParenBytes) + } + + // Display dereferenced value. + switch { + case nilFound == true: + f.fs.Write(nilAngleBytes) + + case cycleFound == true: + f.fs.Write(circularShortBytes) + + default: + f.ignoreNextType = true + f.format(ve) + } +} + +// format is the main workhorse for providing the Formatter interface. It +// uses the passed reflect value to figure out what kind of object we are +// dealing with and formats it appropriately. It is a recursive function, +// however circular data structures are detected and handled properly. +func (f *formatState) format(v reflect.Value) { + // Handle invalid reflect values immediately. + kind := v.Kind() + if kind == reflect.Invalid { + f.fs.Write(invalidAngleBytes) + return + } + + // Handle pointers specially. + if kind == reflect.Ptr { + f.formatPtr(v) + return + } + + // Print type information unless already handled elsewhere. + if !f.ignoreNextType && f.fs.Flag('#') { + f.fs.Write(openParenBytes) + f.fs.Write([]byte(v.Type().String())) + f.fs.Write(closeParenBytes) + } + f.ignoreNextType = false + + // Call Stringer/error interfaces if they exist and the handle methods + // flag is enabled. + if !f.cs.DisableMethods { + if (kind != reflect.Invalid) && (kind != reflect.Interface) { + if handled := handleMethods(f.cs, f.fs, v); handled { + return + } + } + } + + switch kind { + case reflect.Invalid: + // Do nothing. We should never get here since invalid has already + // been handled above. + + case reflect.Bool: + printBool(f.fs, v.Bool()) + + case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: + printInt(f.fs, v.Int(), 10) + + case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: + printUint(f.fs, v.Uint(), 10) + + case reflect.Float32: + printFloat(f.fs, v.Float(), 32) + + case reflect.Float64: + printFloat(f.fs, v.Float(), 64) + + case reflect.Complex64: + printComplex(f.fs, v.Complex(), 32) + + case reflect.Complex128: + printComplex(f.fs, v.Complex(), 64) + + case reflect.Slice: + if v.IsNil() { + f.fs.Write(nilAngleBytes) + break + } + fallthrough + + case reflect.Array: + f.fs.Write(openBracketBytes) + f.depth++ + if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) { + f.fs.Write(maxShortBytes) + } else { + numEntries := v.Len() + for i := 0; i < numEntries; i++ { + if i > 0 { + f.fs.Write(spaceBytes) + } + f.ignoreNextType = true + f.format(f.unpackValue(v.Index(i))) + } + } + f.depth-- + f.fs.Write(closeBracketBytes) + + case reflect.String: + f.fs.Write([]byte(v.String())) + + case reflect.Interface: + // The only time we should get here is for nil interfaces due to + // unpackValue calls. + if v.IsNil() { + f.fs.Write(nilAngleBytes) + } + + case reflect.Ptr: + // Do nothing. We should never get here since pointers have already + // been handled above. + + case reflect.Map: + f.fs.Write(openMapBytes) + f.depth++ + if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) { + f.fs.Write(maxShortBytes) + } else { + keys := v.MapKeys() + if f.cs.SortKeys { + sortValues(keys) + } + for i, key := range keys { + if i > 0 { + f.fs.Write(spaceBytes) + } + f.ignoreNextType = true + f.format(f.unpackValue(key)) + f.fs.Write(colonBytes) + f.ignoreNextType = true + f.format(f.unpackValue(v.MapIndex(key))) + } + } + f.depth-- + f.fs.Write(closeMapBytes) + + case reflect.Struct: + numFields := v.NumField() + f.fs.Write(openBraceBytes) + f.depth++ + if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) { + f.fs.Write(maxShortBytes) + } else { + vt := v.Type() + for i := 0; i < numFields; i++ { + if i > 0 { + f.fs.Write(spaceBytes) + } + vtf := vt.Field(i) + if f.fs.Flag('+') || f.fs.Flag('#') { + f.fs.Write([]byte(vtf.Name)) + f.fs.Write(colonBytes) + } + f.format(f.unpackValue(v.Field(i))) + } + } + f.depth-- + f.fs.Write(closeBraceBytes) + + case reflect.Uintptr: + printHexPtr(f.fs, uintptr(v.Uint())) + + case reflect.UnsafePointer, reflect.Chan, reflect.Func: + printHexPtr(f.fs, v.Pointer()) + + // There were not any other types at the time this code was written, but + // fall back to letting the default fmt package handle it if any get added. + default: + format := f.buildDefaultFormat() + if v.CanInterface() { + fmt.Fprintf(f.fs, format, v.Interface()) + } else { + fmt.Fprintf(f.fs, format, v.String()) + } + } +} + +// Format satisfies the fmt.Formatter interface. See NewFormatter for usage +// details. +func (f *formatState) Format(fs fmt.State, verb rune) { + f.fs = fs + + // Use standard formatting for verbs that are not v. + if verb != 'v' { + format := f.constructOrigFormat(verb) + fmt.Fprintf(fs, format, f.value) + return + } + + if f.value == nil { + if fs.Flag('#') { + fs.Write(interfaceBytes) + } + fs.Write(nilAngleBytes) + return + } + + f.format(reflect.ValueOf(f.value)) +} + +// newFormatter is a helper function to consolidate the logic from the various +// public methods which take varying config states. +func newFormatter(cs *ConfigState, v interface{}) fmt.Formatter { + fs := &formatState{value: v, cs: cs} + fs.pointers = make(map[uintptr]int) + return fs +} + +/* +NewFormatter returns a custom formatter that satisfies the fmt.Formatter +interface. As a result, it integrates cleanly with standard fmt package +printing functions. The formatter is useful for inline printing of smaller data +types similar to the standard %v format specifier. + +The custom formatter only responds to the %v (most compact), %+v (adds pointer +addresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb +combinations. Any other verbs such as %x and %q will be sent to the the +standard fmt package for formatting. In addition, the custom formatter ignores +the width and precision arguments (however they will still work on the format +specifiers not handled by the custom formatter). + +Typically this function shouldn't be called directly. It is much easier to make +use of the custom formatter by calling one of the convenience functions such as +Printf, Println, or Fprintf. +*/ +func NewFormatter(v interface{}) fmt.Formatter { + return newFormatter(&Config, v) +} diff --git a/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/format_test.go b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/format_test.go new file mode 100644 index 00000000000..80c5ef92952 --- /dev/null +++ b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/format_test.go @@ -0,0 +1,1483 @@ +/* + * Copyright (c) 2013 Dave Collins + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* +Test Summary: +NOTE: For each test, a nil pointer, a single pointer and double pointer to the +base test element are also tested to ensure proper indirection across all types. + +- Max int8, int16, int32, int64, int +- Max uint8, uint16, uint32, uint64, uint +- Boolean true and false +- Standard complex64 and complex128 +- Array containing standard ints +- Array containing type with custom formatter on pointer receiver only +- Array containing interfaces +- Slice containing standard float32 values +- Slice containing type with custom formatter on pointer receiver only +- Slice containing interfaces +- Nil slice +- Standard string +- Nil interface +- Sub-interface +- Map with string keys and int vals +- Map with custom formatter type on pointer receiver only keys and vals +- Map with interface keys and values +- Map with nil interface value +- Struct with primitives +- Struct that contains another struct +- Struct that contains custom type with Stringer pointer interface via both + exported and unexported fields +- Struct that contains embedded struct and field to same struct +- Uintptr to 0 (null pointer) +- Uintptr address of real variable +- Unsafe.Pointer to 0 (null pointer) +- Unsafe.Pointer to address of real variable +- Nil channel +- Standard int channel +- Function with no params and no returns +- Function with param and no returns +- Function with multiple params and multiple returns +- Struct that is circular through self referencing +- Structs that are circular through cross referencing +- Structs that are indirectly circular +- Type that panics in its Stringer interface +- Type that has a custom Error interface +- %x passthrough with uint +- %#x passthrough with uint +- %f passthrough with precision +- %f passthrough with width and precision +- %d passthrough with width +- %q passthrough with string +*/ + +package spew_test + +import ( + "bytes" + "fmt" + "github.com/davecgh/go-spew/spew" + "testing" + "unsafe" +) + +// formatterTest is used to describe a test to be perfomed against NewFormatter. +type formatterTest struct { + format string + in interface{} + wants []string +} + +// formatterTests houses all of the tests to be performed against NewFormatter. +var formatterTests = make([]formatterTest, 0) + +// addFormatterTest is a helper method to append the passed input and desired +// result to formatterTests. +func addFormatterTest(format string, in interface{}, wants ...string) { + test := formatterTest{format, in, wants} + formatterTests = append(formatterTests, test) +} + +func addIntFormatterTests() { + // Max int8. + v := int8(127) + nv := (*int8)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "int8" + vs := "127" + addFormatterTest("%v", v, vs) + addFormatterTest("%v", pv, "<*>"+vs) + addFormatterTest("%v", &pv, "<**>"+vs) + addFormatterTest("%v", nv, "") + addFormatterTest("%+v", v, vs) + addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) + addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%#v", v, "("+vt+")"+vs) + addFormatterTest("%#v", pv, "(*"+vt+")"+vs) + addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) + addFormatterTest("%#v", nv, "(*"+vt+")"+"") + addFormatterTest("%#+v", v, "("+vt+")"+vs) + addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) + addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%#+v", nv, "(*"+vt+")"+"") + + // Max int16. + v2 := int16(32767) + nv2 := (*int16)(nil) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "int16" + v2s := "32767" + addFormatterTest("%v", v2, v2s) + addFormatterTest("%v", pv2, "<*>"+v2s) + addFormatterTest("%v", &pv2, "<**>"+v2s) + addFormatterTest("%v", nv2, "") + addFormatterTest("%+v", v2, v2s) + addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) + addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%+v", nv2, "") + addFormatterTest("%#v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) + addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) + addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") + addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) + addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") + + // Max int32. + v3 := int32(2147483647) + nv3 := (*int32)(nil) + pv3 := &v3 + v3Addr := fmt.Sprintf("%p", pv3) + pv3Addr := fmt.Sprintf("%p", &pv3) + v3t := "int32" + v3s := "2147483647" + addFormatterTest("%v", v3, v3s) + addFormatterTest("%v", pv3, "<*>"+v3s) + addFormatterTest("%v", &pv3, "<**>"+v3s) + addFormatterTest("%v", nv3, "") + addFormatterTest("%+v", v3, v3s) + addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s) + addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s) + addFormatterTest("%+v", nv3, "") + addFormatterTest("%#v", v3, "("+v3t+")"+v3s) + addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s) + addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s) + addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") + addFormatterTest("%#+v", v3, "("+v3t+")"+v3s) + addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s) + addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s) + addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") + + // Max int64. + v4 := int64(9223372036854775807) + nv4 := (*int64)(nil) + pv4 := &v4 + v4Addr := fmt.Sprintf("%p", pv4) + pv4Addr := fmt.Sprintf("%p", &pv4) + v4t := "int64" + v4s := "9223372036854775807" + addFormatterTest("%v", v4, v4s) + addFormatterTest("%v", pv4, "<*>"+v4s) + addFormatterTest("%v", &pv4, "<**>"+v4s) + addFormatterTest("%v", nv4, "") + addFormatterTest("%+v", v4, v4s) + addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s) + addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s) + addFormatterTest("%+v", nv4, "") + addFormatterTest("%#v", v4, "("+v4t+")"+v4s) + addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s) + addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s) + addFormatterTest("%#v", nv4, "(*"+v4t+")"+"") + addFormatterTest("%#+v", v4, "("+v4t+")"+v4s) + addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s) + addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s) + addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"") + + // Max int. + v5 := int(2147483647) + nv5 := (*int)(nil) + pv5 := &v5 + v5Addr := fmt.Sprintf("%p", pv5) + pv5Addr := fmt.Sprintf("%p", &pv5) + v5t := "int" + v5s := "2147483647" + addFormatterTest("%v", v5, v5s) + addFormatterTest("%v", pv5, "<*>"+v5s) + addFormatterTest("%v", &pv5, "<**>"+v5s) + addFormatterTest("%v", nv5, "") + addFormatterTest("%+v", v5, v5s) + addFormatterTest("%+v", pv5, "<*>("+v5Addr+")"+v5s) + addFormatterTest("%+v", &pv5, "<**>("+pv5Addr+"->"+v5Addr+")"+v5s) + addFormatterTest("%+v", nv5, "") + addFormatterTest("%#v", v5, "("+v5t+")"+v5s) + addFormatterTest("%#v", pv5, "(*"+v5t+")"+v5s) + addFormatterTest("%#v", &pv5, "(**"+v5t+")"+v5s) + addFormatterTest("%#v", nv5, "(*"+v5t+")"+"") + addFormatterTest("%#+v", v5, "("+v5t+")"+v5s) + addFormatterTest("%#+v", pv5, "(*"+v5t+")("+v5Addr+")"+v5s) + addFormatterTest("%#+v", &pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")"+v5s) + addFormatterTest("%#+v", nv5, "(*"+v5t+")"+"") +} + +func addUintFormatterTests() { + // Max uint8. + v := uint8(255) + nv := (*uint8)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "uint8" + vs := "255" + addFormatterTest("%v", v, vs) + addFormatterTest("%v", pv, "<*>"+vs) + addFormatterTest("%v", &pv, "<**>"+vs) + addFormatterTest("%v", nv, "") + addFormatterTest("%+v", v, vs) + addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) + addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%#v", v, "("+vt+")"+vs) + addFormatterTest("%#v", pv, "(*"+vt+")"+vs) + addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) + addFormatterTest("%#v", nv, "(*"+vt+")"+"") + addFormatterTest("%#+v", v, "("+vt+")"+vs) + addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) + addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%#+v", nv, "(*"+vt+")"+"") + + // Max uint16. + v2 := uint16(65535) + nv2 := (*uint16)(nil) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "uint16" + v2s := "65535" + addFormatterTest("%v", v2, v2s) + addFormatterTest("%v", pv2, "<*>"+v2s) + addFormatterTest("%v", &pv2, "<**>"+v2s) + addFormatterTest("%v", nv2, "") + addFormatterTest("%+v", v2, v2s) + addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) + addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%+v", nv2, "") + addFormatterTest("%#v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) + addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) + addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") + addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) + addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") + + // Max uint32. + v3 := uint32(4294967295) + nv3 := (*uint32)(nil) + pv3 := &v3 + v3Addr := fmt.Sprintf("%p", pv3) + pv3Addr := fmt.Sprintf("%p", &pv3) + v3t := "uint32" + v3s := "4294967295" + addFormatterTest("%v", v3, v3s) + addFormatterTest("%v", pv3, "<*>"+v3s) + addFormatterTest("%v", &pv3, "<**>"+v3s) + addFormatterTest("%v", nv3, "") + addFormatterTest("%+v", v3, v3s) + addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s) + addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s) + addFormatterTest("%+v", nv3, "") + addFormatterTest("%#v", v3, "("+v3t+")"+v3s) + addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s) + addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s) + addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") + addFormatterTest("%#+v", v3, "("+v3t+")"+v3s) + addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s) + addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s) + addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") + + // Max uint64. + v4 := uint64(18446744073709551615) + nv4 := (*uint64)(nil) + pv4 := &v4 + v4Addr := fmt.Sprintf("%p", pv4) + pv4Addr := fmt.Sprintf("%p", &pv4) + v4t := "uint64" + v4s := "18446744073709551615" + addFormatterTest("%v", v4, v4s) + addFormatterTest("%v", pv4, "<*>"+v4s) + addFormatterTest("%v", &pv4, "<**>"+v4s) + addFormatterTest("%v", nv4, "") + addFormatterTest("%+v", v4, v4s) + addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s) + addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s) + addFormatterTest("%+v", nv4, "") + addFormatterTest("%#v", v4, "("+v4t+")"+v4s) + addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s) + addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s) + addFormatterTest("%#v", nv4, "(*"+v4t+")"+"") + addFormatterTest("%#+v", v4, "("+v4t+")"+v4s) + addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s) + addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s) + addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"") + + // Max uint. + v5 := uint(4294967295) + nv5 := (*uint)(nil) + pv5 := &v5 + v5Addr := fmt.Sprintf("%p", pv5) + pv5Addr := fmt.Sprintf("%p", &pv5) + v5t := "uint" + v5s := "4294967295" + addFormatterTest("%v", v5, v5s) + addFormatterTest("%v", pv5, "<*>"+v5s) + addFormatterTest("%v", &pv5, "<**>"+v5s) + addFormatterTest("%v", nv5, "") + addFormatterTest("%+v", v5, v5s) + addFormatterTest("%+v", pv5, "<*>("+v5Addr+")"+v5s) + addFormatterTest("%+v", &pv5, "<**>("+pv5Addr+"->"+v5Addr+")"+v5s) + addFormatterTest("%+v", nv5, "") + addFormatterTest("%#v", v5, "("+v5t+")"+v5s) + addFormatterTest("%#v", pv5, "(*"+v5t+")"+v5s) + addFormatterTest("%#v", &pv5, "(**"+v5t+")"+v5s) + addFormatterTest("%#v", nv5, "(*"+v5t+")"+"") + addFormatterTest("%#+v", v5, "("+v5t+")"+v5s) + addFormatterTest("%#+v", pv5, "(*"+v5t+")("+v5Addr+")"+v5s) + addFormatterTest("%#+v", &pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")"+v5s) + addFormatterTest("%#v", nv5, "(*"+v5t+")"+"") +} + +func addBoolFormatterTests() { + // Boolean true. + v := bool(true) + nv := (*bool)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "bool" + vs := "true" + addFormatterTest("%v", v, vs) + addFormatterTest("%v", pv, "<*>"+vs) + addFormatterTest("%v", &pv, "<**>"+vs) + addFormatterTest("%v", nv, "") + addFormatterTest("%+v", v, vs) + addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) + addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%#v", v, "("+vt+")"+vs) + addFormatterTest("%#v", pv, "(*"+vt+")"+vs) + addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) + addFormatterTest("%#v", nv, "(*"+vt+")"+"") + addFormatterTest("%#+v", v, "("+vt+")"+vs) + addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) + addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%#+v", nv, "(*"+vt+")"+"") + + // Boolean false. + v2 := bool(false) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "bool" + v2s := "false" + addFormatterTest("%v", v2, v2s) + addFormatterTest("%v", pv2, "<*>"+v2s) + addFormatterTest("%v", &pv2, "<**>"+v2s) + addFormatterTest("%+v", v2, v2s) + addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) + addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%#v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) + addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) + addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) + addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) +} + +func addFloatFormatterTests() { + // Standard float32. + v := float32(3.1415) + nv := (*float32)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "float32" + vs := "3.1415" + addFormatterTest("%v", v, vs) + addFormatterTest("%v", pv, "<*>"+vs) + addFormatterTest("%v", &pv, "<**>"+vs) + addFormatterTest("%v", nv, "") + addFormatterTest("%+v", v, vs) + addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) + addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%#v", v, "("+vt+")"+vs) + addFormatterTest("%#v", pv, "(*"+vt+")"+vs) + addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) + addFormatterTest("%#v", nv, "(*"+vt+")"+"") + addFormatterTest("%#+v", v, "("+vt+")"+vs) + addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) + addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%#+v", nv, "(*"+vt+")"+"") + + // Standard float64. + v2 := float64(3.1415926) + nv2 := (*float64)(nil) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "float64" + v2s := "3.1415926" + addFormatterTest("%v", v2, v2s) + addFormatterTest("%v", pv2, "<*>"+v2s) + addFormatterTest("%v", &pv2, "<**>"+v2s) + addFormatterTest("%+v", nv2, "") + addFormatterTest("%+v", v2, v2s) + addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) + addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%+v", nv2, "") + addFormatterTest("%#v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) + addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) + addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") + addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) + addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") +} + +func addComplexFormatterTests() { + // Standard complex64. + v := complex(float32(6), -2) + nv := (*complex64)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "complex64" + vs := "(6-2i)" + addFormatterTest("%v", v, vs) + addFormatterTest("%v", pv, "<*>"+vs) + addFormatterTest("%v", &pv, "<**>"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%+v", v, vs) + addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) + addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%#v", v, "("+vt+")"+vs) + addFormatterTest("%#v", pv, "(*"+vt+")"+vs) + addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) + addFormatterTest("%#v", nv, "(*"+vt+")"+"") + addFormatterTest("%#+v", v, "("+vt+")"+vs) + addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) + addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%#+v", nv, "(*"+vt+")"+"") + + // Standard complex128. + v2 := complex(float64(-6), 2) + nv2 := (*complex128)(nil) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "complex128" + v2s := "(-6+2i)" + addFormatterTest("%v", v2, v2s) + addFormatterTest("%v", pv2, "<*>"+v2s) + addFormatterTest("%v", &pv2, "<**>"+v2s) + addFormatterTest("%+v", nv2, "") + addFormatterTest("%+v", v2, v2s) + addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) + addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%+v", nv2, "") + addFormatterTest("%#v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) + addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) + addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") + addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) + addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") +} + +func addArrayFormatterTests() { + // Array containing standard ints. + v := [3]int{1, 2, 3} + nv := (*[3]int)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "[3]int" + vs := "[1 2 3]" + addFormatterTest("%v", v, vs) + addFormatterTest("%v", pv, "<*>"+vs) + addFormatterTest("%v", &pv, "<**>"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%+v", v, vs) + addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) + addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%#v", v, "("+vt+")"+vs) + addFormatterTest("%#v", pv, "(*"+vt+")"+vs) + addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) + addFormatterTest("%#v", nv, "(*"+vt+")"+"") + addFormatterTest("%#+v", v, "("+vt+")"+vs) + addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) + addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%#+v", nv, "(*"+vt+")"+"") + + // Array containing type with custom formatter on pointer receiver only. + v2 := [3]pstringer{"1", "2", "3"} + nv2 := (*[3]pstringer)(nil) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "[3]spew_test.pstringer" + v2s := "[stringer 1 stringer 2 stringer 3]" + addFormatterTest("%v", v2, v2s) + addFormatterTest("%v", pv2, "<*>"+v2s) + addFormatterTest("%v", &pv2, "<**>"+v2s) + addFormatterTest("%+v", nv2, "") + addFormatterTest("%+v", v2, v2s) + addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) + addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%+v", nv2, "") + addFormatterTest("%#v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) + addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) + addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") + addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) + addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") + + // Array containing interfaces. + v3 := [3]interface{}{"one", int(2), uint(3)} + nv3 := (*[3]interface{})(nil) + pv3 := &v3 + v3Addr := fmt.Sprintf("%p", pv3) + pv3Addr := fmt.Sprintf("%p", &pv3) + v3t := "[3]interface {}" + v3t2 := "string" + v3t3 := "int" + v3t4 := "uint" + v3s := "[one 2 3]" + v3s2 := "[(" + v3t2 + ")one (" + v3t3 + ")2 (" + v3t4 + ")3]" + addFormatterTest("%v", v3, v3s) + addFormatterTest("%v", pv3, "<*>"+v3s) + addFormatterTest("%v", &pv3, "<**>"+v3s) + addFormatterTest("%+v", nv3, "") + addFormatterTest("%+v", v3, v3s) + addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s) + addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s) + addFormatterTest("%+v", nv3, "") + addFormatterTest("%#v", v3, "("+v3t+")"+v3s2) + addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s2) + addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s2) + addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") + addFormatterTest("%#+v", v3, "("+v3t+")"+v3s2) + addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s2) + addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s2) + addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"") +} + +func addSliceFormatterTests() { + // Slice containing standard float32 values. + v := []float32{3.14, 6.28, 12.56} + nv := (*[]float32)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "[]float32" + vs := "[3.14 6.28 12.56]" + addFormatterTest("%v", v, vs) + addFormatterTest("%v", pv, "<*>"+vs) + addFormatterTest("%v", &pv, "<**>"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%+v", v, vs) + addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) + addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%#v", v, "("+vt+")"+vs) + addFormatterTest("%#v", pv, "(*"+vt+")"+vs) + addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) + addFormatterTest("%#v", nv, "(*"+vt+")"+"") + addFormatterTest("%#+v", v, "("+vt+")"+vs) + addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) + addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%#+v", nv, "(*"+vt+")"+"") + + // Slice containing type with custom formatter on pointer receiver only. + v2 := []pstringer{"1", "2", "3"} + nv2 := (*[]pstringer)(nil) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "[]spew_test.pstringer" + v2s := "[stringer 1 stringer 2 stringer 3]" + addFormatterTest("%v", v2, v2s) + addFormatterTest("%v", pv2, "<*>"+v2s) + addFormatterTest("%v", &pv2, "<**>"+v2s) + addFormatterTest("%+v", nv2, "") + addFormatterTest("%+v", v2, v2s) + addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) + addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%+v", nv2, "") + addFormatterTest("%#v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) + addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) + addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") + addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) + addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") + + // Slice containing interfaces. + v3 := []interface{}{"one", int(2), uint(3), nil} + nv3 := (*[]interface{})(nil) + pv3 := &v3 + v3Addr := fmt.Sprintf("%p", pv3) + pv3Addr := fmt.Sprintf("%p", &pv3) + v3t := "[]interface {}" + v3t2 := "string" + v3t3 := "int" + v3t4 := "uint" + v3t5 := "interface {}" + v3s := "[one 2 3 ]" + v3s2 := "[(" + v3t2 + ")one (" + v3t3 + ")2 (" + v3t4 + ")3 (" + v3t5 + + ")]" + addFormatterTest("%v", v3, v3s) + addFormatterTest("%v", pv3, "<*>"+v3s) + addFormatterTest("%v", &pv3, "<**>"+v3s) + addFormatterTest("%+v", nv3, "") + addFormatterTest("%+v", v3, v3s) + addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s) + addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s) + addFormatterTest("%+v", nv3, "") + addFormatterTest("%#v", v3, "("+v3t+")"+v3s2) + addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s2) + addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s2) + addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") + addFormatterTest("%#+v", v3, "("+v3t+")"+v3s2) + addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s2) + addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s2) + addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"") + + // Nil slice. + var v4 []int + nv4 := (*[]int)(nil) + pv4 := &v4 + v4Addr := fmt.Sprintf("%p", pv4) + pv4Addr := fmt.Sprintf("%p", &pv4) + v4t := "[]int" + v4s := "" + addFormatterTest("%v", v4, v4s) + addFormatterTest("%v", pv4, "<*>"+v4s) + addFormatterTest("%v", &pv4, "<**>"+v4s) + addFormatterTest("%+v", nv4, "") + addFormatterTest("%+v", v4, v4s) + addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s) + addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s) + addFormatterTest("%+v", nv4, "") + addFormatterTest("%#v", v4, "("+v4t+")"+v4s) + addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s) + addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s) + addFormatterTest("%#v", nv4, "(*"+v4t+")"+"") + addFormatterTest("%#+v", v4, "("+v4t+")"+v4s) + addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s) + addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s) + addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"") +} + +func addStringFormatterTests() { + // Standard string. + v := "test" + nv := (*string)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "string" + vs := "test" + addFormatterTest("%v", v, vs) + addFormatterTest("%v", pv, "<*>"+vs) + addFormatterTest("%v", &pv, "<**>"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%+v", v, vs) + addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) + addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%#v", v, "("+vt+")"+vs) + addFormatterTest("%#v", pv, "(*"+vt+")"+vs) + addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) + addFormatterTest("%#v", nv, "(*"+vt+")"+"") + addFormatterTest("%#+v", v, "("+vt+")"+vs) + addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) + addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%#+v", nv, "(*"+vt+")"+"") +} + +func addInterfaceFormatterTests() { + // Nil interface. + var v interface{} + nv := (*interface{})(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "interface {}" + vs := "" + addFormatterTest("%v", v, vs) + addFormatterTest("%v", pv, "<*>"+vs) + addFormatterTest("%v", &pv, "<**>"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%+v", v, vs) + addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) + addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%#v", v, "("+vt+")"+vs) + addFormatterTest("%#v", pv, "(*"+vt+")"+vs) + addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) + addFormatterTest("%#v", nv, "(*"+vt+")"+"") + addFormatterTest("%#+v", v, "("+vt+")"+vs) + addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) + addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%#+v", nv, "(*"+vt+")"+"") + + // Sub-interface. + v2 := interface{}(uint16(65535)) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "uint16" + v2s := "65535" + addFormatterTest("%v", v2, v2s) + addFormatterTest("%v", pv2, "<*>"+v2s) + addFormatterTest("%v", &pv2, "<**>"+v2s) + addFormatterTest("%+v", v2, v2s) + addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) + addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%#v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) + addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) + addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) + addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) +} + +func addMapFormatterTests() { + // Map with string keys and int vals. + v := map[string]int{"one": 1, "two": 2} + nv := (*map[string]int)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "map[string]int" + vs := "map[one:1 two:2]" + vs2 := "map[two:2 one:1]" + addFormatterTest("%v", v, vs, vs2) + addFormatterTest("%v", pv, "<*>"+vs, "<*>"+vs2) + addFormatterTest("%v", &pv, "<**>"+vs, "<**>"+vs2) + addFormatterTest("%+v", nv, "") + addFormatterTest("%+v", v, vs, vs2) + addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs, "<*>("+vAddr+")"+vs2) + addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs, + "<**>("+pvAddr+"->"+vAddr+")"+vs2) + addFormatterTest("%+v", nv, "") + addFormatterTest("%#v", v, "("+vt+")"+vs, "("+vt+")"+vs2) + addFormatterTest("%#v", pv, "(*"+vt+")"+vs, "(*"+vt+")"+vs2) + addFormatterTest("%#v", &pv, "(**"+vt+")"+vs, "(**"+vt+")"+vs2) + addFormatterTest("%#v", nv, "(*"+vt+")"+"") + addFormatterTest("%#+v", v, "("+vt+")"+vs, "("+vt+")"+vs2) + addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs, + "(*"+vt+")("+vAddr+")"+vs2) + addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs, + "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs2) + addFormatterTest("%#+v", nv, "(*"+vt+")"+"") + + // Map with custom formatter type on pointer receiver only keys and vals. + v2 := map[pstringer]pstringer{"one": "1"} + nv2 := (*map[pstringer]pstringer)(nil) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "map[spew_test.pstringer]spew_test.pstringer" + v2s := "map[stringer one:stringer 1]" + addFormatterTest("%v", v2, v2s) + addFormatterTest("%v", pv2, "<*>"+v2s) + addFormatterTest("%v", &pv2, "<**>"+v2s) + addFormatterTest("%+v", nv2, "") + addFormatterTest("%+v", v2, v2s) + addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) + addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%+v", nv2, "") + addFormatterTest("%#v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) + addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) + addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") + addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) + addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") + + // Map with interface keys and values. + v3 := map[interface{}]interface{}{"one": 1} + nv3 := (*map[interface{}]interface{})(nil) + pv3 := &v3 + v3Addr := fmt.Sprintf("%p", pv3) + pv3Addr := fmt.Sprintf("%p", &pv3) + v3t := "map[interface {}]interface {}" + v3t1 := "string" + v3t2 := "int" + v3s := "map[one:1]" + v3s2 := "map[(" + v3t1 + ")one:(" + v3t2 + ")1]" + addFormatterTest("%v", v3, v3s) + addFormatterTest("%v", pv3, "<*>"+v3s) + addFormatterTest("%v", &pv3, "<**>"+v3s) + addFormatterTest("%+v", nv3, "") + addFormatterTest("%+v", v3, v3s) + addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s) + addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s) + addFormatterTest("%+v", nv3, "") + addFormatterTest("%#v", v3, "("+v3t+")"+v3s2) + addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s2) + addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s2) + addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") + addFormatterTest("%#+v", v3, "("+v3t+")"+v3s2) + addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s2) + addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s2) + addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"") + + // Map with nil interface value + v4 := map[string]interface{}{"nil": nil} + nv4 := (*map[string]interface{})(nil) + pv4 := &v4 + v4Addr := fmt.Sprintf("%p", pv4) + pv4Addr := fmt.Sprintf("%p", &pv4) + v4t := "map[string]interface {}" + v4t1 := "interface {}" + v4s := "map[nil:]" + v4s2 := "map[nil:(" + v4t1 + ")]" + addFormatterTest("%v", v4, v4s) + addFormatterTest("%v", pv4, "<*>"+v4s) + addFormatterTest("%v", &pv4, "<**>"+v4s) + addFormatterTest("%+v", nv4, "") + addFormatterTest("%+v", v4, v4s) + addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s) + addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s) + addFormatterTest("%+v", nv4, "") + addFormatterTest("%#v", v4, "("+v4t+")"+v4s2) + addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s2) + addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s2) + addFormatterTest("%#v", nv4, "(*"+v4t+")"+"") + addFormatterTest("%#+v", v4, "("+v4t+")"+v4s2) + addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s2) + addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s2) + addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"") +} + +func addStructFormatterTests() { + // Struct with primitives. + type s1 struct { + a int8 + b uint8 + } + v := s1{127, 255} + nv := (*s1)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "spew_test.s1" + vt2 := "int8" + vt3 := "uint8" + vs := "{127 255}" + vs2 := "{a:127 b:255}" + vs3 := "{a:(" + vt2 + ")127 b:(" + vt3 + ")255}" + addFormatterTest("%v", v, vs) + addFormatterTest("%v", pv, "<*>"+vs) + addFormatterTest("%v", &pv, "<**>"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%+v", v, vs2) + addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs2) + addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs2) + addFormatterTest("%+v", nv, "") + addFormatterTest("%#v", v, "("+vt+")"+vs3) + addFormatterTest("%#v", pv, "(*"+vt+")"+vs3) + addFormatterTest("%#v", &pv, "(**"+vt+")"+vs3) + addFormatterTest("%#v", nv, "(*"+vt+")"+"") + addFormatterTest("%#+v", v, "("+vt+")"+vs3) + addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs3) + addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs3) + addFormatterTest("%#+v", nv, "(*"+vt+")"+"") + + // Struct that contains another struct. + type s2 struct { + s1 s1 + b bool + } + v2 := s2{s1{127, 255}, true} + nv2 := (*s2)(nil) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "spew_test.s2" + v2t2 := "spew_test.s1" + v2t3 := "int8" + v2t4 := "uint8" + v2t5 := "bool" + v2s := "{{127 255} true}" + v2s2 := "{s1:{a:127 b:255} b:true}" + v2s3 := "{s1:(" + v2t2 + "){a:(" + v2t3 + ")127 b:(" + v2t4 + ")255} b:(" + + v2t5 + ")true}" + addFormatterTest("%v", v2, v2s) + addFormatterTest("%v", pv2, "<*>"+v2s) + addFormatterTest("%v", &pv2, "<**>"+v2s) + addFormatterTest("%+v", nv2, "") + addFormatterTest("%+v", v2, v2s2) + addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s2) + addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s2) + addFormatterTest("%+v", nv2, "") + addFormatterTest("%#v", v2, "("+v2t+")"+v2s3) + addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s3) + addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s3) + addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") + addFormatterTest("%#+v", v2, "("+v2t+")"+v2s3) + addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s3) + addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s3) + addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") + + // Struct that contains custom type with Stringer pointer interface via both + // exported and unexported fields. + type s3 struct { + s pstringer + S pstringer + } + v3 := s3{"test", "test2"} + nv3 := (*s3)(nil) + pv3 := &v3 + v3Addr := fmt.Sprintf("%p", pv3) + pv3Addr := fmt.Sprintf("%p", &pv3) + v3t := "spew_test.s3" + v3t2 := "spew_test.pstringer" + v3s := "{stringer test stringer test2}" + v3s2 := "{s:stringer test S:stringer test2}" + v3s3 := "{s:(" + v3t2 + ")stringer test S:(" + v3t2 + ")stringer test2}" + addFormatterTest("%v", v3, v3s) + addFormatterTest("%v", pv3, "<*>"+v3s) + addFormatterTest("%v", &pv3, "<**>"+v3s) + addFormatterTest("%+v", nv3, "") + addFormatterTest("%+v", v3, v3s2) + addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s2) + addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s2) + addFormatterTest("%+v", nv3, "") + addFormatterTest("%#v", v3, "("+v3t+")"+v3s3) + addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s3) + addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s3) + addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") + addFormatterTest("%#+v", v3, "("+v3t+")"+v3s3) + addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s3) + addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s3) + addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"") + + // Struct that contains embedded struct and field to same struct. + e := embed{"embedstr"} + v4 := embedwrap{embed: &e, e: &e} + nv4 := (*embedwrap)(nil) + pv4 := &v4 + eAddr := fmt.Sprintf("%p", &e) + v4Addr := fmt.Sprintf("%p", pv4) + pv4Addr := fmt.Sprintf("%p", &pv4) + v4t := "spew_test.embedwrap" + v4t2 := "spew_test.embed" + v4t3 := "string" + v4s := "{<*>{embedstr} <*>{embedstr}}" + v4s2 := "{embed:<*>(" + eAddr + "){a:embedstr} e:<*>(" + eAddr + + "){a:embedstr}}" + v4s3 := "{embed:(*" + v4t2 + "){a:(" + v4t3 + ")embedstr} e:(*" + v4t2 + + "){a:(" + v4t3 + ")embedstr}}" + v4s4 := "{embed:(*" + v4t2 + ")(" + eAddr + "){a:(" + v4t3 + + ")embedstr} e:(*" + v4t2 + ")(" + eAddr + "){a:(" + v4t3 + ")embedstr}}" + addFormatterTest("%v", v4, v4s) + addFormatterTest("%v", pv4, "<*>"+v4s) + addFormatterTest("%v", &pv4, "<**>"+v4s) + addFormatterTest("%+v", nv4, "") + addFormatterTest("%+v", v4, v4s2) + addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s2) + addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s2) + addFormatterTest("%+v", nv4, "") + addFormatterTest("%#v", v4, "("+v4t+")"+v4s3) + addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s3) + addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s3) + addFormatterTest("%#v", nv4, "(*"+v4t+")"+"") + addFormatterTest("%#+v", v4, "("+v4t+")"+v4s4) + addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s4) + addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s4) + addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"") +} + +func addUintptrFormatterTests() { + // Null pointer. + v := uintptr(0) + nv := (*uintptr)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "uintptr" + vs := "" + addFormatterTest("%v", v, vs) + addFormatterTest("%v", pv, "<*>"+vs) + addFormatterTest("%v", &pv, "<**>"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%+v", v, vs) + addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) + addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%#v", v, "("+vt+")"+vs) + addFormatterTest("%#v", pv, "(*"+vt+")"+vs) + addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) + addFormatterTest("%#v", nv, "(*"+vt+")"+"") + addFormatterTest("%#+v", v, "("+vt+")"+vs) + addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) + addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%#+v", nv, "(*"+vt+")"+"") + + // Address of real variable. + i := 1 + v2 := uintptr(unsafe.Pointer(&i)) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "uintptr" + v2s := fmt.Sprintf("%p", &i) + addFormatterTest("%v", v2, v2s) + addFormatterTest("%v", pv2, "<*>"+v2s) + addFormatterTest("%v", &pv2, "<**>"+v2s) + addFormatterTest("%+v", v2, v2s) + addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) + addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%#v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) + addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) + addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) + addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) +} + +func addUnsafePointerFormatterTests() { + // Null pointer. + v := unsafe.Pointer(uintptr(0)) + nv := (*unsafe.Pointer)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "unsafe.Pointer" + vs := "" + addFormatterTest("%v", v, vs) + addFormatterTest("%v", pv, "<*>"+vs) + addFormatterTest("%v", &pv, "<**>"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%+v", v, vs) + addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) + addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%#v", v, "("+vt+")"+vs) + addFormatterTest("%#v", pv, "(*"+vt+")"+vs) + addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) + addFormatterTest("%#v", nv, "(*"+vt+")"+"") + addFormatterTest("%#+v", v, "("+vt+")"+vs) + addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) + addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%#+v", nv, "(*"+vt+")"+"") + + // Address of real variable. + i := 1 + v2 := unsafe.Pointer(&i) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "unsafe.Pointer" + v2s := fmt.Sprintf("%p", &i) + addFormatterTest("%v", v2, v2s) + addFormatterTest("%v", pv2, "<*>"+v2s) + addFormatterTest("%v", &pv2, "<**>"+v2s) + addFormatterTest("%+v", v2, v2s) + addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) + addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%#v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) + addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) + addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) + addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) +} + +func addChanFormatterTests() { + // Nil channel. + var v chan int + pv := &v + nv := (*chan int)(nil) + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "chan int" + vs := "" + addFormatterTest("%v", v, vs) + addFormatterTest("%v", pv, "<*>"+vs) + addFormatterTest("%v", &pv, "<**>"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%+v", v, vs) + addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) + addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%#v", v, "("+vt+")"+vs) + addFormatterTest("%#v", pv, "(*"+vt+")"+vs) + addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) + addFormatterTest("%#v", nv, "(*"+vt+")"+"") + addFormatterTest("%#+v", v, "("+vt+")"+vs) + addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) + addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%#+v", nv, "(*"+vt+")"+"") + + // Real channel. + v2 := make(chan int) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "chan int" + v2s := fmt.Sprintf("%p", v2) + addFormatterTest("%v", v2, v2s) + addFormatterTest("%v", pv2, "<*>"+v2s) + addFormatterTest("%v", &pv2, "<**>"+v2s) + addFormatterTest("%+v", v2, v2s) + addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) + addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%#v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) + addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) + addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) + addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) +} + +func addFuncFormatterTests() { + // Function with no params and no returns. + v := addIntFormatterTests + nv := (*func())(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "func()" + vs := fmt.Sprintf("%p", v) + addFormatterTest("%v", v, vs) + addFormatterTest("%v", pv, "<*>"+vs) + addFormatterTest("%v", &pv, "<**>"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%+v", v, vs) + addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) + addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%#v", v, "("+vt+")"+vs) + addFormatterTest("%#v", pv, "(*"+vt+")"+vs) + addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) + addFormatterTest("%#v", nv, "(*"+vt+")"+"") + addFormatterTest("%#+v", v, "("+vt+")"+vs) + addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) + addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%#+v", nv, "(*"+vt+")"+"") + + // Function with param and no returns. + v2 := TestFormatter + nv2 := (*func(*testing.T))(nil) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "func(*testing.T)" + v2s := fmt.Sprintf("%p", v2) + addFormatterTest("%v", v2, v2s) + addFormatterTest("%v", pv2, "<*>"+v2s) + addFormatterTest("%v", &pv2, "<**>"+v2s) + addFormatterTest("%+v", nv2, "") + addFormatterTest("%+v", v2, v2s) + addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) + addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%+v", nv2, "") + addFormatterTest("%#v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) + addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) + addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") + addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) + addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") + + // Function with multiple params and multiple returns. + var v3 = func(i int, s string) (b bool, err error) { + return true, nil + } + nv3 := (*func(int, string) (bool, error))(nil) + pv3 := &v3 + v3Addr := fmt.Sprintf("%p", pv3) + pv3Addr := fmt.Sprintf("%p", &pv3) + v3t := "func(int, string) (bool, error)" + v3s := fmt.Sprintf("%p", v3) + addFormatterTest("%v", v3, v3s) + addFormatterTest("%v", pv3, "<*>"+v3s) + addFormatterTest("%v", &pv3, "<**>"+v3s) + addFormatterTest("%+v", nv3, "") + addFormatterTest("%+v", v3, v3s) + addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s) + addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s) + addFormatterTest("%+v", nv3, "") + addFormatterTest("%#v", v3, "("+v3t+")"+v3s) + addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s) + addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s) + addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") + addFormatterTest("%#+v", v3, "("+v3t+")"+v3s) + addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s) + addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s) + addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"") +} + +func addCircularFormatterTests() { + // Struct that is circular through self referencing. + type circular struct { + c *circular + } + v := circular{nil} + v.c = &v + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "spew_test.circular" + vs := "{<*>{<*>}}" + vs2 := "{<*>}" + vs3 := "{c:<*>(" + vAddr + "){c:<*>(" + vAddr + ")}}" + vs4 := "{c:<*>(" + vAddr + ")}" + vs5 := "{c:(*" + vt + "){c:(*" + vt + ")}}" + vs6 := "{c:(*" + vt + ")}" + vs7 := "{c:(*" + vt + ")(" + vAddr + "){c:(*" + vt + ")(" + vAddr + + ")}}" + vs8 := "{c:(*" + vt + ")(" + vAddr + ")}" + addFormatterTest("%v", v, vs) + addFormatterTest("%v", pv, "<*>"+vs2) + addFormatterTest("%v", &pv, "<**>"+vs2) + addFormatterTest("%+v", v, vs3) + addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs4) + addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs4) + addFormatterTest("%#v", v, "("+vt+")"+vs5) + addFormatterTest("%#v", pv, "(*"+vt+")"+vs6) + addFormatterTest("%#v", &pv, "(**"+vt+")"+vs6) + addFormatterTest("%#+v", v, "("+vt+")"+vs7) + addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs8) + addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs8) + + // Structs that are circular through cross referencing. + v2 := xref1{nil} + ts2 := xref2{&v2} + v2.ps2 = &ts2 + pv2 := &v2 + ts2Addr := fmt.Sprintf("%p", &ts2) + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "spew_test.xref1" + v2t2 := "spew_test.xref2" + v2s := "{<*>{<*>{<*>}}}" + v2s2 := "{<*>{<*>}}" + v2s3 := "{ps2:<*>(" + ts2Addr + "){ps1:<*>(" + v2Addr + "){ps2:<*>(" + + ts2Addr + ")}}}" + v2s4 := "{ps2:<*>(" + ts2Addr + "){ps1:<*>(" + v2Addr + ")}}" + v2s5 := "{ps2:(*" + v2t2 + "){ps1:(*" + v2t + "){ps2:(*" + v2t2 + + ")}}}" + v2s6 := "{ps2:(*" + v2t2 + "){ps1:(*" + v2t + ")}}" + v2s7 := "{ps2:(*" + v2t2 + ")(" + ts2Addr + "){ps1:(*" + v2t + + ")(" + v2Addr + "){ps2:(*" + v2t2 + ")(" + ts2Addr + + ")}}}" + v2s8 := "{ps2:(*" + v2t2 + ")(" + ts2Addr + "){ps1:(*" + v2t + + ")(" + v2Addr + ")}}" + addFormatterTest("%v", v2, v2s) + addFormatterTest("%v", pv2, "<*>"+v2s2) + addFormatterTest("%v", &pv2, "<**>"+v2s2) + addFormatterTest("%+v", v2, v2s3) + addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s4) + addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s4) + addFormatterTest("%#v", v2, "("+v2t+")"+v2s5) + addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s6) + addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s6) + addFormatterTest("%#+v", v2, "("+v2t+")"+v2s7) + addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s8) + addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s8) + + // Structs that are indirectly circular. + v3 := indirCir1{nil} + tic2 := indirCir2{nil} + tic3 := indirCir3{&v3} + tic2.ps3 = &tic3 + v3.ps2 = &tic2 + pv3 := &v3 + tic2Addr := fmt.Sprintf("%p", &tic2) + tic3Addr := fmt.Sprintf("%p", &tic3) + v3Addr := fmt.Sprintf("%p", pv3) + pv3Addr := fmt.Sprintf("%p", &pv3) + v3t := "spew_test.indirCir1" + v3t2 := "spew_test.indirCir2" + v3t3 := "spew_test.indirCir3" + v3s := "{<*>{<*>{<*>{<*>}}}}" + v3s2 := "{<*>{<*>{<*>}}}" + v3s3 := "{ps2:<*>(" + tic2Addr + "){ps3:<*>(" + tic3Addr + "){ps1:<*>(" + + v3Addr + "){ps2:<*>(" + tic2Addr + ")}}}}" + v3s4 := "{ps2:<*>(" + tic2Addr + "){ps3:<*>(" + tic3Addr + "){ps1:<*>(" + + v3Addr + ")}}}" + v3s5 := "{ps2:(*" + v3t2 + "){ps3:(*" + v3t3 + "){ps1:(*" + v3t + + "){ps2:(*" + v3t2 + ")}}}}" + v3s6 := "{ps2:(*" + v3t2 + "){ps3:(*" + v3t3 + "){ps1:(*" + v3t + + ")}}}" + v3s7 := "{ps2:(*" + v3t2 + ")(" + tic2Addr + "){ps3:(*" + v3t3 + ")(" + + tic3Addr + "){ps1:(*" + v3t + ")(" + v3Addr + "){ps2:(*" + v3t2 + + ")(" + tic2Addr + ")}}}}" + v3s8 := "{ps2:(*" + v3t2 + ")(" + tic2Addr + "){ps3:(*" + v3t3 + ")(" + + tic3Addr + "){ps1:(*" + v3t + ")(" + v3Addr + ")}}}" + addFormatterTest("%v", v3, v3s) + addFormatterTest("%v", pv3, "<*>"+v3s2) + addFormatterTest("%v", &pv3, "<**>"+v3s2) + addFormatterTest("%+v", v3, v3s3) + addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s4) + addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s4) + addFormatterTest("%#v", v3, "("+v3t+")"+v3s5) + addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s6) + addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s6) + addFormatterTest("%#+v", v3, "("+v3t+")"+v3s7) + addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s8) + addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s8) +} + +func addPanicFormatterTests() { + // Type that panics in its Stringer interface. + v := panicer(127) + nv := (*panicer)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "spew_test.panicer" + vs := "(PANIC=test panic)127" + addFormatterTest("%v", v, vs) + addFormatterTest("%v", pv, "<*>"+vs) + addFormatterTest("%v", &pv, "<**>"+vs) + addFormatterTest("%v", nv, "") + addFormatterTest("%+v", v, vs) + addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) + addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%#v", v, "("+vt+")"+vs) + addFormatterTest("%#v", pv, "(*"+vt+")"+vs) + addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) + addFormatterTest("%#v", nv, "(*"+vt+")"+"") + addFormatterTest("%#+v", v, "("+vt+")"+vs) + addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) + addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%#+v", nv, "(*"+vt+")"+"") +} + +func addErrorFormatterTests() { + // Type that has a custom Error interface. + v := customError(127) + nv := (*customError)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "spew_test.customError" + vs := "error: 127" + addFormatterTest("%v", v, vs) + addFormatterTest("%v", pv, "<*>"+vs) + addFormatterTest("%v", &pv, "<**>"+vs) + addFormatterTest("%v", nv, "") + addFormatterTest("%+v", v, vs) + addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) + addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%#v", v, "("+vt+")"+vs) + addFormatterTest("%#v", pv, "(*"+vt+")"+vs) + addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) + addFormatterTest("%#v", nv, "(*"+vt+")"+"") + addFormatterTest("%#+v", v, "("+vt+")"+vs) + addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) + addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%#+v", nv, "(*"+vt+")"+"") +} + +func addPassthroughFormatterTests() { + // %x passthrough with uint. + v := uint(4294967295) + pv := &v + vAddr := fmt.Sprintf("%x", pv) + pvAddr := fmt.Sprintf("%x", &pv) + vs := "ffffffff" + addFormatterTest("%x", v, vs) + addFormatterTest("%x", pv, vAddr) + addFormatterTest("%x", &pv, pvAddr) + + // %#x passthrough with uint. + v2 := int(2147483647) + pv2 := &v2 + v2Addr := fmt.Sprintf("%#x", pv2) + pv2Addr := fmt.Sprintf("%#x", &pv2) + v2s := "0x7fffffff" + addFormatterTest("%#x", v2, v2s) + addFormatterTest("%#x", pv2, v2Addr) + addFormatterTest("%#x", &pv2, pv2Addr) + + // %f passthrough with precision. + addFormatterTest("%.2f", 3.1415, "3.14") + addFormatterTest("%.3f", 3.1415, "3.142") + addFormatterTest("%.4f", 3.1415, "3.1415") + + // %f passthrough with width and precision. + addFormatterTest("%5.2f", 3.1415, " 3.14") + addFormatterTest("%6.3f", 3.1415, " 3.142") + addFormatterTest("%7.4f", 3.1415, " 3.1415") + + // %d passthrough with width. + addFormatterTest("%3d", 127, "127") + addFormatterTest("%4d", 127, " 127") + addFormatterTest("%5d", 127, " 127") + + // %q passthrough with string. + addFormatterTest("%q", "test", "\"test\"") +} + +// TestFormatter executes all of the tests described by formatterTests. +func TestFormatter(t *testing.T) { + // Setup tests. + addIntFormatterTests() + addUintFormatterTests() + addBoolFormatterTests() + addFloatFormatterTests() + addComplexFormatterTests() + addArrayFormatterTests() + addSliceFormatterTests() + addStringFormatterTests() + addInterfaceFormatterTests() + addMapFormatterTests() + addStructFormatterTests() + addUintptrFormatterTests() + addUnsafePointerFormatterTests() + addChanFormatterTests() + addFuncFormatterTests() + addCircularFormatterTests() + addPanicFormatterTests() + addErrorFormatterTests() + addPassthroughFormatterTests() + + t.Logf("Running %d tests", len(formatterTests)) + for i, test := range formatterTests { + buf := new(bytes.Buffer) + spew.Fprintf(buf, test.format, test.in) + s := buf.String() + if testFailed(s, test.wants) { + t.Errorf("Formatter #%d format: %s got: %s %s", i, test.format, s, + stringizeWants(test.wants)) + continue + } + } +} + +func TestPrintSortedKeys(t *testing.T) { + cfg := spew.ConfigState{SortKeys: true} + s := cfg.Sprint(map[int]string{1: "1", 3: "3", 2: "2"}) + expected := "map[1:1 2:2 3:3]" + if s != expected { + t.Errorf("Sorted keys mismatch:\n %v %v", s, expected) + } +} diff --git a/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/internal_test.go b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/internal_test.go new file mode 100644 index 00000000000..10dc0b18a93 --- /dev/null +++ b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/internal_test.go @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2013 Dave Collins + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* +This test file is part of the spew package rather than than the spew_test +package because it needs access to internals to properly test certain cases +which are not possible via the public interface since they should never happen. +*/ + +package spew + +import ( + "bytes" + "reflect" + "testing" + "unsafe" +) + +// dummyFmtState implements a fake fmt.State to use for testing invalid +// reflect.Value handling. This is necessary because the fmt package catches +// invalid values before invoking the formatter on them. +type dummyFmtState struct { + bytes.Buffer +} + +func (dfs *dummyFmtState) Flag(f int) bool { + if f == int('+') { + return true + } + return false +} + +func (dfs *dummyFmtState) Precision() (int, bool) { + return 0, false +} + +func (dfs *dummyFmtState) Width() (int, bool) { + return 0, false +} + +// TestInvalidReflectValue ensures the dump and formatter code handles an +// invalid reflect value properly. This needs access to internal state since it +// should never happen in real code and therefore can't be tested via the public +// API. +func TestInvalidReflectValue(t *testing.T) { + i := 1 + + // Dump invalid reflect value. + v := new(reflect.Value) + buf := new(bytes.Buffer) + d := dumpState{w: buf, cs: &Config} + d.dump(*v) + s := buf.String() + want := "" + if s != want { + t.Errorf("InvalidReflectValue #%d\n got: %s want: %s", i, s, want) + } + i++ + + // Formatter invalid reflect value. + buf2 := new(dummyFmtState) + f := formatState{value: *v, cs: &Config, fs: buf2} + f.format(*v) + s = buf2.String() + want = "" + if s != want { + t.Errorf("InvalidReflectValue #%d got: %s want: %s", i, s, want) + } +} + +// changeKind uses unsafe to intentionally change the kind of a reflect.Value to +// the maximum kind value which does not exist. This is needed to test the +// fallback code which punts to the standard fmt library for new types that +// might get added to the language. +func changeKind(v *reflect.Value, readOnly bool) { + rvf := (*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + offsetFlag)) + *rvf = *rvf | ((1< + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package spew + +import ( + "fmt" + "io" +) + +// Errorf is a wrapper for fmt.Errorf that treats each argument as if it were +// passed with a default Formatter interface returned by NewFormatter. It +// returns the formatted string as a value that satisfies error. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Errorf(format, spew.NewFormatter(a), spew.NewFormatter(b)) +func Errorf(format string, a ...interface{}) (err error) { + return fmt.Errorf(format, convertArgs(a)...) +} + +// Fprint is a wrapper for fmt.Fprint that treats each argument as if it were +// passed with a default Formatter interface returned by NewFormatter. It +// returns the number of bytes written and any write error encountered. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Fprint(w, spew.NewFormatter(a), spew.NewFormatter(b)) +func Fprint(w io.Writer, a ...interface{}) (n int, err error) { + return fmt.Fprint(w, convertArgs(a)...) +} + +// Fprintf is a wrapper for fmt.Fprintf that treats each argument as if it were +// passed with a default Formatter interface returned by NewFormatter. It +// returns the number of bytes written and any write error encountered. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Fprintf(w, format, spew.NewFormatter(a), spew.NewFormatter(b)) +func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) { + return fmt.Fprintf(w, format, convertArgs(a)...) +} + +// Fprintln is a wrapper for fmt.Fprintln that treats each argument as if it +// passed with a default Formatter interface returned by NewFormatter. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Fprintln(w, spew.NewFormatter(a), spew.NewFormatter(b)) +func Fprintln(w io.Writer, a ...interface{}) (n int, err error) { + return fmt.Fprintln(w, convertArgs(a)...) +} + +// Print is a wrapper for fmt.Print that treats each argument as if it were +// passed with a default Formatter interface returned by NewFormatter. It +// returns the number of bytes written and any write error encountered. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Print(spew.NewFormatter(a), spew.NewFormatter(b)) +func Print(a ...interface{}) (n int, err error) { + return fmt.Print(convertArgs(a)...) +} + +// Printf is a wrapper for fmt.Printf that treats each argument as if it were +// passed with a default Formatter interface returned by NewFormatter. It +// returns the number of bytes written and any write error encountered. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Printf(format, spew.NewFormatter(a), spew.NewFormatter(b)) +func Printf(format string, a ...interface{}) (n int, err error) { + return fmt.Printf(format, convertArgs(a)...) +} + +// Println is a wrapper for fmt.Println that treats each argument as if it were +// passed with a default Formatter interface returned by NewFormatter. It +// returns the number of bytes written and any write error encountered. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Println(spew.NewFormatter(a), spew.NewFormatter(b)) +func Println(a ...interface{}) (n int, err error) { + return fmt.Println(convertArgs(a)...) +} + +// Sprint is a wrapper for fmt.Sprint that treats each argument as if it were +// passed with a default Formatter interface returned by NewFormatter. It +// returns the resulting string. See NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Sprint(spew.NewFormatter(a), spew.NewFormatter(b)) +func Sprint(a ...interface{}) string { + return fmt.Sprint(convertArgs(a)...) +} + +// Sprintf is a wrapper for fmt.Sprintf that treats each argument as if it were +// passed with a default Formatter interface returned by NewFormatter. It +// returns the resulting string. See NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Sprintf(format, spew.NewFormatter(a), spew.NewFormatter(b)) +func Sprintf(format string, a ...interface{}) string { + return fmt.Sprintf(format, convertArgs(a)...) +} + +// Sprintln is a wrapper for fmt.Sprintln that treats each argument as if it +// were passed with a default Formatter interface returned by NewFormatter. It +// returns the resulting string. See NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Sprintln(spew.NewFormatter(a), spew.NewFormatter(b)) +func Sprintln(a ...interface{}) string { + return fmt.Sprintln(convertArgs(a)...) +} + +// convertArgs accepts a slice of arguments and returns a slice of the same +// length with each argument converted to a default spew Formatter interface. +func convertArgs(args []interface{}) (formatters []interface{}) { + formatters = make([]interface{}, len(args)) + for index, arg := range args { + formatters[index] = NewFormatter(arg) + } + return formatters +} diff --git a/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/spew_test.go b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/spew_test.go new file mode 100644 index 00000000000..3831ed2fb5e --- /dev/null +++ b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/spew_test.go @@ -0,0 +1,308 @@ +/* + * Copyright (c) 2013 Dave Collins + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package spew_test + +import ( + "bytes" + "fmt" + "github.com/davecgh/go-spew/spew" + "io/ioutil" + "os" + "testing" +) + +// spewFunc is used to identify which public function of the spew package or +// ConfigState a test applies to. +type spewFunc int + +const ( + fCSFdump spewFunc = iota + fCSFprint + fCSFprintf + fCSFprintln + fCSPrint + fCSPrintln + fCSSdump + fCSSprint + fCSSprintf + fCSSprintln + fCSErrorf + fCSNewFormatter + fErrorf + fFprint + fFprintln + fPrint + fPrintln + fSdump + fSprint + fSprintf + fSprintln +) + +// Map of spewFunc values to names for pretty printing. +var spewFuncStrings = map[spewFunc]string{ + fCSFdump: "ConfigState.Fdump", + fCSFprint: "ConfigState.Fprint", + fCSFprintf: "ConfigState.Fprintf", + fCSFprintln: "ConfigState.Fprintln", + fCSSdump: "ConfigState.Sdump", + fCSPrint: "ConfigState.Print", + fCSPrintln: "ConfigState.Println", + fCSSprint: "ConfigState.Sprint", + fCSSprintf: "ConfigState.Sprintf", + fCSSprintln: "ConfigState.Sprintln", + fCSErrorf: "ConfigState.Errorf", + fCSNewFormatter: "ConfigState.NewFormatter", + fErrorf: "spew.Errorf", + fFprint: "spew.Fprint", + fFprintln: "spew.Fprintln", + fPrint: "spew.Print", + fPrintln: "spew.Println", + fSdump: "spew.Sdump", + fSprint: "spew.Sprint", + fSprintf: "spew.Sprintf", + fSprintln: "spew.Sprintln", +} + +func (f spewFunc) String() string { + if s, ok := spewFuncStrings[f]; ok { + return s + } + return fmt.Sprintf("Unknown spewFunc (%d)", int(f)) +} + +// spewTest is used to describe a test to be performed against the public +// functions of the spew package or ConfigState. +type spewTest struct { + cs *spew.ConfigState + f spewFunc + format string + in interface{} + want string +} + +// spewTests houses the tests to be performed against the public functions of +// the spew package and ConfigState. +// +// These tests are only intended to ensure the public functions are exercised +// and are intentionally not exhaustive of types. The exhaustive type +// tests are handled in the dump and format tests. +var spewTests []spewTest + +// redirStdout is a helper function to return the standard output from f as a +// byte slice. +func redirStdout(f func()) ([]byte, error) { + tempFile, err := ioutil.TempFile("", "ss-test") + if err != nil { + return nil, err + } + fileName := tempFile.Name() + defer os.Remove(fileName) // Ignore error + + origStdout := os.Stdout + os.Stdout = tempFile + f() + os.Stdout = origStdout + tempFile.Close() + + return ioutil.ReadFile(fileName) +} + +func initSpewTests() { + // Config states with various settings. + scsDefault := spew.NewDefaultConfig() + scsNoMethods := &spew.ConfigState{Indent: " ", DisableMethods: true} + scsNoPmethods := &spew.ConfigState{Indent: " ", DisablePointerMethods: true} + scsMaxDepth := &spew.ConfigState{Indent: " ", MaxDepth: 1} + scsContinue := &spew.ConfigState{Indent: " ", ContinueOnMethod: true} + + // Variables for tests on types which implement Stringer interface with and + // without a pointer receiver. + ts := stringer("test") + tps := pstringer("test") + + // depthTester is used to test max depth handling for structs, array, slices + // and maps. + type depthTester struct { + ic indirCir1 + arr [1]string + slice []string + m map[string]int + } + dt := depthTester{indirCir1{nil}, [1]string{"arr"}, []string{"slice"}, + map[string]int{"one": 1}} + + // Variable for tests on types which implement error interface. + te := customError(10) + + spewTests = []spewTest{ + {scsDefault, fCSFdump, "", int8(127), "(int8) 127\n"}, + {scsDefault, fCSFprint, "", int16(32767), "32767"}, + {scsDefault, fCSFprintf, "%v", int32(2147483647), "2147483647"}, + {scsDefault, fCSFprintln, "", int(2147483647), "2147483647\n"}, + {scsDefault, fCSPrint, "", int64(9223372036854775807), "9223372036854775807"}, + {scsDefault, fCSPrintln, "", uint8(255), "255\n"}, + {scsDefault, fCSSdump, "", uint8(64), "(uint8) 64\n"}, + {scsDefault, fCSSprint, "", complex(1, 2), "(1+2i)"}, + {scsDefault, fCSSprintf, "%v", complex(float32(3), 4), "(3+4i)"}, + {scsDefault, fCSSprintln, "", complex(float64(5), 6), "(5+6i)\n"}, + {scsDefault, fCSErrorf, "%#v", uint16(65535), "(uint16)65535"}, + {scsDefault, fCSNewFormatter, "%v", uint32(4294967295), "4294967295"}, + {scsDefault, fErrorf, "%v", uint64(18446744073709551615), "18446744073709551615"}, + {scsDefault, fFprint, "", float32(3.14), "3.14"}, + {scsDefault, fFprintln, "", float64(6.28), "6.28\n"}, + {scsDefault, fPrint, "", true, "true"}, + {scsDefault, fPrintln, "", false, "false\n"}, + {scsDefault, fSdump, "", complex(-10, -20), "(complex128) (-10-20i)\n"}, + {scsDefault, fSprint, "", complex(-1, -2), "(-1-2i)"}, + {scsDefault, fSprintf, "%v", complex(float32(-3), -4), "(-3-4i)"}, + {scsDefault, fSprintln, "", complex(float64(-5), -6), "(-5-6i)\n"}, + {scsNoMethods, fCSFprint, "", ts, "test"}, + {scsNoMethods, fCSFprint, "", &ts, "<*>test"}, + {scsNoMethods, fCSFprint, "", tps, "test"}, + {scsNoMethods, fCSFprint, "", &tps, "<*>test"}, + {scsNoPmethods, fCSFprint, "", ts, "stringer test"}, + {scsNoPmethods, fCSFprint, "", &ts, "<*>stringer test"}, + {scsNoPmethods, fCSFprint, "", tps, "test"}, + {scsNoPmethods, fCSFprint, "", &tps, "<*>stringer test"}, + {scsMaxDepth, fCSFprint, "", dt, "{{} [] [] map[]}"}, + {scsMaxDepth, fCSFdump, "", dt, "(spew_test.depthTester) {\n" + + " ic: (spew_test.indirCir1) {\n \n },\n" + + " arr: ([1]string) (len=1 cap=1) {\n \n },\n" + + " slice: ([]string) (len=1 cap=1) {\n \n },\n" + + " m: (map[string]int) (len=1) {\n \n }\n}\n"}, + {scsContinue, fCSFprint, "", ts, "(stringer test) test"}, + {scsContinue, fCSFdump, "", ts, "(spew_test.stringer) " + + "(len=4) (stringer test) \"test\"\n"}, + {scsContinue, fCSFprint, "", te, "(error: 10) 10"}, + {scsContinue, fCSFdump, "", te, "(spew_test.customError) " + + "(error: 10) 10\n"}, + } +} + +// TestSpew executes all of the tests described by spewTests. +func TestSpew(t *testing.T) { + initSpewTests() + + t.Logf("Running %d tests", len(spewTests)) + for i, test := range spewTests { + buf := new(bytes.Buffer) + switch test.f { + case fCSFdump: + test.cs.Fdump(buf, test.in) + + case fCSFprint: + test.cs.Fprint(buf, test.in) + + case fCSFprintf: + test.cs.Fprintf(buf, test.format, test.in) + + case fCSFprintln: + test.cs.Fprintln(buf, test.in) + + case fCSPrint: + b, err := redirStdout(func() { test.cs.Print(test.in) }) + if err != nil { + t.Errorf("%v #%d %v", test.f, i, err) + continue + } + buf.Write(b) + + case fCSPrintln: + b, err := redirStdout(func() { test.cs.Println(test.in) }) + if err != nil { + t.Errorf("%v #%d %v", test.f, i, err) + continue + } + buf.Write(b) + + case fCSSdump: + str := test.cs.Sdump(test.in) + buf.WriteString(str) + + case fCSSprint: + str := test.cs.Sprint(test.in) + buf.WriteString(str) + + case fCSSprintf: + str := test.cs.Sprintf(test.format, test.in) + buf.WriteString(str) + + case fCSSprintln: + str := test.cs.Sprintln(test.in) + buf.WriteString(str) + + case fCSErrorf: + err := test.cs.Errorf(test.format, test.in) + buf.WriteString(err.Error()) + + case fCSNewFormatter: + fmt.Fprintf(buf, test.format, test.cs.NewFormatter(test.in)) + + case fErrorf: + err := spew.Errorf(test.format, test.in) + buf.WriteString(err.Error()) + + case fFprint: + spew.Fprint(buf, test.in) + + case fFprintln: + spew.Fprintln(buf, test.in) + + case fPrint: + b, err := redirStdout(func() { spew.Print(test.in) }) + if err != nil { + t.Errorf("%v #%d %v", test.f, i, err) + continue + } + buf.Write(b) + + case fPrintln: + b, err := redirStdout(func() { spew.Println(test.in) }) + if err != nil { + t.Errorf("%v #%d %v", test.f, i, err) + continue + } + buf.Write(b) + + case fSdump: + str := spew.Sdump(test.in) + buf.WriteString(str) + + case fSprint: + str := spew.Sprint(test.in) + buf.WriteString(str) + + case fSprintf: + str := spew.Sprintf(test.format, test.in) + buf.WriteString(str) + + case fSprintln: + str := spew.Sprintln(test.in) + buf.WriteString(str) + + default: + t.Errorf("%v #%d unrecognized function", test.f, i) + continue + } + s := buf.String() + if test.want != s { + t.Errorf("ConfigState #%d\n got: %s want: %s", i, s, test.want) + continue + } + } +} diff --git a/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/testdata/dumpcgo.go b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/testdata/dumpcgo.go new file mode 100644 index 00000000000..5c87dd456ed --- /dev/null +++ b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/testdata/dumpcgo.go @@ -0,0 +1,82 @@ +// Copyright (c) 2013 Dave Collins +// +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +// NOTE: Due to the following build constraints, this file will only be compiled +// when both cgo is supported and "-tags testcgo" is added to the go test +// command line. This code should really only be in the dumpcgo_test.go file, +// but unfortunately Go will not allow cgo in test files, so this is a +// workaround to allow cgo types to be tested. This configuration is used +// because spew itself does not require cgo to run even though it does handle +// certain cgo types specially. Rather than forcing all clients to require cgo +// and an external C compiler just to run the tests, this scheme makes them +// optional. +// +build cgo,testcgo + +package testdata + +/* +#include +typedef unsigned char custom_uchar_t; + +char *ncp = 0; +char *cp = "test"; +char ca[6] = {'t', 'e', 's', 't', '2', '\0'}; +unsigned char uca[6] = {'t', 'e', 's', 't', '3', '\0'}; +signed char sca[6] = {'t', 'e', 's', 't', '4', '\0'}; +uint8_t ui8ta[6] = {'t', 'e', 's', 't', '5', '\0'}; +custom_uchar_t tuca[6] = {'t', 'e', 's', 't', '6', '\0'}; +*/ +import "C" + +// GetCgoNullCharPointer returns a null char pointer via cgo. This is only +// used for tests. +func GetCgoNullCharPointer() interface{} { + return C.ncp +} + +// GetCgoCharPointer returns a char pointer via cgo. This is only used for +// tests. +func GetCgoCharPointer() interface{} { + return C.cp +} + +// GetCgoCharArray returns a char array via cgo and the array's len and cap. +// This is only used for tests. +func GetCgoCharArray() (interface{}, int, int) { + return C.ca, len(C.ca), cap(C.ca) +} + +// GetCgoUnsignedCharArray returns an unsigned char array via cgo and the +// array's len and cap. This is only used for tests. +func GetCgoUnsignedCharArray() (interface{}, int, int) { + return C.uca, len(C.uca), cap(C.uca) +} + +// GetCgoSignedCharArray returns a signed char array via cgo and the array's len +// and cap. This is only used for tests. +func GetCgoSignedCharArray() (interface{}, int, int) { + return C.sca, len(C.sca), cap(C.sca) +} + +// GetCgoUint8tArray returns a uint8_t array via cgo and the array's len and +// cap. This is only used for tests. +func GetCgoUint8tArray() (interface{}, int, int) { + return C.ui8ta, len(C.ui8ta), cap(C.ui8ta) +} + +// GetCgoTypdefedUnsignedCharArray returns a typedefed unsigned char array via +// cgo and the array's len and cap. This is only used for tests. +func GetCgoTypdefedUnsignedCharArray() (interface{}, int, int) { + return C.tuca, len(C.tuca), cap(C.tuca) +} diff --git a/Godeps/_workspace/src/github.com/ghodss/yaml/.gitignore b/Godeps/_workspace/src/github.com/ghodss/yaml/.gitignore new file mode 100644 index 00000000000..e256a31e00a --- /dev/null +++ b/Godeps/_workspace/src/github.com/ghodss/yaml/.gitignore @@ -0,0 +1,20 @@ +# OSX leaves these everywhere on SMB shares +._* + +# Eclipse files +.classpath +.project +.settings/** + +# Emacs save files +*~ + +# Vim-related files +[._]*.s[a-w][a-z] +[._]s[a-w][a-z] +*.un~ +Session.vim +.netrwhist + +# Go test binaries +*.test diff --git a/Godeps/_workspace/src/github.com/ghodss/yaml/LICENSE b/Godeps/_workspace/src/github.com/ghodss/yaml/LICENSE new file mode 100644 index 00000000000..ed095d4b33d --- /dev/null +++ b/Godeps/_workspace/src/github.com/ghodss/yaml/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Sam Ghods + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Godeps/_workspace/src/github.com/ghodss/yaml/README.md b/Godeps/_workspace/src/github.com/ghodss/yaml/README.md new file mode 100644 index 00000000000..2d603097fc0 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ghodss/yaml/README.md @@ -0,0 +1,114 @@ +# YAML marshaling and unmarshaling support for Go + +## Introduction + +A wrapper around [go-yaml](https://github.com/go-yaml/yaml) designed to enable a better way of handling YAML when marshaling to and from structs. + +In short, this library first converts YAML to JSON using go-yaml and then uses `json.Marshal` and `json.Unmarshal` to convert to or from the struct. This means that it effectively reuses the JSON struct tags as well as the custom JSON methods `MarshalJSON` and `UnmarshalJSON` unlike go-yaml. For a detailed overview of the rationale behind this method, [see this blog post](http://ghodss.com/2014/the-right-way-to-handle-yaml-in-golang/). + +## Compatibility + +This package uses [go-yaml v2](https://github.com/go-yaml/yaml) and therefore supports [everything go-yaml supports](https://github.com/go-yaml/yaml#compatibility). + +## Caveats + +**Caveat #1:** When using `yaml.Marshal` and `yaml.Unmarshal`, binary data should NOT be preceded with the `!!binary` YAML tag. If you do, go-yaml will convert the binary data from base64 to native binary data, which is not compatible with JSON. You can still use binary in your YAML files though - just store them without the `!!binary` tag and decode the base64 in your code (e.g. in the custom JSON methods `MarshalJSON` and `UnmarshalJSON`). This also has the benefit that your YAML and your JSON binary data will be decoded exactly the same way. As an example: + +``` +BAD: + exampleKey: !!binary gIGC + +GOOD: + exampleKey: gIGC +... and decode the base64 data in your code. +``` + +**Caveat #2:** When using `YAMLToJSON` directly, maps with keys that are maps will result in an error since this is not supported by JSON. This error will occur in `Unmarshal` as well since you can't unmarshal map keys anyways since struct fields can't be keys. + +## Installation and usage + +To install, run: + +``` +$ go get github.com/ghodss/yaml +``` + +And import using: + +``` +import "github.com/ghodss/yaml" +``` + +Usage is very similar to the JSON library: + +```go +import ( + "fmt" + + "github.com/ghodss/yaml" +) + +type Person struct { + Name string `json:"name"` // Affects YAML field names too. + Age int `json:"name"` +} + +func main() { + // Marshal a Person struct to YAML. + p := Person{"John", 30} + y, err := yaml.Marshal(p) + if err != nil { + fmt.Printf("err: %v\n", err) + return + } + fmt.Println(string(y)) + /* Output: + name: John + age: 30 + */ + + // Unmarshal the YAML back into a Person struct. + var p2 Person + err := yaml.Unmarshal(y, &p2) + if err != nil { + fmt.Printf("err: %v\n", err) + return + } + fmt.Println(p2) + /* Output: + {John 30} + */ +} +``` + +`yaml.YAMLToJSON` and `yaml.JSONToYAML` methods are also available: + +```go +import ( + "fmt" + + "github.com/ghodss/yaml" +) +func main() { + j := []byte(`{"name": "John", "age": 30}`) + y, err := yaml.JSONToYAML(j) + if err != nil { + fmt.Printf("err: %v\n", err) + return + } + fmt.Println(string(y)) + /* Output: + name: John + age: 30 + */ + j2, err := yaml.YAMLToJSON(y) + if err != nil { + fmt.Printf("err: %v\n", err) + return + } + fmt.Println(string(j2)) + /* Output: + {"age":30,"name":"John"} + */ +} +``` diff --git a/Godeps/_workspace/src/github.com/ghodss/yaml/yaml.go b/Godeps/_workspace/src/github.com/ghodss/yaml/yaml.go new file mode 100644 index 00000000000..b368402ed75 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ghodss/yaml/yaml.go @@ -0,0 +1,152 @@ +package yaml + +import ( + "encoding/json" + "fmt" + "reflect" + "strconv" + + "gopkg.in/v2/yaml" +) + +// Marshals the object into JSON then converts JSON to YAML and returns the +// YAML. +func Marshal(o interface{}) ([]byte, error) { + j, err := json.Marshal(o) + if err != nil { + return nil, fmt.Errorf("error marshaling into JSON: ", err) + } + + y, err := JSONToYAML(j) + if err != nil { + return nil, fmt.Errorf("error converting JSON to YAML: ", err) + } + + return y, nil +} + +// Converts YAML to JSON then uses JSON to unmarshal into an object. +func Unmarshal(y []byte, o interface{}) error { + j, err := YAMLToJSON(y) + if err != nil { + return fmt.Errorf("error converting YAML to JSON: %v", err) + } + + err = json.Unmarshal(j, o) + if err != nil { + return fmt.Errorf("error unmarshaling JSON: %v", err) + } + + return nil +} + +// Convert JSON to YAML. +func JSONToYAML(j []byte) ([]byte, error) { + // Convert the JSON to an object. + var jsonObj interface{} + err := json.Unmarshal(j, &jsonObj) + if err != nil { + return nil, err + } + + // Marshal this object into YAML. + return yaml.Marshal(jsonObj) +} + +// Convert YAML to JSON. Since JSON is a subset of YAML, passing JSON through +// this method should be a no-op. +// +// Things YAML can do that are not supported by JSON: +// * In YAML you can have binary and null keys in your maps. These are invalid +// in JSON. (int and float keys are converted to strings.) +// * Binary data in YAML with the !!binary tag is not supported. If you want to +// use binary data with this library, encode the data as base64 as usual but do +// not use the !!binary tag in your YAML. This will ensure the original base64 +// encoded data makes it all the way through to the JSON. +func YAMLToJSON(y []byte) ([]byte, error) { + // Convert the YAML to an object. + var yamlObj interface{} + err := yaml.Unmarshal(y, &yamlObj) + if err != nil { + return nil, err + } + + // YAML objects are not completely compatible with JSON objects (e.g. you + // can have non-string keys in YAML). So, convert the YAML-compatible object + // to a JSON-compatible object, failing with an error if irrecoverable + // incompatibilties happen along the way. + jsonObj, err := convertToJSONableObject(yamlObj) + if err != nil { + return nil, err + } + + // Convert this object to JSON and return the data. + return json.Marshal(jsonObj) +} + +func convertToJSONableObject(yamlObj interface{}) (interface{}, error) { + var err error + switch typedYAMLObj := yamlObj.(type) { + case map[interface{}]interface{}: + // JSON does not support arbitrary keys in a map, so we must convert + // these keys to strings. + // + // From my reading of go-yaml v2 (specifically the resolve function), + // keys can only have the types string, int, int64, float64, binary + // (unsupported), or null (unsupported). + strMap := make(map[string]interface{}) + for k, v := range typedYAMLObj { + // Resolve the key to a string first. + var keyString string + switch typedKey := k.(type) { + case string: + keyString = typedKey + case int: + keyString = strconv.Itoa(typedKey) + case int64: + // go-yaml will only return an int64 as a key if the system + // architecture is 32-bit and the key's value is between 32-bit + // and 64-bit. Otherwise the key type will simply be int. + keyString = strconv.FormatInt(typedKey, 10) + case float64: + // Stolen from go-yaml to use the same conversion to string as + // the go-yaml library uses to convert float to string when + // Marshaling. + s := strconv.FormatFloat(typedKey, 'g', -1, 32) + switch s { + case "+Inf": + s = ".inf" + case "-Inf": + s = "-.inf" + case "NaN": + s = ".nan" + } + keyString = s + default: + return nil, fmt.Errorf("Unsupported map key of type: %s, key: %+#v, value: %+#v", + reflect.TypeOf(k), k, v) + } + + strMap[keyString], err = convertToJSONableObject(v) + if err != nil { + return nil, err + } + } + return strMap, nil + case []interface{}: + // We need to recurse into arrays in case there are any + // map[interface{}]interface{}'s inside. + arr := make([]interface{}, len(typedYAMLObj)) + for i, v := range typedYAMLObj { + arr[i], err = convertToJSONableObject(v) + if err != nil { + return nil, err + } + } + return arr, nil + default: + return yamlObj, nil + } + + return nil, nil +} diff --git a/Godeps/_workspace/src/github.com/ghodss/yaml/yaml_test.go b/Godeps/_workspace/src/github.com/ghodss/yaml/yaml_test.go new file mode 100644 index 00000000000..27f00ef27ce --- /dev/null +++ b/Godeps/_workspace/src/github.com/ghodss/yaml/yaml_test.go @@ -0,0 +1,210 @@ +package yaml + +import ( + "fmt" + "reflect" + "testing" +) + +type MarshalTest struct { + A int +} + +func TestMarshalYAML(t *testing.T) { + s := MarshalTest{1} + e := []byte("A: 1\n") + + y, err := Marshal(s) + if err != nil { + t.Errorf("error marshaling YAML: %v", err) + } + + if !reflect.DeepEqual(y, e) { + t.Errorf("marshal YAML was unsuccessful, expected: %#v, got: %#v", + string(y), string(e)) + } +} + +func TestUnmarshal(t *testing.T) { + y := []byte(`a: 1`) + s := MarshalTest{} + e := MarshalTest{1} + + err := Unmarshal(y, &s) + if err != nil { + t.Errorf("error unmarshaling YAML: %v", err) + } + + if !reflect.DeepEqual(s, e) { + t.Errorf("unmarshal YAML was unsuccessful, expected: %+#v, got: %+#v", + e, s) + } +} + +type Case struct { + input string + output string + // By default we test that reversing the output == input. But if there is a + // difference in the reversed output, you can optionally specify it here. + reverse *string +} + +type RunType int + +const ( + RunTypeJSONToYAML RunType = iota + RunTypeYAMLToJSON +) + +func TestJSONToYAML(t *testing.T) { + cases := []Case{ + { + `{"t":"a"}`, + "t: a\n", + nil, + }, { + `{"t":null}`, + "t: null\n", + nil, + }, + } + + runCases(t, RunTypeJSONToYAML, cases) +} + +func TestYAMLToJSON(t *testing.T) { + cases := []Case{ + { + "t: a\n", + `{"t":"a"}`, + nil, + }, { + "t: \n", + `{"t":null}`, + strPtr("t: null\n"), + }, { + "t: null\n", + `{"t":null}`, + nil, + }, { + "1: a\n", + `{"1":"a"}`, + strPtr("\"1\": a\n"), + }, { + "1000000000000000000000000000000000000: a\n", + `{"1e+36":"a"}`, + strPtr("\"1e+36\": a\n"), + }, { + "1e+36: a\n", + `{"1e+36":"a"}`, + strPtr("\"1e+36\": a\n"), + }, { + "\"1e+36\": a\n", + `{"1e+36":"a"}`, + nil, + }, { + "\"1.2\": a\n", + `{"1.2":"a"}`, + nil, + }, { + "- t: a\n", + `[{"t":"a"}]`, + nil, + }, { + "- t: a\n" + + "- t:\n" + + " b: 1\n" + + " c: 2\n", + `[{"t":"a"},{"t":{"b":1,"c":2}}]`, + nil, + }, { + `[{t: a}, {t: {b: 1, c: 2}}]`, + `[{"t":"a"},{"t":{"b":1,"c":2}}]`, + strPtr("- t: a\n" + + "- t:\n" + + " b: 1\n" + + " c: 2\n"), + }, { + "- t: \n", + `[{"t":null}]`, + strPtr("- t: null\n"), + }, { + "- t: null\n", + `[{"t":null}]`, + nil, + }, + } + + // Cases that should produce errors. + _ = []Case{ + { + "~: a", + `{"null":"a"}`, + nil, + }, { + "a: !!binary gIGC\n", + "{\"a\":\"\x80\x81\x82\"}", + nil, + }, + } + + runCases(t, RunTypeYAMLToJSON, cases) +} + +func runCases(t *testing.T, runType RunType, cases []Case) { + var f func([]byte) ([]byte, error) + var invF func([]byte) ([]byte, error) + var msg string + var invMsg string + if runType == RunTypeJSONToYAML { + f = JSONToYAML + invF = YAMLToJSON + msg = "JSON to YAML" + invMsg = "YAML back to JSON" + } else { + f = YAMLToJSON + invF = JSONToYAML + msg = "YAML to JSON" + invMsg = "JSON back to YAML" + } + + for _, c := range cases { + // Convert the string. + fmt.Printf("converting %s\n", c.input) + output, err := f([]byte(c.input)) + if err != nil { + t.Errorf("Failed to convert %s, input: `%s`, err: %v", msg, c.input, err) + } + + // Check it against the expected output. + if string(output) != c.output { + t.Errorf("Failed to convert %s, input: `%s`, expected `%s`, got `%s`", + msg, c.input, c.output, string(output)) + } + + // Set the string that we will compare the reversed output to. + reverse := c.input + // If a special reverse string was specified, use that instead. + if c.reverse != nil { + reverse = *c.reverse + } + + // Reverse the output. + input, err := invF(output) + if err != nil { + t.Errorf("Failed to convert %s, input: `%s`, err: %v", invMsg, string(output), err) + } + + // Check the reverse is equal to the input (or to *c.reverse). + if string(input) != reverse { + t.Errorf("Failed to convert %s, input: `%s`, expected `%s`, got `%s`", + invMsg, string(output), reverse, string(input)) + } + } + +} + +// To be able to easily fill in the *Case.reverse string above. +func strPtr(s string) *string { + return &s +} diff --git a/Godeps/_workspace/src/gopkg.in/v1/yaml/resolve.go b/Godeps/_workspace/src/gopkg.in/v1/yaml/resolve.go deleted file mode 100644 index fdc49098b9a..00000000000 --- a/Godeps/_workspace/src/gopkg.in/v1/yaml/resolve.go +++ /dev/null @@ -1,148 +0,0 @@ -package yaml - -import ( - "math" - "strconv" - "strings" -) - -// TODO: merge, timestamps, base 60 floats, omap. - -type resolveMapItem struct { - value interface{} - tag string -} - -var resolveTable = make([]byte, 256) -var resolveMap = make(map[string]resolveMapItem) - -func init() { - t := resolveTable - t[int('+')] = 'S' // Sign - t[int('-')] = 'S' - for _, c := range "0123456789" { - t[int(c)] = 'D' // Digit - } - for _, c := range "yYnNtTfFoO~" { - t[int(c)] = 'M' // In map - } - t[int('.')] = '.' // Float (potentially in map) - t[int('<')] = '<' // Merge - - var resolveMapList = []struct { - v interface{} - tag string - l []string - }{ - {true, "!!bool", []string{"y", "Y", "yes", "Yes", "YES"}}, - {true, "!!bool", []string{"true", "True", "TRUE"}}, - {true, "!!bool", []string{"on", "On", "ON"}}, - {false, "!!bool", []string{"n", "N", "no", "No", "NO"}}, - {false, "!!bool", []string{"false", "False", "FALSE"}}, - {false, "!!bool", []string{"off", "Off", "OFF"}}, - {nil, "!!null", []string{"~", "null", "Null", "NULL"}}, - {math.NaN(), "!!float", []string{".nan", ".NaN", ".NAN"}}, - {math.Inf(+1), "!!float", []string{".inf", ".Inf", ".INF"}}, - {math.Inf(+1), "!!float", []string{"+.inf", "+.Inf", "+.INF"}}, - {math.Inf(-1), "!!float", []string{"-.inf", "-.Inf", "-.INF"}}, - {"<<", "!!merge", []string{"<<"}}, - } - - m := resolveMap - for _, item := range resolveMapList { - for _, s := range item.l { - m[s] = resolveMapItem{item.v, item.tag} - } - } -} - -const longTagPrefix = "tag:yaml.org,2002:" - -func shortTag(tag string) string { - if strings.HasPrefix(tag, longTagPrefix) { - return "!!" + tag[len(longTagPrefix):] - } - return tag -} - -func resolvableTag(tag string) bool { - switch tag { - case "", "!!str", "!!bool", "!!int", "!!float", "!!null": - return true - } - return false -} - -func resolve(tag string, in string) (rtag string, out interface{}) { - tag = shortTag(tag) - if !resolvableTag(tag) { - return tag, in - } - - defer func() { - if tag != "" && tag != rtag { - panic("Can't decode " + rtag + " '" + in + "' as a " + tag) - } - }() - - if in == "" { - return "!!null", nil - } - - c := resolveTable[in[0]] - if c == 0 { - // It's a string for sure. Nothing to do. - return "!!str", in - } - - // Handle things we can lookup in a map. - if item, ok := resolveMap[in]; ok { - return item.tag, item.value - } - - switch c { - case 'M': - // We've already checked the map above. - - case '.': - // Not in the map, so maybe a normal float. - floatv, err := strconv.ParseFloat(in, 64) - if err == nil { - return "!!float", floatv - } - // XXX Handle base 60 floats here (WTF!) - - case 'D', 'S': - // Int, float, or timestamp. - plain := strings.Replace(in, "_", "", -1) - intv, err := strconv.ParseInt(plain, 0, 64) - if err == nil { - if intv == int64(int(intv)) { - return "!!int", int(intv) - } else { - return "!!int", intv - } - } - floatv, err := strconv.ParseFloat(plain, 64) - if err == nil { - return "!!float", floatv - } - if strings.HasPrefix(plain, "0b") { - intv, err := strconv.ParseInt(plain[2:], 2, 64) - if err == nil { - return "!!int", int(intv) - } - } else if strings.HasPrefix(plain, "-0b") { - intv, err := strconv.ParseInt(plain[3:], 2, 64) - if err == nil { - return "!!int", -int(intv) - } - } - // XXX Handle timestamps here. - - default: - panic("resolveTable item not yet handled: " + - string([]byte{c}) + " (with " + in + ")") - } - return "!!str", in -} diff --git a/Godeps/_workspace/src/gopkg.in/v1/yaml/LICENSE b/Godeps/_workspace/src/gopkg.in/v2/yaml/LICENSE similarity index 99% rename from Godeps/_workspace/src/gopkg.in/v1/yaml/LICENSE rename to Godeps/_workspace/src/gopkg.in/v2/yaml/LICENSE index 53320c352b6..a68e67f01b0 100644 --- a/Godeps/_workspace/src/gopkg.in/v1/yaml/LICENSE +++ b/Godeps/_workspace/src/gopkg.in/v2/yaml/LICENSE @@ -1,3 +1,6 @@ + +Copyright (c) 2011-2014 - Canonical Inc. + This software is licensed under the LGPLv3, included below. As a special exception to the GNU Lesser General Public License version 3 diff --git a/Godeps/_workspace/src/gopkg.in/v1/yaml/LICENSE.libyaml b/Godeps/_workspace/src/gopkg.in/v2/yaml/LICENSE.libyaml similarity index 100% rename from Godeps/_workspace/src/gopkg.in/v1/yaml/LICENSE.libyaml rename to Godeps/_workspace/src/gopkg.in/v2/yaml/LICENSE.libyaml diff --git a/Godeps/_workspace/src/gopkg.in/v1/yaml/README.md b/Godeps/_workspace/src/gopkg.in/v2/yaml/README.md similarity index 79% rename from Godeps/_workspace/src/gopkg.in/v1/yaml/README.md rename to Godeps/_workspace/src/gopkg.in/v2/yaml/README.md index 896687b1d87..d6c919e6073 100644 --- a/Godeps/_workspace/src/gopkg.in/v1/yaml/README.md +++ b/Godeps/_workspace/src/gopkg.in/v2/yaml/README.md @@ -12,31 +12,31 @@ C library to parse and generate YAML data quickly and reliably. Compatibility ------------- -The yaml package is almost compatible with YAML 1.1, including support for -anchors, tags, etc. There are still a few missing bits, such as document -merging, base-60 floats (huh?), and multi-document unmarshalling. These -features are not hard to add, and will be introduced as necessary. +The yaml package supports most of YAML 1.1 and 1.2, including support for +anchors, tags, map merging, etc. Multi-document unmarshalling is not yet +implemented, and base-60 floats from YAML 1.1 are purposefully not +supported since they're a poor design and are gone in YAML 1.2. Installation and usage ---------------------- -The import path for the package is *gopkg.in/yaml.v1*. +The import path for the package is *gopkg.in/yaml.v2*. To install it, run: - go get gopkg.in/yaml.v1 + go get gopkg.in/yaml.v2 API documentation ----------------- If opened in a browser, the import path itself leads to the API documentation: - * [https://gopkg.in/yaml.v1](https://gopkg.in/yaml.v1) + * [https://gopkg.in/yaml.v2](https://gopkg.in/yaml.v2) API stability ------------- -The package API for yaml v1 will remain stable as described in [gopkg.in](https://gopkg.in). +The package API for yaml v2 will remain stable as described in [gopkg.in](https://gopkg.in). License @@ -55,7 +55,7 @@ import ( "fmt" "log" - "gopkg.in/yaml.v1" + "gopkg.in/yaml.v2" ) var data = ` diff --git a/Godeps/_workspace/src/gopkg.in/v1/yaml/apic.go b/Godeps/_workspace/src/gopkg.in/v2/yaml/apic.go similarity index 100% rename from Godeps/_workspace/src/gopkg.in/v1/yaml/apic.go rename to Godeps/_workspace/src/gopkg.in/v2/yaml/apic.go diff --git a/Godeps/_workspace/src/gopkg.in/v1/yaml/decode.go b/Godeps/_workspace/src/gopkg.in/v2/yaml/decode.go similarity index 56% rename from Godeps/_workspace/src/gopkg.in/v1/yaml/decode.go rename to Godeps/_workspace/src/gopkg.in/v2/yaml/decode.go index 74eda3cb0eb..554ed32f7c9 100644 --- a/Godeps/_workspace/src/gopkg.in/v1/yaml/decode.go +++ b/Godeps/_workspace/src/gopkg.in/v2/yaml/decode.go @@ -1,7 +1,11 @@ package yaml import ( + "encoding" + "encoding/base64" + "fmt" "reflect" + "runtime/debug" "strconv" "time" ) @@ -36,7 +40,7 @@ type parser struct { func newParser(b []byte) *parser { p := parser{} if !yaml_parser_initialize(&p.parser) { - panic("Failed to initialize YAML emitter") + panic("failed to initialize YAML emitter") } if len(b) == 0 { @@ -47,7 +51,7 @@ func newParser(b []byte) *parser { p.skip() if p.event.typ != yaml_STREAM_START_EVENT { - panic("Expected stream start event, got " + strconv.Itoa(int(p.event.typ))) + panic("expected stream start event, got " + strconv.Itoa(int(p.event.typ))) } p.skip() return &p @@ -63,7 +67,7 @@ func (p *parser) destroy() { func (p *parser) skip() { if p.event.typ != yaml_NO_EVENT { if p.event.typ == yaml_STREAM_END_EVENT { - panic("Attempted to go past the end of stream. Corrupted value?") + failf("attempted to go past the end of stream; corrupted value?") } yaml_event_delete(&p.event) } @@ -87,9 +91,9 @@ func (p *parser) fail() { if len(p.parser.problem) > 0 { msg = p.parser.problem } else { - msg = "Unknown problem parsing YAML content" + msg = "unknown problem parsing YAML content" } - panic(where + msg) + failf("%s%s", where, msg) } func (p *parser) anchor(n *node, anchor []byte) { @@ -114,10 +118,9 @@ func (p *parser) parse() *node { // Happens when attempting to decode an empty buffer. return nil default: - panic("Attempted to parse unknown event: " + - strconv.Itoa(int(p.event.typ))) + panic("attempted to parse unknown event: " + strconv.Itoa(int(p.event.typ))) } - panic("Unreachable") + panic("unreachable") } func (p *parser) node(kind int) *node { @@ -135,8 +138,7 @@ func (p *parser) document() *node { p.skip() n.children = append(n.children, p.parse()) if p.event.typ != yaml_DOCUMENT_END_EVENT { - panic("Expected end of document event but got " + - strconv.Itoa(int(p.event.typ))) + panic("expected end of document event but got " + strconv.Itoa(int(p.event.typ))) } p.skip() return n @@ -187,84 +189,121 @@ func (p *parser) mapping() *node { type decoder struct { doc *node aliases map[string]bool + mapType reflect.Type + terrors []string } +var ( + mapItemType = reflect.TypeOf(MapItem{}) + durationType = reflect.TypeOf(time.Duration(0)) + defaultMapType = reflect.TypeOf(map[interface{}]interface{}{}) + ifaceType = defaultMapType.Elem() +) + func newDecoder() *decoder { - d := &decoder{} + d := &decoder{mapType: defaultMapType} d.aliases = make(map[string]bool) return d } -// d.setter deals with setters and pointer dereferencing and initialization. -// -// It's a slightly convoluted case to handle properly: -// -// - nil pointers should be initialized, unless being set to nil -// - we don't know at this point yet what's the value to SetYAML() with. -// - we can't separate pointer deref/init and setter checking, because -// a setter may be found while going down a pointer chain. -// -// Thus, here is how it takes care of it: -// -// - out is provided as a pointer, so that it can be replaced. -// - when looking at a non-setter ptr, *out=ptr.Elem(), unless tag=!!null -// - when a setter is found, *out=interface{}, and a set() function is -// returned to call SetYAML() with the value of *out once it's defined. -// -func (d *decoder) setter(tag string, out *reflect.Value, good *bool) (set func()) { - if (*out).Kind() != reflect.Ptr && (*out).CanAddr() { - setter, _ := (*out).Addr().Interface().(Setter) - if setter != nil { - var arg interface{} - *out = reflect.ValueOf(&arg).Elem() - return func() { - *good = setter.SetYAML(tag, arg) - } +func (d *decoder) terror(n *node, tag string, out reflect.Value) { + debug.PrintStack() + if n.tag != "" { + tag = n.tag + } + value := n.value + if tag != yaml_SEQ_TAG && tag != yaml_MAP_TAG { + if len(value) > 10 { + value = " `" + value[:7] + "...`" + } else { + value = " `" + value + "`" } } + d.terrors = append(d.terrors, fmt.Sprintf("line %d: cannot unmarshal %s%s into %s", n.line+1, shortTag(tag), value, out.Type())) +} + +func (d *decoder) callUnmarshaler(n *node, u Unmarshaler) (good bool) { + terrlen := len(d.terrors) + err := u.UnmarshalYAML(func(v interface{}) (err error) { + defer handleErr(&err) + d.unmarshal(n, reflect.ValueOf(v)) + if len(d.terrors) > terrlen { + issues := d.terrors[terrlen:] + d.terrors = d.terrors[:terrlen] + return &TypeError{issues} + } + return nil + }) + if e, ok := err.(*TypeError); ok { + d.terrors = append(d.terrors, e.Errors...) + return false + } + if err != nil { + fail(err) + } + return true +} + +// d.prepare initializes and dereferences pointers and calls UnmarshalYAML +// if a value is found to implement it. +// It returns the initialized and dereferenced out value, whether +// unmarshalling was already done by UnmarshalYAML, and if so whether +// its types unmarshalled appropriately. +// +// If n holds a null value, prepare returns before doing anything. +func (d *decoder) prepare(n *node, out reflect.Value) (newout reflect.Value, unmarshaled, good bool) { + //fmt.Printf("yv2 prepare: out.Kind(): %s\n", out.Kind()) + //fmt.Printf("yv2 prepare: n.tag: %s\n", n.tag) + //fmt.Printf("yv2 prepare: n.value: %s\n", n.value) + //fmt.Printf("yv2 prepare: n.kind: %s\n", n.kind) + if (n.tag == yaml_NULL_TAG) || (n.kind == scalarNode && n.tag == "" && (n.value == "" && n.implicit)) { + //fmt.Printf("yv2 prepare: return immediately\n") + return out, false, false + } + //fmt.Printf("yv2 prepare: continue\n") again := true for again { again = false - setter, _ := (*out).Interface().(Setter) - if tag != "!!null" || setter != nil { - if pv := (*out); pv.Kind() == reflect.Ptr { - if pv.IsNil() { - *out = reflect.New(pv.Type().Elem()).Elem() - pv.Set((*out).Addr()) - } else { - *out = pv.Elem() - } - setter, _ = pv.Interface().(Setter) - again = true + if out.Kind() == reflect.Ptr { + //fmt.Printf("yv2 prepare: hit Ptr %s\n", out.Kind()) + if out.IsNil() { + out.Set(reflect.New(out.Type().Elem())) } + out = out.Elem() + again = true } - if setter != nil { - var arg interface{} - *out = reflect.ValueOf(&arg).Elem() - return func() { - *good = setter.SetYAML(tag, arg) + if out.CanAddr() { + if u, ok := out.Addr().Interface().(Unmarshaler); ok { + good = d.callUnmarshaler(n, u) + return out, true, good } } } - return nil + return out, false, false } func (d *decoder) unmarshal(n *node, out reflect.Value) (good bool) { switch n.kind { case documentNode: - good = d.document(n, out) + return d.document(n, out) + case aliasNode: + return d.alias(n, out) + } + out, unmarshaled, good := d.prepare(n, out) + if unmarshaled { + return good + } + switch n.kind { case scalarNode: good = d.scalar(n, out) - case aliasNode: - good = d.alias(n, out) case mappingNode: good = d.mapping(n, out) case sequenceNode: good = d.sequence(n, out) default: - panic("Internal error: unknown node kind: " + strconv.Itoa(n.kind)) + panic("internal error: unknown node kind: " + strconv.Itoa(n.kind)) } - return + return good } func (d *decoder) document(n *node, out reflect.Value) (good bool) { @@ -279,10 +318,10 @@ func (d *decoder) document(n *node, out reflect.Value) (good bool) { func (d *decoder) alias(n *node, out reflect.Value) (good bool) { an, ok := d.doc.anchors[n.value] if !ok { - panic("Unknown anchor '" + n.value + "' referenced") + failf("unknown anchor '%s' referenced", n.value) } if d.aliases[n.value] { - panic("Anchor '" + n.value + "' value contains itself") + failf("anchor '%s' value contains itself", n.value) } d.aliases[n.value] = true good = d.unmarshal(an, out) @@ -290,23 +329,65 @@ func (d *decoder) alias(n *node, out reflect.Value) (good bool) { return good } -var durationType = reflect.TypeOf(time.Duration(0)) +var zeroValue reflect.Value + +func resetMap(out reflect.Value) { + for _, k := range out.MapKeys() { + out.SetMapIndex(k, zeroValue) + } +} func (d *decoder) scalar(n *node, out reflect.Value) (good bool) { + //fmt.Printf("yv2 1 tag: %s, implicit: %v, out.Type(): %s\n", n.tag, n.implicit, out.Type()) + //fmt.Printf("yv2 n.value: %v\n", n.value) + //fmt.Printf("yv2 n.kind: %v\n", n.kind) + //fmt.Printf("yv2 n.tag: %v\n", n.tag) var tag string var resolved interface{} if n.tag == "" && !n.implicit { - tag = "!!str" + //fmt.Printf("yv2 2\n") + tag = yaml_STR_TAG resolved = n.value } else { + //fmt.Printf("yv2 3\n") tag, resolved = resolve(n.tag, n.value) + if tag == yaml_BINARY_TAG { + data, err := base64.StdEncoding.DecodeString(resolved.(string)) + if err != nil { + failf("!!binary value contains invalid base64 data") + } + resolved = string(data) + } } - if set := d.setter(tag, &out, &good); set != nil { - defer set() + //fmt.Printf("yv2 4\n") + if resolved == nil { + //fmt.Printf("yv2 5\n") + if out.Kind() == reflect.Map && !out.CanAddr() { + resetMap(out) + } else { + out.Set(reflect.Zero(out.Type())) + } + return true } + if s, ok := resolved.(string); ok && out.CanAddr() { + //fmt.Printf("yv2 6") + if u, ok := out.Addr().Interface().(encoding.TextUnmarshaler); ok { + err := u.UnmarshalText([]byte(s)) + if err != nil { + fail(err) + } + return true + } + } + //fmt.Printf("yv2 resolved tag: %v\n", tag) + //fmt.Printf("yv2 resolved: %v\n", resolved) + //fmt.Printf("yv2 resolved type: %v\n", reflect.TypeOf(resolved)) switch out.Kind() { case reflect.String: - if resolved != nil { + if tag == yaml_BINARY_TAG { + out.SetString(resolved.(string)) + good = true + } else if resolved != nil { out.SetString(n.value) good = true } @@ -380,19 +461,17 @@ func (d *decoder) scalar(n *node, out reflect.Value) (good bool) { good = true } case reflect.Ptr: - switch resolved.(type) { - case nil: - out.Set(reflect.Zero(out.Type())) + if out.Type().Elem() == reflect.TypeOf(resolved) { + // TODO DOes this make sense? When is out a Ptr except when decoding a nil value? + elem := reflect.New(out.Type().Elem()) + elem.Elem().Set(reflect.ValueOf(resolved)) + out.Set(elem) good = true - default: - if out.Type().Elem() == reflect.TypeOf(resolved) { - elem := reflect.New(out.Type().Elem()) - elem.Elem().Set(reflect.ValueOf(resolved)) - out.Set(elem) - good = true - } } } + if !good { + d.terror(n, tag, out) + } return good } @@ -404,17 +483,16 @@ func settableValueOf(i interface{}) reflect.Value { } func (d *decoder) sequence(n *node, out reflect.Value) (good bool) { - if set := d.setter("!!seq", &out, &good); set != nil { - defer set() - } var iface reflect.Value - if out.Kind() == reflect.Interface { + switch out.Kind() { + case reflect.Slice: + // okay + case reflect.Interface: // No type hints. Will have to use a generic sequence. iface = out out = settableValueOf(make([]interface{}, 0)) - } - - if out.Kind() != reflect.Slice { + default: + d.terror(n, yaml_SEQ_TAG, out) return false } et := out.Type().Elem() @@ -433,27 +511,39 @@ func (d *decoder) sequence(n *node, out reflect.Value) (good bool) { } func (d *decoder) mapping(n *node, out reflect.Value) (good bool) { - if set := d.setter("!!map", &out, &good); set != nil { - defer set() - } - if out.Kind() == reflect.Struct { + switch out.Kind() { + case reflect.Struct: return d.mappingStruct(n, out) - } - - if out.Kind() == reflect.Interface { - // No type hints. Will have to use a generic map. - iface := out - out = settableValueOf(make(map[interface{}]interface{})) - iface.Set(out) - } - - if out.Kind() != reflect.Map { + case reflect.Slice: + return d.mappingSlice(n, out) + case reflect.Map: + // okay + case reflect.Interface: + if d.mapType.Kind() == reflect.Map { + iface := out + out = reflect.MakeMap(d.mapType) + iface.Set(out) + } else { + slicev := reflect.New(d.mapType).Elem() + if !d.mappingSlice(n, slicev) { + return false + } + out.Set(slicev) + return true + } + default: + d.terror(n, yaml_MAP_TAG, out) return false } outt := out.Type() kt := outt.Key() et := outt.Elem() + mapType := d.mapType + if outt.Key() == ifaceType && outt.Elem() == ifaceType { + d.mapType = outt + } + if out.IsNil() { out.Set(reflect.MakeMap(outt)) } @@ -465,12 +555,51 @@ func (d *decoder) mapping(n *node, out reflect.Value) (good bool) { } k := reflect.New(kt).Elem() if d.unmarshal(n.children[i], k) { + kkind := k.Kind() + if kkind == reflect.Interface { + kkind = k.Elem().Kind() + } + if kkind == reflect.Map || kkind == reflect.Slice { + failf("invalid map key: %#v", k.Interface()) + } e := reflect.New(et).Elem() if d.unmarshal(n.children[i+1], e) { out.SetMapIndex(k, e) } } } + d.mapType = mapType + return true +} + +func (d *decoder) mappingSlice(n *node, out reflect.Value) (good bool) { + outt := out.Type() + if outt.Elem() != mapItemType { + d.terror(n, yaml_MAP_TAG, out) + return false + } + + mapType := d.mapType + d.mapType = outt + + var slice []MapItem + var l = len(n.children) + for i := 0; i < l; i += 2 { + if isMerge(n.children[i]) { + d.merge(n.children[i+1], out) + continue + } + item := MapItem{} + k := reflect.ValueOf(&item.Key).Elem() + if d.unmarshal(n.children[i], k) { + v := reflect.ValueOf(&item.Value).Elem() + if d.unmarshal(n.children[i+1], v) { + slice = append(slice, item) + } + } + } + out.Set(reflect.ValueOf(slice)) + d.mapType = mapType return true } @@ -503,36 +632,39 @@ func (d *decoder) mappingStruct(n *node, out reflect.Value) (good bool) { return true } +func failWantMap() { + failf("map merge requires map or sequence of maps as the value") +} + func (d *decoder) merge(n *node, out reflect.Value) { - const wantMap = "map merge requires map or sequence of maps as the value" switch n.kind { case mappingNode: d.unmarshal(n, out) case aliasNode: an, ok := d.doc.anchors[n.value] if ok && an.kind != mappingNode { - panic(wantMap) + failWantMap() } d.unmarshal(n, out) case sequenceNode: // Step backwards as earlier nodes take precedence. - for i := len(n.children)-1; i >= 0; i-- { + for i := len(n.children) - 1; i >= 0; i-- { ni := n.children[i] if ni.kind == aliasNode { an, ok := d.doc.anchors[ni.value] if ok && an.kind != mappingNode { - panic(wantMap) + failWantMap() } } else if ni.kind != mappingNode { - panic(wantMap) + failWantMap() } d.unmarshal(ni, out) } default: - panic(wantMap) + failWantMap() } } func isMerge(n *node) bool { - return n.kind == scalarNode && n.value == "<<" && (n.implicit == true || n.tag == "!!merge" || n.tag == "tag:yaml.org,2002:merge") + return n.kind == scalarNode && n.value == "<<" && (n.implicit == true || n.tag == yaml_MERGE_TAG) } diff --git a/Godeps/_workspace/src/gopkg.in/v1/yaml/decode_test.go b/Godeps/_workspace/src/gopkg.in/v2/yaml/decode_test.go similarity index 56% rename from Godeps/_workspace/src/gopkg.in/v1/yaml/decode_test.go rename to Godeps/_workspace/src/gopkg.in/v2/yaml/decode_test.go index d2b45b37df4..96361fac3c7 100644 --- a/Godeps/_workspace/src/gopkg.in/v1/yaml/decode_test.go +++ b/Godeps/_workspace/src/gopkg.in/v2/yaml/decode_test.go @@ -1,11 +1,17 @@ package yaml_test import ( - . "gopkg.in/check.v1" - "gopkg.in/yaml.v1" + "errors" + "fmt" "math" + "net" "reflect" + "strings" "time" + + "github.com/davecgh/go-spew/spew" + . "gopkg.in/check.v1" + "gopkg.in/v2/yaml" ) var unmarshalIntTest = 123 @@ -199,7 +205,7 @@ var unmarshalTests = []struct { // Map inside interface with no type hints. { "a: {b: c}", - map[string]interface{}{"a": map[interface{}]interface{}{"b": "c"}}, + map[interface{}]interface{}{"a": map[interface{}]interface{}{"b": "c"}}, }, // Structs and type conversions. @@ -316,7 +322,10 @@ var unmarshalTests = []struct { map[string]*string{"foo": new(string)}, }, { "foo: null", - map[string]string{}, + map[string]string{"foo": ""}, + }, { + "foo: null", + map[string]interface{}{"foo": nil}, }, // Ignored field @@ -371,8 +380,58 @@ var unmarshalTests = []struct { "a: 3s", map[string]time.Duration{"a": 3 * time.Second}, }, + + // Issue #24. + { + "a: ", + map[string]string{"a": ""}, + }, + + // Base 60 floats are obsolete and unsupported. + { + "a: 1:1\n", + map[string]string{"a": "1:1"}, + }, + + // Binary data. + { + "a: !!binary gIGC\n", + map[string]string{"a": "\x80\x81\x82"}, + }, { + "a: !!binary |\n " + strings.Repeat("kJCQ", 17) + "kJ\n CQ\n", + map[string]string{"a": strings.Repeat("\x90", 54)}, + }, { + "a: !!binary |\n " + strings.Repeat("A", 70) + "\n ==\n", + map[string]string{"a": strings.Repeat("\x00", 52)}, + }, + + // Ordered maps. + { + "{b: 2, a: 1, d: 4, c: 3, sub: {e: 5}}", + &yaml.MapSlice{{"b", 2}, {"a", 1}, {"d", 4}, {"c", 3}, {"sub", yaml.MapSlice{{"e", 5}}}}, + }, + + // Issue #39. + { + "a:\n b:\n c: d\n", + map[string]struct{ B interface{} }{"a": {map[interface{}]interface{}{"c": "d"}}}, + }, + + // Custom map type. + { + "a: {b: c}", + M{"a": M{"b": "c"}}, + }, + + // Support encoding.TextUnmarshaler. + { + "a: 1.2.3.4\n", + map[string]net.IP{"a": net.IPv4(1, 2, 3, 4)}, + }, } +type M map[interface{}]interface{} + type inlineB struct { B int inlineC `yaml:",inline"` @@ -383,27 +442,33 @@ type inlineC struct { } func (s *S) TestUnmarshal(c *C) { - for i, item := range unmarshalTests { + for _, item := range unmarshalTests { t := reflect.ValueOf(item.value).Type() var value interface{} switch t.Kind() { case reflect.Map: value = reflect.MakeMap(t).Interface() case reflect.String: - t := reflect.ValueOf(item.value).Type() - v := reflect.New(t) - value = v.Interface() + value = reflect.New(t).Interface() + case reflect.Ptr: + value = reflect.New(t.Elem()).Interface() default: - pt := reflect.ValueOf(item.value).Type() - pv := reflect.New(pt.Elem()) - value = pv.Interface() + c.Fatalf("missing case for %s", t) } err := yaml.Unmarshal([]byte(item.data), value) - c.Assert(err, IsNil, Commentf("Item #%d", i)) + if _, ok := err.(*yaml.TypeError); !ok { + c.Assert(err, IsNil) + } if t.Kind() == reflect.String { - c.Assert(*value.(*string), Equals, item.value, Commentf("Item #%d", i)) + c.Assert(*value.(*string), Equals, item.value) } else { - c.Assert(value, DeepEquals, item.value, Commentf("Item #%d", i)) + if !c.Check(value, DeepEquals, item.value) { + fmt.Printf("Spew:\n") + spew.Dump(item.data) + spew.Dump(item.value) + spew.Dump(value) + return + } } } } @@ -418,12 +483,15 @@ func (s *S) TestUnmarshalNaN(c *C) { var unmarshalErrorTests = []struct { data, error string }{ - {"v: !!float 'error'", "YAML error: Can't decode !!str 'error' as a !!float"}, - {"v: [A,", "YAML error: line 1: did not find expected node content"}, - {"v:\n- [A,", "YAML error: line 2: did not find expected node content"}, - {"a: *b\n", "YAML error: Unknown anchor 'b' referenced"}, - {"a: &a\n b: *a\n", "YAML error: Anchor 'a' value contains itself"}, - {"value: -", "YAML error: block sequence entries are not allowed in this context"}, + {"v: !!float 'error'", "yaml: cannot decode !!str `error` as a !!float"}, + {"v: [A,", "yaml: line 1: did not find expected node content"}, + {"v:\n- [A,", "yaml: line 2: did not find expected node content"}, + {"a: *b\n", "yaml: unknown anchor 'b' referenced"}, + {"a: &a\n b: *a\n", "yaml: anchor 'a' value contains itself"}, + {"value: -", "yaml: block sequence entries are not allowed in this context"}, + {"a: !!binary ==", "yaml: !!binary value contains invalid base64 data"}, + {"{[.]}", `yaml: invalid map key: \[\]interface \{\}\{"\."\}`}, + {"{{.}}", `yaml: invalid map key: map\[interface\ \{\}\]interface \{\}\{".":interface \{\}\(nil\)\}`}, } func (s *S) TestUnmarshalErrors(c *C) { @@ -434,7 +502,7 @@ func (s *S) TestUnmarshalErrors(c *C) { } } -var setterTests = []struct { +var unmarshalerTests = []struct { data, tag string value interface{} }{ @@ -447,92 +515,155 @@ var setterTests = []struct { {"_: !!foo 'BAR!'", "!!foo", "BAR!"}, } -var setterResult = map[int]bool{} +var unmarshalerResult = map[int]error{} -type typeWithSetter struct { - tag string +type unmarshalerType struct { value interface{} } -func (o *typeWithSetter) SetYAML(tag string, value interface{}) (ok bool) { - o.tag = tag - o.value = value - if i, ok := value.(int); ok { - if result, ok := setterResult[i]; ok { +func (o *unmarshalerType) UnmarshalYAML(unmarshal func(v interface{}) error) error { + if err := unmarshal(&o.value); err != nil { + return err + } + if i, ok := o.value.(int); ok { + if result, ok := unmarshalerResult[i]; ok { return result } } - return true + return nil } -type setterPointerType struct { - Field *typeWithSetter "_" +type unmarshalerPointer struct { + Field *unmarshalerType "_" } -type setterValueType struct { - Field typeWithSetter "_" +type unmarshalerValue struct { + Field unmarshalerType "_" } -func (s *S) TestUnmarshalWithPointerSetter(c *C) { - for _, item := range setterTests { - obj := &setterPointerType{} +func (s *S) TestUnmarshalerPointerField(c *C) { + for _, item := range unmarshalerTests { + obj := &unmarshalerPointer{} + err := yaml.Unmarshal([]byte(item.data), obj) + c.Assert(err, IsNil) + if item.value == nil { + c.Assert(obj.Field, IsNil) + } else { + c.Assert(obj.Field, NotNil, Commentf("Pointer not initialized (%#v)", item.value)) + c.Assert(obj.Field.value, DeepEquals, item.value) + } + } +} + +func (s *S) TestUnmarshalerValueField(c *C) { + for _, item := range unmarshalerTests { + obj := &unmarshalerValue{} err := yaml.Unmarshal([]byte(item.data), obj) c.Assert(err, IsNil) c.Assert(obj.Field, NotNil, Commentf("Pointer not initialized (%#v)", item.value)) - c.Assert(obj.Field.tag, Equals, item.tag) c.Assert(obj.Field.value, DeepEquals, item.value) } } -func (s *S) TestUnmarshalWithValueSetter(c *C) { - for _, item := range setterTests { - obj := &setterValueType{} - err := yaml.Unmarshal([]byte(item.data), obj) - c.Assert(err, IsNil) - c.Assert(obj.Field, NotNil, Commentf("Pointer not initialized (%#v)", item.value)) - c.Assert(obj.Field.tag, Equals, item.tag) - c.Assert(obj.Field.value, DeepEquals, item.value) - } -} - -func (s *S) TestUnmarshalWholeDocumentWithSetter(c *C) { - obj := &typeWithSetter{} - err := yaml.Unmarshal([]byte(setterTests[0].data), obj) +func (s *S) TestUnmarshalerWholeDocument(c *C) { + obj := &unmarshalerType{} + err := yaml.Unmarshal([]byte(unmarshalerTests[0].data), obj) c.Assert(err, IsNil) - c.Assert(obj.tag, Equals, setterTests[0].tag) value, ok := obj.value.(map[interface{}]interface{}) - c.Assert(ok, Equals, true) - c.Assert(value["_"], DeepEquals, setterTests[0].value) + c.Assert(ok, Equals, true, Commentf("value: %#v", obj.value)) + c.Assert(value["_"], DeepEquals, unmarshalerTests[0].value) } -func (s *S) TestUnmarshalWithFalseSetterIgnoresValue(c *C) { - setterResult[2] = false - setterResult[4] = false +func (s *S) TestUnmarshalerTypeError(c *C) { + unmarshalerResult[2] = &yaml.TypeError{[]string{"foo"}} + unmarshalerResult[4] = &yaml.TypeError{[]string{"bar"}} defer func() { - delete(setterResult, 2) - delete(setterResult, 4) + delete(unmarshalerResult, 2) + delete(unmarshalerResult, 4) }() - m := map[string]*typeWithSetter{} - data := `{abc: 1, def: 2, ghi: 3, jkl: 4}` - err := yaml.Unmarshal([]byte(data), m) - c.Assert(err, IsNil) - c.Assert(m["abc"], NotNil) - c.Assert(m["def"], IsNil) - c.Assert(m["ghi"], NotNil) - c.Assert(m["jkl"], IsNil) + type T struct { + Before int + After int + M map[string]*unmarshalerType + } + var v T + data := `{before: A, m: {abc: 1, def: 2, ghi: 3, jkl: 4}, after: B}` + err := yaml.Unmarshal([]byte(data), &v) + c.Assert(err, ErrorMatches, ""+ + "yaml: unmarshal errors:\n"+ + " line 1: cannot unmarshal !!str `A` into int\n"+ + " foo\n"+ + " bar\n"+ + " line 1: cannot unmarshal !!str `B` into int") + c.Assert(v.M["abc"], NotNil) + c.Assert(v.M["def"], IsNil) + c.Assert(v.M["ghi"], NotNil) + c.Assert(v.M["jkl"], IsNil) - c.Assert(m["abc"].value, Equals, 1) - c.Assert(m["ghi"].value, Equals, 3) + c.Assert(v.M["abc"].value, Equals, 1) + c.Assert(v.M["ghi"].value, Equals, 3) +} + +type proxyTypeError struct{} + +func (v *proxyTypeError) UnmarshalYAML(unmarshal func(interface{}) error) error { + var s string + var a int32 + var b int64 + if err := unmarshal(&s); err != nil { + panic(err) + } + if s == "a" { + if err := unmarshal(&b); err == nil { + panic("should have failed") + } + return unmarshal(&a) + } + if err := unmarshal(&a); err == nil { + panic("should have failed") + } + return unmarshal(&b) +} + +func (s *S) TestUnmarshalerTypeErrorProxying(c *C) { + type T struct { + Before int + After int + M map[string]*proxyTypeError + } + var v T + data := `{before: A, m: {abc: a, def: b}, after: B}` + err := yaml.Unmarshal([]byte(data), &v) + c.Assert(err, ErrorMatches, ""+ + "yaml: unmarshal errors:\n"+ + " line 1: cannot unmarshal !!str `A` into int\n"+ + " line 1: cannot unmarshal !!str `a` into int32\n"+ + " line 1: cannot unmarshal !!str `b` into int64\n"+ + " line 1: cannot unmarshal !!str `B` into int") +} + +type failingUnmarshaler struct{} + +var failingErr = errors.New("failingErr") + +func (ft *failingUnmarshaler) UnmarshalYAML(unmarshal func(interface{}) error) error { + return failingErr +} + +func (s *S) TestUnmarshalerError(c *C) { + err := yaml.Unmarshal([]byte("a: b"), &failingUnmarshaler{}) + c.Assert(err, Equals, failingErr) } // From http://yaml.org/type/merge.html var mergeTests = ` anchors: - - &CENTER { "x": 1, "y": 2 } - - &LEFT { "x": 0, "y": 2 } - - &BIG { "r": 10 } - - &SMALL { "r": 1 } + list: + - &CENTER { "x": 1, "y": 2 } + - &LEFT { "x": 0, "y": 2 } + - &BIG { "r": 10 } + - &SMALL { "r": 1 } # All the following maps are equal: @@ -589,7 +720,7 @@ func (s *S) TestMerge(c *C) { "label": "center/big", } - var m map[string]interface{} + var m map[interface{}]interface{} err := yaml.Unmarshal([]byte(mergeTests), &m) c.Assert(err, IsNil) for name, test := range m { @@ -618,6 +749,85 @@ func (s *S) TestMergeStruct(c *C) { } } +var unmarshalNullTests = []func() interface{}{ + func() interface{} { var v interface{}; v = "v"; return &v }, + func() interface{} { var s = "s"; return &s }, + func() interface{} { var s = "s"; sptr := &s; return &sptr }, + func() interface{} { var i = 1; return &i }, + func() interface{} { var i = 1; iptr := &i; return &iptr }, + func() interface{} { m := map[string]int{"s": 1}; return &m }, + func() interface{} { m := map[string]int{"s": 1}; return m }, +} + +func (s *S) TestUnmarshalNull(c *C) { + for _, test := range unmarshalNullTests { + item := test() + zero := reflect.Zero(reflect.TypeOf(item).Elem()).Interface() + err := yaml.Unmarshal([]byte("null"), item) + c.Assert(err, IsNil) + if reflect.TypeOf(item).Kind() == reflect.Map { + c.Assert(reflect.ValueOf(item).Interface(), DeepEquals, reflect.MakeMap(reflect.TypeOf(item)).Interface()) + } else { + c.Assert(reflect.ValueOf(item).Elem().Interface(), DeepEquals, zero) + } + } +} + +type StringStructContainer struct { + Val StringStruct +} + +type StringStruct struct { + StrVal string + UnmarshalCalled bool // to be able to check that UnmarshalYAML was actually called +} + +// UnmarshalYAML implements the yaml.Unmarshaler interface. +func (s *StringStruct) UnmarshalYAML(unmarshal func(interface{}) error) error { + var value *string + if err := unmarshal(&value); err != nil { + return err + } + s.StrVal = *value + s.UnmarshalCalled = true + return nil +} + +// If a node value is a literal empty string (i.e.: "") but the corresponding +// object to Unmarshal to is a struct or a pointer to a struct, the struct must +// have UnmarshalYAML() called on it with an empty string. +func (s *S) TestUnmarshalEmptyStringToStruct(c *C) { + //j := []byte(`{"val": "null"}`) + // Literal empty string should call UnmarshalYAML. + j := []byte("val: \"\"\n") + v := new(StringStructContainer) + err := yaml.Unmarshal(j, v) + c.Assert(err, IsNil) + c.Assert(v.Val.StrVal, Equals, "") + c.Assert(v.Val.UnmarshalCalled, Equals, true) +} + +func (s *S) TestUnmarshalNullStringToStruct(c *C) { + // "null" string should not call UnmarshalYAML, but instead produce a zero object. + j := []byte("val: null\n") + v := new(StringStructContainer) + err := yaml.Unmarshal(j, v) + c.Assert(err, IsNil) + c.Assert(v.Val.StrVal, Equals, "") + c.Assert(v.Val.UnmarshalCalled, Equals, false) +} + +// "Implicit" document ending should not call UnmarshalYAML, but instead produce a blank object. +func (s *S) TestUnmarshalImplicitEndingToStruct(c *C) { + // "null" string should not call UnmarshalYAML, but instead produce a zero object. + j := []byte("val: \n") + v := new(StringStructContainer) + err := yaml.Unmarshal(j, v) + c.Assert(err, IsNil) + c.Assert(v.Val.StrVal, Equals, "") + c.Assert(v.Val.UnmarshalCalled, Equals, false) +} + //var data []byte //func init() { // var err error diff --git a/Godeps/_workspace/src/gopkg.in/v1/yaml/emitterc.go b/Godeps/_workspace/src/gopkg.in/v2/yaml/emitterc.go similarity index 99% rename from Godeps/_workspace/src/gopkg.in/v1/yaml/emitterc.go rename to Godeps/_workspace/src/gopkg.in/v2/yaml/emitterc.go index 542ffd278aa..9b3dc4a4370 100644 --- a/Godeps/_workspace/src/gopkg.in/v1/yaml/emitterc.go +++ b/Godeps/_workspace/src/gopkg.in/v2/yaml/emitterc.go @@ -973,8 +973,8 @@ func yaml_emitter_analyze_tag(emitter *yaml_emitter_t, tag []byte) bool { if bytes.HasPrefix(tag, tag_directive.prefix) { emitter.tag_data.handle = tag_directive.handle emitter.tag_data.suffix = tag[len(tag_directive.prefix):] + return true } - return true } emitter.tag_data.suffix = tag return true @@ -1279,6 +1279,9 @@ func yaml_emitter_write_tag_content(emitter *yaml_emitter_t, value []byte, need_ for k := 0; k < w; k++ { octet := value[i] i++ + if !put(emitter, '%') { + return false + } c := octet >> 4 if c < 10 { diff --git a/Godeps/_workspace/src/gopkg.in/v1/yaml/encode.go b/Godeps/_workspace/src/gopkg.in/v2/yaml/encode.go similarity index 61% rename from Godeps/_workspace/src/gopkg.in/v1/yaml/encode.go rename to Godeps/_workspace/src/gopkg.in/v2/yaml/encode.go index 1d928b00d8e..82df176f76d 100644 --- a/Godeps/_workspace/src/gopkg.in/v1/yaml/encode.go +++ b/Godeps/_workspace/src/gopkg.in/v2/yaml/encode.go @@ -1,9 +1,12 @@ package yaml import ( + "encoding" "reflect" + "regexp" "sort" "strconv" + "strings" "time" ) @@ -18,6 +21,7 @@ func newEncoder() (e *encoder) { e = &encoder{} e.must(yaml_emitter_initialize(&e.emitter)) yaml_emitter_set_output_string(&e.emitter, &e.out) + yaml_emitter_set_unicode(&e.emitter, true) e.must(yaml_stream_start_event_initialize(&e.event, yaml_UTF8_ENCODING)) e.emit() e.must(yaml_document_start_event_initialize(&e.event, nil, nil, true)) @@ -48,24 +52,45 @@ func (e *encoder) must(ok bool) { if !ok { msg := e.emitter.problem if msg == "" { - msg = "Unknown problem generating YAML content" + msg = "unknown problem generating YAML content" } - panic(msg) + failf("%s", msg) } } func (e *encoder) marshal(tag string, in reflect.Value) { - var value interface{} - if getter, ok := in.Interface().(Getter); ok { - tag, value = getter.GetYAML() - if value == nil { + if !in.IsValid() { + e.nilv() + return + } + //fmt.Printf("marshal 1 in: %s\n", in) + iface := in.Interface() + //fmt.Printf("marshal 1 iface: %s\n", iface) + if m, ok := iface.(Marshaler); ok { + //fmt.Printf("marshal 1 calling MarshalYAML\n") + v, err := m.MarshalYAML() + if err != nil { + fail(err) + } + if v == nil { e.nilv() return } - in = reflect.ValueOf(value) + in = reflect.ValueOf(v) + } else if m, ok := iface.(encoding.TextMarshaler); ok { + text, err := m.MarshalText() + if err != nil { + fail(err) + } + in = reflect.ValueOf(string(text)) } + //fmt.Printf("marshal 2 in: %s\n", in) + //fmt.Printf("marshal 2 in string: %s\n", in.String()) + //fmt.Printf("marshal 2 in Kind: %s\n", in.Kind()) + //fmt.Printf("marshal 2.5 in Kind: %s\n", in.Kind()) switch in.Kind() { case reflect.Interface: + //fmt.Printf("marshal 3\n") if in.IsNil() { e.nilv() } else { @@ -74,20 +99,27 @@ func (e *encoder) marshal(tag string, in reflect.Value) { case reflect.Map: e.mapv(tag, in) case reflect.Ptr: + //fmt.Printf("marshal 4\n") if in.IsNil() { e.nilv() } else { e.marshal(tag, in.Elem()) } case reflect.Struct: + //fmt.Printf("marshal 5\n") e.structv(tag, in) case reflect.Slice: - e.slicev(tag, in) + if in.Type().Elem() == mapItemType { + e.itemsv(tag, in) + } else { + e.slicev(tag, in) + } case reflect.String: + //fmt.Printf("marshal 6 in.String: \n", in.String()) e.stringv(tag, in) case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: if in.Type() == durationType { - e.stringv(tag, reflect.ValueOf(in.Interface().(time.Duration).String())) + e.stringv(tag, reflect.ValueOf(iface.(time.Duration).String())) } else { e.intv(tag, in) } @@ -98,7 +130,7 @@ func (e *encoder) marshal(tag string, in reflect.Value) { case reflect.Bool: e.boolv(tag, in) default: - panic("Can't marshal type yet: " + in.Type().String()) + panic("cannot marshal type: " + in.Type().String()) } } @@ -113,6 +145,16 @@ func (e *encoder) mapv(tag string, in reflect.Value) { }) } +func (e *encoder) itemsv(tag string, in reflect.Value) { + e.mappingv(tag, func() { + slice := in.Convert(reflect.TypeOf([]MapItem{})).Interface().([]MapItem) + for _, item := range slice { + e.marshal("", reflect.ValueOf(item.Key)) + e.marshal("", reflect.ValueOf(item.Value)) + } + }) +} + func (e *encoder) structv(tag string, in reflect.Value) { sinfo, err := getStructInfo(in.Type()) if err != nil { @@ -131,6 +173,7 @@ func (e *encoder) structv(tag string, in reflect.Value) { } e.marshal("", reflect.ValueOf(info.Key)) e.flow = info.Flow + //fmt.Printf("structv mappingv value: %s\n", value) e.marshal("", value) } }) @@ -167,14 +210,54 @@ func (e *encoder) slicev(tag string, in reflect.Value) { e.emit() } +// isBase60 returns whether s is in base 60 notation as defined in YAML 1.1. +// +// The base 60 float notation in YAML 1.1 is a terrible idea and is unsupported +// in YAML 1.2 and by this package, but these should be marshalled quoted for +// the time being for compatibility with other parsers. +func isBase60Float(s string) (result bool) { + // Fast path. + if s == "" { + return false + } + c := s[0] + if !(c == '+' || c == '-' || c >= '0' && c <= '9') || strings.IndexByte(s, ':') < 0 { + return false + } + // Do the full match. + return base60float.MatchString(s) +} + +// From http://yaml.org/type/float.html, except the regular expression there +// is bogus. In practice parsers do not enforce the "\.[0-9_]*" suffix. +var base60float = regexp.MustCompile(`^[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+(?:\.[0-9_]*)?$`) + func (e *encoder) stringv(tag string, in reflect.Value) { + //fmt.Printf("stringv 1\n") var style yaml_scalar_style_t s := in.String() - if rtag, _ := resolve("", s); rtag != "!!str" { + //fmt.Printf("stringv 1 s: %s\n", s) + rtag, rs := resolve("", s) + if rtag == yaml_BINARY_TAG { + //fmt.Printf("stringv 2\n") + if tag == "" || tag == yaml_STR_TAG { + tag = rtag + s = rs.(string) + //fmt.Printf("stringv 3 s: %s\n", s) + } else if tag == yaml_BINARY_TAG { + failf("explicitly tagged !!binary data must be base64-encoded") + } else { + failf("cannot marshal invalid UTF-8 data as %s", shortTag(tag)) + } + } + if tag == "" && (rtag != yaml_STR_TAG || isBase60Float(s)) { style = yaml_DOUBLE_QUOTED_SCALAR_STYLE + } else if strings.Contains(s, "\n") { + style = yaml_LITERAL_SCALAR_STYLE } else { style = yaml_PLAIN_SCALAR_STYLE } + //fmt.Printf("stringv 4 style: %s\n", style) e.emitScalar(s, "", tag, style) } @@ -218,9 +301,6 @@ func (e *encoder) nilv() { func (e *encoder) emitScalar(value, anchor, tag string, style yaml_scalar_style_t) { implicit := tag == "" - if !implicit { - style = yaml_PLAIN_SCALAR_STYLE - } e.must(yaml_scalar_event_initialize(&e.event, []byte(anchor), []byte(tag), []byte(value), implicit, implicit, style)) e.emit() } diff --git a/Godeps/_workspace/src/gopkg.in/v1/yaml/encode_test.go b/Godeps/_workspace/src/gopkg.in/v2/yaml/encode_test.go similarity index 71% rename from Godeps/_workspace/src/gopkg.in/v1/yaml/encode_test.go rename to Godeps/_workspace/src/gopkg.in/v2/yaml/encode_test.go index c7461d5731a..cdbf64a9d6a 100644 --- a/Godeps/_workspace/src/gopkg.in/v1/yaml/encode_test.go +++ b/Godeps/_workspace/src/gopkg.in/v2/yaml/encode_test.go @@ -2,12 +2,14 @@ package yaml_test import ( "fmt" - "gopkg.in/yaml.v1" - . "gopkg.in/check.v1" "math" "strconv" "strings" "time" + + . "gopkg.in/check.v1" + "gopkg.in/yaml.v2" + "net" ) var marshalIntTest = 123 @@ -17,6 +19,9 @@ var marshalTests = []struct { data string }{ { + nil, + "null\n", + }, { &struct{}{}, "{}\n", }, { @@ -87,7 +92,7 @@ var marshalTests = []struct { "v:\n- A\n- B\n", }, { map[string][]string{"v": []string{"A", "B\nC"}}, - "v:\n- A\n- 'B\n\n C'\n", + "v:\n- A\n- |-\n B\n C\n", }, { map[string][]interface{}{"v": []interface{}{"A", 1, map[string][]int{"B": []int{2, 3}}}}, "v:\n- A\n- 1\n- B:\n - 2\n - 3\n", @@ -219,6 +224,49 @@ var marshalTests = []struct { map[string]time.Duration{"a": 3 * time.Second}, "a: 3s\n", }, + + // Issue #24: bug in map merging logic. + { + map[string]string{"a": ""}, + "a: \n", + }, + + // Issue #34: marshal unsupported base 60 floats quoted for compatibility + // with old YAML 1.1 parsers. + { + map[string]string{"a": "1:1"}, + "a: \"1:1\"\n", + }, + + // Binary data. + { + map[string]string{"a": "\x00"}, + "a: \"\\0\"\n", + }, { + map[string]string{"a": "\x80\x81\x82"}, + "a: !!binary gIGC\n", + }, { + map[string]string{"a": strings.Repeat("\x90", 54)}, + "a: !!binary |\n " + strings.Repeat("kJCQ", 17) + "kJ\n CQ\n", + }, + + // Ordered maps. + { + &yaml.MapSlice{{"b", 2}, {"a", 1}, {"d", 4}, {"c", 3}, {"sub", yaml.MapSlice{{"e", 5}}}}, + "b: 2\na: 1\nd: 4\nc: 3\nsub:\n e: 5\n", + }, + + // Encode unicode as utf-8 rather than in escaped form. + { + map[string]string{"a": "你好"}, + "a: 你好\n", + }, + + // Support encoding.TextMarshaler. + { + map[string]net.IP{"a": net.IPv4(1, 2, 3, 4)}, + "a: 1.2.3.4\n", + }, } func (s *S) TestMarshal(c *C) { @@ -232,45 +280,26 @@ func (s *S) TestMarshal(c *C) { var marshalErrorTests = []struct { value interface{} error string -}{ - { - &struct { - B int - inlineB ",inline" - }{1, inlineB{2, inlineC{3}}}, - `Duplicated key 'b' in struct struct \{ B int; .*`, - }, -} + panic string +}{{ + value: &struct { + B int + inlineB ",inline" + }{1, inlineB{2, inlineC{3}}}, + panic: `Duplicated key 'b' in struct struct \{ B int; .*`, +}} func (s *S) TestMarshalErrors(c *C) { for _, item := range marshalErrorTests { - _, err := yaml.Marshal(item.value) - c.Assert(err, ErrorMatches, item.error) + if item.panic != "" { + c.Assert(func() { yaml.Marshal(item.value) }, PanicMatches, item.panic) + } else { + _, err := yaml.Marshal(item.value) + c.Assert(err, ErrorMatches, item.error) + } } } -var marshalTaggedIfaceTest interface{} = &struct{ A string }{"B"} - -var getterTests = []struct { - data, tag string - value interface{} -}{ - {"_:\n hi: there\n", "", map[interface{}]interface{}{"hi": "there"}}, - {"_:\n- 1\n- A\n", "", []interface{}{1, "A"}}, - {"_: 10\n", "", 10}, - {"_: null\n", "", nil}, - {"_: !foo BAR!\n", "!foo", "BAR!"}, - {"_: !foo 1\n", "!foo", "1"}, - {"_: !foo '\"1\"'\n", "!foo", "\"1\""}, - {"_: !foo 1.1\n", "!foo", 1.1}, - {"_: !foo 1\n", "!foo", 1}, - {"_: !foo 1\n", "!foo", uint(1)}, - {"_: !foo true\n", "!foo", true}, - {"_: !foo\n- A\n- B\n", "!foo", []string{"A", "B"}}, - {"_: !foo\n A: B\n", "!foo", map[string]string{"A": "B"}}, - {"_: !foo\n a: B\n", "!foo", &marshalTaggedIfaceTest}, -} - func (s *S) TestMarshalTypeCache(c *C) { var data []byte var err error @@ -287,23 +316,32 @@ func (s *S) TestMarshalTypeCache(c *C) { c.Assert(string(data), Equals, "b: 0\n") } -type typeWithGetter struct { - tag string +var marshalerTests = []struct { + data string + value interface{} +}{ + {"_:\n hi: there\n", map[interface{}]interface{}{"hi": "there"}}, + {"_:\n- 1\n- A\n", []interface{}{1, "A"}}, + {"_: 10\n", 10}, + {"_: null\n", nil}, + {"_: BAR!\n", "BAR!"}, +} + +type marshalerType struct { value interface{} } -func (o typeWithGetter) GetYAML() (tag string, value interface{}) { - return o.tag, o.value +func (o marshalerType) MarshalYAML() (interface{}, error) { + return o.value, nil } -type typeWithGetterField struct { - Field typeWithGetter "_" +type marshalerValue struct { + Field marshalerType "_" } -func (s *S) TestMashalWithGetter(c *C) { - for _, item := range getterTests { - obj := &typeWithGetterField{} - obj.Field.tag = item.tag +func (s *S) TestMarshaler(c *C) { + for _, item := range marshalerTests { + obj := &marshalerValue{} obj.Field.value = item.value data, err := yaml.Marshal(obj) c.Assert(err, IsNil) @@ -311,15 +349,25 @@ func (s *S) TestMashalWithGetter(c *C) { } } -func (s *S) TestUnmarshalWholeDocumentWithGetter(c *C) { - obj := &typeWithGetter{} - obj.tag = "" +func (s *S) TestMarshalerWholeDocument(c *C) { + obj := &marshalerType{} obj.value = map[string]string{"hello": "world!"} data, err := yaml.Marshal(obj) c.Assert(err, IsNil) c.Assert(string(data), Equals, "hello: world!\n") } +type failingMarshaler struct{} + +func (ft *failingMarshaler) MarshalYAML() (interface{}, error) { + return nil, failingErr +} + +func (s *S) TestMarshalerError(c *C) { + _, err := yaml.Marshal(&failingMarshaler{}) + c.Assert(err, Equals, failingErr) +} + func (s *S) TestSortedOutput(c *C) { order := []interface{}{ false, diff --git a/Godeps/_workspace/src/gopkg.in/v1/yaml/parserc.go b/Godeps/_workspace/src/gopkg.in/v2/yaml/parserc.go similarity index 100% rename from Godeps/_workspace/src/gopkg.in/v1/yaml/parserc.go rename to Godeps/_workspace/src/gopkg.in/v2/yaml/parserc.go diff --git a/Godeps/_workspace/src/gopkg.in/v1/yaml/readerc.go b/Godeps/_workspace/src/gopkg.in/v2/yaml/readerc.go similarity index 100% rename from Godeps/_workspace/src/gopkg.in/v1/yaml/readerc.go rename to Godeps/_workspace/src/gopkg.in/v2/yaml/readerc.go diff --git a/Godeps/_workspace/src/gopkg.in/v2/yaml/resolve.go b/Godeps/_workspace/src/gopkg.in/v2/yaml/resolve.go new file mode 100644 index 00000000000..d3bdec6a5d9 --- /dev/null +++ b/Godeps/_workspace/src/gopkg.in/v2/yaml/resolve.go @@ -0,0 +1,188 @@ +package yaml + +import ( + "encoding/base64" + "math" + "strconv" + "strings" + "unicode/utf8" +) + +type resolveMapItem struct { + value interface{} + tag string +} + +var resolveTable = make([]byte, 256) +var resolveMap = make(map[string]resolveMapItem) + +func init() { + t := resolveTable + t[int('+')] = 'S' // Sign + t[int('-')] = 'S' + for _, c := range "0123456789" { + t[int(c)] = 'D' // Digit + } + for _, c := range "yYnNtTfFoO~" { + t[int(c)] = 'M' // In map + } + t[int('.')] = '.' // Float (potentially in map) + + var resolveMapList = []struct { + v interface{} + tag string + l []string + }{ + {true, yaml_BOOL_TAG, []string{"y", "Y", "yes", "Yes", "YES"}}, + {true, yaml_BOOL_TAG, []string{"true", "True", "TRUE"}}, + {true, yaml_BOOL_TAG, []string{"on", "On", "ON"}}, + {false, yaml_BOOL_TAG, []string{"n", "N", "no", "No", "NO"}}, + {false, yaml_BOOL_TAG, []string{"false", "False", "FALSE"}}, + {false, yaml_BOOL_TAG, []string{"off", "Off", "OFF"}}, + {nil, yaml_NULL_TAG, []string{"", "~", "null", "Null", "NULL"}}, + {math.NaN(), yaml_FLOAT_TAG, []string{".nan", ".NaN", ".NAN"}}, + {math.Inf(+1), yaml_FLOAT_TAG, []string{".inf", ".Inf", ".INF"}}, + {math.Inf(+1), yaml_FLOAT_TAG, []string{"+.inf", "+.Inf", "+.INF"}}, + {math.Inf(-1), yaml_FLOAT_TAG, []string{"-.inf", "-.Inf", "-.INF"}}, + {"<<", yaml_MERGE_TAG, []string{"<<"}}, + } + + m := resolveMap + for _, item := range resolveMapList { + for _, s := range item.l { + m[s] = resolveMapItem{item.v, item.tag} + } + } +} + +const longTagPrefix = "tag:yaml.org,2002:" + +func shortTag(tag string) string { + // TODO This can easily be made faster and produce less garbage. + if strings.HasPrefix(tag, longTagPrefix) { + return "!!" + tag[len(longTagPrefix):] + } + return tag +} + +func longTag(tag string) string { + if strings.HasPrefix(tag, "!!") { + return longTagPrefix + tag[2:] + } + return tag +} + +func resolvableTag(tag string) bool { + switch tag { + case "", yaml_STR_TAG, yaml_BOOL_TAG, yaml_INT_TAG, yaml_FLOAT_TAG, yaml_NULL_TAG: + return true + } + return false +} + +func resolve(tag string, in string) (rtag string, out interface{}) { + //fmt.Printf("yv2 resolve tag: %s, in: %s\n", tag, in) + if !resolvableTag(tag) { + return tag, in + } + + defer func() { + switch tag { + case "", rtag, yaml_STR_TAG, yaml_BINARY_TAG: + return + } + failf("cannot decode %s `%s` as a %s", shortTag(rtag), in, shortTag(tag)) + }() + + // Any data is accepted as a !!str or !!binary. + // Otherwise, the prefix is enough of a hint about what it might be. + hint := byte('N') + if in != "" { + hint = resolveTable[in[0]] + } + if hint != 0 && tag != yaml_STR_TAG && tag != yaml_BINARY_TAG { + // Handle things we can lookup in a map. + if item, ok := resolveMap[in]; ok { + return item.tag, item.value + } + + // Base 60 floats are a bad idea, were dropped in YAML 1.2, and + // are purposefully unsupported here. They're still quoted on + // the way out for compatibility with other parser, though. + + switch hint { + case 'M': + // We've already checked the map above. + + case '.': + // Not in the map, so maybe a normal float. + floatv, err := strconv.ParseFloat(in, 64) + if err == nil { + return yaml_FLOAT_TAG, floatv + } + + case 'D', 'S': + // Int, float, or timestamp. + plain := strings.Replace(in, "_", "", -1) + intv, err := strconv.ParseInt(plain, 0, 64) + if err == nil { + if intv == int64(int(intv)) { + return yaml_INT_TAG, int(intv) + } else { + return yaml_INT_TAG, intv + } + } + floatv, err := strconv.ParseFloat(plain, 64) + if err == nil { + return yaml_FLOAT_TAG, floatv + } + if strings.HasPrefix(plain, "0b") { + intv, err := strconv.ParseInt(plain[2:], 2, 64) + if err == nil { + return yaml_INT_TAG, int(intv) + } + } else if strings.HasPrefix(plain, "-0b") { + intv, err := strconv.ParseInt(plain[3:], 2, 64) + if err == nil { + return yaml_INT_TAG, -int(intv) + } + } + // XXX Handle timestamps here. + + default: + panic("resolveTable item not yet handled: " + string(rune(hint)) + " (with " + in + ")") + } + } + if tag == yaml_BINARY_TAG { + return yaml_BINARY_TAG, in + } + if utf8.ValidString(in) { + return yaml_STR_TAG, in + } + return yaml_BINARY_TAG, encodeBase64(in) +} + +// encodeBase64 encodes s as base64 that is broken up into multiple lines +// as appropriate for the resulting length. +func encodeBase64(s string) string { + const lineLen = 70 + encLen := base64.StdEncoding.EncodedLen(len(s)) + lines := encLen/lineLen + 1 + buf := make([]byte, encLen*2+lines) + in := buf[0:encLen] + out := buf[encLen:] + base64.StdEncoding.Encode(in, []byte(s)) + k := 0 + for i := 0; i < len(in); i += lineLen { + j := i + lineLen + if j > len(in) { + j = len(in) + } + k += copy(out[k:], in[i:j]) + if lines > 1 { + out[k] = '\n' + k++ + } + } + return string(out[:k]) +} diff --git a/Godeps/_workspace/src/gopkg.in/v1/yaml/scannerc.go b/Godeps/_workspace/src/gopkg.in/v2/yaml/scannerc.go similarity index 100% rename from Godeps/_workspace/src/gopkg.in/v1/yaml/scannerc.go rename to Godeps/_workspace/src/gopkg.in/v2/yaml/scannerc.go diff --git a/Godeps/_workspace/src/gopkg.in/v1/yaml/sorter.go b/Godeps/_workspace/src/gopkg.in/v2/yaml/sorter.go similarity index 100% rename from Godeps/_workspace/src/gopkg.in/v1/yaml/sorter.go rename to Godeps/_workspace/src/gopkg.in/v2/yaml/sorter.go diff --git a/Godeps/_workspace/src/gopkg.in/v1/yaml/suite_test.go b/Godeps/_workspace/src/gopkg.in/v2/yaml/suite_test.go similarity index 100% rename from Godeps/_workspace/src/gopkg.in/v1/yaml/suite_test.go rename to Godeps/_workspace/src/gopkg.in/v2/yaml/suite_test.go diff --git a/Godeps/_workspace/src/gopkg.in/v1/yaml/writerc.go b/Godeps/_workspace/src/gopkg.in/v2/yaml/writerc.go similarity index 100% rename from Godeps/_workspace/src/gopkg.in/v1/yaml/writerc.go rename to Godeps/_workspace/src/gopkg.in/v2/yaml/writerc.go diff --git a/Godeps/_workspace/src/gopkg.in/v1/yaml/yaml.go b/Godeps/_workspace/src/gopkg.in/v2/yaml/yaml.go similarity index 72% rename from Godeps/_workspace/src/gopkg.in/v1/yaml/yaml.go rename to Godeps/_workspace/src/gopkg.in/v2/yaml/yaml.go index 44b0cc65d47..5d1b86c2198 100644 --- a/Godeps/_workspace/src/gopkg.in/v1/yaml/yaml.go +++ b/Godeps/_workspace/src/gopkg.in/v2/yaml/yaml.go @@ -10,59 +10,52 @@ import ( "errors" "fmt" "reflect" - "runtime" "strings" "sync" ) -func handleErr(err *error) { - if r := recover(); r != nil { - if _, ok := r.(runtime.Error); ok { - panic(r) - } else if _, ok := r.(*reflect.ValueError); ok { - panic(r) - } else if _, ok := r.(externalPanic); ok { - panic(r) - } else if s, ok := r.(string); ok { - *err = errors.New("YAML error: " + s) - } else if e, ok := r.(error); ok { - *err = e - } else { - panic(r) - } - } +// MapSlice encodes and decodes as a YAML map. +// The order of keys is preserved when encoding and decoding. +type MapSlice []MapItem + +// MapItem is an item in a MapSlice. +type MapItem struct { + Key, Value interface{} } -// The Setter interface may be implemented by types to do their own custom -// unmarshalling of YAML values, rather than being implicitly assigned by -// the yaml package machinery. If setting the value works, the method should -// return true. If it returns false, the value is considered unsupported -// and is omitted from maps and slices. -type Setter interface { - SetYAML(tag string, value interface{}) bool +// The Unmarshaler interface may be implemented by types to customize their +// behavior when being unmarshaled from a YAML document. The UnmarshalYAML +// method receives a function that may be called to unmarshal the original +// YAML value into a field or variable. It is safe to call the unmarshal +// function parameter more than once if necessary. +type Unmarshaler interface { + UnmarshalYAML(unmarshal func(interface{}) error) error } -// The Getter interface is implemented by types to do their own custom -// marshalling into a YAML tag and value. -type Getter interface { - GetYAML() (tag string, value interface{}) + +// The Marshaler interface may be implemented by types to customize their +// behavior when being marshaled into a YAML document. The returned value +// is marshaled in place of the original value implementing Marshaler. +// +// If an error is returned by MarshalYAML, the marshaling procedure stops +// and returns with the provided error. +type Marshaler interface { + MarshalYAML() (interface{}, error) } // Unmarshal decodes the first document found within the in byte slice // and assigns decoded values into the out value. // // Maps and pointers (to a struct, string, int, etc) are accepted as out -// values. If an internal pointer within a struct is not initialized, +// values. If an internal pointer within a struct is not initialized, // the yaml package will initialize it if necessary for unmarshalling // the provided data. The out parameter must not be nil. // -// The type of the decoded values and the type of out will be considered, -// and Unmarshal will do the best possible job to unmarshal values -// appropriately. It is NOT considered an error, though, to skip values -// because they are not available in the decoded YAML, or if they are not -// compatible with the out value. To ensure something was properly -// unmarshaled use a map or compare against the previous value for the -// field (usually the zero value). +// The type of the decoded values should be compatible with the respective +// values in out. If one or more values cannot be decoded due to a type +// mismatches, decoding continues partially until the end of the YAML +// content, and a *yaml.TypeError is returned with details for all +// missed values. // // Struct fields are only unmarshalled if they are exported (have an // upper case first letter), and are unmarshalled using the field name @@ -78,7 +71,7 @@ type Getter interface { // F int `yaml:"a,omitempty"` // B int // } -// var T t +// var t T // yaml.Unmarshal([]byte("a: 1\nb: 2"), &t) // // See the documentation of Marshal for the format of tags and a list of @@ -91,7 +84,14 @@ func Unmarshal(in []byte, out interface{}) (err error) { defer p.destroy() node := p.parse() if node != nil { - d.unmarshal(node, reflect.ValueOf(out)) + v := reflect.ValueOf(out) + if v.Kind() == reflect.Ptr && !v.IsNil() { + v = v.Elem() + } + d.unmarshal(node, v) + } + if d.terrors != nil { + return &TypeError{d.terrors} } return nil } @@ -145,6 +145,40 @@ func Marshal(in interface{}) (out []byte, err error) { return } +func handleErr(err *error) { + if v := recover(); v != nil { + if e, ok := v.(yamlError); ok { + *err = e.err + } else { + panic(v) + } + } +} + +type yamlError struct { + err error +} + +func fail(err error) { + panic(yamlError{err}) +} + +func failf(format string, args ...interface{}) { + panic(yamlError{fmt.Errorf("yaml: " + format, args...)}) +} + +// A TypeError is returned by Unmarshal when one or more fields in +// the YAML document cannot be properly decoded into the requested +// types. When this error is returned, the value is still +// unmarshaled partially. +type TypeError struct { + Errors []string +} + +func (e *TypeError) Error() string { + return fmt.Sprintf("yaml: unmarshal errors:\n %s", strings.Join(e.Errors, "\n ")) +} + // -------------------------------------------------------------------------- // Maintain a mapping of keys to structure field indexes @@ -174,12 +208,6 @@ type fieldInfo struct { var structMap = make(map[reflect.Type]*structInfo) var fieldMapMutex sync.RWMutex -type externalPanic string - -func (e externalPanic) String() string { - return string(e) -} - func getStructInfo(st reflect.Type) (*structInfo, error) { fieldMapMutex.RLock() sinfo, found := structMap[st] @@ -220,8 +248,7 @@ func getStructInfo(st reflect.Type) (*structInfo, error) { case "inline": inline = true default: - msg := fmt.Sprintf("Unsupported flag %q in tag %q of type %s", flag, tag, st) - panic(externalPanic(msg)) + return nil, errors.New(fmt.Sprintf("Unsupported flag %q in tag %q of type %s", flag, tag, st)) } } tag = fields[0] @@ -229,6 +256,7 @@ func getStructInfo(st reflect.Type) (*structInfo, error) { if inline { switch field.Type.Kind() { + // TODO: Implement support for inline maps. //case reflect.Map: // if inlineMap >= 0 { // return nil, errors.New("Multiple ,inline maps in struct " + st.String()) @@ -256,8 +284,8 @@ func getStructInfo(st reflect.Type) (*structInfo, error) { fieldsList = append(fieldsList, finfo) } default: - //panic("Option ,inline needs a struct value or map field") - panic("Option ,inline needs a struct value field") + //return nil, errors.New("Option ,inline needs a struct value or map field") + return nil, errors.New("Option ,inline needs a struct value field") } continue } diff --git a/Godeps/_workspace/src/gopkg.in/v1/yaml/yamlh.go b/Godeps/_workspace/src/gopkg.in/v2/yaml/yamlh.go similarity index 99% rename from Godeps/_workspace/src/gopkg.in/v1/yaml/yamlh.go rename to Godeps/_workspace/src/gopkg.in/v2/yaml/yamlh.go index 6624d6c699e..4b020b1b308 100644 --- a/Godeps/_workspace/src/gopkg.in/v1/yaml/yamlh.go +++ b/Godeps/_workspace/src/gopkg.in/v2/yaml/yamlh.go @@ -294,6 +294,10 @@ const ( yaml_SEQ_TAG = "tag:yaml.org,2002:seq" // The tag !!seq is used to denote sequences. yaml_MAP_TAG = "tag:yaml.org,2002:map" // The tag !!map is used to denote mapping. + // Not in original libyaml. + yaml_BINARY_TAG = "tag:yaml.org,2002:binary" + yaml_MERGE_TAG = "tag:yaml.org,2002:merge" + yaml_DEFAULT_SCALAR_TAG = yaml_STR_TAG // The default scalar tag is !!str. yaml_DEFAULT_SEQUENCE_TAG = yaml_SEQ_TAG // The default sequence tag is !!seq. yaml_DEFAULT_MAPPING_TAG = yaml_MAP_TAG // The default mapping tag is !!map. diff --git a/Godeps/_workspace/src/gopkg.in/v1/yaml/yamlprivateh.go b/Godeps/_workspace/src/gopkg.in/v2/yaml/yamlprivateh.go similarity index 100% rename from Godeps/_workspace/src/gopkg.in/v1/yaml/yamlprivateh.go rename to Godeps/_workspace/src/gopkg.in/v2/yaml/yamlprivateh.go diff --git a/contrib/enscope/README.md b/contrib/enscope/README.md index 78b4dcba8e3..0dab0868327 100644 --- a/contrib/enscope/README.md +++ b/contrib/enscope/README.md @@ -16,8 +16,8 @@ $ enscope specFilename configFilename ## Scope schema ``` type EnscopeSpec struct { - NameSuffix string `json:"nameSuffix,omitempty" yaml:"nameSuffix,omitempty"` - Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"` + NameSuffix string `json:"nameSuffix,omitempty"` + Labels map[string]string `json:"labels,omitempty"` } ``` @@ -211,4 +211,4 @@ Output: name: bar-solo-coolapp-prod status: replicas: 0 -``` \ No newline at end of file +``` diff --git a/contrib/enscope/enscope.go b/contrib/enscope/enscope.go index 5df9f8e21ad..33bcc71670a 100644 --- a/contrib/enscope/enscope.go +++ b/contrib/enscope/enscope.go @@ -23,8 +23,8 @@ import ( "os" "strings" + "github.com/ghodss/yaml" "github.com/golang/glog" - "gopkg.in/v1/yaml" ) const usage = "usage: enscope specFilename configFilename" @@ -38,8 +38,8 @@ func checkErr(err error) { // TODO: If name suffix is not specified, deterministically generate it by hashing the labels. type EnscopeSpec struct { - NameSuffix string `json:"nameSuffix,omitempty" yaml:"nameSuffix,omitempty"` - Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"` + NameSuffix string `json:"nameSuffix,omitempty"` + Labels map[string]string `json:"labels,omitempty"` } func main() { diff --git a/contrib/podex/podex.go b/contrib/podex/podex.go index 806927c3584..8f5760d3aa6 100644 --- a/contrib/podex/podex.go +++ b/contrib/podex/podex.go @@ -37,7 +37,7 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1" dockerclient "github.com/fsouza/go-dockerclient" - "gopkg.in/v1/yaml" + "github.com/ghodss/yaml" ) const usage = "usage: podex [-json|-yaml] [-id PODNAME] IMAGES" diff --git a/contrib/simplegen/README.md b/contrib/simplegen/README.md index f2031756f78..a06a5957b4f 100644 --- a/contrib/simplegen/README.md +++ b/contrib/simplegen/README.md @@ -17,13 +17,13 @@ $ simplegen http://some.blog.site.com/k8s-example.yaml ### Schema ``` // Optional: Defaults to image base name if not specified -Name string `yaml:"name,omitempty" json:"name,omitempty"` +Name string `json:"name,omitempty"` // Required. -Image string `yaml:"image" json:"image"` +Image string `json:"image"` // Optional: Defaults to one -Replicas int `yaml:"replicas,omitempty" json:"replicas,omitempty"` +Replicas int `json:"replicas,omitempty"` // Optional: Creates a service if specified: servicePort:containerPort -PortSpec string `yaml:"portSpec,omitempty" json:"portSpec,omitempty"` +PortSpec string `json:"portSpec,omitempty"` ``` ### Example diff --git a/contrib/simplegen/simplegen.go b/contrib/simplegen/simplegen.go index aa569d07b94..752e1f888fb 100644 --- a/contrib/simplegen/simplegen.go +++ b/contrib/simplegen/simplegen.go @@ -35,8 +35,8 @@ import ( // TODO: handle multiple versions correctly "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" + "github.com/ghodss/yaml" "github.com/golang/glog" - "gopkg.in/v1/yaml" ) // TODO: Also handle lists of simple services, and multiple input files @@ -45,13 +45,13 @@ const usage = "usage: simplegen filename" type SimpleService struct { // Optional: Defaults to image base name if not specified - Name string `yaml:"name,omitempty" json:"name,omitempty"` + Name string `json:"name,omitempty"` // Required. - Image string `yaml:"image" json:"image"` + Image string `json:"image"` // Optional: Defaults to one - Replicas int `yaml:"replicas,omitempty" json:"replicas,omitempty"` + Replicas int `json:"replicas,omitempty"` // Optional: Creates a service if specified: servicePort:containerPort - PortSpec string `yaml:"portSpec,omitempty" json:"portSpec,omitempty"` + PortSpec string `json:"portSpec,omitempty"` } func checkErr(err error) { diff --git a/contrib/srvexpand/README.md b/contrib/srvexpand/README.md index 7e1588fc66f..19944a918dc 100644 --- a/contrib/srvexpand/README.md +++ b/contrib/srvexpand/README.md @@ -15,9 +15,9 @@ $ srvexpand myservice.yaml ``` type HierarchicalController struct { // Optional: Defaults to one - Replicas int `yaml:"replicas,omitempty" json:"replicas,omitempty"` + Replicas int `json:"replicas,omitempty"` // Spec defines the behavior of a pod. - Spec v1beta3.PodSpec `json:"spec,omitempty" yaml:"spec,omitempty"` + Spec v1beta3.PodSpec `json:"spec,omitempty"` } type ControllerMap map[string]HierarchicalController @@ -25,9 +25,9 @@ type ControllerMap map[string]HierarchicalController type HierarchicalService struct { // Optional: Creates a service if specified: servicePort:containerPort // TODO: Support multiple protocols - PortSpec string `yaml:"portSpec,omitempty" json:"portSpec,omitempty"` + PortSpec string `json:"portSpec,omitempty"` // Map of replication controllers to create - ControllerMap ControllerMap `json:"controllers,omitempty" yaml:"controllers,omitempty"` + ControllerMap ControllerMap `json:"controllers,omitempty"` } type ServiceMap map[string]HierarchicalService @@ -213,4 +213,4 @@ Output: status: replicas: 0 -``` \ No newline at end of file +``` diff --git a/contrib/srvexpand/srvexpand.go b/contrib/srvexpand/srvexpand.go index 1aeb61e3a0b..2e55dc5492d 100644 --- a/contrib/srvexpand/srvexpand.go +++ b/contrib/srvexpand/srvexpand.go @@ -45,8 +45,8 @@ import ( // it should be possible to specify the version for the whole map. "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta3" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" + "github.com/ghodss/yaml" "github.com/golang/glog" - "gopkg.in/v1/yaml" ) const usage = "usage: srvexpand filename" @@ -62,9 +62,9 @@ const usage = "usage: srvexpand filename" type HierarchicalController struct { // Optional: Defaults to one - Replicas int `yaml:"replicas,omitempty" json:"replicas,omitempty"` + Replicas int `json:"replicas,omitempty"` // Spec defines the behavior of a pod. - Spec v1beta3.PodSpec `json:"spec,omitempty" yaml:"spec,omitempty"` + Spec v1beta3.PodSpec `json:"spec,omitempty"` } type ControllerMap map[string]HierarchicalController @@ -72,9 +72,9 @@ type ControllerMap map[string]HierarchicalController type HierarchicalService struct { // Optional: Creates a service if specified: servicePort:containerPort // TODO: Support multiple protocols - PortSpec string `yaml:"portSpec,omitempty" json:"portSpec,omitempty"` + PortSpec string `json:"portSpec,omitempty"` // Map of replication controllers to create - ControllerMap ControllerMap `json:"controllers,omitempty" yaml:"controllers,omitempty"` + ControllerMap ControllerMap `json:"controllers,omitempty"` } type ServiceMap map[string]HierarchicalService diff --git a/docs/design/namespaces.md b/docs/design/namespaces.md index b80c68259d9..761daa1a50a 100644 --- a/docs/design/namespaces.md +++ b/docs/design/namespaces.md @@ -48,14 +48,14 @@ A *Namespace* is a DNS compatible subdomain. ``` // TypeMeta is shared by all objects sent to, or returned from the client type TypeMeta struct { - Kind string `json:"kind,omitempty" yaml:"kind,omitempty"` - Uid string `json:"uid,omitempty" yaml:"uid,omitempty"` - CreationTimestamp util.Time `json:"creationTimestamp,omitempty" yaml:"creationTimestamp,omitempty"` - SelfLink string `json:"selfLink,omitempty" yaml:"selfLink,omitempty"` - ResourceVersion uint64 `json:"resourceVersion,omitempty" yaml:"resourceVersion,omitempty"` - APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty"` - Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"` - Name string `json:"name,omitempty" yaml:"name,omitempty"` + Kind string `json:"kind,omitempty"` + Uid string `json:"uid,omitempty"` + CreationTimestamp util.Time `json:"creationTimestamp,omitempty"` + SelfLink string `json:"selfLink,omitempty"` + ResourceVersion uint64 `json:"resourceVersion,omitempty"` + APIVersion string `json:"apiVersion,omitempty"` + Namespace string `json:"namespace,omitempty"` + Name string `json:"name,omitempty"` } ``` diff --git a/pkg/api/meta/meta_test.go b/pkg/api/meta/meta_test.go index 18dfd50abe4..2309c11f365 100644 --- a/pkg/api/meta/meta_test.go +++ b/pkg/api/meta/meta_test.go @@ -26,19 +26,19 @@ import ( func TestGenericTypeMeta(t *testing.T) { type TypeMeta struct { - Kind string `json:"kind,omitempty" yaml:"kind,omitempty"` - Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"` - Name string `json:"name,omitempty" yaml:"name,omitempty"` - UID string `json:"uid,omitempty" yaml:"uid,omitempty"` - CreationTimestamp util.Time `json:"creationTimestamp,omitempty" yaml:"creationTimestamp,omitempty"` - SelfLink string `json:"selfLink,omitempty" yaml:"selfLink,omitempty"` - ResourceVersion string `json:"resourceVersion,omitempty" yaml:"resourceVersion,omitempty"` - APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty"` - Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"` - Annotations map[string]string `json:"annotations,omitempty" yaml:"annotations,omitempty"` + Kind string `json:"kind,omitempty"` + Namespace string `json:"namespace,omitempty"` + Name string `json:"name,omitempty"` + UID string `json:"uid,omitempty"` + CreationTimestamp util.Time `json:"creationTimestamp,omitempty"` + SelfLink string `json:"selfLink,omitempty"` + ResourceVersion string `json:"resourceVersion,omitempty"` + APIVersion string `json:"apiVersion,omitempty"` + Labels map[string]string `json:"labels,omitempty"` + Annotations map[string]string `json:"annotations,omitempty"` } type Object struct { - TypeMeta `json:",inline" yaml:",inline"` + TypeMeta `json:",inline"` } j := Object{ TypeMeta{ @@ -112,19 +112,19 @@ func TestGenericTypeMeta(t *testing.T) { } type InternalTypeMeta struct { - Kind string `json:"kind,omitempty" yaml:"kind,omitempty"` - Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"` - Name string `json:"name,omitempty" yaml:"name,omitempty"` - UID string `json:"uid,omitempty" yaml:"uid,omitempty"` - CreationTimestamp util.Time `json:"creationTimestamp,omitempty" yaml:"creationTimestamp,omitempty"` - SelfLink string `json:"selfLink,omitempty" yaml:"selfLink,omitempty"` - ResourceVersion string `json:"resourceVersion,omitempty" yaml:"resourceVersion,omitempty"` - APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty"` - Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"` - Annotations map[string]string `json:"annotations,omitempty" yaml:"annotations,omitempty"` + Kind string `json:"kind,omitempty"` + Namespace string `json:"namespace,omitempty"` + Name string `json:"name,omitempty"` + UID string `json:"uid,omitempty"` + CreationTimestamp util.Time `json:"creationTimestamp,omitempty"` + SelfLink string `json:"selfLink,omitempty"` + ResourceVersion string `json:"resourceVersion,omitempty"` + APIVersion string `json:"apiVersion,omitempty"` + Labels map[string]string `json:"labels,omitempty"` + Annotations map[string]string `json:"annotations,omitempty"` } type InternalObject struct { - TypeMeta InternalTypeMeta `json:",inline" yaml:",inline"` + TypeMeta InternalTypeMeta `json:",inline"` } func (*InternalObject) IsAnAPIObject() {} @@ -269,22 +269,22 @@ func TestGenericTypeMetaAccessor(t *testing.T) { func TestGenericObjectMeta(t *testing.T) { type TypeMeta struct { - Kind string `json:"kind,omitempty" yaml:"kind,omitempty"` - APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty"` + Kind string `json:"kind,omitempty"` + APIVersion string `json:"apiVersion,omitempty"` } type ObjectMeta struct { - Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"` - Name string `json:"name,omitempty" yaml:"name,omitempty"` - UID string `json:"uid,omitempty" yaml:"uid,omitempty"` - CreationTimestamp util.Time `json:"creationTimestamp,omitempty" yaml:"creationTimestamp,omitempty"` - SelfLink string `json:"selfLink,omitempty" yaml:"selfLink,omitempty"` - ResourceVersion string `json:"resourceVersion,omitempty" yaml:"resourceVersion,omitempty"` - Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"` - Annotations map[string]string `json:"annotations,omitempty" yaml:"annotations,omitempty"` + Namespace string `json:"namespace,omitempty"` + Name string `json:"name,omitempty"` + UID string `json:"uid,omitempty"` + CreationTimestamp util.Time `json:"creationTimestamp,omitempty"` + SelfLink string `json:"selfLink,omitempty"` + ResourceVersion string `json:"resourceVersion,omitempty"` + Labels map[string]string `json:"labels,omitempty"` + Annotations map[string]string `json:"annotations,omitempty"` } type Object struct { - TypeMeta `json:",inline" yaml:",inline"` - ObjectMeta `json:"metadata" yaml:"metadata"` + TypeMeta `json:",inline"` + ObjectMeta `json:"metadata"` } j := Object{ TypeMeta{ @@ -375,16 +375,16 @@ func TestGenericObjectMeta(t *testing.T) { func TestGenericListMeta(t *testing.T) { type TypeMeta struct { - Kind string `json:"kind,omitempty" yaml:"kind,omitempty"` - APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty"` + Kind string `json:"kind,omitempty"` + APIVersion string `json:"apiVersion,omitempty"` } type ListMeta struct { - SelfLink string `json:"selfLink,omitempty" yaml:"selfLink,omitempty"` - ResourceVersion string `json:"resourceVersion,omitempty" yaml:"resourceVersion,omitempty"` + SelfLink string `json:"selfLink,omitempty"` + ResourceVersion string `json:"resourceVersion,omitempty"` } type Object struct { - TypeMeta `json:",inline" yaml:",inline"` - ListMeta `json:"metadata" yaml:"metadata"` + TypeMeta `json:",inline"` + ListMeta `json:"metadata"` } j := Object{ TypeMeta{ @@ -442,7 +442,7 @@ func TestGenericListMeta(t *testing.T) { } type MyAPIObject struct { - TypeMeta InternalTypeMeta `json:",inline" yaml:",inline"` + TypeMeta InternalTypeMeta `json:",inline"` } func (*MyAPIObject) IsAnAPIObject() {} diff --git a/pkg/api/serialization_test.go b/pkg/api/serialization_test.go index ac230c4306c..3a36a1816b8 100644 --- a/pkg/api/serialization_test.go +++ b/pkg/api/serialization_test.go @@ -23,6 +23,7 @@ import ( "reflect" "strconv" "testing" + "time" "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest" @@ -138,6 +139,14 @@ var apiObjectFuzzer = fuzz.New().NilChance(.5).NumElements(1, 1).Funcs( c.RandString(): c.RandString(), } }, + func(t *time.Time, c fuzz.Continue) { + // This is necessary because the standard fuzzed time.Time object is + // completely nil, but when JSON unmarshals dates it fills in the + // unexported loc field with the time.UTC object, resulting in + // reflect.DeepEqual returning false in the round trip tests. We solve it + // by using a date that will be identical to the one JSON unmarshals. + *t = time.Date(2000, 1, 1, 1, 1, 1, 0, time.UTC) + }, ) func runTest(t *testing.T, codec runtime.Codec, source runtime.Object) { @@ -162,7 +171,7 @@ func runTest(t *testing.T, codec runtime.Codec, source runtime.Object) { return } if !reflect.DeepEqual(source, obj2) { - t.Errorf("1: %v: diff: %v\nCodec: %v\nData: %s\nSource: %#v", name, util.ObjectDiff(source, obj2), codec, string(data), source) + t.Errorf("1: %v: diff: %v\nCodec: %v\nData: %s\nSource: %#v", name, util.ObjectGoPrintDiff(source, obj2), codec, string(data), source) return } diff --git a/pkg/api/types.go b/pkg/api/types.go index 76953e64449..8b87f8b7da0 100644 --- a/pkg/api/types.go +++ b/pkg/api/types.go @@ -51,25 +51,25 @@ import ( type TypeMeta struct { // Kind is a string value representing the REST resource this object represents. // Servers may infer this from the endpoint the client submits requests to. - Kind string `json:"kind,omitempty" yaml:"kind,omitempty"` + Kind string `json:"kind,omitempty"` // APIVersion defines the versioned schema of this representation of an object. // Servers should convert recognized schemas to the latest internal value, and // may reject unrecognized values. - APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty"` + APIVersion string `json:"apiVersion,omitempty"` } // ListMeta describes metadata that synthetic resources must have, including lists and // various status objects. A resource may have only one of {ObjectMeta, ListMeta}. type ListMeta struct { // SelfLink is a URL representing this object. - SelfLink string `json:"selfLink,omitempty" yaml:"selfLink,omitempty"` + SelfLink string `json:"selfLink,omitempty"` // An opaque value that represents the version of this response for use with optimistic // concurrency and change monitoring endpoints. Clients must treat these values as opaque // and values may only be valid for a particular resource or set of resources. Only servers // will generate resource versions. - ResourceVersion string `json:"resourceVersion,omitempty" yaml:"resourceVersion,omitempty"` + ResourceVersion string `json:"resourceVersion,omitempty"` } // ObjectMeta is metadata that all persisted resources must have, which includes all objects @@ -79,32 +79,32 @@ type ObjectMeta struct { // some resources may allow a client to request the generation of an appropriate name // automatically. Name is primarily intended for creation idempotence and configuration // definition. - Name string `json:"name,omitempty" yaml:"name,omitempty"` + Name string `json:"name,omitempty"` // Namespace defines the space within which name must be unique. An empty namespace is // equivalent to the "default" namespace, but "default" is the canonical representation. // Not all objects are required to be scoped to a namespace - the value of this field for // those objects will be empty. - Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"` + Namespace string `json:"namespace,omitempty"` // SelfLink is a URL representing this object. - SelfLink string `json:"selfLink,omitempty" yaml:"selfLink,omitempty"` + SelfLink string `json:"selfLink,omitempty"` // UID is the unique in time and space value for this object. It is typically generated by // the server on successful creation of a resource and is not allowed to change on PUT // operations. - UID string `json:"uid,omitempty" yaml:"uid,omitempty"` + UID string `json:"uid,omitempty"` // An opaque value that represents the version of this resource. May be used for optimistic // concurrency, change detection, and the watch operation on a resource or set of resources. // Clients must treat these values as opaque and values may only be valid for a particular // resource or set of resources. Only servers will generate resource versions. - ResourceVersion string `json:"resourceVersion,omitempty" yaml:"resourceVersion,omitempty"` + ResourceVersion string `json:"resourceVersion,omitempty"` // CreationTimestamp is a timestamp representing the server time when this object was // created. It is not guaranteed to be set in happens-before order across separate operations. // Clients may not set this value. It is represented in RFC3339 form and is in UTC. - CreationTimestamp util.Time `json:"creationTimestamp,omitempty" yaml:"creationTimestamp,omitempty"` + CreationTimestamp util.Time `json:"creationTimestamp,omitempty"` // Labels are key value pairs that may be used to scope and select individual resources. // Label keys are of the form: @@ -116,13 +116,13 @@ type ObjectMeta struct { // to the user. Other system components that wish to use labels must specify a prefix. The // "kubernetes.io/" prefix is reserved for use by kubernetes components. // TODO: replace map[string]string with labels.LabelSet type - Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"` + Labels map[string]string `json:"labels,omitempty"` // Annotations are unstructured key value data stored with a resource that may be set by // external tooling. They are not queryable and should be preserved when modifying // objects. Annotation keys have the same formatting restrictions as Label keys. See the // comments on Labels for details. - Annotations map[string]string `json:"annotations,omitempty" yaml:"annotations,omitempty"` + Annotations map[string]string `json:"annotations,omitempty"` } const ( @@ -138,11 +138,11 @@ const ( type Volume struct { // Required: This must be a DNS_LABEL. Each volume in a pod must have // a unique name. - Name string `json:"name" yaml:"name"` + Name string `json:"name"` // Source represents the location and type of a volume to mount. // This is optional for now. If not specified, the Volume is implied to be an EmptyDir. // This implied behavior is deprecated and will be removed in a future version. - Source *VolumeSource `json:"source" yaml:"source"` + Source *VolumeSource `json:"source"` } // VolumeSource represents the source location of a valume to mount. @@ -153,19 +153,19 @@ type VolumeSource struct { // things that are allowed to see the host machine. Most containers will NOT need this. // TODO(jonesdl) We need to restrict who can use host directory mounts and who can/can not // mount host directories as read/write. - HostDir *HostDir `json:"hostDir" yaml:"hostDir"` + HostDir *HostDir `json:"hostDir"` // EmptyDir represents a temporary directory that shares a pod's lifetime. - EmptyDir *EmptyDir `json:"emptyDir" yaml:"emptyDir"` + EmptyDir *EmptyDir `json:"emptyDir"` // GCEPersistentDisk represents a GCE Disk resource that is attached to a // kubelet's host machine and then exposed to the pod. - GCEPersistentDisk *GCEPersistentDisk `json:"persistentDisk" yaml:"persistentDisk"` + GCEPersistentDisk *GCEPersistentDisk `json:"persistentDisk"` // GitRepo represents a git repository at a particular revision. - GitRepo *GitRepo `json:"gitRepo" yaml:"gitRepo"` + GitRepo *GitRepo `json:"gitRepo"` } // HostDir represents bare host directory volume. type HostDir struct { - Path string `json:"path" yaml:"path"` + Path string `json:"path"` } type EmptyDir struct{} @@ -187,27 +187,27 @@ const ( // A GCE PD can only be mounted as read/write once. type GCEPersistentDisk struct { // Unique name of the PD resource. Used to identify the disk in GCE - PDName string `yaml:"pdName" json:"pdName"` + PDName string `json:"pdName"` // Required: Filesystem type to mount. // Must be a filesystem type supported by the host operating system. // Ex. "ext4", "xfs", "ntfs" // TODO: how do we prevent errors in the filesystem from compromising the machine - FSType string `yaml:"fsType,omitempty" json:"fsType,omitempty"` + FSType string `json:"fsType,omitempty"` // Optional: Partition on the disk to mount. // If omitted, kubelet will attempt to mount the device name. // Ex. For /dev/sda1, this field is "1", for /dev/sda, this field is 0 or empty. - Partition int `yaml:"partition,omitempty" json:"partition,omitempty"` + Partition int `json:"partition,omitempty"` // Optional: Defaults to false (read/write). ReadOnly here will force // the ReadOnly setting in VolumeMounts. - ReadOnly bool `yaml:"readOnly,omitempty" json:"readOnly,omitempty"` + ReadOnly bool `json:"readOnly,omitempty"` } // GitRepo represents a volume that is pulled from git when the pod is created. type GitRepo struct { // Repository URL - Repository string `yaml:"repository" json:"repository"` + Repository string `json:"repository"` // Commit hash, this is optional - Revision string `yaml:"revision" json:"revision"` + Revision string `json:"revision"` // TODO: Consider credentials here. } @@ -215,49 +215,49 @@ type GitRepo struct { type Port struct { // Optional: If specified, this must be a DNS_LABEL. Each named port // in a pod must have a unique name. - Name string `json:"name,omitempty" yaml:"name,omitempty"` + Name string `json:"name,omitempty"` // Optional: If specified, this must be a valid port number, 0 < x < 65536. - HostPort int `json:"hostPort,omitempty" yaml:"hostPort,omitempty"` + HostPort int `json:"hostPort,omitempty"` // Required: This must be a valid port number, 0 < x < 65536. - ContainerPort int `json:"containerPort" yaml:"containerPort"` + ContainerPort int `json:"containerPort"` // Optional: Supports "TCP" and "UDP". Defaults to "TCP". - Protocol Protocol `json:"protocol,omitempty" yaml:"protocol,omitempty"` + Protocol Protocol `json:"protocol,omitempty"` // Optional: What host IP to bind the external port to. - HostIP string `json:"hostIP,omitempty" yaml:"hostIP,omitempty"` + HostIP string `json:"hostIP,omitempty"` } // VolumeMount describes a mounting of a Volume within a container. type VolumeMount struct { // Required: This must match the Name of a Volume [above]. - Name string `json:"name" yaml:"name"` + Name string `json:"name"` // Optional: Defaults to false (read-write). - ReadOnly bool `json:"readOnly,omitempty" yaml:"readOnly,omitempty"` + ReadOnly bool `json:"readOnly,omitempty"` // Required. - MountPath string `json:"mountPath,omitempty" yaml:"mountPath,omitempty"` + MountPath string `json:"mountPath,omitempty"` } // EnvVar represents an environment variable present in a Container. type EnvVar struct { // Required: This must be a C_IDENTIFIER. - Name string `json:"name" yaml:"name"` + Name string `json:"name"` // Optional: defaults to "". - Value string `json:"value,omitempty" yaml:"value,omitempty"` + Value string `json:"value,omitempty"` } // HTTPGetAction describes an action based on HTTP Get requests. type HTTPGetAction struct { // Optional: Path to access on the HTTP server. - Path string `json:"path,omitempty" yaml:"path,omitempty"` + Path string `json:"path,omitempty"` // Required: Name or number of the port to access on the container. - Port util.IntOrString `json:"port,omitempty" yaml:"port,omitempty"` + Port util.IntOrString `json:"port,omitempty"` // Optional: Host name to connect to, defaults to the pod IP. - Host string `json:"host,omitempty" yaml:"host,omitempty"` + Host string `json:"host,omitempty"` } // TCPSocketAction describes an action based on opening a socket type TCPSocketAction struct { // Required: Port to connect to. - Port util.IntOrString `json:"port,omitempty" yaml:"port,omitempty"` + Port util.IntOrString `json:"port,omitempty"` } // ExecAction describes a "run in container" action. @@ -266,20 +266,20 @@ type ExecAction struct { // command is root ('/') in the container's filesystem. The command is simply exec'd, it is // not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use // a shell, you need to explicitly call out to that shell. - Command []string `yaml:"command,omitempty" json:"command,omitempty"` + Command []string `json:"command,omitempty"` } // LivenessProbe describes a liveness probe to be examined to the container. // TODO: pass structured data to the actions, and document that data here. type LivenessProbe struct { // HTTPGetProbe parameters, required if Type == 'http' - HTTPGet *HTTPGetAction `yaml:"httpGet,omitempty" json:"httpGet,omitempty"` + HTTPGet *HTTPGetAction `json:"httpGet,omitempty"` // TCPSocketProbe parameter, required if Type == 'tcp' - TCPSocket *TCPSocketAction `yaml:"tcpSocket,omitempty" json:"tcpSocket,omitempty"` + TCPSocket *TCPSocketAction `json:"tcpSocket,omitempty"` // ExecProbe parameter, required if Type == 'exec' - Exec *ExecAction `yaml:"exec,omitempty" json:"exec,omitempty"` + Exec *ExecAction `json:"exec,omitempty"` // Length of time before health checking is activated. In seconds. - InitialDelaySeconds int64 `yaml:"initialDelaySeconds,omitempty" json:"initialDelaySeconds,omitempty"` + InitialDelaySeconds int64 `json:"initialDelaySeconds,omitempty"` } // PullPolicy describes a policy for if/when to pull a container image @@ -298,28 +298,28 @@ const ( type Container struct { // Required: This must be a DNS_LABEL. Each container in a pod must // have a unique name. - Name string `json:"name" yaml:"name"` + Name string `json:"name"` // Required. - Image string `json:"image" yaml:"image"` + Image string `json:"image"` // Optional: Defaults to whatever is defined in the image. - Command []string `json:"command,omitempty" yaml:"command,omitempty"` + Command []string `json:"command,omitempty"` // Optional: Defaults to Docker's default. - WorkingDir string `json:"workingDir,omitempty" yaml:"workingDir,omitempty"` - Ports []Port `json:"ports,omitempty" yaml:"ports,omitempty"` - Env []EnvVar `json:"env,omitempty" yaml:"env,omitempty"` + WorkingDir string `json:"workingDir,omitempty"` + Ports []Port `json:"ports,omitempty"` + Env []EnvVar `json:"env,omitempty"` // Optional: Defaults to unlimited. - Memory int `json:"memory,omitempty" yaml:"memory,omitempty"` + Memory int `json:"memory,omitempty"` // Optional: Defaults to unlimited. - CPU int `json:"cpu,omitempty" yaml:"cpu,omitempty"` - VolumeMounts []VolumeMount `json:"volumeMounts,omitempty" yaml:"volumeMounts,omitempty"` - LivenessProbe *LivenessProbe `json:"livenessProbe,omitempty" yaml:"livenessProbe,omitempty"` - Lifecycle *Lifecycle `json:"lifecycle,omitempty" yaml:"lifecycle,omitempty"` + CPU int `json:"cpu,omitempty"` + VolumeMounts []VolumeMount `json:"volumeMounts,omitempty"` + LivenessProbe *LivenessProbe `json:"livenessProbe,omitempty"` + Lifecycle *Lifecycle `json:"lifecycle,omitempty"` // Optional: Defaults to /dev/termination-log - TerminationMessagePath string `json:"terminationMessagePath,omitempty" yaml:"terminationMessagePath,omitempty"` + TerminationMessagePath string `json:"terminationMessagePath,omitempty"` // Optional: Default to false. - Privileged bool `json:"privileged,omitempty" yaml:"privileged,omitempty"` + Privileged bool `json:"privileged,omitempty"` // Optional: Policy for pulling images for this container - ImagePullPolicy PullPolicy `json:"imagePullPolicy" yaml:"imagePullPolicy"` + ImagePullPolicy PullPolicy `json:"imagePullPolicy"` } // Handler defines a specific action that should be taken @@ -327,9 +327,9 @@ type Container struct { type Handler struct { // One and only one of the following should be specified. // Exec specifies the action to take. - Exec *ExecAction `json:"exec,omitempty" yaml:"exec,omitempty"` + Exec *ExecAction `json:"exec,omitempty"` // HTTPGet specifies the http request to perform. - HTTPGet *HTTPGetAction `json:"httpGet,omitempty" yaml:"httpGet,omitempty"` + HTTPGet *HTTPGetAction `json:"httpGet,omitempty"` } // Lifecycle describes actions that the management system should take in response to container lifecycle @@ -338,10 +338,10 @@ type Handler struct { type Lifecycle struct { // PostStart is called immediately after a container is created. If the handler fails, the container // is terminated and restarted. - PostStart *Handler `json:"postStart,omitempty" yaml:"postStart,omitempty"` + PostStart *Handler `json:"postStart,omitempty"` // PreStop is called immediately before a container is terminated. The reason for termination is // passed to the handler. Regardless of the outcome of the handler, the container is eventually terminated. - PreStop *Handler `yaml:"preStop,omitempty" json:"preStop,omitempty"` + PreStop *Handler `json:"preStop,omitempty"` } // The below types are used by kube_client and api_server. @@ -368,43 +368,43 @@ const ( type ContainerStateWaiting struct { // Reason could be pulling image, - Reason string `json:"reason,omitempty" yaml:"reason,omitempty"` + Reason string `json:"reason,omitempty"` } type ContainerStateRunning struct { - StartedAt time.Time `json:"startedAt,omitempty" yaml:"startedAt,omitempty"` + StartedAt time.Time `json:"startedAt,omitempty"` } type ContainerStateTerminated struct { - ExitCode int `json:"exitCode" yaml:"exitCode"` - Signal int `json:"signal,omitempty" yaml:"signal,omitempty"` - Reason string `json:"reason,omitempty" yaml:"reason,omitempty"` - Message string `json:"message,omitempty" yaml:"message,omitempty"` - StartedAt time.Time `json:"startedAt,omitempty" yaml:"startedAt,omitempty"` - FinishedAt time.Time `json:"finishedAt,omitempty" yaml:"finishedAt,omitempty"` + ExitCode int `json:"exitCode"` + Signal int `json:"signal,omitempty"` + Reason string `json:"reason,omitempty"` + Message string `json:"message,omitempty"` + StartedAt time.Time `json:"startedAt,omitempty"` + FinishedAt time.Time `json:"finishedAt,omitempty"` } // ContainerState holds a possible state of container. // Only one of its members may be specified. // If none of them is specified, the default one is ContainerStateWaiting. type ContainerState struct { - Waiting *ContainerStateWaiting `json:"waiting,omitempty" yaml:"waiting,omitempty"` - Running *ContainerStateRunning `json:"running,omitempty" yaml:"running,omitempty"` - Termination *ContainerStateTerminated `json:"termination,omitempty" yaml:"termination,omitempty"` + Waiting *ContainerStateWaiting `json:"waiting,omitempty"` + Running *ContainerStateRunning `json:"running,omitempty"` + Termination *ContainerStateTerminated `json:"termination,omitempty"` } type ContainerStatus struct { // TODO(dchen1107): Should we rename PodStatus to a more generic name or have a separate states // defined for container? - State ContainerState `json:"state,omitempty" yaml:"state,omitempty"` + State ContainerState `json:"state,omitempty"` // Note that this is calculated from dead containers. But those containers are subject to // garbage collection. This value will get capped at 5 by GC. - RestartCount int `json:"restartCount" yaml:"restartCount"` + RestartCount int `json:"restartCount"` // TODO(dchen1107): Deprecated this soon once we pull entire PodStatus from node, // not just PodInfo. Now we need this to remove docker.Container from API - PodIP string `json:"podIP,omitempty" yaml:"podIP,omitempty"` + PodIP string `json:"podIP,omitempty"` // TODO(dchen1107): Need to decide how to represent this in v1beta3 - Image string `yaml:"image" json:"image"` + Image string `json:"image"` } // PodInfo contains one entry for every container with available info. @@ -423,20 +423,20 @@ type RestartPolicyNever struct{} // If none of the following policies is specified, the default one // is RestartPolicyAlways. type RestartPolicy struct { - Always *RestartPolicyAlways `json:"always,omitempty" yaml:"always,omitempty"` - OnFailure *RestartPolicyOnFailure `json:"onFailure,omitempty" yaml:"onFailure,omitempty"` - Never *RestartPolicyNever `json:"never,omitempty" yaml:"never,omitempty"` + Always *RestartPolicyAlways `json:"always,omitempty"` + OnFailure *RestartPolicyOnFailure `json:"onFailure,omitempty"` + Never *RestartPolicyNever `json:"never,omitempty"` } // PodState is the state of a pod, used as either input (desired state) or output (current state). type PodState struct { - Manifest ContainerManifest `json:"manifest,omitempty" yaml:"manifest,omitempty"` - Status PodPhase `json:"status,omitempty" yaml:"status,omitempty"` + Manifest ContainerManifest `json:"manifest,omitempty"` + Status PodPhase `json:"status,omitempty"` // A human readable message indicating details about why the pod is in this state. - Message string `json:"message,omitempty" yaml:"message,omitempty"` - Host string `json:"host,omitempty" yaml:"host,omitempty"` - HostIP string `json:"hostIP,omitempty" yaml:"hostIP,omitempty"` - PodIP string `json:"podIP,omitempty" yaml:"podIP,omitempty"` + Message string `json:"message,omitempty"` + Host string `json:"host,omitempty"` + HostIP string `json:"hostIP,omitempty"` + PodIP string `json:"podIP,omitempty"` // The key of this map is the *name* of the container within the manifest; it has one // entry per container in the manifest. The value of this map is currently the output @@ -444,36 +444,36 @@ type PodState struct { // upon. // TODO: Make real decisions about what our info should look like. Re-enable fuzz test // when we have done this. - Info PodInfo `json:"info,omitempty" yaml:"info,omitempty"` + Info PodInfo `json:"info,omitempty"` } // PodList is a list of Pods. type PodList struct { - TypeMeta `json:",inline" yaml:",inline"` - ListMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"` + TypeMeta `json:",inline"` + ListMeta `json:"metadata,omitempty"` - Items []Pod `json:"items" yaml:"items"` + Items []Pod `json:"items"` } // PodSpec is a description of a pod type PodSpec struct { - Volumes []Volume `json:"volumes" yaml:"volumes"` - Containers []Container `json:"containers" yaml:"containers"` - RestartPolicy RestartPolicy `json:"restartPolicy,omitempty" yaml:"restartPolicy,omitempty"` + Volumes []Volume `json:"volumes"` + Containers []Container `json:"containers"` + RestartPolicy RestartPolicy `json:"restartPolicy,omitempty"` // NodeSelector is a selector which must be true for the pod to fit on a node - NodeSelector map[string]string `json:"nodeSelector,omitempty" yaml:"nodeSelector,omitempty"` + NodeSelector map[string]string `json:"nodeSelector,omitempty"` } // PodStatus represents information about the status of a pod. Status may trail the actual // state of a system. type PodStatus struct { - Phase PodPhase `json:"phase,omitempty" yaml:"phase,omitempty"` + Phase PodPhase `json:"phase,omitempty"` // Host is the name of the node that this Pod is currently bound to, or empty if no // assignment has been done. - Host string `json:"host,omitempty" yaml:"host,omitempty"` - HostIP string `json:"hostIP,omitempty" yaml:"hostIP,omitempty"` - PodIP string `json:"podIP,omitempty" yaml:"podIP,omitempty"` + Host string `json:"host,omitempty"` + HostIP string `json:"hostIP,omitempty"` + PodIP string `json:"podIP,omitempty"` // The key of this map is the *name* of the container within the manifest; it has one // entry per container in the manifest. The value of this map is currently the output @@ -481,46 +481,46 @@ type PodStatus struct { // upon. // TODO: Make real decisions about what our info should look like. Re-enable fuzz test // when we have done this. - Info PodInfo `json:"info,omitempty" yaml:"info,omitempty"` + Info PodInfo `json:"info,omitempty"` } // Pod is a collection of containers, used as either input (create, update) or as output (list, get). type Pod struct { - TypeMeta `json:",inline" yaml:",inline"` - ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"` + TypeMeta `json:",inline"` + ObjectMeta `json:"metadata,omitempty"` // Spec defines the behavior of a pod. - Spec PodSpec `json:"spec,omitempty" yaml:"spec,omitempty"` + Spec PodSpec `json:"spec,omitempty"` // Status represents the current information about a pod. This data may not be up // to date. - Status PodStatus `json:"status,omitempty" yaml:"status,omitempty"` + Status PodStatus `json:"status,omitempty"` } // PodTemplateSpec describes the data a pod should have when created from a template type PodTemplateSpec struct { // Metadata of the pods created from this template. - ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"` + ObjectMeta `json:"metadata,omitempty"` // Spec defines the behavior of a pod. - Spec PodSpec `json:"spec,omitempty" yaml:"spec,omitempty"` + Spec PodSpec `json:"spec,omitempty"` } // PodTemplate describes a template for creating copies of a predefined pod. type PodTemplate struct { - TypeMeta `json:",inline" yaml:",inline"` - ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"` + TypeMeta `json:",inline"` + ObjectMeta `json:"metadata,omitempty"` // Spec defines the pods that will be created from this template - Spec PodTemplateSpec `json:"spec,omitempty" yaml:"spec,omitempty"` + Spec PodTemplateSpec `json:"spec,omitempty"` } // PodTemplateList is a list of PodTemplates. type PodTemplateList struct { - TypeMeta `json:",inline" yaml:",inline"` - ListMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"` + TypeMeta `json:",inline"` + ListMeta `json:"metadata,omitempty"` - Items []PodTemplate `json:"items" yaml:"items"` + Items []PodTemplate `json:"items"` } // ReplicationControllerSpec is the specification of a replication controller. @@ -528,57 +528,57 @@ type PodTemplateList struct { // a TemplateRef or a Template set. type ReplicationControllerSpec struct { // Replicas is the number of desired replicas. - Replicas int `json:"replicas" yaml:"replicas"` + Replicas int `json:"replicas"` // Selector is a label query over pods that should match the Replicas count. - Selector map[string]string `json:"selector" yaml:"selector"` + Selector map[string]string `json:"selector"` // TemplateRef is a reference to an object that describes the pod that will be created if // insufficient replicas are detected. This reference is ignored if a Template is set. // Must be set before converting to a v1beta3 API object - TemplateRef *ObjectReference `json:"templateRef,omitempty" yaml:"templateRef,omitempty"` + TemplateRef *ObjectReference `json:"templateRef,omitempty"` // Template is the object that describes the pod that will be created if // insufficient replicas are detected. Internally, this takes precedence over a // TemplateRef. // Must be set before converting to a v1beta1 or v1beta2 API object. - Template *PodTemplateSpec `json:"template,omitempty" yaml:"template,omitempty"` + Template *PodTemplateSpec `json:"template,omitempty"` } // ReplicationControllerStatus represents the current status of a replication // controller. type ReplicationControllerStatus struct { // Replicas is the number of actual replicas. - Replicas int `json:"replicas" yaml:"replicas"` + Replicas int `json:"replicas"` } // ReplicationController represents the configuration of a replication controller. type ReplicationController struct { - TypeMeta `json:",inline" yaml:",inline"` - ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"` + TypeMeta `json:",inline"` + ObjectMeta `json:"metadata,omitempty"` // Spec defines the desired behavior of this replication controller. - Spec ReplicationControllerSpec `json:"spec,omitempty" yaml:"spec,omitempty"` + Spec ReplicationControllerSpec `json:"spec,omitempty"` // Status is the current status of this replication controller. This data may be // out of date by some window of time. - Status ReplicationControllerStatus `json:"status,omitempty" yaml:"status,omitempty"` + Status ReplicationControllerStatus `json:"status,omitempty"` } // ReplicationControllerList is a collection of replication controllers. type ReplicationControllerList struct { - TypeMeta `json:",inline" yaml:",inline"` - ListMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"` + TypeMeta `json:",inline"` + ListMeta `json:"metadata,omitempty"` - Items []ReplicationController `json:"items" yaml:"items"` + Items []ReplicationController `json:"items"` } // ServiceList holds a list of services. type ServiceList struct { - TypeMeta `json:",inline" yaml:",inline"` - ListMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"` + TypeMeta `json:",inline"` + ListMeta `json:"metadata,omitempty"` - Items []Service `json:"items" yaml:"items"` + Items []Service `json:"items"` } // ServiceStatus represents the current status of a service @@ -588,74 +588,74 @@ type ServiceStatus struct{} type ServiceSpec struct { // Port is the TCP or UDP port that will be made available to each pod for connecting to the pods // proxied by this service. - Port int `json:"port" yaml:"port"` + Port int `json:"port"` // Optional: Supports "TCP" and "UDP". Defaults to "TCP". - Protocol Protocol `json:"protocol,omitempty" yaml:"protocol,omitempty"` + Protocol Protocol `json:"protocol,omitempty"` // This service will route traffic to pods having labels matching this selector. - Selector map[string]string `json:"selector,omitempty" yaml:"selector,omitempty"` + Selector map[string]string `json:"selector,omitempty"` // PortalIP is usually assigned by the master. If specified by the user // we will try to respect it or else fail the request. This field can // not be changed by updates. - PortalIP string `json:"portalIP,omitempty" yaml:"portalIP,omitempty"` + PortalIP string `json:"portalIP,omitempty"` // ProxyPort is assigned by the master. If 0, the proxy will choose an ephemeral port. // TODO: This is awkward - if we had a BoundService, it would be better factored. - ProxyPort int `json:"proxyPort,omitempty" yaml:"proxyPort,omitempty"` + ProxyPort int `json:"proxyPort,omitempty"` // CreateExternalLoadBalancer indicates whether a load balancer should be created for this service. - CreateExternalLoadBalancer bool `json:"createExternalLoadBalancer,omitempty" yaml:"createExternalLoadBalancer,omitempty"` + CreateExternalLoadBalancer bool `json:"createExternalLoadBalancer,omitempty"` // PublicIPs are used by external load balancers. - PublicIPs []string `json:"publicIPs,omitempty" yaml:"publicIPs,omitempty"` + PublicIPs []string `json:"publicIPs,omitempty"` // ContainerPort is the name of the port on the container to direct traffic to. // Optional, if unspecified use the first port on the container. - ContainerPort util.IntOrString `json:"containerPort,omitempty" yaml:"containerPort,omitempty"` + ContainerPort util.IntOrString `json:"containerPort,omitempty"` } // Service is a named abstraction of software service (for example, mysql) consisting of local port // (for example 3306) that the proxy listens on, and the selector that determines which pods // will answer requests sent through the proxy. type Service struct { - TypeMeta `json:",inline" yaml:",inline"` - ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"` + TypeMeta `json:",inline"` + ObjectMeta `json:"metadata,omitempty"` // Spec defines the behavior of a service. - Spec ServiceSpec `json:"spec,omitempty" yaml:"spec,omitempty"` + Spec ServiceSpec `json:"spec,omitempty"` // Status represents the current status of a service. - Status ServiceStatus `json:"status,omitempty" yaml:"status,omitempty"` + Status ServiceStatus `json:"status,omitempty"` } // Endpoints is a collection of endpoints that implement the actual service, for example: // Name: "mysql", Endpoints: ["10.10.1.1:1909", "10.10.2.2:8834"] type Endpoints struct { - TypeMeta `json:",inline" yaml:",inline"` - ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"` + TypeMeta `json:",inline"` + ObjectMeta `json:"metadata,omitempty"` - Endpoints []string `json:"endpoints,omitempty" yaml:"endpoints,omitempty"` + Endpoints []string `json:"endpoints,omitempty"` } // EndpointsList is a list of endpoints. type EndpointsList struct { - TypeMeta `json:",inline" yaml:",inline"` - ListMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"` + TypeMeta `json:",inline"` + ListMeta `json:"metadata,omitempty"` - Items []Endpoints `json:"items" yaml:"items"` + Items []Endpoints `json:"items"` } // NodeSpec describes the attributes that a node is created with. type NodeSpec struct { // Capacity represents the available resources of a node - Capacity ResourceList `json:"capacity,omitempty" yaml:"capacity,omitempty"` + Capacity ResourceList `json:"capacity,omitempty"` } // NodeStatus is information about the current status of a node. type NodeStatus struct { // Queried from cloud provider, if available. - HostIP string `json:"hostIP,omitempty" yaml:"hostIP,omitempty"` + HostIP string `json:"hostIP,omitempty"` } // NodeResources is an object for conveying resource information about a node. @@ -663,7 +663,7 @@ type NodeStatus struct { // TODO: Use ResourceList instead? type NodeResources struct { // Capacity represents the available resources of a node - Capacity ResourceList `json:"capacity,omitempty" yaml:"capacity,omitempty"` + Capacity ResourceList `json:"capacity,omitempty"` } type ResourceName string @@ -674,56 +674,56 @@ type ResourceList map[ResourceName]util.IntOrString // The name of the minion according to etcd is in ObjectMeta.Name. // TODO: Rename to Node type Minion struct { - TypeMeta `json:",inline" yaml:",inline"` - ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"` + TypeMeta `json:",inline"` + ObjectMeta `json:"metadata,omitempty"` // Spec defines the behavior of a node. - Spec NodeSpec `json:"spec,omitempty" yaml:"spec,omitempty"` + Spec NodeSpec `json:"spec,omitempty"` // Status describes the current status of a Node - Status NodeStatus `json:"status,omitempty" yaml:"status,omitempty"` + Status NodeStatus `json:"status,omitempty"` } // MinionList is a list of minions. type MinionList struct { - TypeMeta `json:",inline" yaml:",inline"` - ListMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"` + TypeMeta `json:",inline"` + ListMeta `json:"metadata,omitempty"` - Items []Minion `json:"items" yaml:"items"` + Items []Minion `json:"items"` } // Binding is written by a scheduler to cause a pod to be bound to a host. type Binding struct { - TypeMeta `json:",inline" yaml:",inline"` - ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"` + TypeMeta `json:",inline"` + ObjectMeta `json:"metadata,omitempty"` - PodID string `json:"podID" yaml:"podID"` - Host string `json:"host" yaml:"host"` + PodID string `json:"podID"` + Host string `json:"host"` } // Status is a return value for calls that don't return other objects. // TODO: this could go in apiserver, but I'm including it here so clients needn't // import both. type Status struct { - TypeMeta `json:",inline" yaml:",inline"` - ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"` + TypeMeta `json:",inline"` + ObjectMeta `json:"metadata,omitempty"` // One of: "Success", "Failure", "Working" (for operations not yet completed) - Status string `json:"status,omitempty" yaml:"status,omitempty"` + Status string `json:"status,omitempty"` // A human-readable description of the status of this operation. - Message string `json:"message,omitempty" yaml:"message,omitempty"` + Message string `json:"message,omitempty"` // A machine-readable description of why this operation is in the // "Failure" or "Working" status. If this value is empty there // is no information available. A Reason clarifies an HTTP status // code but does not override it. - Reason StatusReason `json:"reason,omitempty" yaml:"reason,omitempty"` + Reason StatusReason `json:"reason,omitempty"` // Extended data associated with the reason. Each reason may define its // own extended details. This field is optional and the data returned // is not guaranteed to conform to any schema except that defined by // the reason type. - Details *StatusDetails `json:"details,omitempty" yaml:"details,omitempty"` + Details *StatusDetails `json:"details,omitempty"` // Suggested HTTP return code for this status, 0 if not set. - Code int `json:"code,omitempty" yaml:"code,omitempty"` + Code int `json:"code,omitempty"` } // StatusDetails is a set of additional properties that MAY be set by the @@ -736,13 +736,13 @@ type StatusDetails struct { // The ID attribute of the resource associated with the status StatusReason // (when there is a single ID which can be described). // TODO: replace with Name with v1beta3 - ID string `json:"id,omitempty" yaml:"id,omitempty"` + ID string `json:"id,omitempty"` // The kind attribute of the resource associated with the status StatusReason. // On some operations may differ from the requested resource Kind. - Kind string `json:"kind,omitempty" yaml:"kind,omitempty"` + Kind string `json:"kind,omitempty"` // The Causes array includes more details associated with the StatusReason // failure. Not all StatusReasons may provide detailed causes. - Causes []StatusCause `json:"causes,omitempty" yaml:"causes,omitempty"` + Causes []StatusCause `json:"causes,omitempty"` } // Values of Status.Status @@ -832,10 +832,10 @@ const ( type StatusCause struct { // A machine-readable description of the cause of the error. If this value is // empty there is no information available. - Type CauseType `json:"reason,omitempty" yaml:"reason,omitempty"` + Type CauseType `json:"reason,omitempty"` // A human-readable description of the cause of the error. This field may be // presented as-is to a reader. - Message string `json:"message,omitempty" yaml:"message,omitempty"` + Message string `json:"message,omitempty"` // The field of the resource that has caused this error, as named by its JSON // serialization. May include dot and postfix notation for nested attributes. // Arrays are zero-indexed. Fields may appear more than once in an array of @@ -845,7 +845,7 @@ type StatusCause struct { // Examples: // "name" - the field "name" on the current resource // "items[0].name" - the field "name" on the first array entry in "items" - Field string `json:"field,omitempty" yaml:"field,omitempty"` + Field string `json:"field,omitempty"` } // CauseType is a machine readable value providing more detail about what @@ -873,26 +873,26 @@ const ( // ServerOp is an operation delivered to API clients. type ServerOp struct { - TypeMeta `yaml:",inline" json:",inline"` - ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"` + TypeMeta `json:",inline"` + ObjectMeta `json:"metadata,omitempty"` } // ServerOpList is a list of operations, as delivered to API clients. type ServerOpList struct { - TypeMeta `yaml:",inline" json:",inline"` - ListMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"` + TypeMeta `json:",inline"` + ListMeta `json:"metadata,omitempty"` - Items []ServerOp `yaml:"items" json:"items"` + Items []ServerOp `json:"items"` } // ObjectReference contains enough information to let you inspect or modify the referred object. type ObjectReference struct { - Kind string `json:"kind,omitempty" yaml:"kind,omitempty"` - Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"` - Name string `json:"name,omitempty" yaml:"name,omitempty"` - UID string `json:"uid,omitempty" yaml:"uid,omitempty"` - APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty"` - ResourceVersion string `json:"resourceVersion,omitempty" yaml:"resourceVersion,omitempty"` + Kind string `json:"kind,omitempty"` + Namespace string `json:"namespace,omitempty"` + Name string `json:"name,omitempty"` + UID string `json:"uid,omitempty"` + APIVersion string `json:"apiVersion,omitempty"` + ResourceVersion string `json:"resourceVersion,omitempty"` // Optional. If referring to a piece of an object instead of an entire object, this string // should contain a valid field access statement. For example, @@ -901,17 +901,17 @@ type ObjectReference struct { // both go and JavaScript. This is syntax is chosen only to have some well-defined way of // referencing a part of an object. // TODO: this design is not final and this field is subject to change in the future. - FieldPath string `json:"fieldPath,omitempty" yaml:"fieldPath,omitempty"` + FieldPath string `json:"fieldPath,omitempty"` } // Event is a report of an event somewhere in the cluster. // TODO: Decide whether to store these separately or with the object they apply to. type Event struct { - TypeMeta `yaml:",inline" json:",inline"` - ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"` + TypeMeta `json:",inline"` + ObjectMeta `json:"metadata,omitempty"` // Required. The object that this event is about. - InvolvedObject ObjectReference `json:"involvedObject,omitempty" yaml:"involvedObject,omitempty"` + InvolvedObject ObjectReference `json:"involvedObject,omitempty"` // Should be a short, machine understandable string that describes the current status // of the referred object. This should not give the reason for being in this state. @@ -920,32 +920,32 @@ type Event struct { // always be used for the same status. // TODO: define a way of making sure these are consistent and don't collide. // TODO: provide exact specification for format. - Status string `json:"status,omitempty" yaml:"status,omitempty"` + Status string `json:"status,omitempty"` // Optional; this should be a short, machine understandable string that gives the reason // for the transition into the object's current status. For example, if ObjectStatus is // "cantStart", StatusReason might be "imageNotFound". // TODO: provide exact specification for format. - Reason string `json:"reason,omitempty" yaml:"reason,omitempty"` + Reason string `json:"reason,omitempty"` // Optional. A human-readable description of the status of this operation. // TODO: decide on maximum length. - Message string `json:"message,omitempty" yaml:"message,omitempty"` + Message string `json:"message,omitempty"` // Optional. The component reporting this event. Should be a short machine understandable string. // TODO: provide exact specification for format. - Source string `json:"source,omitempty" yaml:"source,omitempty"` + Source string `json:"source,omitempty"` // The time at which the client recorded the event. (Time of server receipt is in TypeMeta.) - Timestamp util.Time `json:"timestamp,omitempty" yaml:"timestamp,omitempty"` + Timestamp util.Time `json:"timestamp,omitempty"` } // EventList is a list of events. type EventList struct { - TypeMeta `yaml:",inline" json:",inline"` - ListMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"` + TypeMeta `json:",inline"` + ListMeta `json:"metadata,omitempty"` - Items []Event `yaml:"items" json:"items"` + Items []Event `json:"items"` } // ContainerManifest corresponds to the Container Manifest format, documented at: @@ -954,48 +954,48 @@ type EventList struct { // DEPRECATED: Replaced with BoundPod type ContainerManifest struct { // Required: This must be a supported version string, such as "v1beta1". - Version string `yaml:"version" json:"version"` + Version string `json:"version"` // Required: This must be a DNS_SUBDOMAIN. // TODO: ID on Manifest is deprecated and will be removed in the future. - ID string `yaml:"id" json:"id"` + ID string `json:"id"` // TODO: UUID on Manifest is deprecated in the future once we are done // with the API refactoring. It is required for now to determine the instance // of a Pod. - UUID string `yaml:"uuid,omitempty" json:"uuid,omitempty"` - Volumes []Volume `yaml:"volumes" json:"volumes"` - Containers []Container `yaml:"containers" json:"containers"` - RestartPolicy RestartPolicy `json:"restartPolicy,omitempty" yaml:"restartPolicy,omitempty"` + UUID string `json:"uuid,omitempty"` + Volumes []Volume `json:"volumes"` + Containers []Container `json:"containers"` + RestartPolicy RestartPolicy `json:"restartPolicy,omitempty"` } // ContainerManifestList is used to communicate container manifests to kubelet. // DEPRECATED: Replaced with BoundPods type ContainerManifestList struct { - TypeMeta `json:",inline" yaml:",inline"` - ListMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"` + TypeMeta `json:",inline"` + ListMeta `json:"metadata,omitempty"` - Items []ContainerManifest `json:"items" yaml:"items,omitempty"` + Items []ContainerManifest `json:"items"` } // BoundPod is a collection of containers that should be run on a host. A BoundPod // defines how a Pod may change after a Binding is created. A Pod is a request to // execute a pod, whereas a BoundPod is the specification that would be run on a server. type BoundPod struct { - TypeMeta `json:",inline" yaml:",inline"` - ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"` + TypeMeta `json:",inline"` + ObjectMeta `json:"metadata,omitempty"` // Spec defines the behavior of a pod. - Spec PodSpec `json:"spec,omitempty" yaml:"spec,omitempty"` + Spec PodSpec `json:"spec,omitempty"` } // BoundPods is a list of Pods bound to a common server. The resource version of // the pod list is guaranteed to only change when the list of bound pods changes. type BoundPods struct { - TypeMeta `json:",inline" yaml:",inline"` - ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"` + TypeMeta `json:",inline"` + ObjectMeta `json:"metadata,omitempty"` // Host is the name of a node that these pods were bound to. - Host string `json:"host" yaml:"host"` + Host string `json:"host"` // Items is the list of all pods bound to a given host. - Items []BoundPod `json:"items" yaml:"items"` + Items []BoundPod `json:"items"` } diff --git a/pkg/api/unversioned.go b/pkg/api/unversioned.go index 4f405580b13..302c0eaa1a8 100644 --- a/pkg/api/unversioned.go +++ b/pkg/api/unversioned.go @@ -22,5 +22,5 @@ package api // version negotiation. APIVersions isn't just an unnamed array of // strings in order to allow for future evolution, though unversioned type APIVersions struct { - Versions []string `json:"versions" yaml:"versions"` + Versions []string `json:"versions"` } diff --git a/pkg/api/v1beta1/types.go b/pkg/api/v1beta1/types.go index 0d7a3a69fe2..fad4907f123 100644 --- a/pkg/api/v1beta1/types.go +++ b/pkg/api/v1beta1/types.go @@ -50,34 +50,34 @@ import ( // This is used as the representation of Kubernetes workloads. type ContainerManifest struct { // Required: This must be a supported version string, such as "v1beta1". - Version string `yaml:"version" json:"version" description:"manifest version; must be v1beta1"` + Version string `json:"version" description:"manifest version; must be v1beta1"` // Required: This must be a DNS_SUBDOMAIN. // TODO: ID on Manifest is deprecated and will be removed in the future. - ID string `yaml:"id" json:"id" description:"manifest name; must be a DNS_SUBDOMAIN"` + ID string `json:"id" description:"manifest name; must be a DNS_SUBDOMAIN"` // TODO: UUID on Manifext is deprecated in the future once we are done // with the API refactory. It is required for now to determine the instance // of a Pod. - UUID string `yaml:"uuid,omitempty" json:"uuid,omitempty" description:"manifest UUID"` - Volumes []Volume `yaml:"volumes" json:"volumes" description:"list of volumes that can be mounted by containers belonging to the pod"` - Containers []Container `yaml:"containers" json:"containers" description:"list of containers belonging to the pod"` - RestartPolicy RestartPolicy `json:"restartPolicy,omitempty" yaml:"restartPolicy,omitempty" description:"restart policy for all containers within the pod; one of RestartPolicyAlways, RestartPolicyOnFailure, RestartPolicyNever"` + UUID string `json:"uuid,omitempty" description:"manifest UUID"` + Volumes []Volume `json:"volumes" description:"list of volumes that can be mounted by containers belonging to the pod"` + Containers []Container `json:"containers" description:"list of containers belonging to the pod"` + RestartPolicy RestartPolicy `json:"restartPolicy,omitempty" description:"restart policy for all containers within the pod; one of RestartPolicyAlways, RestartPolicyOnFailure, RestartPolicyNever"` } // ContainerManifestList is used to communicate container manifests to kubelet. type ContainerManifestList struct { - TypeMeta `json:",inline" yaml:",inline"` - Items []ContainerManifest `json:"items" yaml:"items" description:"list of pod container manifests"` + TypeMeta `json:",inline"` + Items []ContainerManifest `json:"items" description:"list of pod container manifests"` } // Volume represents a named volume in a pod that may be accessed by any containers in the pod. type Volume struct { // Required: This must be a DNS_LABEL. Each volume in a pod must have // a unique name. - Name string `yaml:"name" json:"name" description:"volume name; must be a DNS_LABEL and unique within the pod"` + Name string `json:"name" description:"volume name; must be a DNS_LABEL and unique within the pod"` // Source represents the location and type of a volume to mount. // This is optional for now. If not specified, the Volume is implied to be an EmptyDir. // This implied behavior is deprecated and will be removed in a future version. - Source *VolumeSource `yaml:"source" json:"source" description:"location and type of volume to mount; at most one of HostDir, EmptyDir, GCEPersistentDisk, or GitRepo; default is EmptyDir"` + Source *VolumeSource `json:"source" description:"location and type of volume to mount; at most one of HostDir, EmptyDir, GCEPersistentDisk, or GitRepo; default is EmptyDir"` } // VolumeSource represents the source location of a valume to mount. @@ -88,19 +88,19 @@ type VolumeSource struct { // things that are allowed to see the host machine. Most containers will NOT need this. // TODO(jonesdl) We need to restrict who can use host directory mounts and // who can/can not mount host directories as read/write. - HostDir *HostDir `yaml:"hostDir" json:"hostDir" description:"pre-existing host directory; generally for privileged system daemons or other agents tied to the host"` + HostDir *HostDir `json:"hostDir" description:"pre-existing host directory; generally for privileged system daemons or other agents tied to the host"` // EmptyDir represents a temporary directory that shares a pod's lifetime. - EmptyDir *EmptyDir `yaml:"emptyDir" json:"emptyDir" description:"temporary directory that shares a pod's lifetime"` + EmptyDir *EmptyDir `json:"emptyDir" description:"temporary directory that shares a pod's lifetime"` // GCEPersistentDisk represents a GCE Disk resource that is attached to a // kubelet's host machine and then exposed to the pod. - GCEPersistentDisk *GCEPersistentDisk `yaml:"persistentDisk" json:"persistentDisk" description:"GCE disk resource attached to the host machine on demand"` + GCEPersistentDisk *GCEPersistentDisk `json:"persistentDisk" description:"GCE disk resource attached to the host machine on demand"` // GitRepo represents a git repository at a particular revision. - GitRepo *GitRepo `json:"gitRepo" yaml:"gitRepo" description:"git repository at a particular revision"` + GitRepo *GitRepo `json:"gitRepo" description:"git repository at a particular revision"` } // HostDir represents bare host directory volume. type HostDir struct { - Path string `yaml:"path" json:"path" description:"path of the directory on the host"` + Path string `json:"path" description:"path of the directory on the host"` } type EmptyDir struct{} @@ -122,59 +122,59 @@ const ( // A GCE PD can only be mounted as read/write once. type GCEPersistentDisk struct { // Unique name of the PD resource. Used to identify the disk in GCE - PDName string `yaml:"pdName" json:"pdName" description:"unique name of the PD resource in GCE"` + PDName string `json:"pdName" description:"unique name of the PD resource in GCE"` // Required: Filesystem type to mount. // Must be a filesystem type supported by the host operating system. // Ex. "ext4", "xfs", "ntfs" // TODO: how do we prevent errors in the filesystem from compromising the machine // TODO: why omitempty if required? - FSType string `yaml:"fsType,omitempty" json:"fsType,omitempty" description:"file system type to mount, such as ext4, xfs, ntfs"` + FSType string `json:"fsType,omitempty" description:"file system type to mount, such as ext4, xfs, ntfs"` // Optional: Partition on the disk to mount. // If omitted, kubelet will attempt to mount the device name. // Ex. For /dev/sda1, this field is "1", for /dev/sda, this field 0 or empty. - Partition int `yaml:"partition,omitempty" json:"partition,omitempty" description:"partition on the disk to mount (e.g., '1' for /dev/sda1); if omitted the plain device name (e.g., /dev/sda) will be mounted"` + Partition int `json:"partition,omitempty" description:"partition on the disk to mount (e.g., '1' for /dev/sda1); if omitted the plain device name (e.g., /dev/sda) will be mounted"` // Optional: Defaults to false (read/write). ReadOnly here will force // the ReadOnly setting in VolumeMounts. - ReadOnly bool `yaml:"readOnly,omitempty" json:"readOnly,omitempty" description:"read-only if true, read-write otherwise (false or unspecified)"` + ReadOnly bool `json:"readOnly,omitempty" description:"read-only if true, read-write otherwise (false or unspecified)"` } // GitRepo represents a volume that is pulled from git when the pod is created. type GitRepo struct { // Repository URL - Repository string `yaml:"repository" json:"repository" description:"repository URL"` + Repository string `json:"repository" description:"repository URL"` // Commit hash, this is optional - Revision string `yaml:"revision" json:"revision" description:"commit hash for the specified revision"` + Revision string `json:"revision" description:"commit hash for the specified revision"` } // Port represents a network port in a single container type Port struct { // Optional: If specified, this must be a DNS_LABEL. Each named port // in a pod must have a unique name. - Name string `yaml:"name,omitempty" json:"name,omitempty" description:"name for the port that can be referred to by services; must be a DNS_LABEL and unique without the pod"` + Name string `json:"name,omitempty" description:"name for the port that can be referred to by services; must be a DNS_LABEL and unique without the pod"` // Optional: If specified, this must be a valid port number, 0 < x < 65536. - HostPort int `yaml:"hostPort,omitempty" json:"hostPort,omitempty" description:"number of port to expose on the host; most containers do not need this"` + HostPort int `json:"hostPort,omitempty" description:"number of port to expose on the host; most containers do not need this"` // Required: This must be a valid port number, 0 < x < 65536. - ContainerPort int `yaml:"containerPort" json:"containerPort" description:"number of port to expose on the pod's IP address"` + ContainerPort int `json:"containerPort" description:"number of port to expose on the pod's IP address"` // Optional: Defaults to "TCP". - Protocol Protocol `yaml:"protocol,omitempty" json:"protocol,omitempty" description:"protocol for port; must be UDP or TCP; TCP if unspecified"` + Protocol Protocol `json:"protocol,omitempty" description:"protocol for port; must be UDP or TCP; TCP if unspecified"` // Optional: What host IP to bind the external port to. - HostIP string `yaml:"hostIP,omitempty" json:"hostIP,omitempty" description:"host IP to bind the port to"` + HostIP string `json:"hostIP,omitempty" description:"host IP to bind the port to"` } // VolumeMount describes a mounting of a Volume within a container. type VolumeMount struct { // Required: This must match the Name of a Volume [above]. - Name string `yaml:"name" json:"name" description:"name of the volume to mount"` + Name string `json:"name" description:"name of the volume to mount"` // Optional: Defaults to false (read-write). - ReadOnly bool `yaml:"readOnly,omitempty" json:"readOnly,omitempty" description:"mounted read-only if true, read-write otherwise (false or unspecified)"` + ReadOnly bool `json:"readOnly,omitempty" description:"mounted read-only if true, read-write otherwise (false or unspecified)"` // Required. // Exactly one of the following must be set. If both are set, prefer MountPath. // DEPRECATED: Path will be removed in a future version of the API. - MountPath string `yaml:"mountPath,omitempty" json:"mountPath,omitempty" description:"path within the container at which the volume should be mounted; overrides path"` - Path string `yaml:"path,omitempty" json:"path,omitempty" description:"path within the container at which the volume should be mounted; deprecated"` + MountPath string `json:"mountPath,omitempty" description:"path within the container at which the volume should be mounted; overrides path"` + Path string `json:"path,omitempty" description:"path within the container at which the volume should be mounted; deprecated"` // One of: "LOCAL" (local volume) or "HOST" (external mount from the host). Default: LOCAL. // DEPRECATED: MountType will be removed in a future version of the API. - MountType string `yaml:"mountType,omitempty" json:"mountType,omitempty" description:"LOCAL or HOST; defaults to LOCAL; deprecated"` + MountType string `json:"mountType,omitempty" description:"LOCAL or HOST; defaults to LOCAL; deprecated"` } // EnvVar represents an environment variable present in a Container. @@ -182,26 +182,26 @@ type EnvVar struct { // Required: This must be a C_IDENTIFIER. // Exactly one of the following must be set. If both are set, prefer Name. // DEPRECATED: EnvVar.Key will be removed in a future version of the API. - Name string `yaml:"name" json:"name" description:"name of the environment variable; must be a C_IDENTIFIER"` - Key string `yaml:"key,omitempty" json:"key,omitempty" description:"name of the environment variable; must be a C_IDENTIFIER; deprecated - use name instead"` + Name string `json:"name" description:"name of the environment variable; must be a C_IDENTIFIER"` + Key string `json:"key,omitempty" description:"name of the environment variable; must be a C_IDENTIFIER; deprecated - use name instead"` // Optional: defaults to "". - Value string `yaml:"value,omitempty" json:"value,omitempty" description:"value of the environment variable; defaults to empty string"` + Value string `json:"value,omitempty" description:"value of the environment variable; defaults to empty string"` } // HTTPGetAction describes an action based on HTTP Get requests. type HTTPGetAction struct { // Optional: Path to access on the HTTP server. - Path string `yaml:"path,omitempty" json:"path,omitempty" description:"path to access on the HTTP server"` + Path string `json:"path,omitempty" description:"path to access on the HTTP server"` // Required: Name or number of the port to access on the container. - Port util.IntOrString `yaml:"port,omitempty" json:"port,omitempty" description:"number or name of the port to access on the container"` + Port util.IntOrString `json:"port,omitempty" description:"number or name of the port to access on the container"` // Optional: Host name to connect to, defaults to the pod IP. - Host string `yaml:"host,omitempty" json:"host,omitempty" description:"hostname to connect to; defaults to pod IP"` + Host string `json:"host,omitempty" description:"hostname to connect to; defaults to pod IP"` } // TCPSocketAction describes an action based on opening a socket type TCPSocketAction struct { // Required: Port to connect to. - Port util.IntOrString `yaml:"port,omitempty" json:"port,omitempty" description:"number of name of the port to access on the container"` + Port util.IntOrString `json:"port,omitempty" description:"number of name of the port to access on the container"` } // ExecAction describes a "run in container" action. @@ -211,20 +211,20 @@ type ExecAction struct { // not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use // a shell, you need to explicitly call out to that shell. // A return code of zero is treated as 'Healthy', non-zero is 'Unhealthy' - Command []string `yaml:"command,omitempty" json:"command,omitempty" description:"command line to execute inside the container; working directory for the command is root ('/') in the container's file system; the command is exec'd, not run inside a shell; exit status of 0 is treated as live/healthy and non-zero is unhealthy"` + Command []string `json:"command,omitempty" description:"command line to execute inside the container; working directory for the command is root ('/') in the container's file system; the command is exec'd, not run inside a shell; exit status of 0 is treated as live/healthy and non-zero is unhealthy"` } // LivenessProbe describes a liveness probe to be examined to the container. // TODO: pass structured data to the actions, and document that data here. type LivenessProbe struct { // HTTPGetProbe parameters, required if Type == 'http' - HTTPGet *HTTPGetAction `yaml:"httpGet,omitempty" json:"httpGet,omitempty" description:"parameters for HTTP-based liveness probe"` + HTTPGet *HTTPGetAction `json:"httpGet,omitempty" description:"parameters for HTTP-based liveness probe"` // TCPSocketProbe parameter, required if Type == 'tcp' - TCPSocket *TCPSocketAction `yaml:"tcpSocket,omitempty" json:"tcpSocket,omitempty" description:"parameters for TCP-based liveness probe"` + TCPSocket *TCPSocketAction `json:"tcpSocket,omitempty" description:"parameters for TCP-based liveness probe"` // ExecProbe parameter, required if Type == 'exec' - Exec *ExecAction `yaml:"exec,omitempty" json:"exec,omitempty" description:"parameters for exec-based liveness probe"` + Exec *ExecAction `json:"exec,omitempty" description:"parameters for exec-based liveness probe"` // Length of time before health checking is activated. In seconds. - InitialDelaySeconds int64 `yaml:"initialDelaySeconds,omitempty" json:"initialDelaySeconds,omitempty" description:"number of seconds after the container has started before liveness probes are initiated"` + InitialDelaySeconds int64 `json:"initialDelaySeconds,omitempty" description:"number of seconds after the container has started before liveness probes are initiated"` } // PullPolicy describes a policy for if/when to pull a container image @@ -243,28 +243,28 @@ const ( type Container struct { // Required: This must be a DNS_LABEL. Each container in a pod must // have a unique name. - Name string `yaml:"name" json:"name" description:"name of the container; must be a DNS_LABEL and unique within the pod"` + Name string `json:"name" description:"name of the container; must be a DNS_LABEL and unique within the pod"` // Required. - Image string `yaml:"image" json:"image" description:"Docker image name"` + Image string `json:"image" description:"Docker image name"` // Optional: Defaults to whatever is defined in the image. - Command []string `yaml:"command,omitempty" json:"command,omitempty" description:"command argv array; not executed within a shell; defaults to entrypoint or command in the image"` + Command []string `json:"command,omitempty" description:"command argv array; not executed within a shell; defaults to entrypoint or command in the image"` // Optional: Defaults to Docker's default. - WorkingDir string `yaml:"workingDir,omitempty" json:"workingDir,omitempty" description:"container's working directory; defaults to image's default"` - Ports []Port `yaml:"ports,omitempty" json:"ports,omitempty" description:"list of ports to expose from the container"` - Env []EnvVar `yaml:"env,omitempty" json:"env,omitempty" description:"list of environment variables to set in the container"` + WorkingDir string `json:"workingDir,omitempty" description:"container's working directory; defaults to image's default"` + Ports []Port `json:"ports,omitempty" description:"list of ports to expose from the container"` + Env []EnvVar `json:"env,omitempty" description:"list of environment variables to set in the container"` // Optional: Defaults to unlimited. - Memory int `yaml:"memory,omitempty" json:"memory,omitempty" description:"memory limit in bytes; defaults to unlimited"` + Memory int `json:"memory,omitempty" description:"memory limit in bytes; defaults to unlimited"` // Optional: Defaults to unlimited. - CPU int `yaml:"cpu,omitempty" json:"cpu,omitempty" description:"CPU share in thousandths of a core"` - VolumeMounts []VolumeMount `yaml:"volumeMounts,omitempty" json:"volumeMounts,omitempty" description:"pod volumes to mount into the container's filesystem"` - LivenessProbe *LivenessProbe `yaml:"livenessProbe,omitempty" json:"livenessProbe,omitempty" description:"periodic probe of container liveness; container will be restarted if the probe fails"` - Lifecycle *Lifecycle `yaml:"lifecycle,omitempty" json:"lifecycle,omitempty" description:"actions that the management system should take in response to container lifecycle events"` + CPU int `json:"cpu,omitempty" description:"CPU share in thousandths of a core"` + VolumeMounts []VolumeMount `json:"volumeMounts,omitempty" description:"pod volumes to mount into the container's filesystem"` + LivenessProbe *LivenessProbe `json:"livenessProbe,omitempty" description:"periodic probe of container liveness; container will be restarted if the probe fails"` + Lifecycle *Lifecycle `json:"lifecycle,omitempty" description:"actions that the management system should take in response to container lifecycle events"` // Optional: Defaults to /dev/termination-log - TerminationMessagePath string `yaml:"terminationMessagePath,omitempty" json:"terminationMessagePath,omitempty" description:"path at which the file to which the container's termination message will be written is mounted into the container's filesystem; message written is intended to be brief final status, such as an assertion failure message; defaults to /dev/termination-log"` + TerminationMessagePath string `json:"terminationMessagePath,omitempty" description:"path at which the file to which the container's termination message will be written is mounted into the container's filesystem; message written is intended to be brief final status, such as an assertion failure message; defaults to /dev/termination-log"` // Optional: Default to false. - Privileged bool `json:"privileged,omitempty" yaml:"privileged,omitempty" description:"whether or not the container is granted privileged status; defaults to false"` + Privileged bool `json:"privileged,omitempty" description:"whether or not the container is granted privileged status; defaults to false"` // Optional: Policy for pulling images for this container - ImagePullPolicy PullPolicy `json:"imagePullPolicy" yaml:"imagePullPolicy" description:"image pull policy; one of PullAlways, PullNever, PullIfNotPresent; defaults to PullAlways if :latest tag is specified, or PullIfNotPresent otherwise"` + ImagePullPolicy PullPolicy `json:"imagePullPolicy" description:"image pull policy; one of PullAlways, PullNever, PullIfNotPresent; defaults to PullAlways if :latest tag is specified, or PullIfNotPresent otherwise"` } // Handler defines a specific action that should be taken @@ -273,9 +273,9 @@ type Container struct { type Handler struct { // One and only one of the following should be specified. // Exec specifies the action to take. - Exec *ExecAction `yaml:"exec,omitempty" json:"exec,omitempty" description:"exec-based hook handler"` + Exec *ExecAction `json:"exec,omitempty" description:"exec-based hook handler"` // HTTPGet specifies the http request to perform. - HTTPGet *HTTPGetAction `yaml:"httpGet,omitempty" json:"httpGet,omitempty" description:"HTTP-based hook handler"` + HTTPGet *HTTPGetAction `json:"httpGet,omitempty" description:"HTTP-based hook handler"` } // Lifecycle describes actions that the management system should take in response to container lifecycle @@ -284,29 +284,29 @@ type Handler struct { type Lifecycle struct { // PostStart is called immediately after a container is created. If the handler fails, the container // is terminated and restarted. - PostStart *Handler `yaml:"postStart,omitempty" json:"postStart,omitempty" description:"called immediately after a container is started; if the handler fails, the container is terminated and restarted according to its restart policy; other management of the container blocks until the hook completes"` + PostStart *Handler `json:"postStart,omitempty" description:"called immediately after a container is started; if the handler fails, the container is terminated and restarted according to its restart policy; other management of the container blocks until the hook completes"` // PreStop is called immediately before a container is terminated. The reason for termination is // passed to the handler. Regardless of the outcome of the handler, the container is eventually terminated. - PreStop *Handler `yaml:"preStop,omitempty" json:"preStop,omitempty" description:"called before a container is terminated; the container is terminated after the handler completes; other management of the container blocks until the hook completes"` + PreStop *Handler `json:"preStop,omitempty" description:"called before a container is terminated; the container is terminated after the handler completes; other management of the container blocks until the hook completes"` } // The below types are used by kube_client and api_server. // TypeMeta is shared by all objects sent to, or returned from the client. type TypeMeta struct { - Kind string `json:"kind,omitempty" yaml:"kind,omitempty" description:"kind of object, in CamelCase"` - ID string `json:"id,omitempty" yaml:"id,omitempty" description:"name of the object; must be a DNS_SUBDOMAIN and unique among all objects of the same kind within the same namespace; used in resource URLs"` - UID string `json:"uid,omitempty" yaml:"uid,omitempty" description:"UUID assigned by the system upon creation, unique across space and time"` - CreationTimestamp util.Time `json:"creationTimestamp,omitempty" yaml:"creationTimestamp,omitempty" description:"RFC 3339 date and time at which the object was created; recorded by the system; null for lists"` - SelfLink string `json:"selfLink,omitempty" yaml:"selfLink,omitempty" description:"URL for the object"` - ResourceVersion uint64 `json:"resourceVersion,omitempty" yaml:"resourceVersion,omitempty" description:"string that identifies the internal version of this object that can be used by clients to determine when objects have changed; value must be treated as opaque by clients and passed unmodified back to the server"` - APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty" description:"version of the schema the object should have"` - Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty" description:"namespace to which the object belongs; must be a DNS_SUBDOMAIN; 'default' by default"` + Kind string `json:"kind,omitempty" description:"kind of object, in CamelCase"` + ID string `json:"id,omitempty" description:"name of the object; must be a DNS_SUBDOMAIN and unique among all objects of the same kind within the same namespace; used in resource URLs"` + UID string `json:"uid,omitempty" description:"UUID assigned by the system upon creation, unique across space and time"` + CreationTimestamp util.Time `json:"creationTimestamp,omitempty" description:"RFC 3339 date and time at which the object was created; recorded by the system; null for lists"` + SelfLink string `json:"selfLink,omitempty" description:"URL for the object"` + ResourceVersion uint64 `json:"resourceVersion,omitempty" description:"string that identifies the internal version of this object that can be used by clients to determine when objects have changed; value must be treated as opaque by clients and passed unmodified back to the server"` + APIVersion string `json:"apiVersion,omitempty" description:"version of the schema the object should have"` + Namespace string `json:"namespace,omitempty" description:"namespace to which the object belongs; must be a DNS_SUBDOMAIN; 'default' by default"` // Annotations are unstructured key value data stored with a resource that may be set by // external tooling. They are not queryable and should be preserved when modifying // objects. - Annotations map[string]string `json:"annotations,omitempty" yaml:"annotations,omitempty" description:"map of string keys and values that can be used by external tooling to store and retrieve arbitrary metadata about the object"` + Annotations map[string]string `json:"annotations,omitempty" description:"map of string keys and values that can be used by external tooling to store and retrieve arbitrary metadata about the object"` } // PodStatus represents a status of a pod. @@ -324,46 +324,46 @@ const ( type ContainerStateWaiting struct { // Reason could be pulling image, - Reason string `json:"reason,omitempty" yaml:"reason,omitempty" description:"(brief) reason the container is not yet running, such as pulling its image"` + Reason string `json:"reason,omitempty" description:"(brief) reason the container is not yet running, such as pulling its image"` } type ContainerStateRunning struct { // TODO: change to util.Time - StartedAt time.Time `json:"startedAt,omitempty" yaml:"startedAt,omitempty" description:"time at which the container was last (re-)started"` + StartedAt time.Time `json:"startedAt,omitempty" description:"time at which the container was last (re-)started"` } type ContainerStateTerminated struct { - ExitCode int `json:"exitCode" yaml:"exitCode" description:"exit status from the last termination of the container"` - Signal int `json:"signal,omitempty" yaml:"signal,omitempty" description:"signal from the last termination of the container"` - Reason string `json:"reason,omitempty" yaml:"reason,omitempty" description:"(brief) reason from the last termination of the container"` - Message string `json:"message,omitempty" yaml:"message,omitempty" description:"message regarding the last termination of the container"` + ExitCode int `json:"exitCode" description:"exit status from the last termination of the container"` + Signal int `json:"signal,omitempty" description:"signal from the last termination of the container"` + Reason string `json:"reason,omitempty" description:"(brief) reason from the last termination of the container"` + Message string `json:"message,omitempty" description:"message regarding the last termination of the container"` // TODO: change to util.Time - StartedAt time.Time `json:"startedAt,omitempty" yaml:"startedAt,omitempty" description:"time at which previous execution of the container started"` + StartedAt time.Time `json:"startedAt,omitempty" description:"time at which previous execution of the container started"` // TODO: change to util.Time - FinishedAt time.Time `json:"finishedAt,omitempty" yaml:"finishedAt,omitempty" description:"time at which the container last terminated"` + FinishedAt time.Time `json:"finishedAt,omitempty" description:"time at which the container last terminated"` } // ContainerState holds a possible state of container. // Only one of its members may be specified. // If none of them is specified, the default one is ContainerStateWaiting. type ContainerState struct { - Waiting *ContainerStateWaiting `json:"waiting,omitempty" yaml:"waiting,omitempty" description:"details about a waiting container"` - Running *ContainerStateRunning `json:"running,omitempty" yaml:"running,omitempty" description:"details about a running container"` - Termination *ContainerStateTerminated `json:"termination,omitempty" yaml:"termination,omitempty" description:"details about a terminated container"` + Waiting *ContainerStateWaiting `json:"waiting,omitempty" description:"details about a waiting container"` + Running *ContainerStateRunning `json:"running,omitempty" description:"details about a running container"` + Termination *ContainerStateTerminated `json:"termination,omitempty" description:"details about a terminated container"` } type ContainerStatus struct { // TODO(dchen1107): Should we rename PodStatus to a more generic name or have a separate states // defined for container? - State ContainerState `json:"state,omitempty" yaml:"state,omitempty" description:"details about the container's current condition"` + State ContainerState `json:"state,omitempty" description:"details about the container's current condition"` // Note that this is calculated from dead containers. But those containers are subject to // garbage collection. This value will get capped at 5 by GC. - RestartCount int `json:"restartCount" yaml:"restartCount" description:"the number of times the container has been restarted, currently based on the number of dead containers that have not yet been removed"` + RestartCount int `json:"restartCount" description:"the number of times the container has been restarted, currently based on the number of dead containers that have not yet been removed"` // TODO(dchen1107): Deprecated this soon once we pull entire PodStatus from node, // not just PodInfo. Now we need this to remove docker.Container from API - PodIP string `json:"podIP,omitempty" yaml:"podIP,omitempty" description:"pod's IP address"` + PodIP string `json:"podIP,omitempty" description:"pod's IP address"` // TODO(dchen1107): Need to decide how to reprensent this in v1beta3 - Image string `yaml:"image" json:"image" description:"image of the container"` + Image string `json:"image" description:"image of the container"` } // PodInfo contains one entry for every container with available info. @@ -381,127 +381,127 @@ type RestartPolicy struct { // Only one of the following restart policy may be specified. // If none of the following policies is specified, the default one // is RestartPolicyAlways. - Always *RestartPolicyAlways `json:"always,omitempty" yaml:"always,omitempty" description:"always restart the container after termination"` - OnFailure *RestartPolicyOnFailure `json:"onFailure,omitempty" yaml:"onFailure,omitempty" description:"restart the container if it fails for any reason, but not if it succeeds (exit 0)"` - Never *RestartPolicyNever `json:"never,omitempty" yaml:"never,omitempty" description:"never restart the container"` + Always *RestartPolicyAlways `json:"always,omitempty" description:"always restart the container after termination"` + OnFailure *RestartPolicyOnFailure `json:"onFailure,omitempty" description:"restart the container if it fails for any reason, but not if it succeeds (exit 0)"` + Never *RestartPolicyNever `json:"never,omitempty" description:"never restart the container"` } // PodState is the state of a pod, used as either input (desired state) or output (current state). type PodState struct { - Manifest ContainerManifest `json:"manifest,omitempty" yaml:"manifest,omitempty" description:"manifest of containers and volumes comprising the pod"` - Status PodStatus `json:"status,omitempty" yaml:"status,omitempty" description:"current condition of the pod, Waiting, Running, or Terminated"` + Manifest ContainerManifest `json:"manifest,omitempty" description:"manifest of containers and volumes comprising the pod"` + Status PodStatus `json:"status,omitempty" description:"current condition of the pod, Waiting, Running, or Terminated"` // A human readable message indicating details about why the pod is in this state. - Message string `json:"message,omitempty" yaml:"message,omitempty" description:"human readable message indicating details about why the pod is in this condition"` - Host string `json:"host,omitempty" yaml:"host,omitempty" description:"host to which the pod is assigned; empty if not yet scheduled"` - HostIP string `json:"hostIP,omitempty" yaml:"hostIP,omitempty" description:"IP address of the host to which the pod is assigned; empty if not yet scheduled"` - PodIP string `json:"podIP,omitempty" yaml:"podIP,omitempty" description:"IP address allocated to the pod; routable at least within the cluster; empty if not yet allocated"` + Message string `json:"message,omitempty" description:"human readable message indicating details about why the pod is in this condition"` + Host string `json:"host,omitempty" description:"host to which the pod is assigned; empty if not yet scheduled"` + HostIP string `json:"hostIP,omitempty" description:"IP address of the host to which the pod is assigned; empty if not yet scheduled"` + PodIP string `json:"podIP,omitempty" description:"IP address allocated to the pod; routable at least within the cluster; empty if not yet allocated"` // The key of this map is the *name* of the container within the manifest; it has one // entry per container in the manifest. The value of this map is ContainerStatus for // the container. - Info PodInfo `json:"info,omitempty" yaml:"info,omitempty" description:"map of container name to container status"` + Info PodInfo `json:"info,omitempty" description:"map of container name to container status"` } // PodList is a list of Pods. type PodList struct { - TypeMeta `json:",inline" yaml:",inline"` - Items []Pod `json:"items" yaml:"items" description:"list of pods"` + TypeMeta `json:",inline"` + Items []Pod `json:"items" description:"list of pods"` } // Pod is a collection of containers, used as either input (create, update) or as output (list, get). type Pod struct { - TypeMeta `json:",inline" yaml:",inline"` - Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty" description:"map of string keys and values that can be used to organize and categorize pods; may match selectors of replication controllers and services"` - DesiredState PodState `json:"desiredState,omitempty" yaml:"desiredState,omitempty" description:"specification of the desired state of the pod"` - CurrentState PodState `json:"currentState,omitempty" yaml:"currentState,omitempty" description:"current state of the pod"` + TypeMeta `json:",inline"` + Labels map[string]string `json:"labels,omitempty" description:"map of string keys and values that can be used to organize and categorize pods; may match selectors of replication controllers and services"` + DesiredState PodState `json:"desiredState,omitempty" description:"specification of the desired state of the pod"` + CurrentState PodState `json:"currentState,omitempty" description:"current state of the pod"` // NodeSelector is a selector which must be true for the pod to fit on a node - NodeSelector map[string]string `json:"nodeSelector,omitempty" yaml:"nodeSelector,omitempty" description:"selector which must match a node's labels for the pod to be scheduled on that node"` + NodeSelector map[string]string `json:"nodeSelector,omitempty" description:"selector which must match a node's labels for the pod to be scheduled on that node"` } // ReplicationControllerState is the state of a replication controller, either input (create, update) or as output (list, get). type ReplicationControllerState struct { - Replicas int `json:"replicas" yaml:"replicas" description:"number of replicas (desired or observed, as appropriate)"` - ReplicaSelector map[string]string `json:"replicaSelector,omitempty" yaml:"replicaSelector,omitempty" description:"label keys and values that must match in order to be controlled by this replication controller"` - PodTemplate PodTemplate `json:"podTemplate,omitempty" yaml:"podTemplate,omitempty" description:"template for pods to be created by this replication controller when the observed number of replicas is less than the desired number of replicas"` + Replicas int `json:"replicas" description:"number of replicas (desired or observed, as appropriate)"` + ReplicaSelector map[string]string `json:"replicaSelector,omitempty" description:"label keys and values that must match in order to be controlled by this replication controller"` + PodTemplate PodTemplate `json:"podTemplate,omitempty" description:"template for pods to be created by this replication controller when the observed number of replicas is less than the desired number of replicas"` } // ReplicationControllerList is a collection of replication controllers. type ReplicationControllerList struct { - TypeMeta `json:",inline" yaml:",inline"` - Items []ReplicationController `json:"items" yaml:"items" description:"list of replication controllers"` + TypeMeta `json:",inline"` + Items []ReplicationController `json:"items" description:"list of replication controllers"` } // ReplicationController represents the configuration of a replication controller. type ReplicationController struct { - TypeMeta `json:",inline" yaml:",inline"` - DesiredState ReplicationControllerState `json:"desiredState,omitempty" yaml:"desiredState,omitempty" description:"specification of the desired state of the replication controller"` - CurrentState ReplicationControllerState `json:"currentState,omitempty" yaml:"currentState,omitempty" description:"current state of the replication controller"` - Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty" description:"map of string keys and values that can be used to organize and categorize replication controllers"` + TypeMeta `json:",inline"` + DesiredState ReplicationControllerState `json:"desiredState,omitempty" description:"specification of the desired state of the replication controller"` + CurrentState ReplicationControllerState `json:"currentState,omitempty" description:"current state of the replication controller"` + Labels map[string]string `json:"labels,omitempty" description:"map of string keys and values that can be used to organize and categorize replication controllers"` } // PodTemplate holds the information used for creating pods. type PodTemplate struct { - DesiredState PodState `json:"desiredState,omitempty" yaml:"desiredState,omitempty" description:"specification of the desired state of pods created from this template"` - Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty" description:"map of string keys and values that can be used to organize and categorize the pods created from the template; must match the selector of the replication controller to which the template belongs; may match selectors of services"` + DesiredState PodState `json:"desiredState,omitempty" description:"specification of the desired state of pods created from this template"` + Labels map[string]string `json:"labels,omitempty" description:"map of string keys and values that can be used to organize and categorize the pods created from the template; must match the selector of the replication controller to which the template belongs; may match selectors of services"` } // ServiceList holds a list of services. type ServiceList struct { - TypeMeta `json:",inline" yaml:",inline"` - Items []Service `json:"items" yaml:"items" description:"list of services"` + TypeMeta `json:",inline"` + Items []Service `json:"items" description:"list of services"` } // Service is a named abstraction of software service (for example, mysql) consisting of local port // (for example 3306) that the proxy listens on, and the selector that determines which pods // will answer requests sent through the proxy. type Service struct { - TypeMeta `json:",inline" yaml:",inline"` + TypeMeta `json:",inline"` // Required. - Port int `json:"port" yaml:"port" description:"port exposed by the service"` + Port int `json:"port" description:"port exposed by the service"` // Optional: Defaults to "TCP". - Protocol Protocol `yaml:"protocol,omitempty" json:"protocol,omitempty" description:"protocol for port; must be UDP or TCP; TCP if unspecified"` + Protocol Protocol `json:"protocol,omitempty" description:"protocol for port; must be UDP or TCP; TCP if unspecified"` // This service's labels. - Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty" description:"map of string keys and values that can be used to organize and categorize services"` + Labels map[string]string `json:"labels,omitempty" description:"map of string keys and values that can be used to organize and categorize services"` // This service will route traffic to pods having labels matching this selector. - Selector map[string]string `json:"selector,omitempty" yaml:"selector,omitempty" description:"label keys and values that must match in order to receive traffic for this service"` - CreateExternalLoadBalancer bool `json:"createExternalLoadBalancer,omitempty" yaml:"createExternalLoadBalancer,omitempty" description:"set up a cloud-provider-specific load balancer on an external IP"` + Selector map[string]string `json:"selector,omitempty" description:"label keys and values that must match in order to receive traffic for this service"` + CreateExternalLoadBalancer bool `json:"createExternalLoadBalancer,omitempty" description:"set up a cloud-provider-specific load balancer on an external IP"` // PublicIPs are used by external load balancers. - PublicIPs []string `json:"publicIPs,omitempty" yaml:"publicIPs,omitempty" description:"externally visible IPs from which to select the address for the external load balancer"` + PublicIPs []string `json:"publicIPs,omitempty" description:"externally visible IPs from which to select the address for the external load balancer"` // ContainerPort is the name of the port on the container to direct traffic to. // Optional, if unspecified use the first port on the container. - ContainerPort util.IntOrString `json:"containerPort,omitempty" yaml:"containerPort,omitempty" description:"number or name of the port to access on the containers belonging to pods targeted by the service"` + ContainerPort util.IntOrString `json:"containerPort,omitempty" description:"number or name of the port to access on the containers belonging to pods targeted by the service"` // PortalIP is usually assigned by the master. If specified by the user // we will try to respect it or else fail the request. This field can // not be changed by updates. - PortalIP string `json:"portalIP,omitempty" yaml:"portalIP,omitempty" description:"IP address of the service; usually assigned by the system; if specified, it will be allocated to the service if unused, and creation of the service will fail otherwise; cannot be updated"` + PortalIP string `json:"portalIP,omitempty" description:"IP address of the service; usually assigned by the system; if specified, it will be allocated to the service if unused, and creation of the service will fail otherwise; cannot be updated"` // ProxyPort is assigned by the master. If specified by the user it will be ignored. - ProxyPort int `json:"proxyPort,omitempty" yaml:"proxyPort,omitempty" description:"if non-zero, a pre-allocated host port used for this service by the proxy on each node; assigned by the master and ignored on input"` + ProxyPort int `json:"proxyPort,omitempty" description:"if non-zero, a pre-allocated host port used for this service by the proxy on each node; assigned by the master and ignored on input"` } // Endpoints is a collection of endpoints that implement the actual service, for example: // Name: "mysql", Endpoints: ["10.10.1.1:1909", "10.10.2.2:8834"] type Endpoints struct { - TypeMeta `json:",inline" yaml:",inline"` - Endpoints []string `json:"endpoints,omitempty" yaml:"endpoints,omitempty" description:"list of endpoints corresponding to a service, of the form address:port, such as 10.10.1.1:1909"` + TypeMeta `json:",inline"` + Endpoints []string `json:"endpoints,omitempty" description:"list of endpoints corresponding to a service, of the form address:port, such as 10.10.1.1:1909"` } // EndpointsList is a list of endpoints. type EndpointsList struct { - TypeMeta `json:",inline" yaml:",inline"` - Items []Endpoints `json:"items" yaml:"items" description:"list of service endpoint lists"` + TypeMeta `json:",inline"` + Items []Endpoints `json:"items" description:"list of service endpoint lists"` } // NodeResources represents resources on a Kubernetes system node // see https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/resources.md for more details. type NodeResources struct { // Capacity represents the available resources. - Capacity ResourceList `json:"capacity,omitempty" yaml:"capacity,omitempty" description:"resource capacity of a node represented as a map of resource name to quantity of resource"` + Capacity ResourceList `json:"capacity,omitempty" description:"resource capacity of a node represented as a map of resource name to quantity of resource"` } type ResourceName string @@ -511,52 +511,52 @@ type ResourceList map[ResourceName]util.IntOrString // Minion is a worker node in Kubernetenes. // The name of the minion according to etcd is in ID. type Minion struct { - TypeMeta `json:",inline" yaml:",inline"` + TypeMeta `json:",inline"` // Queried from cloud provider, if available. - HostIP string `json:"hostIP,omitempty" yaml:"hostIP,omitempty" description:"IP address of the node"` + HostIP string `json:"hostIP,omitempty" description:"IP address of the node"` // Resources available on the node - NodeResources NodeResources `json:"resources,omitempty" yaml:"resources,omitempty" description:"characterization of node resources"` + NodeResources NodeResources `json:"resources,omitempty" description:"characterization of node resources"` // Labels for the node - Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty" description:"map of string keys and values that can be used to organize and categorize minions; labels of a minion assigned by the scheduler must match the scheduled pod's nodeSelector"` + Labels map[string]string `json:"labels,omitempty" description:"map of string keys and values that can be used to organize and categorize minions; labels of a minion assigned by the scheduler must match the scheduled pod's nodeSelector"` } // MinionList is a list of minions. type MinionList struct { - TypeMeta `json:",inline" yaml:",inline"` + TypeMeta `json:",inline"` // DEPRECATED: the below Minions is due to a naming mistake and // will be replaced with Items in the future. - Minions []Minion `json:"minions,omitempty" yaml:"minions,omitempty" description:"list of nodes; deprecated"` - Items []Minion `json:"items" yaml:"items" description:"list of nodes"` + Minions []Minion `json:"minions,omitempty" description:"list of nodes; deprecated"` + Items []Minion `json:"items" description:"list of nodes"` } // Binding is written by a scheduler to cause a pod to be bound to a host. type Binding struct { - TypeMeta `json:",inline" yaml:",inline"` - PodID string `json:"podID" yaml:"podID" description:"name of the pod to bind"` - Host string `json:"host" yaml:"host" description:"host to which to bind the specified pod"` + TypeMeta `json:",inline"` + PodID string `json:"podID" description:"name of the pod to bind"` + Host string `json:"host" description:"host to which to bind the specified pod"` } // Status is a return value for calls that don't return other objects. // TODO: this could go in apiserver, but I'm including it here so clients needn't // import both. type Status struct { - TypeMeta `json:",inline" yaml:",inline"` + TypeMeta `json:",inline"` // One of: "Success", "Failure", "Working" (for operations not yet completed) - Status string `json:"status,omitempty" yaml:"status,omitempty" description:"status of the operation; either Working (not yet completed), Success, or Failure"` + Status string `json:"status,omitempty" description:"status of the operation; either Working (not yet completed), Success, or Failure"` // A human-readable description of the status of this operation. - Message string `json:"message,omitempty" yaml:"message,omitempty" description:"human-readable description of the status of this operation"` + Message string `json:"message,omitempty" description:"human-readable description of the status of this operation"` // A machine-readable description of why this operation is in the // "Failure" or "Working" status. If this value is empty there // is no information available. A Reason clarifies an HTTP status // code but does not override it. - Reason StatusReason `json:"reason,omitempty" yaml:"reason,omitempty" description:"machine-readable description of why this operation is in the 'Failure' or 'Working' status; if this value is empty there is no information available; a reason clarifies an HTTP status code but does not override it"` + Reason StatusReason `json:"reason,omitempty" description:"machine-readable description of why this operation is in the 'Failure' or 'Working' status; if this value is empty there is no information available; a reason clarifies an HTTP status code but does not override it"` // Extended data associated with the reason. Each reason may define its // own extended details. This field is optional and the data returned // is not guaranteed to conform to any schema except that defined by // the reason type. - Details *StatusDetails `json:"details,omitempty" yaml:"details,omitempty" description:"extended data associated with the reason; each reason may define its own extended details; this field is optional and the data returned is not guaranteed to conform to any schema except that defined by the reason type"` + Details *StatusDetails `json:"details,omitempty" description:"extended data associated with the reason; each reason may define its own extended details; this field is optional and the data returned is not guaranteed to conform to any schema except that defined by the reason type"` // Suggested HTTP return code for this status, 0 if not set. - Code int `json:"code,omitempty" yaml:"code,omitempty" description:"suggested HTTP return code for this status; 0 if not set"` + Code int `json:"code,omitempty" description:"suggested HTTP return code for this status; 0 if not set"` } // StatusDetails is a set of additional properties that MAY be set by the @@ -568,13 +568,13 @@ type Status struct { type StatusDetails struct { // The ID attribute of the resource associated with the status StatusReason // (when there is a single ID which can be described). - ID string `json:"id,omitempty" yaml:"id,omitempty" description:"the ID attribute of the resource associated with the status StatusReason (when there is a single ID which can be described)"` + ID string `json:"id,omitempty" description:"the ID attribute of the resource associated with the status StatusReason (when there is a single ID which can be described)"` // The kind attribute of the resource associated with the status StatusReason. // On some operations may differ from the requested resource Kind. - Kind string `json:"kind,omitempty" yaml:"kind,omitempty" description:"the kind attribute of the resource associated with the status StatusReason; on some operations may differ from the requested resource Kind"` + Kind string `json:"kind,omitempty" description:"the kind attribute of the resource associated with the status StatusReason; on some operations may differ from the requested resource Kind"` // The Causes array includes more details associated with the StatusReason // failure. Not all StatusReasons may provide detailed causes. - Causes []StatusCause `json:"causes,omitempty" yaml:"causes,omitempty" description:"the Causes array includes more details associated with the StatusReason failure; not all StatusReasons may provide detailed causes"` + Causes []StatusCause `json:"causes,omitempty" description:"the Causes array includes more details associated with the StatusReason failure; not all StatusReasons may provide detailed causes"` } // Values of Status.Status @@ -638,10 +638,10 @@ const ( type StatusCause struct { // A machine-readable description of the cause of the error. If this value is // empty there is no information available. - Type CauseType `json:"reason,omitempty" yaml:"reason,omitempty" description:"machine-readable description of the cause of the error; if this value is empty there is no information available"` + Type CauseType `json:"reason,omitempty" description:"machine-readable description of the cause of the error; if this value is empty there is no information available"` // A human-readable description of the cause of the error. This field may be // presented as-is to a reader. - Message string `json:"message,omitempty" yaml:"message,omitempty" description:"human-readable description of the cause of the error; this field may be presented as-is to a reader"` + Message string `json:"message,omitempty" description:"human-readable description of the cause of the error; this field may be presented as-is to a reader"` // The field of the resource that has caused this error, as named by its JSON // serialization. May include dot and postfix notation for nested attributes. // Arrays are zero-indexed. Fields may appear more than once in an array of @@ -651,7 +651,7 @@ type StatusCause struct { // Examples: // "name" - the field "name" on the current resource // "items[0].name" - the field "name" on the first array entry in "items" - Field string `json:"field,omitempty" yaml:"field,omitempty" description:"field of the resource that has caused this error, as named by its JSON serialization; may include dot and postfix notation for nested attributes; arrays are zero-indexed; fields may appear more than once in an array of causes due to fields having multiple errors"` + Field string `json:"field,omitempty" description:"field of the resource that has caused this error, as named by its JSON serialization; may include dot and postfix notation for nested attributes; arrays are zero-indexed; fields may appear more than once in an array of causes due to fields having multiple errors"` } // CauseType is a machine readable value providing more detail about what @@ -679,23 +679,23 @@ const ( // ServerOp is an operation delivered to API clients. type ServerOp struct { - TypeMeta `yaml:",inline" json:",inline"` + TypeMeta `json:",inline"` } // ServerOpList is a list of operations, as delivered to API clients. type ServerOpList struct { - TypeMeta `yaml:",inline" json:",inline"` - Items []ServerOp `yaml:"items" json:"items" description:"list of operations"` + TypeMeta `json:",inline"` + Items []ServerOp `json:"items" description:"list of operations"` } // ObjectReference contains enough information to let you inspect or modify the referred object. type ObjectReference struct { - Kind string `json:"kind,omitempty" yaml:"kind,omitempty" description:"kind of the referent"` - Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty" description:"namespace of the referent"` - ID string `json:"name,omitempty" yaml:"name,omitempty" description:"id of the referent"` - UID string `json:"uid,omitempty" yaml:"uid,omitempty" description:"uid of the referent"` - APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty" description:"API version of the referent"` - ResourceVersion string `json:"resourceVersion,omitempty" yaml:"resourceVersion,omitempty" description:"specific resourceVersion to which this reference is made, if any"` + Kind string `json:"kind,omitempty" description:"kind of the referent"` + Namespace string `json:"namespace,omitempty" description:"namespace of the referent"` + ID string `json:"name,omitempty" description:"id of the referent"` + UID string `json:"uid,omitempty" description:"uid of the referent"` + APIVersion string `json:"apiVersion,omitempty" description:"API version of the referent"` + ResourceVersion string `json:"resourceVersion,omitempty" description:"specific resourceVersion to which this reference is made, if any"` // Optional. If referring to a piece of an object instead of an entire object, this string // should contain a valid field access statement. For example, @@ -704,16 +704,16 @@ type ObjectReference struct { // both go and JavaScript. This is syntax is chosen only to have some well-defined way of // referencing a part of an object. // TODO: this design is not final and this field is subject to change in the future. - FieldPath string `json:"fieldPath,omitempty" yaml:"fieldPath,omitempty" description:"if referring to a piece of an object instead of an entire object, this string should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]"` + FieldPath string `json:"fieldPath,omitempty" description:"if referring to a piece of an object instead of an entire object, this string should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]"` } // Event is a report of an event somewhere in the cluster. // TODO: Decide whether to store these separately or with the object they apply to. type Event struct { - TypeMeta `yaml:",inline" json:",inline"` + TypeMeta `json:",inline"` // Required. The object that this event is about. - InvolvedObject ObjectReference `json:"involvedObject,omitempty" yaml:"involvedObject,omitempty" description:"object that this event is about"` + InvolvedObject ObjectReference `json:"involvedObject,omitempty" description:"object that this event is about"` // Should be a short, machine understandable string that describes the current status // of the referred object. This should not give the reason for being in this state. @@ -722,61 +722,61 @@ type Event struct { // always be used for the same status. // TODO: define a way of making sure these are consistent and don't collide. // TODO: provide exact specification for format. - Status string `json:"status,omitempty" yaml:"status,omitempty" description:"short, machine understandable string that describes the current status of the referred object"` + Status string `json:"status,omitempty" description:"short, machine understandable string that describes the current status of the referred object"` // Optional; this should be a short, machine understandable string that gives the reason // for the transition into the object's current status. For example, if ObjectStatus is // "cantStart", StatusReason might be "imageNotFound". // TODO: provide exact specification for format. - Reason string `json:"reason,omitempty" yaml:"reason,omitempty" description:"short, machine understandable string that gives the reason for the transition into the object's current status"` + Reason string `json:"reason,omitempty" description:"short, machine understandable string that gives the reason for the transition into the object's current status"` // Optional. A human-readable description of the status of this operation. // TODO: decide on maximum length. - Message string `json:"message,omitempty" yaml:"message,omitempty" description:"human-readable description of the status of this operation"` + Message string `json:"message,omitempty" description:"human-readable description of the status of this operation"` // Optional. The component reporting this event. Should be a short machine understandable string. // TODO: provide exact specification for format. - Source string `json:"source,omitempty" yaml:"source,omitempty" description:"component reporting this event; short machine understandable string"` + Source string `json:"source,omitempty" description:"component reporting this event; short machine understandable string"` // The time at which the client recorded the event. (Time of server receipt is in TypeMeta.) - Timestamp util.Time `json:"timestamp,omitempty" yaml:"timestamp,omitempty" description:"time at which the client recorded the event"` + Timestamp util.Time `json:"timestamp,omitempty" description:"time at which the client recorded the event"` } // EventList is a list of events. type EventList struct { - TypeMeta `yaml:",inline" json:",inline"` - Items []Event `yaml:"items" json:"items" description:"list of events"` + TypeMeta `json:",inline"` + Items []Event `json:"items" description:"list of events"` } // Backported from v1beta3 to replace ContainerManifest // PodSpec is a description of a pod type PodSpec struct { - Volumes []Volume `json:"volumes" yaml:"volumes" description:"list of volumes that can be mounted by containers belonging to the pod"` - Containers []Container `json:"containers" yaml:"containers" description:"list of containers belonging to the pod"` - RestartPolicy RestartPolicy `json:"restartPolicy,omitempty" yaml:"restartPolicy,omitempty" description:"restart policy for all containers within the pod; one of RestartPolicyAlways, RestartPolicyOnFailure, RestartPolicyNever"` + Volumes []Volume `json:"volumes" description:"list of volumes that can be mounted by containers belonging to the pod"` + Containers []Container `json:"containers" description:"list of containers belonging to the pod"` + RestartPolicy RestartPolicy `json:"restartPolicy,omitempty" description:"restart policy for all containers within the pod; one of RestartPolicyAlways, RestartPolicyOnFailure, RestartPolicyNever"` // NodeSelector is a selector which must be true for the pod to fit on a node - NodeSelector map[string]string `json:"nodeSelector,omitempty" yaml:"nodeSelector,omitempty" description:"selector which must match a node's labels for the pod to be scheduled on that node"` + NodeSelector map[string]string `json:"nodeSelector,omitempty" description:"selector which must match a node's labels for the pod to be scheduled on that node"` } // BoundPod is a collection of containers that should be run on a host. A BoundPod // defines how a Pod may change after a Binding is created. A Pod is a request to // execute a pod, whereas a BoundPod is the specification that would be run on a server. type BoundPod struct { - TypeMeta `json:",inline" yaml:",inline"` + TypeMeta `json:",inline"` // Spec defines the behavior of a pod. - Spec PodSpec `json:"spec,omitempty" yaml:"spec,omitempty" description:"specification of the desired state of containers and volumes comprising the pod"` + Spec PodSpec `json:"spec,omitempty" description:"specification of the desired state of containers and volumes comprising the pod"` } // BoundPods is a list of Pods bound to a common server. The resource version of // the pod list is guaranteed to only change when the list of bound pods changes. type BoundPods struct { - TypeMeta `json:",inline" yaml:",inline"` + TypeMeta `json:",inline"` // Host is the name of a node that these pods were bound to. - Host string `json:"host" yaml:"host" description:"name of a node that these pods were bound to"` + Host string `json:"host" description:"name of a node that these pods were bound to"` // Items is the list of all pods bound to a given host. - Items []BoundPod `json:"items" yaml:"items" description:"list of all pods bound to a given host"` + Items []BoundPod `json:"items" description:"list of all pods bound to a given host"` } diff --git a/pkg/api/v1beta2/types.go b/pkg/api/v1beta2/types.go index 91db025fbe9..b5b1f1adca4 100644 --- a/pkg/api/v1beta2/types.go +++ b/pkg/api/v1beta2/types.go @@ -49,11 +49,11 @@ import ( type Volume struct { // Required: This must be a DNS_LABEL. Each volume in a pod must have // a unique name. - Name string `yaml:"name" json:"name" description:"volume name; must be a DNS_LABEL and unique within the pod"` + Name string `json:"name" description:"volume name; must be a DNS_LABEL and unique within the pod"` // Source represents the location and type of a volume to mount. // This is optional for now. If not specified, the Volume is implied to be an EmptyDir. // This implied behavior is deprecated and will be removed in a future version. - Source *VolumeSource `yaml:"source" json:"source" description:"location and type of volume to mount; at most one of HostDir, EmptyDir, GCEPersistentDisk, or GitRepo; default is EmptyDir"` + Source *VolumeSource `json:"source" description:"location and type of volume to mount; at most one of HostDir, EmptyDir, GCEPersistentDisk, or GitRepo; default is EmptyDir"` } // VolumeSource represents the source location of a valume to mount. @@ -64,19 +64,19 @@ type VolumeSource struct { // things that are allowed to see the host machine. Most containers will NOT need this. // TODO(jonesdl) We need to restrict who can use host directory mounts and // who can/can not mount host directories as read/write. - HostDir *HostDir `yaml:"hostDir" json:"hostDir" description:"pre-existing host directory; generally for privileged system daemons or other agents tied to the host"` + HostDir *HostDir `json:"hostDir" description:"pre-existing host directory; generally for privileged system daemons or other agents tied to the host"` // EmptyDir represents a temporary directory that shares a pod's lifetime. - EmptyDir *EmptyDir `yaml:"emptyDir" json:"emptyDir" description:"temporary directory that shares a pod's lifetime"` + EmptyDir *EmptyDir `json:"emptyDir" description:"temporary directory that shares a pod's lifetime"` // A persistent disk that is mounted to the // kubelet's host machine and then exposed to the pod. - GCEPersistentDisk *GCEPersistentDisk `yaml:"persistentDisk" json:"persistentDisk" description:"GCE disk resource attached to the host machine on demand"` + GCEPersistentDisk *GCEPersistentDisk `json:"persistentDisk" description:"GCE disk resource attached to the host machine on demand"` // GitRepo represents a git repository at a particular revision. - GitRepo *GitRepo `json:"gitRepo" yaml:"gitRepo" description:"git repository at a particular revision"` + GitRepo *GitRepo `json:"gitRepo" description:"git repository at a particular revision"` } // HostDir represents bare host directory volume. type HostDir struct { - Path string `yaml:"path" json:"path" description:"path of the directory on the host"` + Path string `json:"path" description:"path of the directory on the host"` } type EmptyDir struct{} @@ -95,15 +95,15 @@ const ( type Port struct { // Optional: If specified, this must be a DNS_LABEL. Each named port // in a pod must have a unique name. - Name string `yaml:"name,omitempty" json:"name,omitempty" description:"name for the port that can be referred to by services; must be a DNS_LABEL and unique without the pod"` + Name string `json:"name,omitempty" description:"name for the port that can be referred to by services; must be a DNS_LABEL and unique without the pod"` // Optional: If specified, this must be a valid port number, 0 < x < 65536. - HostPort int `yaml:"hostPort,omitempty" json:"hostPort,omitempty" description:"number of port to expose on the host; most containers do not need this"` + HostPort int `json:"hostPort,omitempty" description:"number of port to expose on the host; most containers do not need this"` // Required: This must be a valid port number, 0 < x < 65536. - ContainerPort int `yaml:"containerPort" json:"containerPort" description:"number of port to expose on the pod's IP address"` + ContainerPort int `json:"containerPort" description:"number of port to expose on the pod's IP address"` // Optional: Defaults to "TCP". - Protocol Protocol `yaml:"protocol,omitempty" json:"protocol,omitempty" description:"protocol for port; must be UDP or TCP; TCP if unspecified"` + Protocol Protocol `json:"protocol,omitempty" description:"protocol for port; must be UDP or TCP; TCP if unspecified"` // Optional: What host IP to bind the external port to. - HostIP string `yaml:"hostIP,omitempty" json:"hostIP,omitempty" description:"host IP to bind the port to"` + HostIP string `json:"hostIP,omitempty" description:"host IP to bind the port to"` } // GCEPersistentDisk represents a Persistent Disk resource in Google Compute Engine. @@ -113,62 +113,62 @@ type Port struct { // A GCE PD can only be mounted as read/write once. type GCEPersistentDisk struct { // Unique name of the PD resource. Used to identify the disk in GCE - PDName string `yaml:"pdName" json:"pdName" description:"unique name of the PD resource in GCE"` + PDName string `json:"pdName" description:"unique name of the PD resource in GCE"` // Required: Filesystem type to mount. // Must be a filesystem type supported by the host operating system. // Ex. "ext4", "xfs", "ntfs" // TODO: how do we prevent errors in the filesystem from compromising the machine // TODO: why omitempty if required? - FSType string `yaml:"fsType,omitempty" json:"fsType,omitempty" description:"file system type to mount, such as ext4, xfs, ntfs"` + FSType string `json:"fsType,omitempty" description:"file system type to mount, such as ext4, xfs, ntfs"` // Optional: Partition on the disk to mount. // If omitted, kubelet will attempt to mount the device name. // Ex. For /dev/sda1, this field is "1", for /dev/sda, this field 0 or empty. - Partition int `yaml:"partition,omitempty" json:"partition,omitempty" description:"partition on the disk to mount (e.g., '1' for /dev/sda1); if omitted the plain device name (e.g., /dev/sda) will be mounted"` + Partition int `json:"partition,omitempty" description:"partition on the disk to mount (e.g., '1' for /dev/sda1); if omitted the plain device name (e.g., /dev/sda) will be mounted"` // Optional: Defaults to false (read/write). ReadOnly here will force // the ReadOnly setting in VolumeMounts. - ReadOnly bool `yaml:"readOnly,omitempty" json:"readOnly,omitempty" description:"read-only if true, read-write otherwise (false or unspecified)"` + ReadOnly bool `json:"readOnly,omitempty" description:"read-only if true, read-write otherwise (false or unspecified)"` } // GitRepo represents a volume that is pulled from git when the pod is created. type GitRepo struct { // Repository URL - Repository string `yaml:"repository" json:"repository" description:"repository URL"` + Repository string `json:"repository" description:"repository URL"` // Commit hash, this is optional - Revision string `yaml:"revision" json:"revision" description:"commit hash for the specified revision"` + Revision string `json:"revision" description:"commit hash for the specified revision"` } // VolumeMount describes a mounting of a Volume within a container. type VolumeMount struct { // Required: This must match the Name of a Volume [above]. - Name string `yaml:"name" json:"name" description:"name of the volume to mount"` + Name string `json:"name" description:"name of the volume to mount"` // Optional: Defaults to false (read-write). - ReadOnly bool `yaml:"readOnly,omitempty" json:"readOnly,omitempty" description:"mounted read-only if true, read-write otherwise (false or unspecified)"` + ReadOnly bool `json:"readOnly,omitempty" description:"mounted read-only if true, read-write otherwise (false or unspecified)"` // Required. - MountPath string `yaml:"mountPath,omitempty" json:"mountPath,omitempty" description:"path within the container at which the volume should be mounted"` + MountPath string `json:"mountPath,omitempty" description:"path within the container at which the volume should be mounted"` } // EnvVar represents an environment variable present in a Container. type EnvVar struct { // Required: This must be a C_IDENTIFIER. - Name string `yaml:"name" json:"name" description:"name of the environment variable; must be a C_IDENTIFIER"` + Name string `json:"name" description:"name of the environment variable; must be a C_IDENTIFIER"` // Optional: defaults to "". - Value string `yaml:"value,omitempty" json:"value,omitempty" description:"value of the environment variable; defaults to empty string"` + Value string `json:"value,omitempty" description:"value of the environment variable; defaults to empty string"` } // HTTPGetAction describes an action based on HTTP Get requests. type HTTPGetAction struct { // Optional: Path to access on the HTTP server. - Path string `yaml:"path,omitempty" json:"path,omitempty" description:"path to access on the HTTP server"` + Path string `json:"path,omitempty" description:"path to access on the HTTP server"` // Required: Name or number of the port to access on the container. - Port util.IntOrString `yaml:"port,omitempty" json:"port,omitempty" description:"number or name of the port to access on the container"` + Port util.IntOrString `json:"port,omitempty" description:"number or name of the port to access on the container"` // Optional: Host name to connect to, defaults to the pod IP. - Host string `yaml:"host,omitempty" json:"host,omitempty" description:"hostname to connect to; defaults to pod IP"` + Host string `json:"host,omitempty" description:"hostname to connect to; defaults to pod IP"` } // TCPSocketAction describes an action based on opening a socket type TCPSocketAction struct { // Required: Port to connect to. - Port util.IntOrString `yaml:"port,omitempty" json:"port,omitempty" description:"number of name of the port to access on the container"` + Port util.IntOrString `json:"port,omitempty" description:"number of name of the port to access on the container"` } // ExecAction describes a "run in container" action. @@ -177,20 +177,20 @@ type ExecAction struct { // command is root ('/') in the container's filesystem. The command is simply exec'd, it is // not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use // a shell, you need to explicitly call out to that shell. - Command []string `yaml:"command,omitempty" json:"command,omitempty" description:"command line to execute inside the container; working directory for the command is root ('/') in the container's file system; the command is exec'd, not run inside a shell; exit status of 0 is treated as live/healthy and non-zero is unhealthy"` + Command []string `json:"command,omitempty" description:"command line to execute inside the container; working directory for the command is root ('/') in the container's file system; the command is exec'd, not run inside a shell; exit status of 0 is treated as live/healthy and non-zero is unhealthy"` } // LivenessProbe describes a liveness probe to be examined to the container. // TODO: pass structured data to the actions, and document that data here. type LivenessProbe struct { // HTTPGetProbe parameters, required if Type == 'http' - HTTPGet *HTTPGetAction `yaml:"httpGet,omitempty" json:"httpGet,omitempty" description:"parameters for HTTP-based liveness probe"` + HTTPGet *HTTPGetAction `json:"httpGet,omitempty" description:"parameters for HTTP-based liveness probe"` // TCPSocketProbe parameter, required if Type == 'tcp' - TCPSocket *TCPSocketAction `yaml:"tcpSocket,omitempty" json:"tcpSocket,omitempty" description:"parameters for TCP-based liveness probe"` + TCPSocket *TCPSocketAction `json:"tcpSocket,omitempty" description:"parameters for TCP-based liveness probe"` // ExecProbe parameter, required if Type == 'exec' - Exec *ExecAction `yaml:"exec,omitempty" json:"exec,omitempty" description:"parameters for exec-based liveness probe"` + Exec *ExecAction `json:"exec,omitempty" description:"parameters for exec-based liveness probe"` // Length of time before health checking is activated. In seconds. - InitialDelaySeconds int64 `yaml:"initialDelaySeconds,omitempty" json:"initialDelaySeconds,omitempty" description:"number of seconds after the container has started before liveness probes are initiated"` + InitialDelaySeconds int64 `json:"initialDelaySeconds,omitempty" description:"number of seconds after the container has started before liveness probes are initiated"` } // PullPolicy describes a policy for if/when to pull a container image @@ -209,28 +209,28 @@ const ( type Container struct { // Required: This must be a DNS_LABEL. Each container in a pod must // have a unique name. - Name string `yaml:"name" json:"name" description:"name of the container; must be a DNS_LABEL and unique within the pod"` + Name string `json:"name" description:"name of the container; must be a DNS_LABEL and unique within the pod"` // Required. - Image string `yaml:"image" json:"image" description:"Docker image name"` + Image string `json:"image" description:"Docker image name"` // Optional: Defaults to whatever is defined in the image. - Command []string `yaml:"command,omitempty" json:"command,omitempty" description:"command argv array; not executed within a shell; defaults to entrypoint or command in the image"` + Command []string `json:"command,omitempty" description:"command argv array; not executed within a shell; defaults to entrypoint or command in the image"` // Optional: Defaults to Docker's default. - WorkingDir string `yaml:"workingDir,omitempty" json:"workingDir,omitempty" description:"container's working directory; defaults to image's default"` - Ports []Port `yaml:"ports,omitempty" json:"ports,omitempty" description:"list of ports to expose from the container"` - Env []EnvVar `yaml:"env,omitempty" json:"env,omitempty" description:"list of environment variables to set in the container"` + WorkingDir string `json:"workingDir,omitempty" description:"container's working directory; defaults to image's default"` + Ports []Port `json:"ports,omitempty" description:"list of ports to expose from the container"` + Env []EnvVar `json:"env,omitempty" description:"list of environment variables to set in the container"` // Optional: Defaults to unlimited. - Memory int `yaml:"memory,omitempty" json:"memory,omitempty" description:"memory limit in bytes; defaults to unlimited"` + Memory int `json:"memory,omitempty" description:"memory limit in bytes; defaults to unlimited"` // Optional: Defaults to unlimited. - CPU int `yaml:"cpu,omitempty" json:"cpu,omitempty" description:"CPU share in thousandths of a core"` - VolumeMounts []VolumeMount `yaml:"volumeMounts,omitempty" json:"volumeMounts,omitempty" description:"pod volumes to mount into the container's filesystem"` - LivenessProbe *LivenessProbe `yaml:"livenessProbe,omitempty" json:"livenessProbe,omitempty" description:"periodic probe of container liveness; container will be restarted if the probe fails"` - Lifecycle *Lifecycle `yaml:"lifecycle,omitempty" json:"lifecycle,omitempty" description:"actions that the management system should take in response to container lifecycle events"` + CPU int `json:"cpu,omitempty" description:"CPU share in thousandths of a core"` + VolumeMounts []VolumeMount `json:"volumeMounts,omitempty" description:"pod volumes to mount into the container's filesystem"` + LivenessProbe *LivenessProbe `json:"livenessProbe,omitempty" description:"periodic probe of container liveness; container will be restarted if the probe fails"` + Lifecycle *Lifecycle `json:"lifecycle,omitempty" description:"actions that the management system should take in response to container lifecycle events"` // Optional: Defaults to /dev/termination-log - TerminationMessagePath string `yaml:"terminationMessagePath,omitempty" json:"terminationMessagePath,omitempty" description:"path at which the file to which the container's termination message will be written is mounted into the container's filesystem; message written is intended to be brief final status, such as an assertion failure message; defaults to /dev/termination-log"` + TerminationMessagePath string `json:"terminationMessagePath,omitempty" description:"path at which the file to which the container's termination message will be written is mounted into the container's filesystem; message written is intended to be brief final status, such as an assertion failure message; defaults to /dev/termination-log"` // Optional: Default to false. - Privileged bool `json:"privileged,omitempty" yaml:"privileged,omitempty" description:"whether or not the container is granted privileged status; defaults to false"` + Privileged bool `json:"privileged,omitempty" description:"whether or not the container is granted privileged status; defaults to false"` // Optional: Policy for pulling images for this container - ImagePullPolicy PullPolicy `json:"imagePullPolicy" yaml:"imagePullPolicy" description:"image pull policy; one of PullAlways, PullNever, PullIfNotPresent; defaults to PullAlways if :latest tag is specified, or PullIfNotPresent otherwise"` + ImagePullPolicy PullPolicy `json:"imagePullPolicy" description:"image pull policy; one of PullAlways, PullNever, PullIfNotPresent; defaults to PullAlways if :latest tag is specified, or PullIfNotPresent otherwise"` } // Handler defines a specific action that should be taken @@ -238,9 +238,9 @@ type Container struct { type Handler struct { // One and only one of the following should be specified. // Exec specifies the action to take. - Exec *ExecAction `yaml:"exec,omitempty" json:"exec,omitempty" description:"exec-based hook handler"` + Exec *ExecAction `json:"exec,omitempty" description:"exec-based hook handler"` // HTTPGet specifies the http request to perform. - HTTPGet *HTTPGetAction `yaml:"httpGet,omitempty" json:"httpGet,omitempty" description:"HTTP-based hook handler"` + HTTPGet *HTTPGetAction `json:"httpGet,omitempty" description:"HTTP-based hook handler"` } // Lifecycle describes actions that the management system should take in response to container lifecycle @@ -249,29 +249,29 @@ type Handler struct { type Lifecycle struct { // PostStart is called immediately after a container is created. If the handler fails, the container // is terminated and restarted. - PostStart *Handler `yaml:"postStart,omitempty" json:"postStart,omitempty" description:"called immediately after a container is started; if the handler fails, the container is terminated and restarted according to its restart policy; other management of the container blocks until the hook completes"` + PostStart *Handler `json:"postStart,omitempty" description:"called immediately after a container is started; if the handler fails, the container is terminated and restarted according to its restart policy; other management of the container blocks until the hook completes"` // PreStop is called immediately before a container is terminated. The reason for termination is // passed to the handler. Regardless of the outcome of the handler, the container is eventually terminated. - PreStop *Handler `yaml:"preStop,omitempty" json:"preStop,omitempty" description:"called before a container is terminated; the container is terminated after the handler completes; other management of the container blocks until the hook completes"` + PreStop *Handler `json:"preStop,omitempty" description:"called before a container is terminated; the container is terminated after the handler completes; other management of the container blocks until the hook completes"` } // The below types are used by kube_client and api_server. // TypeMeta is shared by all objects sent to, or returned from the client. type TypeMeta struct { - Kind string `json:"kind,omitempty" yaml:"kind,omitempty" description:"kind of object, in CamelCase"` - ID string `json:"id,omitempty" yaml:"id,omitempty" description:"name of the object; must be a DNS_SUBDOMAIN and unique among all objects of the same kind within the same namespace; used in resource URLs"` - UID string `json:"uid,omitempty" yaml:"uid,omitempty" description:"UUID assigned by the system upon creation, unique across space and time"` - CreationTimestamp util.Time `json:"creationTimestamp,omitempty" yaml:"creationTimestamp,omitempty" description:"RFC 3339 date and time at which the object was created; recorded by the system; null for lists"` - SelfLink string `json:"selfLink,omitempty" yaml:"selfLink,omitempty" description:"URL for the object"` - ResourceVersion uint64 `json:"resourceVersion,omitempty" yaml:"resourceVersion,omitempty" description:"string that identifies the internal version of this object that can be used by clients to determine when objects have changed; value must be treated as opaque by clients and passed unmodified back to the server"` - APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty" description:"version of the schema the object should have"` - Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty" description:"namespace to which the object belongs; must be a DNS_SUBDOMAIN; 'default' by default"` + Kind string `json:"kind,omitempty" description:"kind of object, in CamelCase"` + ID string `json:"id,omitempty" description:"name of the object; must be a DNS_SUBDOMAIN and unique among all objects of the same kind within the same namespace; used in resource URLs"` + UID string `json:"uid,omitempty" description:"UUID assigned by the system upon creation, unique across space and time"` + CreationTimestamp util.Time `json:"creationTimestamp,omitempty" description:"RFC 3339 date and time at which the object was created; recorded by the system; null for lists"` + SelfLink string `json:"selfLink,omitempty" description:"URL for the object"` + ResourceVersion uint64 `json:"resourceVersion,omitempty" description:"string that identifies the internal version of this object that can be used by clients to determine when objects have changed; value must be treated as opaque by clients and passed unmodified back to the server"` + APIVersion string `json:"apiVersion,omitempty" description:"version of the schema the object should have"` + Namespace string `json:"namespace,omitempty" description:"namespace to which the object belongs; must be a DNS_SUBDOMAIN; 'default' by default"` // Annotations are unstructured key value data stored with a resource that may be set by // external tooling. They are not queryable and should be preserved when modifying // objects. - Annotations map[string]string `json:"annotations,omitempty" yaml:"annotations,omitempty" description:"map of string keys and values that can be used by external tooling to store and retrieve arbitrary metadata about the object"` + Annotations map[string]string `json:"annotations,omitempty" description:"map of string keys and values that can be used by external tooling to store and retrieve arbitrary metadata about the object"` } // PodStatus represents a status of a pod. @@ -289,46 +289,46 @@ const ( type ContainerStateWaiting struct { // Reason could be pulling image, - Reason string `json:"reason,omitempty" yaml:"reason,omitempty" description:"(brief) reason the container is not yet running, such as pulling its image"` + Reason string `json:"reason,omitempty" description:"(brief) reason the container is not yet running, such as pulling its image"` } type ContainerStateRunning struct { // TODO: change to util.Time - StartedAt time.Time `json:"startedAt,omitempty" yaml:"startedAt,omitempty" description:"time at which the container was last (re-)started"` + StartedAt time.Time `json:"startedAt,omitempty" description:"time at which the container was last (re-)started"` } type ContainerStateTerminated struct { - ExitCode int `json:"exitCode" yaml:"exitCode" description:"exit status from the last termination of the container"` - Signal int `json:"signal,omitempty" yaml:"signal,omitempty" description:"signal from the last termination of the container"` - Reason string `json:"reason,omitempty" yaml:"reason,omitempty" description:"(brief) reason from the last termination of the container"` - Message string `json:"message,omitempty" yaml:"message,omitempty" description:"message regarding the last termination of the container"` + ExitCode int `json:"exitCode" description:"exit status from the last termination of the container"` + Signal int `json:"signal,omitempty" description:"signal from the last termination of the container"` + Reason string `json:"reason,omitempty" description:"(brief) reason from the last termination of the container"` + Message string `json:"message,omitempty" description:"message regarding the last termination of the container"` // TODO: change to util.Time - StartedAt time.Time `json:"startedAt,omitempty" yaml:"startedAt,omitempty" description:"time at which previous execution of the container started"` + StartedAt time.Time `json:"startedAt,omitempty" description:"time at which previous execution of the container started"` // TODO: change to util.Time - FinishedAt time.Time `json:"finishedAt,omitempty" yaml:"finishedAt,omitempty" description:"time at which the container last terminated"` + FinishedAt time.Time `json:"finishedAt,omitempty" description:"time at which the container last terminated"` } // ContainerState holds a possible state of container. // Only one of its members may be specified. // If none of them is specified, the default one is ContainerStateWaiting. type ContainerState struct { - Waiting *ContainerStateWaiting `json:"waiting,omitempty" yaml:"waiting,omitempty" description:"details about a waiting container"` - Running *ContainerStateRunning `json:"running,omitempty" yaml:"running,omitempty" description:"details about a running container"` - Termination *ContainerStateTerminated `json:"termination,omitempty" yaml:"termination,omitempty" description:"details about a terminated container"` + Waiting *ContainerStateWaiting `json:"waiting,omitempty" description:"details about a waiting container"` + Running *ContainerStateRunning `json:"running,omitempty" description:"details about a running container"` + Termination *ContainerStateTerminated `json:"termination,omitempty" description:"details about a terminated container"` } type ContainerStatus struct { // TODO(dchen1107): Should we rename PodStatus to a more generic name or have a separate states // defined for container? - State ContainerState `json:"state,omitempty" yaml:"state,omitempty" description:"details about the container's current condition"` + State ContainerState `json:"state,omitempty" description:"details about the container's current condition"` // Note that this is calculated from dead containers. But those containers are subject to // garbage collection. This value will get capped at 5 by GC. - RestartCount int `json:"restartCount" yaml:"restartCount" description:"the number of times the container has been restarted, currently based on the number of dead containers that have not yet been removed"` + RestartCount int `json:"restartCount" description:"the number of times the container has been restarted, currently based on the number of dead containers that have not yet been removed"` // TODO(dchen1107): Deprecated this soon once we pull entire PodStatus from node, // not just PodInfo. Now we need this to remove docker.Container from API - PodIP string `json:"podIP,omitempty" yaml:"podIP,omitempty" description:"pod's IP address"` + PodIP string `json:"podIP,omitempty" description:"pod's IP address"` // TODO(dchen1107): Need to decide how to reprensent this in v1beta3 - Image string `yaml:"image" json:"image" description:"image of the container"` + Image string `json:"image" description:"image of the container"` } // PodInfo contains one entry for every container with available info. @@ -346,127 +346,127 @@ type RestartPolicy struct { // Only one of the following restart policies may be specified. // If none of the following policies is specified, the default one // is RestartPolicyAlways. - Always *RestartPolicyAlways `json:"always,omitempty" yaml:"always,omitempty" description:"always restart the container after termination"` - OnFailure *RestartPolicyOnFailure `json:"onFailure,omitempty" yaml:"onFailure,omitempty" description:"restart the container if it fails for any reason, but not if it succeeds (exit 0)"` - Never *RestartPolicyNever `json:"never,omitempty" yaml:"never,omitempty" description:"never restart the container"` + Always *RestartPolicyAlways `json:"always,omitempty" description:"always restart the container after termination"` + OnFailure *RestartPolicyOnFailure `json:"onFailure,omitempty" description:"restart the container if it fails for any reason, but not if it succeeds (exit 0)"` + Never *RestartPolicyNever `json:"never,omitempty" description:"never restart the container"` } // PodState is the state of a pod, used as either input (desired state) or output (current state). type PodState struct { - Manifest ContainerManifest `json:"manifest,omitempty" yaml:"manifest,omitempty" description:"manifest of containers and volumes comprising the pod"` - Status PodStatus `json:"status,omitempty" yaml:"status,omitempty" description:"current condition of the pod, Waiting, Running, or Terminated"` + Manifest ContainerManifest `json:"manifest,omitempty" description:"manifest of containers and volumes comprising the pod"` + Status PodStatus `json:"status,omitempty" description:"current condition of the pod, Waiting, Running, or Terminated"` // A human readable message indicating details about why the pod is in this state. - Message string `json:"message,omitempty" yaml:"message,omitempty" description:"human readable message indicating details about why the pod is in this condition"` - Host string `json:"host,omitempty" yaml:"host,omitempty" description:"host to which the pod is assigned; empty if not yet scheduled"` - HostIP string `json:"hostIP,omitempty" yaml:"hostIP,omitempty" description:"IP address of the host to which the pod is assigned; empty if not yet scheduled"` - PodIP string `json:"podIP,omitempty" yaml:"podIP,omitempty" description:"IP address allocated to the pod; routable at least within the cluster; empty if not yet allocated"` + Message string `json:"message,omitempty" description:"human readable message indicating details about why the pod is in this condition"` + Host string `json:"host,omitempty" description:"host to which the pod is assigned; empty if not yet scheduled"` + HostIP string `json:"hostIP,omitempty" description:"IP address of the host to which the pod is assigned; empty if not yet scheduled"` + PodIP string `json:"podIP,omitempty" description:"IP address allocated to the pod; routable at least within the cluster; empty if not yet allocated"` // The key of this map is the *name* of the container within the manifest; it has one // entry per container in the manifest. The value of this map is ContainerStatus for // the container. - Info PodInfo `json:"info,omitempty" yaml:"info,omitempty" description:"map of container name to container status"` + Info PodInfo `json:"info,omitempty" description:"map of container name to container status"` } // PodList is a list of Pods. type PodList struct { - TypeMeta `json:",inline" yaml:",inline"` - Items []Pod `json:"items" yaml:"items" description:"list of pods"` + TypeMeta `json:",inline"` + Items []Pod `json:"items" description:"list of pods"` } // Pod is a collection of containers, used as either input (create, update) or as output (list, get). type Pod struct { - TypeMeta `json:",inline" yaml:",inline"` - Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty" description:"map of string keys and values that can be used to organize and categorize pods; may match selectors of replication controllers and services"` - DesiredState PodState `json:"desiredState,omitempty" yaml:"desiredState,omitempty" description:"specification of the desired state of the pod"` - CurrentState PodState `json:"currentState,omitempty" yaml:"currentState,omitempty" description:"current state of the pod"` + TypeMeta `json:",inline"` + Labels map[string]string `json:"labels,omitempty" description:"map of string keys and values that can be used to organize and categorize pods; may match selectors of replication controllers and services"` + DesiredState PodState `json:"desiredState,omitempty" description:"specification of the desired state of the pod"` + CurrentState PodState `json:"currentState,omitempty" description:"current state of the pod"` // NodeSelector is a selector which must be true for the pod to fit on a node - NodeSelector map[string]string `json:"nodeSelector,omitempty" yaml:"nodeSelector,omitempty" description:"selector which must match a node's labels for the pod to be scheduled on that node"` + NodeSelector map[string]string `json:"nodeSelector,omitempty" description:"selector which must match a node's labels for the pod to be scheduled on that node"` } // ReplicationControllerState is the state of a replication controller, either input (create, update) or as output (list, get). type ReplicationControllerState struct { - Replicas int `json:"replicas" yaml:"replicas" description:"number of replicas (desired or observed, as appropriate)"` - ReplicaSelector map[string]string `json:"replicaSelector,omitempty" yaml:"replicaSelector,omitempty" description:"label keys and values that must match in order to be controlled by this replication controller"` - PodTemplate PodTemplate `json:"podTemplate,omitempty" yaml:"podTemplate,omitempty" description:"template for pods to be created by this replication controller when the observed number of replicas is less than the desired number of replicas"` + Replicas int `json:"replicas" description:"number of replicas (desired or observed, as appropriate)"` + ReplicaSelector map[string]string `json:"replicaSelector,omitempty" description:"label keys and values that must match in order to be controlled by this replication controller"` + PodTemplate PodTemplate `json:"podTemplate,omitempty" description:"template for pods to be created by this replication controller when the observed number of replicas is less than the desired number of replicas"` } // ReplicationControllerList is a collection of replication controllers. type ReplicationControllerList struct { - TypeMeta `json:",inline" yaml:",inline"` - Items []ReplicationController `json:"items" yaml:"items" description:"list of replication controllers"` + TypeMeta `json:",inline"` + Items []ReplicationController `json:"items" description:"list of replication controllers"` } // ReplicationController represents the configuration of a replication controller. type ReplicationController struct { - TypeMeta `json:",inline" yaml:",inline"` - DesiredState ReplicationControllerState `json:"desiredState,omitempty" yaml:"desiredState,omitempty" description:"specification of the desired state of the replication controller"` - CurrentState ReplicationControllerState `json:"currentState,omitempty" yaml:"currentState,omitempty" description:"current state of the replication controller"` - Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty" description:"map of string keys and values that can be used to organize and categorize replication controllers"` + TypeMeta `json:",inline"` + DesiredState ReplicationControllerState `json:"desiredState,omitempty" description:"specification of the desired state of the replication controller"` + CurrentState ReplicationControllerState `json:"currentState,omitempty" description:"current state of the replication controller"` + Labels map[string]string `json:"labels,omitempty" description:"map of string keys and values that can be used to organize and categorize replication controllers"` } // PodTemplate holds the information used for creating pods. type PodTemplate struct { - DesiredState PodState `json:"desiredState,omitempty" yaml:"desiredState,omitempty" description:"specification of the desired state of pods created from this template"` - Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty" description:"map of string keys and values that can be used to organize and categorize the pods created from the template; must match the selector of the replication controller to which the template belongs; may match selectors of services"` + DesiredState PodState `json:"desiredState,omitempty" description:"specification of the desired state of pods created from this template"` + Labels map[string]string `json:"labels,omitempty" description:"map of string keys and values that can be used to organize and categorize the pods created from the template; must match the selector of the replication controller to which the template belongs; may match selectors of services"` } // ServiceList holds a list of services. type ServiceList struct { - TypeMeta `json:",inline" yaml:",inline"` - Items []Service `json:"items" yaml:"items" description:"list of services"` + TypeMeta `json:",inline"` + Items []Service `json:"items" description:"list of services"` } // Service is a named abstraction of software service (for example, mysql) consisting of local port // (for example 3306) that the proxy listens on, and the selector that determines which pods // will answer requests sent through the proxy. type Service struct { - TypeMeta `json:",inline" yaml:",inline"` + TypeMeta `json:",inline"` // Required. - Port int `json:"port" yaml:"port" description:"port exposed by the service"` + Port int `json:"port" description:"port exposed by the service"` // Optional: Defaults to "TCP". - Protocol Protocol `yaml:"protocol,omitempty" json:"protocol,omitempty" description:"protocol for port; must be UDP or TCP; TCP if unspecified"` + Protocol Protocol `json:"protocol,omitempty" description:"protocol for port; must be UDP or TCP; TCP if unspecified"` // This service's labels. - Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty" description:"map of string keys and values that can be used to organize and categorize services"` + Labels map[string]string `json:"labels,omitempty" description:"map of string keys and values that can be used to organize and categorize services"` // This service will route traffic to pods having labels matching this selector. - Selector map[string]string `json:"selector,omitempty" yaml:"selector,omitempty" description:"label keys and values that must match in order to receive traffic for this service"` - CreateExternalLoadBalancer bool `json:"createExternalLoadBalancer,omitempty" yaml:"createExternalLoadBalancer,omitempty" description:"set up a cloud-provider-specific load balancer on an external IP"` + Selector map[string]string `json:"selector,omitempty" description:"label keys and values that must match in order to receive traffic for this service"` + CreateExternalLoadBalancer bool `json:"createExternalLoadBalancer,omitempty" description:"set up a cloud-provider-specific load balancer on an external IP"` // PublicIPs are used by external load balancers. - PublicIPs []string `json:"publicIPs,omitempty" yaml:"publicIPs,omitempty" description:"externally visible IPs from which to select the address for the external load balancer"` + PublicIPs []string `json:"publicIPs,omitempty" description:"externally visible IPs from which to select the address for the external load balancer"` // ContainerPort is the name of the port on the container to direct traffic to. // Optional, if unspecified use the first port on the container. - ContainerPort util.IntOrString `json:"containerPort,omitempty" yaml:"containerPort,omitempty" description:"number or name of the port to access on the containers belonging to pods targeted by the service"` + ContainerPort util.IntOrString `json:"containerPort,omitempty" description:"number or name of the port to access on the containers belonging to pods targeted by the service"` // PortalIP is usually assigned by the master. If specified by the user // we will try to respect it or else fail the request. This field can // not be changed by updates. - PortalIP string `json:"portalIP,omitempty" yaml:"portalIP,omitempty" description:"IP address of the service; usually assigned by the system; if specified, it will be allocated to the service if unused, and creation of the service will fail otherwise; cannot be updated"` + PortalIP string `json:"portalIP,omitempty" description:"IP address of the service; usually assigned by the system; if specified, it will be allocated to the service if unused, and creation of the service will fail otherwise; cannot be updated"` // ProxyPort is assigned by the master. If specified by the user it will be ignored. - ProxyPort int `json:"proxyPort,omitempty" yaml:"proxyPort,omitempty" description:"if non-zero, a pre-allocated host port used for this service by the proxy on each node; assigned by the master and ignored on input"` + ProxyPort int `json:"proxyPort,omitempty" description:"if non-zero, a pre-allocated host port used for this service by the proxy on each node; assigned by the master and ignored on input"` } // Endpoints is a collection of endpoints that implement the actual service, for example: // Name: "mysql", Endpoints: ["10.10.1.1:1909", "10.10.2.2:8834"] type Endpoints struct { - TypeMeta `json:",inline" yaml:",inline"` - Endpoints []string `json:"endpoints,omitempty" yaml:"endpoints,omitempty" description:"list of endpoints corresponding to a service, of the form address:port, such as 10.10.1.1:1909"` + TypeMeta `json:",inline"` + Endpoints []string `json:"endpoints,omitempty" description:"list of endpoints corresponding to a service, of the form address:port, such as 10.10.1.1:1909"` } // EndpointsList is a list of endpoints. type EndpointsList struct { - TypeMeta `json:",inline" yaml:",inline"` - Items []Endpoints `json:"items" yaml:"items" description:"list of service endpoint lists"` + TypeMeta `json:",inline"` + Items []Endpoints `json:"items" description:"list of service endpoint lists"` } // NodeResources represents resources on a Kubernetes system node // see https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/resources.md for more details. type NodeResources struct { // Capacity represents the available resources. - Capacity ResourceList `json:"capacity,omitempty" yaml:"capacity,omitempty" description:"resource capacity of a node represented as a map of resource name to quantity of resource"` + Capacity ResourceList `json:"capacity,omitempty" description:"resource capacity of a node represented as a map of resource name to quantity of resource"` } type ResourceName string @@ -476,49 +476,49 @@ type ResourceList map[ResourceName]util.IntOrString // Minion is a worker node in Kubernetenes. // The name of the minion according to etcd is in ID. type Minion struct { - TypeMeta `json:",inline" yaml:",inline"` + TypeMeta `json:",inline"` // Queried from cloud provider, if available. - HostIP string `json:"hostIP,omitempty" yaml:"hostIP,omitempty" description:"IP address of the node"` + HostIP string `json:"hostIP,omitempty" description:"IP address of the node"` // Resources available on the node - NodeResources NodeResources `json:"resources,omitempty" yaml:"resources,omitempty" description:"characterization of node resources"` + NodeResources NodeResources `json:"resources,omitempty" description:"characterization of node resources"` // Labels for the node - Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty" description:"map of string keys and values that can be used to organize and categorize minions; labels of a minion assigned by the scheduler must match the scheduled pod's nodeSelector"` + Labels map[string]string `json:"labels,omitempty" description:"map of string keys and values that can be used to organize and categorize minions; labels of a minion assigned by the scheduler must match the scheduled pod's nodeSelector"` } // MinionList is a list of minions. type MinionList struct { - TypeMeta `json:",inline" yaml:",inline"` - Items []Minion `json:"items" yaml:"items" description:"list of nodes"` + TypeMeta `json:",inline"` + Items []Minion `json:"items" description:"list of nodes"` } // Binding is written by a scheduler to cause a pod to be bound to a host. type Binding struct { - TypeMeta `json:",inline" yaml:",inline"` - PodID string `json:"podID" yaml:"podID" description:"name of the pod to bind"` - Host string `json:"host" yaml:"host" description:"host to which to bind the specified pod"` + TypeMeta `json:",inline"` + PodID string `json:"podID" description:"name of the pod to bind"` + Host string `json:"host" description:"host to which to bind the specified pod"` } // Status is a return value for calls that don't return other objects. // TODO: this could go in apiserver, but I'm including it here so clients needn't // import both. type Status struct { - TypeMeta `json:",inline" yaml:",inline"` + TypeMeta `json:",inline"` // One of: "Success", "Failure", "Working" (for operations not yet completed) - Status string `json:"status,omitempty" yaml:"status,omitempty" description:"status of the operation; either Working (not yet completed), Success, or Failure"` + Status string `json:"status,omitempty" description:"status of the operation; either Working (not yet completed), Success, or Failure"` // A human-readable description of the status of this operation. - Message string `json:"message,omitempty" yaml:"message,omitempty" description:"human-readable description of the status of this operation"` + Message string `json:"message,omitempty" description:"human-readable description of the status of this operation"` // A machine-readable description of why this operation is in the // "Failure" or "Working" status. If this value is empty there // is no information available. A Reason clarifies an HTTP status // code but does not override it. - Reason StatusReason `json:"reason,omitempty" yaml:"reason,omitempty" description:"machine-readable description of why this operation is in the 'Failure' or 'Working' status; if this value is empty there is no information available; a reason clarifies an HTTP status code but does not override it"` + Reason StatusReason `json:"reason,omitempty" description:"machine-readable description of why this operation is in the 'Failure' or 'Working' status; if this value is empty there is no information available; a reason clarifies an HTTP status code but does not override it"` // Extended data associated with the reason. Each reason may define its // own extended details. This field is optional and the data returned // is not guaranteed to conform to any schema except that defined by // the reason type. - Details *StatusDetails `json:"details,omitempty" yaml:"details,omitempty" description:"extended data associated with the reason; each reason may define its own extended details; this field is optional and the data returned is not guaranteed to conform to any schema except that defined by the reason type"` + Details *StatusDetails `json:"details,omitempty" description:"extended data associated with the reason; each reason may define its own extended details; this field is optional and the data returned is not guaranteed to conform to any schema except that defined by the reason type"` // Suggested HTTP return code for this status, 0 if not set. - Code int `json:"code,omitempty" yaml:"code,omitempty" description:"suggested HTTP return code for this status; 0 if not set"` + Code int `json:"code,omitempty" description:"suggested HTTP return code for this status; 0 if not set"` } // StatusDetails is a set of additional properties that MAY be set by the @@ -530,13 +530,13 @@ type Status struct { type StatusDetails struct { // The ID attribute of the resource associated with the status StatusReason // (when there is a single ID which can be described). - ID string `json:"id,omitempty" yaml:"id,omitempty" description:"the ID attribute of the resource associated with the status StatusReason (when there is a single ID which can be described)"` + ID string `json:"id,omitempty" description:"the ID attribute of the resource associated with the status StatusReason (when there is a single ID which can be described)"` // The kind attribute of the resource associated with the status StatusReason. // On some operations may differ from the requested resource Kind. - Kind string `json:"kind,omitempty" yaml:"kind,omitempty" description:"the kind attribute of the resource associated with the status StatusReason; on some operations may differ from the requested resource Kind"` + Kind string `json:"kind,omitempty" description:"the kind attribute of the resource associated with the status StatusReason; on some operations may differ from the requested resource Kind"` // The Causes array includes more details associated with the StatusReason // failure. Not all StatusReasons may provide detailed causes. - Causes []StatusCause `json:"causes,omitempty" yaml:"causes,omitempty" description:"the Causes array includes more details associated with the StatusReason failure; not all StatusReasons may provide detailed causes"` + Causes []StatusCause `json:"causes,omitempty" description:"the Causes array includes more details associated with the StatusReason failure; not all StatusReasons may provide detailed causes"` } // Values of Status.Status @@ -613,10 +613,10 @@ const ( type StatusCause struct { // A machine-readable description of the cause of the error. If this value is // empty there is no information available. - Type CauseType `json:"reason,omitempty" yaml:"reason,omitempty" description:"machine-readable description of the cause of the error; if this value is empty there is no information available"` + Type CauseType `json:"reason,omitempty" description:"machine-readable description of the cause of the error; if this value is empty there is no information available"` // A human-readable description of the cause of the error. This field may be // presented as-is to a reader. - Message string `json:"message,omitempty" yaml:"message,omitempty" description:"human-readable description of the cause of the error; this field may be presented as-is to a reader"` + Message string `json:"message,omitempty" description:"human-readable description of the cause of the error; this field may be presented as-is to a reader"` // The field of the resource that has caused this error, as named by its JSON // serialization. May include dot and postfix notation for nested attributes. // Arrays are zero-indexed. Fields may appear more than once in an array of @@ -626,7 +626,7 @@ type StatusCause struct { // Examples: // "name" - the field "name" on the current resource // "items[0].name" - the field "name" on the first array entry in "items" - Field string `json:"field,omitempty" yaml:"field,omitempty" description:"field of the resource that has caused this error, as named by its JSON serialization; may include dot and postfix notation for nested attributes; arrays are zero-indexed; fields may appear more than once in an array of causes due to fields having multiple errors"` + Field string `json:"field,omitempty" description:"field of the resource that has caused this error, as named by its JSON serialization; may include dot and postfix notation for nested attributes; arrays are zero-indexed; fields may appear more than once in an array of causes due to fields having multiple errors"` } // CauseType is a machine readable value providing more detail about what @@ -654,23 +654,23 @@ const ( // ServerOp is an operation delivered to API clients. type ServerOp struct { - TypeMeta `yaml:",inline" json:",inline"` + TypeMeta `json:",inline"` } // ServerOpList is a list of operations, as delivered to API clients. type ServerOpList struct { - TypeMeta `yaml:",inline" json:",inline"` - Items []ServerOp `yaml:"items" json:"items" description:"list of operations"` + TypeMeta `json:",inline"` + Items []ServerOp `json:"items" description:"list of operations"` } // ObjectReference contains enough information to let you inspect or modify the referred object. type ObjectReference struct { - Kind string `json:"kind,omitempty" yaml:"kind,omitempty" description:"kind of the referent"` - Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty" description:"namespace of the referent"` - ID string `json:"name,omitempty" yaml:"name,omitempty" description:"id of the referent"` - UID string `json:"uid,omitempty" yaml:"uid,omitempty" description:"uid of the referent"` - APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty" description:"API version of the referent"` - ResourceVersion string `json:"resourceVersion,omitempty" yaml:"resourceVersion,omitempty" description:"specific resourceVersion to which this reference is made, if any"` + Kind string `json:"kind,omitempty" description:"kind of the referent"` + Namespace string `json:"namespace,omitempty" description:"namespace of the referent"` + ID string `json:"name,omitempty" description:"id of the referent"` + UID string `json:"uid,omitempty" description:"uid of the referent"` + APIVersion string `json:"apiVersion,omitempty" description:"API version of the referent"` + ResourceVersion string `json:"resourceVersion,omitempty" description:"specific resourceVersion to which this reference is made, if any"` // Optional. If referring to a piece of an object instead of an entire object, this string // should contain a valid field access statement. For example, @@ -679,16 +679,16 @@ type ObjectReference struct { // both go and JavaScript. This is syntax is chosen only to have some well-defined way of // referencing a part of an object. // TODO: this design is not final and this field is subject to change in the future. - FieldPath string `json:"fieldPath,omitempty" yaml:"fieldPath,omitempty" description:"if referring to a piece of an object instead of an entire object, this string should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]"` + FieldPath string `json:"fieldPath,omitempty" description:"if referring to a piece of an object instead of an entire object, this string should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]"` } // Event is a report of an event somewhere in the cluster. // TODO: Decide whether to store these separately or with the object they apply to. type Event struct { - TypeMeta `yaml:",inline" json:",inline"` + TypeMeta `json:",inline"` // Required. The object that this event is about. - InvolvedObject ObjectReference `json:"involvedObject,omitempty" yaml:"involvedObject,omitempty" description:"object that this event is about"` + InvolvedObject ObjectReference `json:"involvedObject,omitempty" description:"object that this event is about"` // Should be a short, machine understandable string that describes the current status // of the referred object. This should not give the reason for being in this state. @@ -697,30 +697,30 @@ type Event struct { // always be used for the same status. // TODO: define a way of making sure these are consistent and don't collide. // TODO: provide exact specification for format. - Status string `json:"status,omitempty" yaml:"status,omitempty" description:"short, machine understandable string that describes the current status of the referred object"` + Status string `json:"status,omitempty" description:"short, machine understandable string that describes the current status of the referred object"` // Optional; this should be a short, machine understandable string that gives the reason // for the transition into the object's current status. For example, if ObjectStatus is // "cantStart", StatusReason might be "imageNotFound". // TODO: provide exact specification for format. - Reason string `json:"reason,omitempty" yaml:"reason,omitempty" description:"short, machine understandable string that gives the reason for the transition into the object's current status"` + Reason string `json:"reason,omitempty" description:"short, machine understandable string that gives the reason for the transition into the object's current status"` // Optional. A human-readable description of the status of this operation. // TODO: decide on maximum length. - Message string `json:"message,omitempty" yaml:"message,omitempty" description:"human-readable description of the status of this operation"` + Message string `json:"message,omitempty" description:"human-readable description of the status of this operation"` // Optional. The component reporting this event. Should be a short machine understandable string. // TODO: provide exact specification for format. - Source string `json:"source,omitempty" yaml:"source,omitempty" description:"component reporting this event; short machine understandable string"` + Source string `json:"source,omitempty" description:"component reporting this event; short machine understandable string"` // The time at which the client recorded the event. (Time of server receipt is in TypeMeta.) - Timestamp util.Time `json:"timestamp,omitempty" yaml:"timestamp,omitempty" description:"time at which the client recorded the event"` + Timestamp util.Time `json:"timestamp,omitempty" description:"time at which the client recorded the event"` } // EventList is a list of events. type EventList struct { - TypeMeta `yaml:",inline" json:",inline"` - Items []Event `yaml:"items" json:"items" description:"list of events"` + TypeMeta `json:",inline"` + Items []Event `json:"items" description:"list of events"` } // ContainerManifest corresponds to the Container Manifest format, documented at: @@ -729,55 +729,55 @@ type EventList struct { // DEPRECATED: Replaced with BoundPod type ContainerManifest struct { // Required: This must be a supported version string, such as "v1beta1". - Version string `yaml:"version" json:"version" description:"manifest version; must be v1beta1"` + Version string `json:"version" description:"manifest version; must be v1beta1"` // Required: This must be a DNS_SUBDOMAIN. // TODO: ID on Manifest is deprecated and will be removed in the future. - ID string `yaml:"id" json:"id" description:"manifest name; must be a DNS_SUBDOMAIN"` + ID string `json:"id" description:"manifest name; must be a DNS_SUBDOMAIN"` // TODO: UUID on Manifext is deprecated in the future once we are done // with the API refactory. It is required for now to determine the instance // of a Pod. - UUID string `yaml:"uuid,omitempty" json:"uuid,omitempty" description:"manifest UUID"` - Volumes []Volume `yaml:"volumes" json:"volumes" description:"list of volumes that can be mounted by containers belonging to the pod"` - Containers []Container `yaml:"containers" json:"containers" description:"list of containers belonging to the pod"` - RestartPolicy RestartPolicy `json:"restartPolicy,omitempty" yaml:"restartPolicy,omitempty" description:"restart policy for all containers within the pod; one of RestartPolicyAlways, RestartPolicyOnFailure, RestartPolicyNever"` + UUID string `json:"uuid,omitempty" description:"manifest UUID"` + Volumes []Volume `json:"volumes" description:"list of volumes that can be mounted by containers belonging to the pod"` + Containers []Container `json:"containers" description:"list of containers belonging to the pod"` + RestartPolicy RestartPolicy `json:"restartPolicy,omitempty" description:"restart policy for all containers within the pod; one of RestartPolicyAlways, RestartPolicyOnFailure, RestartPolicyNever"` } // ContainerManifestList is used to communicate container manifests to kubelet. // DEPRECATED: Replaced with BoundPods type ContainerManifestList struct { - TypeMeta `json:",inline" yaml:",inline"` - Items []ContainerManifest `json:"items" yaml:"items" description:"list of pod container manifests"` + TypeMeta `json:",inline"` + Items []ContainerManifest `json:"items" description:"list of pod container manifests"` } // Backported from v1beta3 to replace ContainerManifest // PodSpec is a description of a pod type PodSpec struct { - Volumes []Volume `json:"volumes" yaml:"volumes" description:"list of volumes that can be mounted by containers belonging to the pod"` - Containers []Container `json:"containers" yaml:"containers" description:"list of containers belonging to the pod"` - RestartPolicy RestartPolicy `json:"restartPolicy,omitempty" yaml:"restartPolicy,omitempty" description:"restart policy for all containers within the pod; one of RestartPolicyAlways, RestartPolicyOnFailure, RestartPolicyNever"` + Volumes []Volume `json:"volumes" description:"list of volumes that can be mounted by containers belonging to the pod"` + Containers []Container `json:"containers" description:"list of containers belonging to the pod"` + RestartPolicy RestartPolicy `json:"restartPolicy,omitempty" description:"restart policy for all containers within the pod; one of RestartPolicyAlways, RestartPolicyOnFailure, RestartPolicyNever"` // NodeSelector is a selector which must be true for the pod to fit on a node - NodeSelector map[string]string `json:"nodeSelector,omitempty" yaml:"nodeSelector,omitempty" description:"selector which must match a node's labels for the pod to be scheduled on that node"` + NodeSelector map[string]string `json:"nodeSelector,omitempty" description:"selector which must match a node's labels for the pod to be scheduled on that node"` } // BoundPod is a collection of containers that should be run on a host. A BoundPod // defines how a Pod may change after a Binding is created. A Pod is a request to // execute a pod, whereas a BoundPod is the specification that would be run on a server. type BoundPod struct { - TypeMeta `json:",inline" yaml:",inline"` + TypeMeta `json:",inline"` // Spec defines the behavior of a pod. - Spec PodSpec `json:"spec,omitempty" yaml:"spec,omitempty" description:"specification of the desired state of containers and volumes comprising the pod"` + Spec PodSpec `json:"spec,omitempty" description:"specification of the desired state of containers and volumes comprising the pod"` } // BoundPods is a list of Pods bound to a common server. The resource version of // the pod list is guaranteed to only change when the list of bound pods changes. type BoundPods struct { - TypeMeta `json:",inline" yaml:",inline"` + TypeMeta `json:",inline"` // Host is the name of a node that these pods were bound to. - Host string `json:"host" yaml:"host" description:"name of a node that these pods were bound to"` + Host string `json:"host" description:"name of a node that these pods were bound to"` // Items is the list of all pods bound to a given host. - Items []BoundPod `json:"items" yaml:"items" description:"list of all pods bound to a given host"` + Items []BoundPod `json:"items" description:"list of all pods bound to a given host"` } diff --git a/pkg/api/v1beta3/types.go b/pkg/api/v1beta3/types.go index 92b982114d4..65160c5dc6c 100644 --- a/pkg/api/v1beta3/types.go +++ b/pkg/api/v1beta3/types.go @@ -51,25 +51,25 @@ import ( type TypeMeta struct { // Kind is a string value representing the REST resource this object represents. // Servers may infer this from the endpoint the client submits requests to. - Kind string `json:"kind,omitempty" yaml:"kind,omitempty"` + Kind string `json:"kind,omitempty"` // APIVersion defines the versioned schema of this representation of an object. // Servers should convert recognized schemas to the latest internal value, and // may reject unrecognized values. - APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty"` + APIVersion string `json:"apiVersion,omitempty"` } // ListMeta describes metadata that synthetic resources must have, including lists and // various status objects. type ListMeta struct { // SelfLink is a URL representing this object. - SelfLink string `json:"selfLink,omitempty" yaml:"selfLink,omitempty"` + SelfLink string `json:"selfLink,omitempty"` // An opaque value that represents the version of this response for use with optimistic // concurrency and change monitoring endpoints. Clients must treat these values as opaque // and values may only be valid for a particular resource or set of resources. Only servers // will generate resource versions. - ResourceVersion string `json:"resourceVersion,omitempty" yaml:"resourceVersion,omitempty"` + ResourceVersion string `json:"resourceVersion,omitempty"` } // ObjectMeta is metadata that all persisted resources must have, which includes all objects @@ -79,41 +79,41 @@ type ObjectMeta struct { // some resources may allow a client to request the generation of an appropriate name // automatically. Name is primarily intended for creation idempotence and configuration // definition. - Name string `json:"name,omitempty" yaml:"name,omitempty"` + Name string `json:"name,omitempty"` // Namespace defines the space within which name must be unique. An empty namespace is // equivalent to the "default" namespace, but "default" is the canonical representation. // Not all objects are required to be scoped to a namespace - the value of this field for // those objects will be empty. - Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"` + Namespace string `json:"namespace,omitempty"` // SelfLink is a URL representing this object. - SelfLink string `json:"selfLink,omitempty" yaml:"selfLink,omitempty"` + SelfLink string `json:"selfLink,omitempty"` // UID is the unique in time and space value for this object. It is typically generated by // the server on successful creation of a resource and is not allowed to change on PUT // operations. - UID string `json:"uid,omitempty" yaml:"uid,omitempty"` + UID string `json:"uid,omitempty"` // An opaque value that represents the version of this resource. May be used for optimistic // concurrency, change detection, and the watch operation on a resource or set of resources. // Clients must treat these values as opaque and values may only be valid for a particular // resource or set of resources. Only servers will generate resource versions. - ResourceVersion string `json:"resourceVersion,omitempty" yaml:"resourceVersion,omitempty"` + ResourceVersion string `json:"resourceVersion,omitempty"` // CreationTimestamp is a timestamp representing the server time when this object was // created. It is not guaranteed to be set in happens-before order across separate operations. // Clients may not set this value. It is represented in RFC3339 form and is in UTC. - CreationTimestamp util.Time `json:"creationTimestamp,omitempty" yaml:"creationTimestamp,omitempty"` + CreationTimestamp util.Time `json:"creationTimestamp,omitempty"` // Labels are key value pairs that may be used to scope and select individual resources. // TODO: replace map[string]string with labels.LabelSet type - Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"` + Labels map[string]string `json:"labels,omitempty"` // Annotations are unstructured key value data stored with a resource that may be set by // external tooling. They are not queryable and should be preserved when modifying // objects. - Annotations map[string]string `json:"annotations,omitempty" yaml:"annotations,omitempty"` + Annotations map[string]string `json:"annotations,omitempty"` } const ( @@ -131,39 +131,39 @@ const ( //// directly. //type ContainerManifest struct { // // Required: This must be a supported version string, such as "v1beta1". -// Version string `json:"version" yaml:"version"` +// Version string `json:"version"` // // Required: This must be a DNS_SUBDOMAIN. // // TODO: ID on Manifest is deprecated and will be removed in the future. -// ID string `json:"id" yaml:"id"` +// ID string `json:"id"` // // TODO: UUID on Manifest is deprecated in the future once we are done // // with the API refactoring. It is required for now to determine the instance // // of a Pod. -// UUID string `json:"uuid,omitempty" yaml:"uuid,omitempty"` -// Volumes []Volume `json:"volumes" yaml:"volumes"` -// Containers []Container `json:"containers" yaml:"containers"` -// RestartPolicy RestartPolicy `json:"restartPolicy,omitempty" yaml:"restartPolicy,omitempty"` +// UUID string `json:"uuid,omitempty"` +// Volumes []Volume `json:"volumes"` +// Containers []Container `json:"containers"` +// RestartPolicy RestartPolicy `json:"restartPolicy,omitempty"` //} // //// ContainerManifestList is used to communicate container manifests to kubelet. //// DEPRECATED: Exists to allow backwards compatible storage for clients accessing etcd //// directly. //type ContainerManifestList struct { -// TypeMeta `json:",inline" yaml:",inline"` +// TypeMeta `json:",inline"` // // ID is the legacy field representing Name -// ID string `json:"id,omitempty" yaml:"id,omitempty"` +// ID string `json:"id,omitempty"` // -// Items []ContainerManifest `json:"items,omitempty" yaml:"items,omitempty"` +// Items []ContainerManifest `json:"items,omitempty"` //} // Volume represents a named volume in a pod that may be accessed by any containers in the pod. type Volume struct { // Required: This must be a DNS_LABEL. Each volume in a pod must have // a unique name. - Name string `json:"name" yaml:"name"` + Name string `json:"name"` // Source represents the location and type of a volume to mount. // This is optional for now. If not specified, the Volume is implied to be an EmptyDir. // This implied behavior is deprecated and will be removed in a future version. - Source *VolumeSource `json:"source" yaml:"source"` + Source *VolumeSource `json:"source"` } // VolumeSource represents the source location of a valume to mount. @@ -174,19 +174,19 @@ type VolumeSource struct { // things that are allowed to see the host machine. Most containers will NOT need this. // TODO(jonesdl) We need to restrict who can use host directory mounts and who can/can not // mount host directories as read/write. - HostDir *HostDir `json:"hostDir" yaml:"hostDir"` + HostDir *HostDir `json:"hostDir"` // EmptyDir represents a temporary directory that shares a pod's lifetime. - EmptyDir *EmptyDir `json:"emptyDir" yaml:"emptyDir"` + EmptyDir *EmptyDir `json:"emptyDir"` // GCEPersistentDisk represents a GCE Disk resource that is attached to a // kubelet's host machine and then exposed to the pod. - GCEPersistentDisk *GCEPersistentDisk `yaml:"persistentDisk" json:"persistentDisk"` + GCEPersistentDisk *GCEPersistentDisk `json:"persistentDisk"` // GitRepo represents a git repository at a particular revision. - GitRepo *GitRepo `json:"gitRepo" yaml:"gitRepo"` + GitRepo *GitRepo `json:"gitRepo"` } // HostDir represents bare host directory volume. type HostDir struct { - Path string `json:"path" yaml:"path"` + Path string `json:"path"` } type EmptyDir struct{} @@ -208,76 +208,76 @@ const ( // A GCE PD can only be mounted as read/write once. type GCEPersistentDisk struct { // Unique name of the PD resource. Used to identify the disk in GCE - PDName string `yaml:"pdName" json:"pdName"` + PDName string `json:"pdName"` // Required: Filesystem type to mount. // Must be a filesystem type supported by the host operating system. // Ex. "ext4", "xfs", "ntfs" // TODO: how do we prevent errors in the filesystem from compromising the machine - FSType string `yaml:"fsType,omitempty" json:"fsType,omitempty"` + FSType string `json:"fsType,omitempty"` // Optional: Partition on the disk to mount. // If omitted, kubelet will attempt to mount the device name. // Ex. For /dev/sda1, this field is "1", for /dev/sda, this field is 0 or empty. - Partition int `yaml:"partition,omitempty" json:"partition,omitempty"` + Partition int `json:"partition,omitempty"` // Optional: Defaults to false (read/write). ReadOnly here will force // the ReadOnly setting in VolumeMounts. - ReadOnly bool `yaml:"readOnly,omitempty" json:"readOnly,omitempty"` + ReadOnly bool `json:"readOnly,omitempty"` } // GitRepo represents a volume that is pulled from git when the pod is created. type GitRepo struct { // Repository URL - Repository string `yaml:"repository" json:"repository"` + Repository string `json:"repository"` // Commit hash, this is optional - Revision string `yaml:"revision" json:"revision"` + Revision string `json:"revision"` } // Port represents a network port in a single container. type Port struct { // Optional: If specified, this must be a DNS_LABEL. Each named port // in a pod must have a unique name. - Name string `json:"name,omitempty" yaml:"name,omitempty"` + Name string `json:"name,omitempty"` // Optional: If specified, this must be a valid port number, 0 < x < 65536. - HostPort int `json:"hostPort,omitempty" yaml:"hostPort,omitempty"` + HostPort int `json:"hostPort,omitempty"` // Required: This must be a valid port number, 0 < x < 65536. - ContainerPort int `json:"containerPort" yaml:"containerPort"` + ContainerPort int `json:"containerPort"` // Optional: Supports "TCP" and "UDP". Defaults to "TCP". - Protocol Protocol `json:"protocol,omitempty" yaml:"protocol,omitempty"` + Protocol Protocol `json:"protocol,omitempty"` // Optional: What host IP to bind the external port to. - HostIP string `json:"hostIP,omitempty" yaml:"hostIP,omitempty"` + HostIP string `json:"hostIP,omitempty"` } // VolumeMount describes a mounting of a Volume within a container. type VolumeMount struct { // Required: This must match the Name of a Volume [above]. - Name string `json:"name" yaml:"name"` + Name string `json:"name"` // Optional: Defaults to false (read-write). - ReadOnly bool `json:"readOnly,omitempty" yaml:"readOnly,omitempty"` + ReadOnly bool `json:"readOnly,omitempty"` // Required. - MountPath string `json:"mountPath,omitempty" yaml:"mountPath,omitempty"` + MountPath string `json:"mountPath,omitempty"` } // EnvVar represents an environment variable present in a Container. type EnvVar struct { // Required: This must be a C_IDENTIFIER. - Name string `json:"name" yaml:"name"` + Name string `json:"name"` // Optional: defaults to "". - Value string `json:"value,omitempty" yaml:"value,omitempty"` + Value string `json:"value,omitempty"` } // HTTPGetAction describes an action based on HTTP Get requests. type HTTPGetAction struct { // Optional: Path to access on the HTTP server. - Path string `json:"path,omitempty" yaml:"path,omitempty"` + Path string `json:"path,omitempty"` // Required: Name or number of the port to access on the container. - Port util.IntOrString `json:"port,omitempty" yaml:"port,omitempty"` + Port util.IntOrString `json:"port,omitempty"` // Optional: Host name to connect to, defaults to the pod IP. - Host string `json:"host,omitempty" yaml:"host,omitempty"` + Host string `json:"host,omitempty"` } // TCPSocketAction describes an action based on opening a socket type TCPSocketAction struct { // Required: Port to connect to. - Port util.IntOrString `json:"port,omitempty" yaml:"port,omitempty"` + Port util.IntOrString `json:"port,omitempty"` } // ExecAction describes a "run in container" action. @@ -286,22 +286,22 @@ type ExecAction struct { // command is root ('/') in the container's filesystem. The command is simply exec'd, it is // not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use // a shell, you need to explicitly call out to that shell. - Command []string `json:"command,omitempty" yaml:"command,omitempty"` + Command []string `json:"command,omitempty"` } // LivenessProbe describes how to probe a container for liveness. // TODO: pass structured data to the actions, and document that data here. type LivenessProbe struct { // Type of liveness probe. Current legal values "HTTP", "TCP", "Exec" - Type string `json:"type,omitempty" yaml:"type,omitempty"` + Type string `json:"type,omitempty"` // HTTPGetProbe parameters, required if Type == 'HTTP' - HTTPGet *HTTPGetAction `json:"httpGet,omitempty" yaml:"httpGet,omitempty"` + HTTPGet *HTTPGetAction `json:"httpGet,omitempty"` // TCPSocketProbe parameter, required if Type == 'TCP' - TCPSocket *TCPSocketAction `json:"tcpSocket,omitempty" yaml:"tcpSocket,omitempty"` + TCPSocket *TCPSocketAction `json:"tcpSocket,omitempty"` // ExecProbe parameter, required if Type == 'Exec' - Exec *ExecAction `json:"exec,omitempty" yaml:"exec,omitempty"` + Exec *ExecAction `json:"exec,omitempty"` // Length of time before health checking is activated. In seconds. - InitialDelaySeconds int64 `json:"initialDelaySeconds,omitempty" yaml:"initialDelaySeconds,omitempty"` + InitialDelaySeconds int64 `json:"initialDelaySeconds,omitempty"` } // PullPolicy describes a policy for if/when to pull a container image @@ -320,28 +320,28 @@ const ( type Container struct { // Required: This must be a DNS_LABEL. Each container in a pod must // have a unique name. - Name string `json:"name" yaml:"name"` + Name string `json:"name"` // Required. - Image string `json:"image" yaml:"image"` + Image string `json:"image"` // Optional: Defaults to whatever is defined in the image. - Command []string `json:"command,omitempty" yaml:"command,omitempty"` + Command []string `json:"command,omitempty"` // Optional: Defaults to Docker's default. - WorkingDir string `json:"workingDir,omitempty" yaml:"workingDir,omitempty"` - Ports []Port `json:"ports,omitempty" yaml:"ports,omitempty"` - Env []EnvVar `json:"env,omitempty" yaml:"env,omitempty"` + WorkingDir string `json:"workingDir,omitempty"` + Ports []Port `json:"ports,omitempty"` + Env []EnvVar `json:"env,omitempty"` // Optional: Defaults to unlimited. - Memory int `json:"memory,omitempty" yaml:"memory,omitempty"` + Memory int `json:"memory,omitempty"` // Optional: Defaults to unlimited. - CPU int `json:"cpu,omitempty" yaml:"cpu,omitempty"` - VolumeMounts []VolumeMount `json:"volumeMounts,omitempty" yaml:"volumeMounts,omitempty"` - LivenessProbe *LivenessProbe `json:"livenessProbe,omitempty" yaml:"livenessProbe,omitempty"` - Lifecycle *Lifecycle `json:"lifecycle,omitempty" yaml:"lifecycle,omitempty"` + CPU int `json:"cpu,omitempty"` + VolumeMounts []VolumeMount `json:"volumeMounts,omitempty"` + LivenessProbe *LivenessProbe `json:"livenessProbe,omitempty"` + Lifecycle *Lifecycle `json:"lifecycle,omitempty"` // Optional: Defaults to /dev/termination-log - TerminationMessagePath string `json:"terminationMessagePath,omitempty" yaml:"terminationMessagePath,omitempty"` + TerminationMessagePath string `json:"terminationMessagePath,omitempty"` // Optional: Default to false. - Privileged bool `json:"privileged,omitempty" yaml:"privileged,omitempty"` + Privileged bool `json:"privileged,omitempty"` // Optional: Policy for pulling images for this container - ImagePullPolicy PullPolicy `json:"imagePullPolicy" yaml:"imagePullPolicy"` + ImagePullPolicy PullPolicy `json:"imagePullPolicy"` } // Handler defines a specific action that should be taken @@ -349,9 +349,9 @@ type Container struct { type Handler struct { // One and only one of the following should be specified. // Exec specifies the action to take. - Exec *ExecAction `json:"exec,omitempty" yaml:"exec,omitempty"` + Exec *ExecAction `json:"exec,omitempty"` // HTTPGet specifies the http request to perform. - HTTPGet *HTTPGetAction `json:"httpGet,omitempty" yaml:"httpGet,omitempty"` + HTTPGet *HTTPGetAction `json:"httpGet,omitempty"` } // Lifecycle describes actions that the management system should take in response to container lifecycle @@ -360,10 +360,10 @@ type Handler struct { type Lifecycle struct { // PostStart is called immediately after a container is created. If the handler fails, the container // is terminated and restarted. - PostStart *Handler `json:"postStart,omitempty" yaml:"postStart,omitempty"` + PostStart *Handler `json:"postStart,omitempty"` // PreStop is called immediately before a container is terminated. The reason for termination is // passed to the handler. Regardless of the outcome of the handler, the container is eventually terminated. - PreStop *Handler `json:"preStop,omitempty" yaml:"preStop,omitempty"` + PreStop *Handler `json:"preStop,omitempty"` } // PodPhase is a label for the condition of a pod at the current time. @@ -388,38 +388,38 @@ const ( type ContainerStateWaiting struct { // Reason could be pulling image, - Reason string `json:"reason,omitempty" yaml:"reason,omitempty"` + Reason string `json:"reason,omitempty"` } type ContainerStateRunning struct { - StartedAt time.Time `json:"startedAt,omitempty" yaml:"startedAt,omitempty"` + StartedAt time.Time `json:"startedAt,omitempty"` } type ContainerStateTerminated struct { - ExitCode int `json:"exitCode" yaml:"exitCode"` - Signal int `json:"signal,omitempty" yaml:"signal,omitempty"` - Reason string `json:"reason,omitempty" yaml:"reason,omitempty"` - Message string `json:"message,omitempty" yaml:"message,omitempty"` - StartedAt time.Time `json:"startedAt,omitempty" yaml:"startedAt,omitempty"` - FinishedAt time.Time `json:"finishedAt,omitempty" yaml:"finishedAt,omitempty"` + ExitCode int `json:"exitCode"` + Signal int `json:"signal,omitempty"` + Reason string `json:"reason,omitempty"` + Message string `json:"message,omitempty"` + StartedAt time.Time `json:"startedAt,omitempty"` + FinishedAt time.Time `json:"finishedAt,omitempty"` } // ContainerState holds a possible state of container. // Only one of its members may be specified. // If none of them is specified, the default one is ContainerStateWaiting. type ContainerState struct { - Waiting *ContainerStateWaiting `json:"waiting,omitempty" yaml:"waiting,omitempty"` - Running *ContainerStateRunning `json:"running,omitempty" yaml:"running,omitempty"` - Termination *ContainerStateTerminated `json:"termination,omitempty" yaml:"termination,omitempty"` + Waiting *ContainerStateWaiting `json:"waiting,omitempty"` + Running *ContainerStateRunning `json:"running,omitempty"` + Termination *ContainerStateTerminated `json:"termination,omitempty"` } type ContainerStatus struct { // TODO(dchen1107): Should we rename PodStatus to a more generic name or have a separate states // defined for container? - State ContainerState `json:"state,omitempty" yaml:"state,omitempty"` + State ContainerState `json:"state,omitempty"` // Note that this is calculated from dead containers. But those containers are subject to // garbage collection. This value will get capped at 5 by GC. - RestartCount int `json:"restartCount" yaml:"restartCount"` + RestartCount int `json:"restartCount"` // TODO(dchen1107): Introduce our own NetworkSettings struct here? // TODO(dchen1107): Which image the container is running with? } @@ -439,32 +439,32 @@ type RestartPolicy struct { // Only one of the following restart policies may be specified. // If none of the following policies is specified, the default one // is RestartPolicyAlways. - Always *RestartPolicyAlways `json:"always,omitempty" yaml:"always,omitempty"` - OnFailure *RestartPolicyOnFailure `json:"onFailure,omitempty" yaml:"onFailure,omitempty"` - Never *RestartPolicyNever `json:"never,omitempty" yaml:"never,omitempty"` + Always *RestartPolicyAlways `json:"always,omitempty"` + OnFailure *RestartPolicyOnFailure `json:"onFailure,omitempty"` + Never *RestartPolicyNever `json:"never,omitempty"` } // PodSpec is a description of a pod type PodSpec struct { - Volumes []Volume `json:"volumes" yaml:"volumes"` - Containers []Container `json:"containers" yaml:"containers"` - RestartPolicy RestartPolicy `json:"restartPolicy,omitempty" yaml:"restartPolicy,omitempty"` + Volumes []Volume `json:"volumes"` + Containers []Container `json:"containers"` + RestartPolicy RestartPolicy `json:"restartPolicy,omitempty"` // NodeSelector is a selector which must be true for the pod to fit on a node - NodeSelector map[string]string `json:"nodeSelector,omitempty" yaml:"nodeSelector,omitempty"` + NodeSelector map[string]string `json:"nodeSelector,omitempty"` } // PodStatus represents information about the status of a pod. Status may trail the actual // state of a system. type PodStatus struct { - Phase PodPhase `json:"phase,omitempty" yaml:"phase,omitempty"` + Phase PodPhase `json:"phase,omitempty"` // A human readable message indicating details about why the pod is in this state. - Message string `json:"message,omitempty" yaml:"message,omitempty"` + Message string `json:"message,omitempty"` // Host is the name of the node that this Pod is currently bound to, or empty if no // assignment has been done. - Host string `json:"host,omitempty" yaml:"host,omitempty"` - HostIP string `json:"hostIP,omitempty" yaml:"hostIP,omitempty"` - PodIP string `json:"podIP,omitempty" yaml:"podIP,omitempty"` + Host string `json:"host,omitempty"` + HostIP string `json:"hostIP,omitempty"` + PodIP string `json:"podIP,omitempty"` // The key of this map is the *name* of the container within the manifest; it has one // entry per container in the manifest. The value of this map is currently the output @@ -472,121 +472,121 @@ type PodStatus struct { // upon. // TODO: Make real decisions about what our info should look like. Re-enable fuzz test // when we have done this. - Info PodInfo `json:"info,omitempty" yaml:"info,omitempty"` + Info PodInfo `json:"info,omitempty"` } // Pod is a collection of containers that can run on a host. This resource is created // by clients and scheduled onto hosts. BoundPod represents the state of this resource // to hosts. type Pod struct { - TypeMeta `json:",inline" yaml:",inline"` - ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"` + TypeMeta `json:",inline"` + ObjectMeta `json:"metadata,omitempty"` // Spec defines the behavior of a pod. - Spec PodSpec `json:"spec,omitempty" yaml:"spec,omitempty"` + Spec PodSpec `json:"spec,omitempty"` // Status represents the current information about a pod. This data may not be up // to date. - Status PodStatus `json:"status,omitempty" yaml:"status,omitempty"` + Status PodStatus `json:"status,omitempty"` } // PodList is a list of Pods. type PodList struct { - TypeMeta `json:",inline" yaml:",inline"` - ListMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"` + TypeMeta `json:",inline"` + ListMeta `json:"metadata,omitempty"` - Items []Pod `json:"items" yaml:"items"` + Items []Pod `json:"items"` } // PodTemplateSpec describes the data a pod should have when created from a template type PodTemplateSpec struct { // Metadata of the pods created from this template. - ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"` + ObjectMeta `json:"metadata,omitempty"` // Spec defines the behavior of a pod. - Spec PodSpec `json:"spec,omitempty" yaml:"spec,omitempty"` + Spec PodSpec `json:"spec,omitempty"` } // PodTemplate describes a template for creating copies of a predefined pod. type PodTemplate struct { - TypeMeta `json:",inline" yaml:",inline"` - ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"` + TypeMeta `json:",inline"` + ObjectMeta `json:"metadata,omitempty"` // Spec defines the behavior of a pod. - Spec PodTemplateSpec `json:"spec,omitempty" yaml:"spec,omitempty"` + Spec PodTemplateSpec `json:"spec,omitempty"` } // PodTemplateList is a list of PodTemplates. type PodTemplateList struct { - TypeMeta `json:",inline" yaml:",inline"` - ListMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"` + TypeMeta `json:",inline"` + ListMeta `json:"metadata,omitempty"` - Items []PodTemplate `json:"items" yaml:"items"` + Items []PodTemplate `json:"items"` } // BoundPod is a collection of containers that should be run on a host. A BoundPod // defines how a Pod may change after a Binding is created. A Pod is a request to // execute a pod, whereas a BoundPod is the specification that would be run on a server. type BoundPod struct { - TypeMeta `json:",inline" yaml:",inline"` - ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"` + TypeMeta `json:",inline"` + ObjectMeta `json:"metadata,omitempty"` // Spec defines the behavior of a pod. - Spec PodSpec `json:"spec,omitempty" yaml:"spec,omitempty"` + Spec PodSpec `json:"spec,omitempty"` } // BoundPods is a list of Pods bound to a common server. The resource version of // the pod list is guaranteed to only change when the list of bound pods changes. type BoundPods struct { - TypeMeta `json:",inline" yaml:",inline"` - ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"` + TypeMeta `json:",inline"` + ObjectMeta `json:"metadata,omitempty"` // Host is the name of a node that these pods were bound to. - Host string `json:"host" yaml:"host"` + Host string `json:"host"` // Items is the list of all pods bound to a given host. - Items []BoundPod `json:"items" yaml:"items"` + Items []BoundPod `json:"items"` } // ReplicationControllerSpec is the specification of a replication controller. type ReplicationControllerSpec struct { // Replicas is the number of desired replicas. - Replicas int `json:"replicas" yaml:"replicas"` + Replicas int `json:"replicas"` // Selector is a label query over pods that should match the Replicas count. - Selector map[string]string `json:"selector,omitempty" yaml:"selector,omitempty"` + Selector map[string]string `json:"selector,omitempty"` // Template is a reference to an object that describes the pod that will be created if // insufficient replicas are detected. - Template ObjectReference `json:"template,omitempty" yaml:"template,omitempty"` + Template ObjectReference `json:"template,omitempty"` } // ReplicationControllerStatus represents the current status of a replication // controller. type ReplicationControllerStatus struct { // Replicas is the number of actual replicas. - Replicas int `json:"replicas" yaml:"replicas"` + Replicas int `json:"replicas"` } // ReplicationController represents the configuration of a replication controller. type ReplicationController struct { - TypeMeta `json:",inline" yaml:",inline"` - ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"` + TypeMeta `json:",inline"` + ObjectMeta `json:"metadata,omitempty"` // Spec defines the desired behavior of this replication controller. - Spec ReplicationControllerSpec `json:"spec,omitempty" yaml:"spec,omitempty"` + Spec ReplicationControllerSpec `json:"spec,omitempty"` // Status is the current status of this replication controller. This data may be // out of date by some window of time. - Status ReplicationControllerStatus `json:"status,omitempty" yaml:"status,omitempty"` + Status ReplicationControllerStatus `json:"status,omitempty"` } // ReplicationControllerList is a collection of replication controllers. type ReplicationControllerList struct { - TypeMeta `json:",inline" yaml:",inline"` - ListMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"` + TypeMeta `json:",inline"` + ListMeta `json:"metadata,omitempty"` - Items []ReplicationController `json:"items" yaml:"items"` + Items []ReplicationController `json:"items"` } // ServiceStatus represents the current status of a service @@ -596,83 +596,83 @@ type ServiceStatus struct{} type ServiceSpec struct { // Port is the TCP or UDP port that will be made available to each pod for connecting to the pods // proxied by this service. - Port int `json:"port" yaml:"port"` + Port int `json:"port"` // Optional: Supports "TCP" and "UDP". Defaults to "TCP". - Protocol Protocol `json:"protocol,omitempty" yaml:"protocol,omitempty"` + Protocol Protocol `json:"protocol,omitempty"` // This service will route traffic to pods having labels matching this selector. - Selector map[string]string `json:"selector,omitempty" yaml:"selector,omitempty"` + Selector map[string]string `json:"selector,omitempty"` // PortalIP is usually assigned by the master. If specified by the user // we will try to respect it or else fail the request. This field can // not be changed by updates. - PortalIP string `json:"portalIP,omitempty" yaml:"portalIP,omitempty"` + PortalIP string `json:"portalIP,omitempty"` // ProxyPort is assigned by the master. If 0, the proxy will choose an ephemeral port. - ProxyPort int `json:"proxyPort,omitempty" yaml:"proxyPort,omitempty"` + ProxyPort int `json:"proxyPort,omitempty"` // CreateExternalLoadBalancer indicates whether a load balancer should be created for this service. - CreateExternalLoadBalancer bool `json:"createExternalLoadBalancer,omitempty" yaml:"createExternalLoadBalancer,omitempty"` + CreateExternalLoadBalancer bool `json:"createExternalLoadBalancer,omitempty"` // PublicIPs are used by external load balancers. - PublicIPs []string `json:"publicIPs,omitempty" yaml:"publicIPs,omitempty"` + PublicIPs []string `json:"publicIPs,omitempty"` // ContainerPort is the name of the port on the container to direct traffic to. // Optional, if unspecified use the first port on the container. - ContainerPort util.IntOrString `json:"containerPort,omitempty" yaml:"containerPort,omitempty"` + ContainerPort util.IntOrString `json:"containerPort,omitempty"` } // Service is a named abstraction of software service (for example, mysql) consisting of local port // (for example 3306) that the proxy listens on, and the selector that determines which pods // will answer requests sent through the proxy. type Service struct { - TypeMeta `json:",inline" yaml:",inline"` - ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"` + TypeMeta `json:",inline"` + ObjectMeta `json:"metadata,omitempty"` // Spec defines the behavior of a service. - Spec ServiceSpec `json:"spec,omitempty" yaml:"spec,omitempty"` + Spec ServiceSpec `json:"spec,omitempty"` // Status represents the current status of a service. - Status ServiceStatus `json:"status,omitempty" yaml:"status,omitempty"` + Status ServiceStatus `json:"status,omitempty"` } // ServiceList holds a list of services. type ServiceList struct { - TypeMeta `json:",inline" yaml:",inline"` - ListMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"` + TypeMeta `json:",inline"` + ListMeta `json:"metadata,omitempty"` - Items []Service `json:"items" yaml:"items"` + Items []Service `json:"items"` } // Endpoints is a collection of endpoints that implement the actual service, for example: // Name: "mysql", Endpoints: ["10.10.1.1:1909", "10.10.2.2:8834"] type Endpoints struct { - TypeMeta `json:",inline" yaml:",inline"` - ObjectMeta `json:"metadata" yaml:"metadata"` + TypeMeta `json:",inline"` + ObjectMeta `json:"metadata"` // Endpoints is the list of host ports that satisfy the service selector - Endpoints []string `json:"endpoints" yaml:"endpoints"` + Endpoints []string `json:"endpoints"` } // EndpointsList is a list of endpoints. type EndpointsList struct { - TypeMeta `json:",inline" yaml:",inline"` - ListMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"` + TypeMeta `json:",inline"` + ListMeta `json:"metadata,omitempty"` - Items []Endpoints `json:"items" yaml:"items"` + Items []Endpoints `json:"items"` } // NodeSpec describes the attributes that a node is created with. type NodeSpec struct { // Capacity represents the available resources of a node // see https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/resources.md for more details. - Capacity ResourceList `json:"capacity,omitempty" yaml:"capacity,omitempty"` + Capacity ResourceList `json:"capacity,omitempty"` } // NodeStatus is information about the current status of a node. type NodeStatus struct { // Queried from cloud provider, if available. - HostIP string `json:"hostIP,omitempty" yaml:"hostIP,omitempty"` + HostIP string `json:"hostIP,omitempty"` } type ResourceName string @@ -682,57 +682,57 @@ type ResourceList map[ResourceName]util.IntOrString // Node is a worker node in Kubernetes. // The name of the node according to etcd is in ID. type Node struct { - TypeMeta `json:",inline" yaml:",inline"` - ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"` + TypeMeta `json:",inline"` + ObjectMeta `json:"metadata,omitempty"` // Spec defines the behavior of a node. - Spec NodeSpec `json:"spec,omitempty" yaml:"spec,omitempty"` + Spec NodeSpec `json:"spec,omitempty"` // Status describes the current status of a Node - Status NodeStatus `json:"status,omitempty" yaml:"status,omitempty"` + Status NodeStatus `json:"status,omitempty"` } // NodeList is a list of minions. type NodeList struct { - TypeMeta `json:",inline" yaml:",inline"` - ListMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"` + TypeMeta `json:",inline"` + ListMeta `json:"metadata,omitempty"` - Items []Node `json:"items" yaml:"items"` + Items []Node `json:"items"` } // Binding is written by a scheduler to cause a pod to be bound to a node. Name is not // required for Bindings. type Binding struct { - TypeMeta `json:",inline" yaml:",inline"` - ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"` + TypeMeta `json:",inline"` + ObjectMeta `json:"metadata,omitempty"` // PodID is a Pod name to be bound to a node. - PodID string `json:"podID" yaml:"podID"` + PodID string `json:"podID"` // Host is the name of a node to bind to. - Host string `json:"host" yaml:"host"` + Host string `json:"host"` } // Status is a return value for calls that don't return other objects. type Status struct { - TypeMeta `json:",inline" yaml:",inline"` - ListMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"` + TypeMeta `json:",inline"` + ListMeta `json:"metadata,omitempty"` // One of: "Success", "Failure", "Working" (for operations not yet completed) - Status string `json:"status,omitempty" yaml:"status,omitempty"` + Status string `json:"status,omitempty"` // A human-readable description of the status of this operation. - Message string `json:"message,omitempty" yaml:"message,omitempty"` + Message string `json:"message,omitempty"` // A machine-readable description of why this operation is in the // "Failure" or "Working" status. If this value is empty there // is no information available. A Reason clarifies an HTTP status // code but does not override it. - Reason StatusReason `json:"reason,omitempty" yaml:"reason,omitempty"` + Reason StatusReason `json:"reason,omitempty"` // Extended data associated with the reason. Each reason may define its // own extended details. This field is optional and the data returned // is not guaranteed to conform to any schema except that defined by // the reason type. - Details *StatusDetails `json:"details,omitempty" yaml:"details,omitempty"` + Details *StatusDetails `json:"details,omitempty"` // Suggested HTTP return code for this status, 0 if not set. - Code int `json:"code,omitempty" yaml:"code,omitempty"` + Code int `json:"code,omitempty"` } // StatusDetails is a set of additional properties that MAY be set by the @@ -744,13 +744,13 @@ type Status struct { type StatusDetails struct { // The ID attribute of the resource associated with the status StatusReason // (when there is a single ID which can be described). - ID string `json:"id,omitempty" yaml:"id,omitempty"` + ID string `json:"id,omitempty"` // The kind attribute of the resource associated with the status StatusReason. // On some operations may differ from the requested resource Kind. - Kind string `json:"kind,omitempty" yaml:"kind,omitempty"` + Kind string `json:"kind,omitempty"` // The Causes array includes more details associated with the StatusReason // failure. Not all StatusReasons may provide detailed causes. - Causes []StatusCause `json:"causes,omitempty" yaml:"causes,omitempty"` + Causes []StatusCause `json:"causes,omitempty"` } // Values of Status.Status @@ -827,10 +827,10 @@ const ( type StatusCause struct { // A machine-readable description of the cause of the error. If this value is // empty there is no information available. - Type CauseType `json:"reason,omitempty" yaml:"reason,omitempty"` + Type CauseType `json:"reason,omitempty"` // A human-readable description of the cause of the error. This field may be // presented as-is to a reader. - Message string `json:"message,omitempty" yaml:"message,omitempty"` + Message string `json:"message,omitempty"` // The field of the resource that has caused this error, as named by its JSON // serialization. May include dot and postfix notation for nested attributes. // Arrays are zero-indexed. Fields may appear more than once in an array of @@ -840,7 +840,7 @@ type StatusCause struct { // Examples: // "name" - the field "name" on the current resource // "items[0].name" - the field "name" on the first array entry in "items" - Field string `json:"field,omitempty" yaml:"field,omitempty"` + Field string `json:"field,omitempty"` } // CauseType is a machine readable value providing more detail about what @@ -870,26 +870,26 @@ const ( // Operation is assigned by the server when an operation is started, and can be used by // clients to retrieve the final result of the operation at a later time. type Operation struct { - TypeMeta `json:",inline" yaml:",inline"` - ObjectMeta `json:"metadata" yaml:"metadata"` + TypeMeta `json:",inline"` + ObjectMeta `json:"metadata"` } // OperationList is a list of operations, as delivered to API clients. type OperationList struct { - TypeMeta `json:",inline" yaml:",inline"` - ListMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"` + TypeMeta `json:",inline"` + ListMeta `json:"metadata,omitempty"` - Items []Operation `json:"items" yaml:"items"` + Items []Operation `json:"items"` } // ObjectReference contains enough information to let you inspect or modify the referred object. type ObjectReference struct { - Kind string `json:"kind,omitempty" yaml:"kind,omitempty"` - Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"` - Name string `json:"name,omitempty" yaml:"name,omitempty"` - UID string `json:"uid,omitempty" yaml:"uid,omitempty"` - APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty"` - ResourceVersion string `json:"resourceVersion,omitempty" yaml:"resourceVersion,omitempty"` + Kind string `json:"kind,omitempty"` + Namespace string `json:"namespace,omitempty"` + Name string `json:"name,omitempty"` + UID string `json:"uid,omitempty"` + APIVersion string `json:"apiVersion,omitempty"` + ResourceVersion string `json:"resourceVersion,omitempty"` // Optional. If referring to a piece of an object instead of an entire object, this string // should contain a valid field access statement. For example, @@ -898,17 +898,17 @@ type ObjectReference struct { // both go and JavaScript. This is syntax is chosen only to have some well-defined way of // referencing a part of an object. // TODO: this design is not final and this field is subject to change in the future. - FieldPath string `json:"fieldPath,omitempty" yaml:"fieldPath,omitempty"` + FieldPath string `json:"fieldPath,omitempty"` } // Event is a report of an event somewhere in the cluster. // TODO: Decide whether to store these separately or with the object they apply to. type Event struct { - TypeMeta `json:",inline" yaml:",inline"` - ObjectMeta `json:"metadata" yaml:"metadata"` + TypeMeta `json:",inline"` + ObjectMeta `json:"metadata"` // Required. The object that this event is about. - InvolvedObject ObjectReference `json:"involvedObject,omitempty" yaml:"involvedObject,omitempty"` + InvolvedObject ObjectReference `json:"involvedObject,omitempty"` // Should be a short, machine understandable string that describes the current status // of the referred object. This should not give the reason for being in this state. @@ -917,30 +917,30 @@ type Event struct { // always be used for the same status. // TODO: define a way of making sure these are consistent and don't collide. // TODO: provide exact specification for format. - Condition string `json:"condition,omitempty" yaml:"condition,omitempty"` + Condition string `json:"condition,omitempty"` // Optional; this should be a short, machine understandable string that gives the reason // for the transition into the object's current status. For example, if ObjectStatus is // "cantStart", StatusReason might be "imageNotFound". // TODO: provide exact specification for format. - Reason string `json:"reason,omitempty" yaml:"reason,omitempty"` + Reason string `json:"reason,omitempty"` // Optional. A human-readable description of the status of this operation. // TODO: decide on maximum length. - Message string `json:"message,omitempty" yaml:"message,omitempty"` + Message string `json:"message,omitempty"` // Optional. The component reporting this event. Should be a short machine understandable string. // TODO: provide exact specification for format. - Source string `json:"source,omitempty" yaml:"source,omitempty"` + Source string `json:"source,omitempty"` // The time at which the client recorded the event. (Time of server receipt is in TypeMeta.) - Timestamp util.Time `json:"timestamp,omitempty" yaml:"timestamp,omitempty"` + Timestamp util.Time `json:"timestamp,omitempty"` } // EventList is a list of events. type EventList struct { - TypeMeta `json:",inline" yaml:",inline"` - ListMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"` + TypeMeta `json:",inline"` + ListMeta `json:"metadata,omitempty"` - Items []Event `json:"items" yaml:"items"` + Items []Event `json:"items"` } diff --git a/pkg/apiserver/apiserver_test.go b/pkg/apiserver/apiserver_test.go index 709bddf06f1..fc17d7c54d9 100644 --- a/pkg/apiserver/apiserver_test.go +++ b/pkg/apiserver/apiserver_test.go @@ -95,17 +95,17 @@ func init() { } type Simple struct { - api.TypeMeta `yaml:",inline" json:",inline"` - api.ObjectMeta `yaml:"metadata" json:"metadata"` - Other string `yaml:"other,omitempty" json:"other,omitempty"` + api.TypeMeta `json:",inline"` + api.ObjectMeta `json:"metadata"` + Other string `json:"other,omitempty"` } func (*Simple) IsAnAPIObject() {} type SimpleList struct { - api.TypeMeta `yaml:",inline" json:",inline"` - api.ListMeta `yaml:"metadata,inline" json:"metadata,inline"` - Items []Simple `yaml:"items,omitempty" json:"items,omitempty"` + api.TypeMeta `json:",inline"` + api.ListMeta `json:"metadata,inline"` + Items []Simple `json:"items,omitempty"` } func (*SimpleList) IsAnAPIObject() {} diff --git a/pkg/apiserver/watch_test.go b/pkg/apiserver/watch_test.go index 6b83efa3201..ce31b9b8150 100644 --- a/pkg/apiserver/watch_test.go +++ b/pkg/apiserver/watch_test.go @@ -32,8 +32,8 @@ import ( // watchJSON defines the expected JSON wire equivalent of watch.Event type watchJSON struct { - Type watch.EventType `json:"type,omitempty" yaml:"type,omitempty"` - Object json.RawMessage `json:"object,omitempty" yaml:"object,omitempty"` + Type watch.EventType `json:"type,omitempty"` + Object json.RawMessage `json:"object,omitempty"` } var watchTestTable = []struct { diff --git a/pkg/auth/authorizer/abac/abac.go b/pkg/auth/authorizer/abac/abac.go index f7fbd7ec106..03b704c2eec 100644 --- a/pkg/auth/authorizer/abac/abac.go +++ b/pkg/auth/authorizer/abac/abac.go @@ -37,7 +37,7 @@ import ( // body.Namespace, if we want to add that feature, without affecting the // meta.Namespace. type policy struct { - User string `json:"user,omitempty" yaml:"user,omitempty"` + User string `json:"user,omitempty"` // TODO: add support for groups as well as users. // TODO: add support for robot accounts as well as human user accounts. // TODO: decide how to namespace user names when multiple authentication @@ -51,9 +51,9 @@ type policy struct { // the API, we don't have to add lots of policy? // TODO: make this a proper REST object with its own registry. - Readonly bool `json:"readonly,omitempty" yaml:"readonly,omitempty"` - Kind string `json:"kind,omitempty" yaml:"kind,omitempty"` - Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"` + Readonly bool `json:"readonly,omitempty"` + Kind string `json:"kind,omitempty"` + Namespace string `json:"namespace,omitempty"` // TODO: "expires" string in RFC3339 format. diff --git a/pkg/conversion/decode.go b/pkg/conversion/decode.go index bf5dc16c5b9..81be6bb5bef 100644 --- a/pkg/conversion/decode.go +++ b/pkg/conversion/decode.go @@ -20,7 +20,7 @@ import ( "errors" "fmt" - "gopkg.in/v1/yaml" + "github.com/ghodss/yaml" ) // Decode converts a YAML or JSON string back into a pointer to an api object. diff --git a/pkg/conversion/meta.go b/pkg/conversion/meta.go index 0fe9cdd6484..18c0d966e93 100644 --- a/pkg/conversion/meta.go +++ b/pkg/conversion/meta.go @@ -20,7 +20,7 @@ import ( "fmt" "reflect" - "gopkg.in/v1/yaml" + "github.com/ghodss/yaml" ) // MetaFactory is used to store and retrieve the version and kind @@ -55,8 +55,8 @@ type SimpleMetaFactory struct { // encoding of an object, or an error. func (SimpleMetaFactory) Interpret(data []byte) (version, kind string, err error) { findKind := struct { - APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty"` - Kind string `json:"kind,omitempty" yaml:"kind,omitempty"` + APIVersion string `json:"apiVersion,omitempty"` + Kind string `json:"kind,omitempty"` }{} // yaml is a superset of json, so we use it to decode here. That way, // we understand both. diff --git a/pkg/conversion/meta_test.go b/pkg/conversion/meta_test.go index f7ede632123..12b502c21fa 100644 --- a/pkg/conversion/meta_test.go +++ b/pkg/conversion/meta_test.go @@ -94,14 +94,14 @@ func TestSimpleMetaFactoryUpdateStruct(t *testing.T) { func TestMetaValues(t *testing.T) { type InternalSimple struct { - APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty"` - Kind string `json:"kind,omitempty" yaml:"kind,omitempty"` - TestString string `json:"testString" yaml:"testString"` + APIVersion string `json:"apiVersion,omitempty"` + Kind string `json:"kind,omitempty"` + TestString string `json:"testString"` } type ExternalSimple struct { - APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty"` - Kind string `json:"kind,omitempty" yaml:"kind,omitempty"` - TestString string `json:"testString" yaml:"testString"` + APIVersion string `json:"apiVersion,omitempty"` + Kind string `json:"kind,omitempty"` + TestString string `json:"testString"` } s := NewScheme() s.AddKnownTypeWithName("", "Simple", &InternalSimple{}) @@ -194,14 +194,14 @@ func TestMetaValues(t *testing.T) { func TestMetaValuesUnregisteredConvert(t *testing.T) { type InternalSimple struct { - Version string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty"` - Kind string `json:"kind,omitempty" yaml:"kind,omitempty"` - TestString string `json:"testString" yaml:"testString"` + Version string `json:"apiVersion,omitempty"` + Kind string `json:"kind,omitempty"` + TestString string `json:"testString"` } type ExternalSimple struct { - Version string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty"` - Kind string `json:"kind,omitempty" yaml:"kind,omitempty"` - TestString string `json:"testString" yaml:"testString"` + Version string `json:"apiVersion,omitempty"` + Kind string `json:"kind,omitempty"` + TestString string `json:"testString"` } s := NewScheme() s.InternalVersion = "" diff --git a/pkg/conversion/scheme_test.go b/pkg/conversion/scheme_test.go index 0c0ef43b728..146afd0587f 100644 --- a/pkg/conversion/scheme_test.go +++ b/pkg/conversion/scheme_test.go @@ -26,73 +26,73 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/util" + "github.com/ghodss/yaml" "github.com/google/gofuzz" - "gopkg.in/v1/yaml" ) var fuzzIters = flag.Int("fuzz_iters", 50, "How many fuzzing iterations to do.") // Test a weird version/kind embedding format. type MyWeirdCustomEmbeddedVersionKindField struct { - ID string `yaml:"ID,omitempty" json:"ID,omitempty"` - APIVersion string `json:"myVersionKey,omitempty" yaml:"myVersionKey,omitempty"` - ObjectKind string `json:"myKindKey,omitempty" yaml:"myKindKey,omitempty"` - Z string `yaml:"Z,omitempty" json:"Z,omitempty"` - Y uint64 `yaml:"Y,omitempty" json:"Y,omitempty"` + ID string `json:"ID,omitempty"` + APIVersion string `json:"myVersionKey,omitempty"` + ObjectKind string `json:"myKindKey,omitempty"` + Z string `json:"Z,omitempty"` + Y uint64 `json:"Y,omitempty"` } type TestType1 struct { - MyWeirdCustomEmbeddedVersionKindField `json:",inline" yaml:",inline"` - A string `yaml:"A,omitempty" json:"A,omitempty"` - B int `yaml:"B,omitempty" json:"B,omitempty"` - C int8 `yaml:"C,omitempty" json:"C,omitempty"` - D int16 `yaml:"D,omitempty" json:"D,omitempty"` - E int32 `yaml:"E,omitempty" json:"E,omitempty"` - F int64 `yaml:"F,omitempty" json:"F,omitempty"` - G uint `yaml:"G,omitempty" json:"G,omitempty"` - H uint8 `yaml:"H,omitempty" json:"H,omitempty"` - I uint16 `yaml:"I,omitempty" json:"I,omitempty"` - J uint32 `yaml:"J,omitempty" json:"J,omitempty"` - K uint64 `yaml:"K,omitempty" json:"K,omitempty"` - L bool `yaml:"L,omitempty" json:"L,omitempty"` - M map[string]int `yaml:"M,omitempty" json:"M,omitempty"` - N map[string]TestType2 `yaml:"N,omitempty" json:"N,omitempty"` - O *TestType2 `yaml:"O,omitempty" json:"O,omitempty"` - P []TestType2 `yaml:"Q,omitempty" json:"Q,omitempty"` + MyWeirdCustomEmbeddedVersionKindField `json:",inline"` + A string `json:"A,omitempty"` + B int `json:"B,omitempty"` + C int8 `json:"C,omitempty"` + D int16 `json:"D,omitempty"` + E int32 `json:"E,omitempty"` + F int64 `json:"F,omitempty"` + G uint `json:"G,omitempty"` + H uint8 `json:"H,omitempty"` + I uint16 `json:"I,omitempty"` + J uint32 `json:"J,omitempty"` + K uint64 `json:"K,omitempty"` + L bool `json:"L,omitempty"` + M map[string]int `json:"M,omitempty"` + N map[string]TestType2 `json:"N,omitempty"` + O *TestType2 `json:"O,omitempty"` + P []TestType2 `json:"Q,omitempty"` } type TestType2 struct { - A string `yaml:"A,omitempty" json:"A,omitempty"` - B int `yaml:"B,omitempty" json:"B,omitempty"` + A string `json:"A,omitempty"` + B int `json:"B,omitempty"` } type ExternalTestType2 struct { - A string `yaml:"A,omitempty" json:"A,omitempty"` - B int `yaml:"B,omitempty" json:"B,omitempty"` + A string `json:"A,omitempty"` + B int `json:"B,omitempty"` } type ExternalTestType1 struct { - MyWeirdCustomEmbeddedVersionKindField `json:",inline" yaml:",inline"` - A string `yaml:"A,omitempty" json:"A,omitempty"` - B int `yaml:"B,omitempty" json:"B,omitempty"` - C int8 `yaml:"C,omitempty" json:"C,omitempty"` - D int16 `yaml:"D,omitempty" json:"D,omitempty"` - E int32 `yaml:"E,omitempty" json:"E,omitempty"` - F int64 `yaml:"F,omitempty" json:"F,omitempty"` - G uint `yaml:"G,omitempty" json:"G,omitempty"` - H uint8 `yaml:"H,omitempty" json:"H,omitempty"` - I uint16 `yaml:"I,omitempty" json:"I,omitempty"` - J uint32 `yaml:"J,omitempty" json:"J,omitempty"` - K uint64 `yaml:"K,omitempty" json:"K,omitempty"` - L bool `yaml:"L,omitempty" json:"L,omitempty"` - M map[string]int `yaml:"M,omitempty" json:"M,omitempty"` - N map[string]ExternalTestType2 `yaml:"N,omitempty" json:"N,omitempty"` - O *ExternalTestType2 `yaml:"O,omitempty" json:"O,omitempty"` - P []ExternalTestType2 `yaml:"Q,omitempty" json:"Q,omitempty"` + MyWeirdCustomEmbeddedVersionKindField `json:",inline"` + A string `json:"A,omitempty"` + B int `json:"B,omitempty"` + C int8 `json:"C,omitempty"` + D int16 `json:"D,omitempty"` + E int32 `json:"E,omitempty"` + F int64 `json:"F,omitempty"` + G uint `json:"G,omitempty"` + H uint8 `json:"H,omitempty"` + I uint16 `json:"I,omitempty"` + J uint32 `json:"J,omitempty"` + K uint64 `json:"K,omitempty"` + L bool `json:"L,omitempty"` + M map[string]int `json:"M,omitempty"` + N map[string]ExternalTestType2 `json:"N,omitempty"` + O *ExternalTestType2 `json:"O,omitempty"` + P []ExternalTestType2 `json:"Q,omitempty"` } type ExternalInternalSame struct { - MyWeirdCustomEmbeddedVersionKindField `json:",inline" yaml:",inline"` - A TestType2 `yaml:"A,omitempty" json:"A,omitempty"` + MyWeirdCustomEmbeddedVersionKindField `json:",inline"` + A TestType2 `json:"A,omitempty"` } // TestObjectFuzzer can randomly populate all the above objects. @@ -139,8 +139,8 @@ type testMetaFactory struct{} func (testMetaFactory) Interpret(data []byte) (version, kind string, err error) { findKind := struct { - APIVersion string `json:"myVersionKey,omitempty" yaml:"myVersionKey,omitempty"` - ObjectKind string `json:"myKindKey,omitempty" yaml:"myKindKey,omitempty"` + APIVersion string `json:"myVersionKey,omitempty"` + ObjectKind string `json:"myKindKey,omitempty"` }{} // yaml is a superset of json, so we use it to decode here. That way, // we understand both. diff --git a/pkg/kubecfg/kubecfg.go b/pkg/kubecfg/kubecfg.go index dd120b58bc2..2e9b73b3453 100644 --- a/pkg/kubecfg/kubecfg.go +++ b/pkg/kubecfg/kubecfg.go @@ -33,8 +33,8 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/util" "github.com/GoogleCloudPlatform/kubernetes/pkg/util/wait" "github.com/GoogleCloudPlatform/kubernetes/pkg/version" + "github.com/ghodss/yaml" "github.com/golang/glog" - "gopkg.in/v1/yaml" ) func GetServerVersion(client *client.Client) (*version.Info, error) { diff --git a/pkg/kubecfg/parse_test.go b/pkg/kubecfg/parse_test.go index d9a53fb9818..4100fbfc6e3 100644 --- a/pkg/kubecfg/parse_test.go +++ b/pkg/kubecfg/parse_test.go @@ -24,7 +24,7 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" - "gopkg.in/v1/yaml" + "github.com/ghodss/yaml" ) func TestParseBadStorage(t *testing.T) { @@ -121,9 +121,9 @@ func TestParseController(t *testing.T) { } type TestParseType struct { - api.TypeMeta `json:",inline" yaml:",inline"` - api.ObjectMeta `json:"metadata" yaml:"metadata"` - Data string `json:"data" yaml:"data"` + api.TypeMeta `json:",inline"` + api.ObjectMeta `json:"metadata"` + Data string `json:"data"` } func (*TestParseType) IsAnAPIObject() {} diff --git a/pkg/kubecfg/resource_printer.go b/pkg/kubecfg/resource_printer.go index 263525b377a..1bef4e1cab2 100644 --- a/pkg/kubecfg/resource_printer.go +++ b/pkg/kubecfg/resource_printer.go @@ -29,8 +29,8 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" + "github.com/ghodss/yaml" "github.com/golang/glog" - "gopkg.in/v1/yaml" ) // ResourcePrinter is an interface that knows how to print API resources. diff --git a/pkg/kubecfg/resource_printer_test.go b/pkg/kubecfg/resource_printer_test.go index ef16bdc0884..ef5abd96048 100644 --- a/pkg/kubecfg/resource_printer_test.go +++ b/pkg/kubecfg/resource_printer_test.go @@ -26,15 +26,15 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest" - "gopkg.in/v1/yaml" + "github.com/ghodss/yaml" ) func TestYAMLPrinterPrint(t *testing.T) { type testStruct struct { - Key string `yaml:"Key" json:"Key"` - Map map[string]int `yaml:"Map" json:"Map"` - StringList []string `yaml:"StringList" json:"StringList"` - IntList []int `yaml:"IntList" json:"IntList"` + Key string `json:"Key"` + Map map[string]int `json:"Map"` + StringList []string `json:"StringList"` + IntList []int `json:"IntList"` } testData := testStruct{ "testValue", diff --git a/pkg/kubectl/cmd/createall.go b/pkg/kubectl/cmd/createall.go index b8e912db1d6..4f7aa26b7b1 100644 --- a/pkg/kubectl/cmd/createall.go +++ b/pkg/kubectl/cmd/createall.go @@ -24,9 +24,9 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/config" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" + "github.com/ghodss/yaml" "github.com/golang/glog" "github.com/spf13/cobra" - "gopkg.in/v1/yaml" ) // DataToObjects converts the raw JSON data into API objects diff --git a/pkg/kubectl/resource_printer.go b/pkg/kubectl/resource_printer.go index b3b4955b732..384d6c84c1c 100644 --- a/pkg/kubectl/resource_printer.go +++ b/pkg/kubectl/resource_printer.go @@ -29,8 +29,8 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" + "github.com/ghodss/yaml" "github.com/golang/glog" - "gopkg.in/v1/yaml" ) // GetPrinter takes a format type, an optional format argument, a version and a convertor diff --git a/pkg/kubectl/resource_printer_test.go b/pkg/kubectl/resource_printer_test.go index 676d9d7a0d3..7285567694f 100644 --- a/pkg/kubectl/resource_printer_test.go +++ b/pkg/kubectl/resource_printer_test.go @@ -29,16 +29,16 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" - "gopkg.in/v1/yaml" + "github.com/ghodss/yaml" ) type testStruct struct { - api.TypeMeta `yaml:",inline" json:",inline"` - api.ObjectMeta `yaml:"metadata,omitempty" json:"metadata,omitempty"` - Key string `yaml:"Key" json:"Key"` - Map map[string]int `yaml:"Map" json:"Map"` - StringList []string `yaml:"StringList" json:"StringList"` - IntList []int `yaml:"IntList" json:"IntList"` + api.TypeMeta `json:",inline"` + api.ObjectMeta `json:"metadata,omitempty"` + Key string `json:"Key"` + Map map[string]int `json:"Map"` + StringList []string `json:"StringList"` + IntList []int `json:"IntList"` } func (ts *testStruct) IsAnAPIObject() {} diff --git a/pkg/kubelet/config/config.go b/pkg/kubelet/config/config.go index d2868c71af2..01e29c7afda 100644 --- a/pkg/kubelet/config/config.go +++ b/pkg/kubelet/config/config.go @@ -287,7 +287,7 @@ func (s *podStorage) Sync() { func (s *podStorage) MergedState() interface{} { s.podLock.RLock() defer s.podLock.RUnlock() - var pods []api.BoundPod + pods := make([]api.BoundPod, 0) for _, sourcePods := range s.pods { for _, podRef := range sourcePods { pod, err := api.Scheme.Copy(podRef) diff --git a/pkg/kubelet/config/config_test.go b/pkg/kubelet/config/config_test.go index 5c291aa31ff..30921d814fe 100644 --- a/pkg/kubelet/config/config_test.go +++ b/pkg/kubelet/config/config_test.go @@ -59,10 +59,13 @@ func CreateValidPod(name, namespace, source string) api.BoundPod { } func CreatePodUpdate(op kubelet.PodOperation, pods ...api.BoundPod) kubelet.PodUpdate { - if len(pods) == 0 { - return kubelet.PodUpdate{Op: op} - } + // We deliberately return an empty slice instead of a nil pointer here + // because reflect.DeepEqual differentiates between the two and we need to + // pick one for consistency. newPods := make([]api.BoundPod, len(pods)) + if len(pods) == 0 { + return kubelet.PodUpdate{newPods, op} + } for i := range pods { newPods[i] = pods[i] } diff --git a/pkg/kubelet/config/file.go b/pkg/kubelet/config/file.go index 7728716b898..6f45ea5d945 100644 --- a/pkg/kubelet/config/file.go +++ b/pkg/kubelet/config/file.go @@ -33,8 +33,8 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" + "github.com/ghodss/yaml" "github.com/golang/glog" - "gopkg.in/v1/yaml" ) type sourceFile struct { @@ -97,12 +97,13 @@ func extractFromDir(name string) ([]api.BoundPod, error) { if err != nil { return nil, fmt.Errorf("glob failed: %v", err) } + + pods := make([]api.BoundPod, 0) if len(dirents) == 0 { - return nil, nil + return pods, nil } sort.Strings(dirents) - pods := []api.BoundPod{} for _, path := range dirents { statInfo, err := os.Stat(path) if err != nil { diff --git a/pkg/kubelet/config/file_test.go b/pkg/kubelet/config/file_test.go index 91e6ab9c380..7e47e7d350e 100644 --- a/pkg/kubelet/config/file_test.go +++ b/pkg/kubelet/config/file_test.go @@ -29,7 +29,7 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api/validation" "github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet" - "gopkg.in/v1/yaml" + "github.com/ghodss/yaml" ) func ExampleManifestAndPod(id string) (api.ContainerManifest, api.BoundPod) { diff --git a/pkg/kubelet/config/http.go b/pkg/kubelet/config/http.go index 39dc9a46c2e..b9694f3cfbc 100644 --- a/pkg/kubelet/config/http.go +++ b/pkg/kubelet/config/http.go @@ -29,8 +29,8 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" + "github.com/ghodss/yaml" "github.com/golang/glog" - "gopkg.in/v1/yaml" ) type sourceURL struct { diff --git a/pkg/kubelet/server.go b/pkg/kubelet/server.go index b77f6ca2526..a32e3cf2522 100644 --- a/pkg/kubelet/server.go +++ b/pkg/kubelet/server.go @@ -35,9 +35,9 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/healthz" "github.com/GoogleCloudPlatform/kubernetes/pkg/httplog" "github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/dockertools" + "github.com/ghodss/yaml" "github.com/golang/glog" "github.com/google/cadvisor/info" - "gopkg.in/v1/yaml" ) // Server is a http.Handler which exposes kubelet functionality over HTTP. diff --git a/pkg/kubelet/types.go b/pkg/kubelet/types.go index 818104a9a12..bb2d87f7d19 100644 --- a/pkg/kubelet/types.go +++ b/pkg/kubelet/types.go @@ -43,6 +43,10 @@ const ( // For setting the state of the system to a given state for this source configuration, set // Pods as desired and Op to SET, which will reset the system state to that specified in this // operation for this source channel. To remove all pods, set Pods to empty object and Op to SET. +// +// Additionally, Pods should never be nil - it should always point to an empty slice. While +// functionally similar, this helps our unit tests properly check that the correct PodUpdates +// are generated. type PodUpdate struct { Pods []api.BoundPod Op PodOperation diff --git a/pkg/runtime/embedded.go b/pkg/runtime/embedded.go deleted file mode 100644 index 11ac2894651..00000000000 --- a/pkg/runtime/embedded.go +++ /dev/null @@ -1,86 +0,0 @@ -/* -Copyright 2014 Google Inc. All rights reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package runtime - -import ( - "gopkg.in/v1/yaml" -) - -// Encode()/Decode() are the canonical way of converting an API object to/from -// wire format. This file provides utility functions which permit doing so -// recursively, such that API objects of types known only at run time can be -// embedded within other API types. - -// UnmarshalJSON implements the json.Unmarshaler interface. -func CodecUnmarshalJSON(codec Codec, b []byte) (Object, error) { - // Handle JSON's "null": Decode() doesn't expect it. - if len(b) == 4 && string(b) == "null" { - return nil, nil - } - - obj, err := codec.Decode(b) - if err != nil { - return nil, err - } - return obj, nil -} - -// MarshalJSON implements the json.Marshaler interface. -func CodecMarshalJSON(codec Codec, obj Object) ([]byte, error) { - if obj == nil { - // Encode unset/nil objects as JSON's "null". - return []byte("null"), nil - } - - return codec.Encode(obj) -} - -// SetYAML implements the yaml.Setter interface. -func CodecSetYAML(codec Codec, tag string, value interface{}) (Object, bool) { - if value == nil { - return nil, true - } - // Why does the yaml package send value as a map[interface{}]interface{}? - // It's especially frustrating because encoding/json does the right thing - // by giving a []byte. So here we do the embarrasing thing of re-encode and - // de-encode the right way. - // TODO: Write a version of Decode that uses reflect to turn this value - // into an API object. - b, err := yaml.Marshal(value) - if err != nil { - panic("yaml can't reverse its own object") - } - obj, err := codec.Decode(b) - if err != nil { - return nil, false - } - return obj, true -} - -// GetYAML implements the yaml.Getter interface. -func CodecGetYAML(codec Codec, obj Object) (tag string, value interface{}) { - if obj == nil { - value = "null" - return - } - // Encode returns JSON, which is conveniently a subset of YAML. - v, err := codec.Encode(obj) - if err != nil { - panic("impossible to encode API object!") - } - return tag, v -} diff --git a/pkg/runtime/embedded_test.go b/pkg/runtime/embedded_test.go index c7b7c721d91..9fb795c95bb 100644 --- a/pkg/runtime/embedded_test.go +++ b/pkg/runtime/embedded_test.go @@ -28,17 +28,17 @@ var scheme = runtime.NewScheme() var Codec = runtime.CodecFor(scheme, "v1test") type EmbeddedTest struct { - runtime.TypeMeta `yaml:",inline" json:",inline"` - ID string `yaml:"id,omitempty" json:"id,omitempty"` - Object runtime.EmbeddedObject `yaml:"object,omitempty" json:"object,omitempty"` - EmptyObject runtime.EmbeddedObject `yaml:"emptyObject,omitempty" json:"emptyObject,omitempty"` + runtime.TypeMeta `json:",inline"` + ID string `json:"id,omitempty"` + Object runtime.EmbeddedObject `json:"object,omitempty"` + EmptyObject runtime.EmbeddedObject `json:"emptyObject,omitempty"` } type EmbeddedTestExternal struct { - runtime.TypeMeta `yaml:",inline" json:",inline"` - ID string `yaml:"id,omitempty" json:"id,omitempty"` - Object runtime.RawExtension `yaml:"object,omitempty" json:"object,omitempty"` - EmptyObject runtime.RawExtension `yaml:"emptyObject,omitempty" json:"emptyObject,omitempty"` + runtime.TypeMeta `json:",inline"` + ID string `json:"id,omitempty"` + Object runtime.RawExtension `json:"object,omitempty"` + EmptyObject runtime.RawExtension `json:"emptyObject,omitempty"` } func (*EmbeddedTest) IsAnAPIObject() {} diff --git a/pkg/runtime/extension.go b/pkg/runtime/extension.go index eebc9dcfa94..8f94f2b578f 100644 --- a/pkg/runtime/extension.go +++ b/pkg/runtime/extension.go @@ -16,11 +16,7 @@ limitations under the License. package runtime -import ( - "errors" - - "gopkg.in/v1/yaml" -) +import "errors" func (re *RawExtension) UnmarshalJSON(in []byte) error { if re == nil { @@ -33,28 +29,3 @@ func (re *RawExtension) UnmarshalJSON(in []byte) error { func (re *RawExtension) MarshalJSON() ([]byte, error) { return re.RawJSON, nil } - -// SetYAML implements the yaml.Setter interface. -func (re *RawExtension) SetYAML(tag string, value interface{}) bool { - if value == nil { - re.RawJSON = []byte("null") - return true - } - // Why does the yaml package send value as a map[interface{}]interface{}? - // It's especially frustrating because encoding/json does the right thing - // by giving a []byte. So here we do the embarrasing thing of re-encode and - // de-encode the right way. - // TODO: Write a version of Decode that uses reflect to turn this value - // into an API object. - b, err := yaml.Marshal(value) - if err != nil { - panic("yaml can't reverse its own object") - } - re.RawJSON = b - return true -} - -// GetYAML implements the yaml.Getter interface. -func (re *RawExtension) GetYAML() (tag string, value interface{}) { - return tag, re.RawJSON -} diff --git a/pkg/runtime/scheme.go b/pkg/runtime/scheme.go index 2f05401fb78..3984eabd2d5 100644 --- a/pkg/runtime/scheme.go +++ b/pkg/runtime/scheme.go @@ -40,7 +40,7 @@ func (self *Scheme) fromScope(s conversion.Scope) (inVersion, outVersion string, // emptyPlugin is used to copy the Kind field to and from plugin objects. type emptyPlugin struct { - PluginBase `json:",inline" yaml:",inline"` + PluginBase `json:",inline"` } // embeddedObjectToRawExtension does the conversion you would expect from the name, using the information diff --git a/pkg/runtime/scheme_test.go b/pkg/runtime/scheme_test.go index 36aac48e3cc..d68c99d0aba 100644 --- a/pkg/runtime/scheme_test.go +++ b/pkg/runtime/scheme_test.go @@ -25,18 +25,18 @@ import ( ) type TypeMeta struct { - Kind string `json:"kind,omitempty" yaml:"kind,omitempty"` - APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty"` + Kind string `json:"kind,omitempty"` + APIVersion string `json:"apiVersion,omitempty"` } type InternalSimple struct { - TypeMeta `json:",inline" yaml:",inline"` - TestString string `json:"testString" yaml:"testString"` + TypeMeta `json:",inline"` + TestString string `json:"testString"` } type ExternalSimple struct { - TypeMeta `json:",inline" yaml:",inline"` - TestString string `json:"testString" yaml:"testString"` + TypeMeta `json:",inline"` + TestString string `json:"testString"` } func (*InternalSimple) IsAnAPIObject() {} @@ -157,23 +157,23 @@ func TestBadJSONRejection(t *testing.T) { } type ExtensionA struct { - runtime.PluginBase `json:",inline" yaml:",inline"` - TestString string `json:"testString" yaml:"testString"` + runtime.PluginBase `json:",inline"` + TestString string `json:"testString"` } type ExtensionB struct { - runtime.PluginBase `json:",inline" yaml:",inline"` - TestString string `json:"testString" yaml:"testString"` + runtime.PluginBase `json:",inline"` + TestString string `json:"testString"` } type ExternalExtensionType struct { - TypeMeta `json:",inline" yaml:",inline"` - Extension runtime.RawExtension `json:"extension" yaml:"extension"` + TypeMeta `json:",inline"` + Extension runtime.RawExtension `json:"extension"` } type InternalExtensionType struct { - TypeMeta `json:",inline" yaml:",inline"` - Extension runtime.EmbeddedObject `json:"extension" yaml:"extension"` + TypeMeta `json:",inline"` + Extension runtime.EmbeddedObject `json:"extension"` } func (*ExtensionA) IsAnAPIObject() {} diff --git a/pkg/runtime/types.go b/pkg/runtime/types.go index f79ec42f4d2..aa7eec39201 100644 --- a/pkg/runtime/types.go +++ b/pkg/runtime/types.go @@ -26,7 +26,7 @@ import ( // TypeMeta is shared by all top level objects. The proper way to use it is to inline it in your type, // like this: // type MyAwesomeAPIObject struct { -// runtime.TypeMeta `yaml:",inline" json:",inline"` +// runtime.TypeMeta `json:",inline"` // ... // other fields // } // func (*MyAwesomeAPIObject) IsAnAPIObject() {} @@ -35,21 +35,21 @@ import ( // your own with the same fields. // type TypeMeta struct { - APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty"` - Kind string `json:"kind,omitempty" yaml:"kind,omitempty"` + APIVersion string `json:"apiVersion,omitempty"` + Kind string `json:"kind,omitempty"` - Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"` - Name string `json:"name,omitempty" yaml:"name,omitempty"` - UID string `json:"uid,omitempty" yaml:"uid,omitempty"` - CreationTimestamp util.Time `json:"creationTimestamp,omitempty" yaml:"creationTimestamp,omitempty"` - SelfLink string `json:"selfLink,omitempty" yaml:"selfLink,omitempty"` - ResourceVersion string `json:"resourceVersion,omitempty" yaml:"resourceVersion,omitempty"` + Namespace string `json:"namespace,omitempty"` + Name string `json:"name,omitempty"` + UID string `json:"uid,omitempty"` + CreationTimestamp util.Time `json:"creationTimestamp,omitempty"` + SelfLink string `json:"selfLink,omitempty"` + ResourceVersion string `json:"resourceVersion,omitempty"` } // PluginBase is like TypeMeta, but it's intended for plugin objects that won't ever be encoded // except while embedded in other objects. type PluginBase struct { - Kind string `json:"kind,omitempty" yaml:"kind,omitempty"` + Kind string `json:"kind,omitempty"` } // EmbeddedObject has appropriate encoder and decoder functions, such that on the wire, it's @@ -74,22 +74,22 @@ type EmbeddedObject struct { // // // Internal package: // type MyAPIObject struct { -// runtime.TypeMeta `yaml:",inline" json:",inline"` -// MyPlugin runtime.EmbeddedObject `json:"myPlugin" yaml:"myPlugin"` +// runtime.TypeMeta `json:",inline"` +// MyPlugin runtime.EmbeddedObject `json:"myPlugin"` // } // type PluginA struct { -// runtime.PluginBase `yaml:",inline" json:",inline"` -// AOption string `yaml:"aOption" json:"aOption"` +// runtime.PluginBase `json:",inline"` +// AOption string `json:"aOption"` // } // // // External package: // type MyAPIObject struct { -// runtime.TypeMeta `yaml:",inline" json:",inline"` -// MyPlugin runtime.RawExtension `json:"myPlugin" yaml:"myPlugin"` +// runtime.TypeMeta `json:",inline"` +// MyPlugin runtime.RawExtension `json:"myPlugin"` // } // type PluginA struct { -// runtime.PluginBase `yaml:",inline" json:",inline"` -// AOption string `yaml:"aOption" json:"aOption"` +// runtime.PluginBase `json:",inline"` +// AOption string `json:"aOption"` // } // // // On the wire, the JSON will look something like this: @@ -118,7 +118,7 @@ type RawExtension struct { // TypeMeta features-- kind, version, resourceVersion, etc. // TODO: Not implemented yet! type Unknown struct { - TypeMeta `yaml:",inline" json:",inline"` + TypeMeta `json:",inline"` // RawJSON will hold the complete JSON of the object which couldn't be matched // with a registered type. Most likely, nothing should be done with this // except for passing it through the system. diff --git a/pkg/tools/etcd_tools_test.go b/pkg/tools/etcd_tools_test.go index 7bf2950b19d..6a9e7fa0482 100644 --- a/pkg/tools/etcd_tools_test.go +++ b/pkg/tools/etcd_tools_test.go @@ -36,9 +36,9 @@ type fakeClientGetSet struct { } type TestResource struct { - api.TypeMeta `json:",inline" yaml:",inline"` - api.ObjectMeta `json:"metadata" yaml:"metadata"` - Value int `json:"value" yaml:"value,omitempty"` + api.TypeMeta `json:",inline"` + api.ObjectMeta `json:"metadata"` + Value int `json:"value"` } func (*TestResource) IsAnAPIObject() {} diff --git a/pkg/util/diff.go b/pkg/util/diff.go index 343733ded45..0000fa35747 100644 --- a/pkg/util/diff.go +++ b/pkg/util/diff.go @@ -19,6 +19,8 @@ package util import ( "encoding/json" "fmt" + + "github.com/davecgh/go-spew/spew" ) // StringDiff diffs a and b and returns a human readable diff. @@ -56,13 +58,19 @@ func ObjectDiff(a, b interface{}) string { return StringDiff(string(ab), string(bb)) } -// ObjectGoPrintDiff is like ObjectDiff, but uses go's %#v formatter to print the -// objects, in case json isn't showing you the difference. (reflect.DeepEqual makes -// a distinction between nil and empty slices, for example, even though nothing else -// really does.) +// ObjectGoPrintDiff is like ObjectDiff, but uses go-spew to print the objects, +// which shows absolutely everything by recursing into every single pointer +// (go's %#v formatters OTOH stop at a certain point). This is needed when you +// can't figure out why reflect.DeepEqual is returning false and nothing is +// showing you differences. This will. func ObjectGoPrintDiff(a, b interface{}) string { + s := spew.ConfigState{ + Indent: " ", + // Extra deep spew. + DisableMethods: true, + } return StringDiff( - fmt.Sprintf("%#v", a), - fmt.Sprintf("%#v", b), + s.Sdump(a), + s.Sdump(b), ) } diff --git a/pkg/util/time.go b/pkg/util/time.go index 2c4226f1c19..0b9bed866a8 100644 --- a/pkg/util/time.go +++ b/pkg/util/time.go @@ -79,35 +79,3 @@ func (t Time) MarshalJSON() ([]byte, error) { return json.Marshal(t.Format(time.RFC3339)) } - -// SetYAML implements the yaml.Setter interface. -func (t *Time) SetYAML(tag string, value interface{}) bool { - if value == nil { - t.Time = time.Time{} - return true - } - - str, ok := value.(string) - if !ok { - return false - } - - pt, err := time.Parse(time.RFC3339, str) - if err != nil { - return false - } - - t.Time = pt - return true -} - -// GetYAML implements the yaml.Getter interface. -func (t Time) GetYAML() (tag string, value interface{}) { - if t.IsZero() { - value = "null" - return - } - - value = t.Format(time.RFC3339) - return tag, value -} diff --git a/pkg/util/time_test.go b/pkg/util/time_test.go index 3722ada63f2..23a8fd3347f 100644 --- a/pkg/util/time_test.go +++ b/pkg/util/time_test.go @@ -22,11 +22,11 @@ import ( "testing" "time" - "gopkg.in/v1/yaml" + "github.com/ghodss/yaml" ) type TimeHolder struct { - T Time `json:"t" yaml:"t"` + T Time `json:"t"` } func TestTimeMarshalYAML(t *testing.T) { @@ -34,7 +34,7 @@ func TestTimeMarshalYAML(t *testing.T) { input Time result string }{ - {Time{}, "t: \"null\"\n"}, + {Time{}, "t: null\n"}, {Date(1998, time.May, 5, 5, 5, 5, 50, time.UTC), "t: 1998-05-05T05:05:05Z\n"}, {Date(1998, time.May, 5, 5, 5, 5, 0, time.UTC), "t: 1998-05-05T05:05:05Z\n"}, } @@ -56,7 +56,7 @@ func TestTimeUnmarshalYAML(t *testing.T) { input string result Time }{ - {"t: \"null\"\n", Time{}}, + {"t: null\n", Time{}}, {"t: 1998-05-05T05:05:05Z\n", Date(1998, time.May, 5, 5, 5, 5, 0, time.UTC)}, } diff --git a/pkg/util/util.go b/pkg/util/util.go index 7baffc31af7..93424cdffa4 100644 --- a/pkg/util/util.go +++ b/pkg/util/util.go @@ -88,34 +88,6 @@ func NewIntOrStringFromString(val string) IntOrString { return IntOrString{Kind: IntstrString, StrVal: val} } -// SetYAML implements the yaml.Setter interface. -func (intstr *IntOrString) SetYAML(tag string, value interface{}) bool { - switch v := value.(type) { - case int: - intstr.Kind = IntstrInt - intstr.IntVal = v - return true - case string: - intstr.Kind = IntstrString - intstr.StrVal = v - return true - } - return false -} - -// GetYAML implements the yaml.Getter interface. -func (intstr IntOrString) GetYAML() (tag string, value interface{}) { - switch intstr.Kind { - case IntstrInt: - value = intstr.IntVal - case IntstrString: - value = intstr.StrVal - default: - panic("impossible IntOrString.Kind") - } - return -} - // UnmarshalJSON implements the json.Unmarshaller interface. func (intstr *IntOrString) UnmarshalJSON(value []byte) error { if value[0] == '"' { diff --git a/pkg/util/util_test.go b/pkg/util/util_test.go index 2c253c33a27..585d2ad7410 100644 --- a/pkg/util/util_test.go +++ b/pkg/util/util_test.go @@ -21,7 +21,7 @@ import ( "reflect" "testing" - "gopkg.in/v1/yaml" + "github.com/ghodss/yaml" ) func TestHandleCrash(t *testing.T) { @@ -54,7 +54,7 @@ func TestNewIntOrStringFromString(t *testing.T) { } type IntOrStringHolder struct { - IOrS IntOrString `json:"val" yaml:"val"` + IOrS IntOrString `json:"val"` } func TestIntOrStringUnmarshalYAML(t *testing.T) { diff --git a/pkg/version/version.go b/pkg/version/version.go index 1343e4bde26..551b03f329f 100644 --- a/pkg/version/version.go +++ b/pkg/version/version.go @@ -20,11 +20,11 @@ package version // TODO: Add []string of api versions supported? It's still unclear // how we'll want to distribute that information. type Info struct { - Major string `json:"major" yaml:"major"` - Minor string `json:"minor" yaml:"minor"` - GitVersion string `json:"gitVersion" yaml:"gitVersion"` - GitCommit string `json:"gitCommit" yaml:"gitCommit"` - GitTreeState string `json:"gitTreeState" yaml:"gitTreeState"` + Major string `json:"major"` + Minor string `json:"minor"` + GitVersion string `json:"gitVersion"` + GitCommit string `json:"gitCommit"` + GitTreeState string `json:"gitTreeState"` } // Get returns the overall codebase version. It's for detecting diff --git a/pkg/watch/json/types.go b/pkg/watch/json/types.go index 0b0e7812b7b..6688e0fbba2 100644 --- a/pkg/watch/json/types.go +++ b/pkg/watch/json/types.go @@ -29,12 +29,12 @@ import ( // These are not API objects and are unversioned today. type watchEvent struct { // The type of the watch event; added, modified, or deleted. - Type watch.EventType `json:"type,omitempty" yaml:"type,omitempty"` + Type watch.EventType `json:"type,omitempty"` // For added or modified objects, this is the new object; for deleted objects, // it's the state of the object immediately prior to its deletion. // For errors, it's an api.Status. - Object runtime.RawExtension `json:"object,omitempty" yaml:"object,omitempty"` + Object runtime.RawExtension `json:"object,omitempty"` } // Object converts a watch.Event into an appropriately serializable JSON object