Commit 79d755ff authored by Daniel Smith's avatar Daniel Smith

Merge pull request #2676 from ghodss/move-to-ghodss-yaml

Move from go-yaml/yaml v1 to ghodss/yaml
parents 8a726b80 63998542
......@@ -45,6 +45,10 @@
"Rev": "23142f6773a676cc2cae8dd0cb90b2ea761c853f"
},
{
"ImportPath": "github.com/davecgh/go-spew/spew",
"Rev": "83f84dc933714d51504ceed59f43ead21d096fe7"
},
{
"ImportPath": "github.com/elazarl/go-bindata-assetfs",
"Rev": "ae4665cf2d188c65764c73fe4af5378acc549510"
},
......@@ -59,6 +63,10 @@
"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"
}
]
}
/*
* Copyright (c) 2013 Dave Collins <dave@davec.name>
*
* 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)
}
}
}
/*
* Copyright (c) 2013 Dave Collins <dave@davec.name>
*
* 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) <nil>
}),
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 <*><shown>}
%+v: <*>(0xf84003e260){ui8:1 c:<*>(0xf84003e260)<shown>}
%#v: (*main.circular){ui8:(uint8)1 c:(*main.circular)<shown>}
%#+v: (*main.circular)(0xf84003e260){ui8:(uint8)1 c:(*main.circular)(0xf84003e260)<shown>}
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
// Copyright (c) 2013 Dave Collins <dave@davec.name>
//
// 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+")(<nil>)\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")
}
// Copyright (c) 2013 Dave Collins <dave@davec.name>
//
// 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.
}
/*
* Copyright (c) 2013 Dave Collins <dave@davec.name>
*
* 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) <nil>
// },
// 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 <*><shown>}}
}
// 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) <nil>
// },
// 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) <nil>
// },
// 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
}
/*
* Copyright (c) 2013 Dave Collins <dave@davec.name>
*
* 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 := "<invalid>"
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 = "<invalid>"
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<<flagKindWidth - 1) << flagKindShift)
if readOnly {
*rvf |= flagRO
} else {
*rvf &= ^uintptr(flagRO)
}
}
// TestAddedReflectValue tests functionaly of the dump and formatter code which
// falls back to the standard fmt library for new types that might get added to
// the language.
func TestAddedReflectValue(t *testing.T) {
i := 1
// Dump using a reflect.Value that is exported.
v := reflect.ValueOf(int8(5))
changeKind(&v, false)
buf := new(bytes.Buffer)
d := dumpState{w: buf, cs: &Config}
d.dump(v)
s := buf.String()
want := "(int8) 5"
if s != want {
t.Errorf("TestAddedReflectValue #%d\n got: %s want: %s", i, s, want)
}
i++
// Dump using a reflect.Value that is not exported.
changeKind(&v, true)
buf.Reset()
d.dump(v)
s = buf.String()
want = "(int8) <int8 Value>"
if s != want {
t.Errorf("TestAddedReflectValue #%d\n got: %s want: %s", i, s, want)
}
i++
// Formatter using a reflect.Value that is exported.
changeKind(&v, false)
buf2 := new(dummyFmtState)
f := formatState{value: v, cs: &Config, fs: buf2}
f.format(v)
s = buf2.String()
want = "5"
if s != want {
t.Errorf("TestAddedReflectValue #%d got: %s want: %s", i, s, want)
}
i++
// Formatter using a reflect.Value that is not exported.
changeKind(&v, true)
buf2.Reset()
f = formatState{value: v, cs: &Config, fs: buf2}
f.format(v)
s = buf2.String()
want = "<int8 Value>"
if s != want {
t.Errorf("TestAddedReflectValue #%d got: %s want: %s", i, s, want)
}
}
// SortValues makes the internal sortValues function available to the test
// package.
func SortValues(values []reflect.Value) {
sortValues(values)
}
/*
* Copyright (c) 2013 Dave Collins <dave@davec.name>
*
* 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
}
/*
* Copyright (c) 2013 Dave Collins <dave@davec.name>
*
* 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, "{{<max>} [<max>] [<max>] map[<max>]}"},
{scsMaxDepth, fCSFdump, "", dt, "(spew_test.depthTester) {\n" +
" ic: (spew_test.indirCir1) {\n <max depth reached>\n },\n" +
" arr: ([1]string) (len=1 cap=1) {\n <max depth reached>\n },\n" +
" slice: ([]string) (len=1 cap=1) {\n <max depth reached>\n },\n" +
" m: (map[string]int) (len=1) {\n <max depth reached>\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
}
}
}
// Copyright (c) 2013 Dave Collins <dave@davec.name>
//
// 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 <stdint.h>
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)
}
# 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
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.
# 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"}
*/
}
```
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
}
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
}
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
......
......@@ -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 = `
......
......@@ -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 {
......
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()
}
......@@ -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": "<foo>"},
"a: <foo>\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,
......
package yaml
import (
"encoding/base64"
"math"
"strconv"
"strings"
"unicode/utf8"
)
// TODO: merge, timestamps, base 60 floats, omap.
type resolveMapItem struct {
value interface{}
tag string
......@@ -27,25 +27,24 @@ func init() {
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{"<<"}},
{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
......@@ -59,90 +58,131 @@ func init() {
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 "", "!!str", "!!bool", "!!int", "!!float", "!!null":
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{}) {
tag = shortTag(tag)
//fmt.Printf("yv2 resolve tag: %s, in: %s\n", tag, in)
if !resolvableTag(tag) {
return tag, in
}
defer func() {
if tag != "" && tag != rtag {
panic("Can't decode " + rtag + " '" + in + "' as a " + tag)
switch tag {
case "", rtag, yaml_STR_TAG, yaml_BINARY_TAG:
return
}
failf("cannot decode %s `%s` as a %s", shortTag(rtag), in, shortTag(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
// 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
}
// 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 c {
case 'M':
// We've already checked the map above.
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 "!!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
case '.':
// Not in the map, so maybe a normal float.
floatv, err := strconv.ParseFloat(in, 64)
if err == nil {
return yaml_FLOAT_TAG, floatv
}
}
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)
case 'D', 'S':
// Int, float, or timestamp.
plain := strings.Replace(in, "_", "", -1)
intv, err := strconv.ParseInt(plain, 0, 64)
if err == nil {
return "!!int", int(intv)
if intv == int64(int(intv)) {
return yaml_INT_TAG, int(intv)
} else {
return yaml_INT_TAG, intv
}
}
} else if strings.HasPrefix(plain, "-0b") {
intv, err := strconv.ParseInt(plain[3:], 2, 64)
floatv, err := strconv.ParseFloat(plain, 64)
if err == nil {
return "!!int", -int(intv)
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 + ")")
}
// XXX Handle timestamps here.
}
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)
}
default:
panic("resolveTable item not yet handled: " +
string([]byte{c}) + " (with " + 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 "!!str", in
return string(out[:k])
}
......@@ -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
}
......
......@@ -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.
......
......@@ -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
```
......@@ -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() {
......
......@@ -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"
......
......@@ -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
......
......@@ -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) {
......
......@@ -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
```
......@@ -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
......
......@@ -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"`
}
```
......
......@@ -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() {}
......
......@@ -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
}
......
......@@ -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"`
}
......@@ -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() {}
......
......@@ -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 {
......
......@@ -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.
......
......@@ -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.
......
......@@ -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.
......
......@@ -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 = ""
......
......@@ -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.
......
......@@ -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) {
......
......@@ -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() {}
......
......@@ -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.
......
......@@ -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",
......
......@@ -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
......
......@@ -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
......
......@@ -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() {}
......
......@@ -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)
......
......@@ -59,10 +59,13 @@ func CreateValidPod(name, namespace, source string) api.BoundPod {
}
func CreatePodUpdate(op kubelet.PodOperation, pods ...api.BoundPod) kubelet.PodUpdate {
// 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{Op: op}
return kubelet.PodUpdate{newPods, op}
}
newPods := make([]api.BoundPod, len(pods))
for i := range pods {
newPods[i] = pods[i]
}
......
......@@ -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 {
......
......@@ -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) {
......
......@@ -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 {
......
......@@ -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.
......
......@@ -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
......
/*
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
}
......@@ -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() {}
......
......@@ -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
}
......@@ -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
......
......@@ -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() {}
......
......@@ -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.
......
......@@ -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() {}
......
......@@ -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),
)
}
......@@ -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
}
......@@ -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)},
}
......
......@@ -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] == '"' {
......
......@@ -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) {
......
......@@ -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
......
......@@ -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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment