diff options
Diffstat (limited to 'vendor/github.com/imdario/mergo')
-rw-r--r-- | vendor/github.com/imdario/mergo/.gitignore | 33 | ||||
-rw-r--r-- | vendor/github.com/imdario/mergo/README.md | 58 | ||||
-rw-r--r-- | vendor/github.com/imdario/mergo/issue17_test.go | 4 | ||||
-rw-r--r-- | vendor/github.com/imdario/mergo/issue33_test.go | 33 | ||||
-rw-r--r-- | vendor/github.com/imdario/mergo/issue50_test.go | 18 | ||||
-rw-r--r-- | vendor/github.com/imdario/mergo/issue52_test.go | 99 | ||||
-rw-r--r-- | vendor/github.com/imdario/mergo/map.go | 30 | ||||
-rw-r--r-- | vendor/github.com/imdario/mergo/merge.go | 90 | ||||
-rw-r--r-- | vendor/github.com/imdario/mergo/mergo.go | 2 | ||||
-rw-r--r-- | vendor/github.com/imdario/mergo/mergo_test.go | 71 |
10 files changed, 383 insertions, 55 deletions
diff --git a/vendor/github.com/imdario/mergo/.gitignore b/vendor/github.com/imdario/mergo/.gitignore new file mode 100644 index 000000000..529c3412b --- /dev/null +++ b/vendor/github.com/imdario/mergo/.gitignore @@ -0,0 +1,33 @@ +#### joe made this: http://goel.io/joe + +#### go #### +# Binaries for programs and plugins +*.exe +*.dll +*.so +*.dylib + +# Test binary, build with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736 +.glide/ + +#### vim #### +# Swap +[._]*.s[a-v][a-z] +[._]*.sw[a-p] +[._]s[a-v][a-z] +[._]sw[a-p] + +# Session +Session.vim + +# Temporary +.netrwhist +*~ +# Auto-generated tag files +tags diff --git a/vendor/github.com/imdario/mergo/README.md b/vendor/github.com/imdario/mergo/README.md index b13106979..f6b7858ad 100644 --- a/vendor/github.com/imdario/mergo/README.md +++ b/vendor/github.com/imdario/mergo/README.md @@ -71,10 +71,10 @@ if err := mergo.Merge(&dst, src); err != nil { } ``` -Also, you can merge overwriting values using MergeWithOverwrite. +Also, you can merge overwriting values using the transformer WithOverride. ```go -if err := mergo.MergeWithOverwrite(&dst, src); err != nil { +if err := mergo.Merge(&dst, src, WithOverride); err != nil { // ... } ``` @@ -87,7 +87,7 @@ if err := mergo.Map(&dst, srcMap); err != nil { } ``` -Warning: if you map a struct to map, it won't do it recursively. Don't expect Mergo to map struct members of your struct as map[string]interface{}. They will be just assigned as values. +Warning: if you map a struct to map, it won't do it recursively. Don't expect Mergo to map struct members of your struct as `map[string]interface{}`. They will be just assigned as values. More information and examples in [godoc documentation](http://godoc.org/github.com/imdario/mergo). @@ -111,13 +111,10 @@ func main() { A: "one", B: 2, } - dest := Foo{ A: "two", } - mergo.Merge(&dest, src) - fmt.Println(dest) // Will print // {two 2} @@ -126,7 +123,54 @@ func main() { Note: if test are failing due missing package, please execute: - go get gopkg.in/yaml.v1 + go get gopkg.in/yaml.v2 + +### Transformers + +Transformers allow to merge specific types differently than in the default behavior. In other words, now you can customize how some types are merged. For example, `time.Time` is a struct; it doesn't have zero value but IsZero can return true because it has fields with zero value. How can we merge a non-zero `time.Time`? + +```go +package main + +import ( + "fmt" + "reflect" + "time" +) + +type timeTransfomer struct { +} + +func (t timeTransfomer) Transformer(typ reflect.Type) func(dst, src reflect.Value) error { + if typ == reflect.TypeOf(time.Time{}) { + return func(dst, src reflect.Value) error { + if dst.CanSet() { + isZero := dst.MethodByName("IsZero") + result := isZero.Call([]reflect.Value{}) + if result[0].Bool() { + dst.Set(src) + } + } + } + } + return nil +} + +type Snapshot struct { + Time time.Time + // ... +} + +func main() { + src := Snapshot{time.Now()} + dest := Snapshot{} + mergo.Merge(&dest, src, WithTransformers(timeTransfomer{})) + fmt.Println(dest) + // Will print + // { 2018-01-12 01:15:00 +0000 UTC m=+0.000000001 } +} +``` + ## Contact me diff --git a/vendor/github.com/imdario/mergo/issue17_test.go b/vendor/github.com/imdario/mergo/issue17_test.go index 0ee96f377..f9de805ab 100644 --- a/vendor/github.com/imdario/mergo/issue17_test.go +++ b/vendor/github.com/imdario/mergo/issue17_test.go @@ -17,9 +17,9 @@ var ( func TestIssue17MergeWithOverwrite(t *testing.T) { var something map[string]interface{} if err := json.Unmarshal([]byte(request), &something); err != nil { - t.Errorf("Error while Unmarshalling maprequest %s", err) + t.Errorf("Error while Unmarshalling maprequest: %s", err) } if err := MergeWithOverwrite(&something, maprequest); err != nil { - t.Errorf("Error while merging %s", err) + t.Errorf("Error while merging: %s", err) } } diff --git a/vendor/github.com/imdario/mergo/issue33_test.go b/vendor/github.com/imdario/mergo/issue33_test.go new file mode 100644 index 000000000..c2d4a60d3 --- /dev/null +++ b/vendor/github.com/imdario/mergo/issue33_test.go @@ -0,0 +1,33 @@ +package mergo + +import ( + "testing" +) + +type Foo struct { + Str string + Bslice []byte +} + +func TestIssue33Merge(t *testing.T) { + dest := Foo{Str: "a"} + toMerge := Foo{ + Str: "b", + Bslice: []byte{1, 2}, + } + if err := Merge(&dest, toMerge); err != nil { + t.Errorf("Error while merging: %s", err) + } + // Merge doesn't overwrite an attribute if in destination it doesn't have a zero value. + // In this case, Str isn't a zero value string. + if dest.Str != "a" { + t.Errorf("dest.Str should have not been override as it has a non-zero value: dest.Str(%v) != 'a'", dest.Str) + } + // If we want to override, we must use MergeWithOverwrite or Merge using WithOverride. + if err := Merge(&dest, toMerge, WithOverride); err != nil { + t.Errorf("Error while merging: %s", err) + } + if dest.Str != toMerge.Str { + t.Errorf("dest.Str should have been override: dest.Str(%v) == toMerge.Str(%v)", dest.Str, toMerge.Str) + } +} diff --git a/vendor/github.com/imdario/mergo/issue50_test.go b/vendor/github.com/imdario/mergo/issue50_test.go new file mode 100644 index 000000000..89aa36345 --- /dev/null +++ b/vendor/github.com/imdario/mergo/issue50_test.go @@ -0,0 +1,18 @@ +package mergo + +import ( + "testing" + "time" +) + +type testStruct struct { + time.Duration +} + +func TestIssue50Merge(t *testing.T) { + to := testStruct{} + from := testStruct{} + if err := Merge(&to, from); err != nil { + t.Fail() + } +} diff --git a/vendor/github.com/imdario/mergo/issue52_test.go b/vendor/github.com/imdario/mergo/issue52_test.go new file mode 100644 index 000000000..62cd9fa7c --- /dev/null +++ b/vendor/github.com/imdario/mergo/issue52_test.go @@ -0,0 +1,99 @@ +package mergo + +import ( + "reflect" + "testing" + "time" +) + +type structWithTime struct { + Birth time.Time +} + +type timeTransfomer struct { + overwrite bool +} + +func (t timeTransfomer) Transformer(typ reflect.Type) func(dst, src reflect.Value) error { + if typ == reflect.TypeOf(time.Time{}) { + return func(dst, src reflect.Value) error { + if dst.CanSet() { + if t.overwrite { + isZero := src.MethodByName("IsZero") + result := isZero.Call([]reflect.Value{}) + if !result[0].Bool() { + dst.Set(src) + } + } else { + isZero := dst.MethodByName("IsZero") + result := isZero.Call([]reflect.Value{}) + if result[0].Bool() { + dst.Set(src) + } + } + } + return nil + } + } + return nil +} + +func TestOverwriteZeroSrcTime(t *testing.T) { + now := time.Now() + dst := structWithTime{now} + src := structWithTime{} + if err := MergeWithOverwrite(&dst, src); err != nil { + t.FailNow() + } + if !dst.Birth.IsZero() { + t.Fatalf("dst should have been overwritten: dst.Birth(%v) != now(%v)", dst.Birth, now) + } +} + +func TestOverwriteZeroSrcTimeWithTransformer(t *testing.T) { + now := time.Now() + dst := structWithTime{now} + src := structWithTime{} + if err := MergeWithOverwrite(&dst, src, WithTransformers(timeTransfomer{true})); err != nil { + t.FailNow() + } + if dst.Birth.IsZero() { + t.Fatalf("dst should not have been overwritten: dst.Birth(%v) != now(%v)", dst.Birth, now) + } +} + +func TestOverwriteZeroDstTime(t *testing.T) { + now := time.Now() + dst := structWithTime{} + src := structWithTime{now} + if err := MergeWithOverwrite(&dst, src); err != nil { + t.FailNow() + } + if dst.Birth.IsZero() { + t.Fatalf("dst should have been overwritten: dst.Birth(%v) != zero(%v)", dst.Birth, time.Time{}) + } +} + +func TestZeroDstTime(t *testing.T) { + now := time.Now() + dst := structWithTime{} + src := structWithTime{now} + if err := Merge(&dst, src); err != nil { + t.FailNow() + } + if !dst.Birth.IsZero() { + t.Fatalf("dst should not have been overwritten: dst.Birth(%v) != zero(%v)", dst.Birth, time.Time{}) + } +} + +func TestZeroDstTimeWithTransformer(t *testing.T) { + now := time.Now() + dst := structWithTime{} + src := structWithTime{now} + if err := Merge(&dst, src, WithTransformers(timeTransfomer{})); err != nil { + t.FailNow() + } + if dst.Birth.IsZero() { + t.Fatalf("dst should have been overwritten: dst.Birth(%v) != now(%v)", dst.Birth, now) + } +} diff --git a/vendor/github.com/imdario/mergo/map.go b/vendor/github.com/imdario/mergo/map.go index 99002565f..209814329 100644 --- a/vendor/github.com/imdario/mergo/map.go +++ b/vendor/github.com/imdario/mergo/map.go @@ -31,7 +31,8 @@ func isExported(field reflect.StructField) bool { // Traverses recursively both values, assigning src's fields values to dst. // The map argument tracks comparisons that have already been seen, which allows // short circuiting on recursive types. -func deepMap(dst, src reflect.Value, visited map[uintptr]*visit, depth int, overwrite bool) (err error) { +func deepMap(dst, src reflect.Value, visited map[uintptr]*visit, depth int, config *config) (err error) { + overwrite := config.overwrite if dst.CanAddr() { addr := dst.UnsafeAddr() h := 17 * addr @@ -97,15 +98,15 @@ func deepMap(dst, src reflect.Value, visited map[uintptr]*visit, depth int, over continue } if srcKind == dstKind { - if err = deepMerge(dstElement, srcElement, visited, depth+1, overwrite); err != nil { + if err = deepMerge(dstElement, srcElement, visited, depth+1, config); err != nil { return } } else if dstKind == reflect.Interface && dstElement.Kind() == reflect.Interface { - if err = deepMerge(dstElement, srcElement, visited, depth+1, overwrite); err != nil { + if err = deepMerge(dstElement, srcElement, visited, depth+1, config); err != nil { return } } else if srcKind == reflect.Map { - if err = deepMap(dstElement, srcElement, visited, depth+1, overwrite); err != nil { + if err = deepMap(dstElement, srcElement, visited, depth+1, config); err != nil { return } } else { @@ -127,28 +128,35 @@ func deepMap(dst, src reflect.Value, visited map[uintptr]*visit, depth int, over // doesn't apply if dst is a map. // This is separated method from Merge because it is cleaner and it keeps sane // semantics: merging equal types, mapping different (restricted) types. -func Map(dst, src interface{}) error { - return _map(dst, src, false) +func Map(dst, src interface{}, opts ...func(*config)) error { + return _map(dst, src, opts...) } // MapWithOverwrite will do the same as Map except that non-empty dst attributes will be overriden by // non-empty src attribute values. -func MapWithOverwrite(dst, src interface{}) error { - return _map(dst, src, true) +// Deprecated: Use Map(…) with WithOverride +func MapWithOverwrite(dst, src interface{}, opts ...func(*config)) error { + return _map(dst, src, append(opts, WithOverride)...) } -func _map(dst, src interface{}, overwrite bool) error { +func _map(dst, src interface{}, opts ...func(*config)) error { var ( vDst, vSrc reflect.Value err error ) + config := &config{} + + for _, opt := range opts { + opt(config) + } + if vDst, vSrc, err = resolveValues(dst, src); err != nil { return err } // To be friction-less, we redirect equal-type arguments // to deepMerge. Only because arguments can be anything. if vSrc.Kind() == vDst.Kind() { - return deepMerge(vDst, vSrc, make(map[uintptr]*visit), 0, overwrite) + return deepMerge(vDst, vSrc, make(map[uintptr]*visit), 0, config) } switch vSrc.Kind() { case reflect.Struct: @@ -162,5 +170,5 @@ func _map(dst, src interface{}, overwrite bool) error { default: return ErrNotSupported } - return deepMap(vDst, vSrc, make(map[uintptr]*visit), 0, overwrite) + return deepMap(vDst, vSrc, make(map[uintptr]*visit), 0, config) } diff --git a/vendor/github.com/imdario/mergo/merge.go b/vendor/github.com/imdario/mergo/merge.go index 052b9fe78..04629a3dc 100644 --- a/vendor/github.com/imdario/mergo/merge.go +++ b/vendor/github.com/imdario/mergo/merge.go @@ -8,14 +8,12 @@ package mergo -import ( - "reflect" -) +import "reflect" func hasExportedField(dst reflect.Value) (exported bool) { for i, n := 0, dst.NumField(); i < n; i++ { field := dst.Type().Field(i) - if field.Anonymous { + if field.Anonymous && dst.Field(i).Kind() == reflect.Struct { exported = exported || hasExportedField(dst.Field(i)) } else { exported = exported || len(field.PkgPath) == 0 @@ -24,10 +22,21 @@ func hasExportedField(dst reflect.Value) (exported bool) { return } +type config struct { + overwrite bool + transformers transformers +} + +type transformers interface { + Transformer(reflect.Type) func(dst, src reflect.Value) error +} + // Traverses recursively both values, assigning src's fields values to dst. // The map argument tracks comparisons that have already been seen, which allows // short circuiting on recursive types. -func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, overwrite bool) (err error) { +func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, config *config) (err error) { + overwrite := config.overwrite + if !src.IsValid() { return } @@ -44,11 +53,19 @@ func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, ov // Remember, remember... visited[h] = &visit{addr, typ, seen} } + + if config.transformers != nil { + if fn := config.transformers.Transformer(dst.Type()); fn != nil { + err = fn(dst, src) + return + } + } + switch dst.Kind() { case reflect.Struct: if hasExportedField(dst) { for i, n := 0, dst.NumField(); i < n; i++ { - if err = deepMerge(dst.Field(i), src.Field(i), visited, depth+1, overwrite); err != nil { + if err = deepMerge(dst.Field(i), src.Field(i), visited, depth+1, config); err != nil { return } } @@ -84,9 +101,21 @@ func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, ov case reflect.Ptr: fallthrough case reflect.Map: - if err = deepMerge(dstElement, srcElement, visited, depth+1, overwrite); err != nil { + if err = deepMerge(dstElement, srcElement, visited, depth+1, config); err != nil { return } + case reflect.Slice: + srcSlice := reflect.ValueOf(srcElement.Interface()) + + var dstSlice reflect.Value + if !dstElement.IsValid() || dstElement.IsNil() { + dstSlice = reflect.MakeSlice(srcSlice.Type(), 0, srcSlice.Len()) + } else { + dstSlice = reflect.ValueOf(dstElement.Interface()) + } + + dstSlice = reflect.AppendSlice(dstSlice, srcSlice) + dst.SetMapIndex(key, dstSlice) } } if dstElement.IsValid() && reflect.TypeOf(srcElement.Interface()).Kind() == reflect.Map { @@ -100,20 +129,25 @@ func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, ov dst.SetMapIndex(key, srcElement) } } + case reflect.Slice: + dst.Set(reflect.AppendSlice(dst, src)) case reflect.Ptr: fallthrough case reflect.Interface: + if src.IsNil() { + break + } if src.Kind() != reflect.Interface { if dst.IsNil() || overwrite { if dst.CanSet() && (overwrite || isEmptyValue(dst)) { dst.Set(src) } } else if src.Kind() == reflect.Ptr { - if err = deepMerge(dst.Elem(), src.Elem(), visited, depth+1, overwrite); err != nil { + if err = deepMerge(dst.Elem(), src.Elem(), visited, depth+1, config); err != nil { return } } else if dst.Elem().Type() == src.Type() { - if err = deepMerge(dst.Elem(), src, visited, depth+1, overwrite); err != nil { + if err = deepMerge(dst.Elem(), src, visited, depth+1, config); err != nil { return } } else { @@ -121,13 +155,11 @@ func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, ov } break } - if src.IsNil() { - break - } else if dst.IsNil() || overwrite { + if dst.IsNil() || overwrite { if dst.CanSet() && (overwrite || isEmptyValue(dst)) { dst.Set(src) } - } else if err = deepMerge(dst.Elem(), src.Elem(), visited, depth+1, overwrite); err != nil { + } else if err = deepMerge(dst.Elem(), src.Elem(), visited, depth+1, config); err != nil { return } default: @@ -142,26 +174,46 @@ func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, ov // src attributes if they themselves are not empty. dst and src must be valid same-type structs // and dst must be a pointer to struct. // It won't merge unexported (private) fields and will do recursively any exported field. -func Merge(dst, src interface{}) error { - return merge(dst, src, false) +func Merge(dst, src interface{}, opts ...func(*config)) error { + return merge(dst, src, opts...) } // MergeWithOverwrite will do the same as Merge except that non-empty dst attributes will be overriden by // non-empty src attribute values. -func MergeWithOverwrite(dst, src interface{}) error { - return merge(dst, src, true) +// Deprecated: use Merge(…) with WithOverride +func MergeWithOverwrite(dst, src interface{}, opts ...func(*config)) error { + return merge(dst, src, append(opts, WithOverride)...) +} + +// WithTransformers adds transformers to merge, allowing to customize the merging of some types. +func WithTransformers(transformers transformers) func(*config) { + return func(config *config) { + config.transformers = transformers + } } -func merge(dst, src interface{}, overwrite bool) error { +// WithOverride will make merge override non-empty dst attributes with non-empty src attributes values. +func WithOverride(config *config) { + config.overwrite = true +} + +func merge(dst, src interface{}, opts ...func(*config)) error { var ( vDst, vSrc reflect.Value err error ) + + config := &config{} + + for _, opt := range opts { + opt(config) + } + if vDst, vSrc, err = resolveValues(dst, src); err != nil { return err } if vDst.Type() != vSrc.Type() { return ErrDifferentArgumentsTypes } - return deepMerge(vDst, vSrc, make(map[uintptr]*visit), 0, overwrite) + return deepMerge(vDst, vSrc, make(map[uintptr]*visit), 0, config) } diff --git a/vendor/github.com/imdario/mergo/mergo.go b/vendor/github.com/imdario/mergo/mergo.go index 79ccdf5cb..f823c5517 100644 --- a/vendor/github.com/imdario/mergo/mergo.go +++ b/vendor/github.com/imdario/mergo/mergo.go @@ -32,7 +32,7 @@ type visit struct { next *visit } -// From src/pkg/encoding/json. +// From src/pkg/encoding/json/encode.go. func isEmptyValue(v reflect.Value) bool { switch v.Kind() { case reflect.Array, reflect.Map, reflect.Slice, reflect.String: diff --git a/vendor/github.com/imdario/mergo/mergo_test.go b/vendor/github.com/imdario/mergo/mergo_test.go index e167c332a..2ae7791d8 100644 --- a/vendor/github.com/imdario/mergo/mergo_test.go +++ b/vendor/github.com/imdario/mergo/mergo_test.go @@ -225,30 +225,71 @@ func TestPointerStructNil(t *testing.T) { } } -func TestSliceStruct(t *testing.T) { - a := sliceTest{} - b := sliceTest{[]int{1, 2, 3}} - if err := Merge(&a, b); err != nil { +func testSlice(t *testing.T, a []int, b []int) { + bc := b + e := append(a, b...) + + sa := sliceTest{a} + sb := sliceTest{b} + if err := Merge(&sa, sb); err != nil { t.FailNow() } - if len(b.S) != 3 { - t.FailNow() + if !reflect.DeepEqual(sb.S, bc) { + t.Fatalf("Source slice was modified %d != %d", sb.S, bc) } - if len(a.S) != len(b.S) { - t.Fatalf("b not merged in a proper way %d != %d", len(a.S), len(b.S)) + if !reflect.DeepEqual(sa.S, e) { + t.Fatalf("b not merged in a proper way %d != %d", sa.S, e) } - a = sliceTest{[]int{1}} - b = sliceTest{[]int{1, 2, 3}} - if err := Merge(&a, b); err != nil { + ma := map[string][]int{"S": a} + mb := map[string][]int{"S": b} + if err := Merge(&ma, mb); err != nil { t.FailNow() } - if len(a.S) != 1 { - t.FailNow() + if !reflect.DeepEqual(mb["S"], bc) { + t.Fatalf("Source slice was modified %d != %d", mb["S"], bc) } - if len(a.S) == len(b.S) { - t.Fatalf("b merged unexpectedly %d != %d", len(a.S), len(b.S)) + if !reflect.DeepEqual(ma["S"], e) { + t.Fatalf("b not merged in a proper way %d != %d", ma["S"], e) } + + if a == nil { + // test case with missing dst key + ma := map[string][]int{} + mb := map[string][]int{"S": b} + if err := Merge(&ma, mb); err != nil { + t.FailNow() + } + if !reflect.DeepEqual(mb["S"], bc) { + t.Fatalf("Source slice was modified %d != %d", mb["S"], bc) + } + if !reflect.DeepEqual(ma["S"], e) { + t.Fatalf("b not merged in a proper way %d != %d", ma["S"], e) + } + } + + if b == nil { + // test case with missing src key + ma := map[string][]int{"S": a} + mb := map[string][]int{} + if err := Merge(&ma, mb); err != nil { + t.FailNow() + } + if !reflect.DeepEqual(mb["S"], bc) { + t.Fatalf("Source slice was modified %d != %d", mb["S"], bc) + } + if !reflect.DeepEqual(ma["S"], e) { + t.Fatalf("b not merged in a proper way %d != %d", ma["S"], e) + } + } +} + +func TestSlice(t *testing.T) { + testSlice(t, nil, []int{1, 2, 3}) + testSlice(t, []int{}, []int{1, 2, 3}) + testSlice(t, []int{1}, []int{2, 3}) + testSlice(t, []int{1}, []int{}) + testSlice(t, []int{1}, nil) } func TestEmptyMaps(t *testing.T) { |