aboutsummaryrefslogtreecommitdiff
path: root/vendor/github.com/imdario/mergo
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/imdario/mergo')
-rw-r--r--vendor/github.com/imdario/mergo/CODE_OF_CONDUCT.md46
-rw-r--r--vendor/github.com/imdario/mergo/README.md29
-rw-r--r--vendor/github.com/imdario/mergo/issue23_test.go27
-rw-r--r--vendor/github.com/imdario/mergo/issue38_test.go59
-rw-r--r--vendor/github.com/imdario/mergo/map.go24
-rw-r--r--vendor/github.com/imdario/mergo/merge.go52
-rw-r--r--vendor/github.com/imdario/mergo/mergo.go2
-rw-r--r--vendor/github.com/imdario/mergo/mergo_test.go143
8 files changed, 359 insertions, 23 deletions
diff --git a/vendor/github.com/imdario/mergo/CODE_OF_CONDUCT.md b/vendor/github.com/imdario/mergo/CODE_OF_CONDUCT.md
new file mode 100644
index 000000000..469b44907
--- /dev/null
+++ b/vendor/github.com/imdario/mergo/CODE_OF_CONDUCT.md
@@ -0,0 +1,46 @@
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
+
+## Our Standards
+
+Examples of behavior that contributes to creating a positive environment include:
+
+* Using welcoming and inclusive language
+* Being respectful of differing viewpoints and experiences
+* Gracefully accepting constructive criticism
+* Focusing on what is best for the community
+* Showing empathy towards other community members
+
+Examples of unacceptable behavior by participants include:
+
+* The use of sexualized language or imagery and unwelcome sexual attention or advances
+* Trolling, insulting/derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or electronic address, without explicit permission
+* Other conduct which could reasonably be considered inappropriate in a professional setting
+
+## Our Responsibilities
+
+Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
+
+Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
+
+## Scope
+
+This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at i@dario.im. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
+
+Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
+
+[homepage]: http://contributor-covenant.org
+[version]: http://contributor-covenant.org/version/1/4/
diff --git a/vendor/github.com/imdario/mergo/README.md b/vendor/github.com/imdario/mergo/README.md
index f4769cdd7..b13106979 100644
--- a/vendor/github.com/imdario/mergo/README.md
+++ b/vendor/github.com/imdario/mergo/README.md
@@ -30,7 +30,7 @@ If you were using Mergo **before** April 6th 2015, please check your project wor
### Mergo in the wild
- [docker/docker](https://github.com/docker/docker/)
-- [GoogleCloudPlatform/kubernetes](https://github.com/GoogleCloudPlatform/kubernetes)
+- [kubernetes/kubernetes](https://github.com/kubernetes/kubernetes)
- [imdario/zas](https://github.com/imdario/zas)
- [soniah/dnsmadeeasy](https://github.com/soniah/dnsmadeeasy)
- [EagerIO/Stout](https://github.com/EagerIO/Stout)
@@ -50,6 +50,7 @@ If you were using Mergo **before** April 6th 2015, please check your project wor
- [thoas/picfit](https://github.com/thoas/picfit)
- [mantasmatelis/whooplist-server](https://github.com/mantasmatelis/whooplist-server)
- [jnuthong/item_search](https://github.com/jnuthong/item_search)
+- [Iris Web Framework](https://github.com/kataras/iris)
## Installation
@@ -64,15 +65,27 @@ If you were using Mergo **before** April 6th 2015, please check your project wor
You can only merge same-type structs with exported fields initialized as zero value of their type and same-types maps. Mergo won't merge unexported (private) fields but will do recursively any exported one. Also maps will be merged recursively except for structs inside maps (because they are not addressable using Go reflection).
- if err := mergo.Merge(&dst, src); err != nil {
- // ...
- }
+```go
+if err := mergo.Merge(&dst, src); err != nil {
+ // ...
+}
+```
+
+Also, you can merge overwriting values using MergeWithOverwrite.
+
+```go
+if err := mergo.MergeWithOverwrite(&dst, src); err != nil {
+ // ...
+}
+```
Additionally, you can map a map[string]interface{} to a struct (and otherwise, from struct to map), following the same restrictions as in Merge(). Keys are capitalized to find each corresponding exported field.
- if err := mergo.Map(&dst, srcMap); err != nil {
- // ...
- }
+```go
+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.
@@ -96,11 +109,11 @@ type Foo struct {
func main() {
src := Foo{
A: "one",
+ B: 2,
}
dest := Foo{
A: "two",
- B: 2,
}
mergo.Merge(&dest, src)
diff --git a/vendor/github.com/imdario/mergo/issue23_test.go b/vendor/github.com/imdario/mergo/issue23_test.go
new file mode 100644
index 000000000..9c3258413
--- /dev/null
+++ b/vendor/github.com/imdario/mergo/issue23_test.go
@@ -0,0 +1,27 @@
+package mergo
+
+import (
+ "testing"
+ "time"
+)
+
+type document struct {
+ Created *time.Time
+}
+
+func TestIssue23MergeWithOverwrite(t *testing.T) {
+ now := time.Now()
+ dst := document{
+ &now,
+ }
+ expected := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)
+ src := document{
+ &expected,
+ }
+ if err := MergeWithOverwrite(&dst, src); err != nil {
+ t.Errorf("Error while merging %s", err)
+ }
+ if dst.Created != src.Created {
+ t.Fatalf("Created not merged in properly: dst.Created(%v) != src.Created(%v)", dst.Created, src.Created)
+ }
+}
diff --git a/vendor/github.com/imdario/mergo/issue38_test.go b/vendor/github.com/imdario/mergo/issue38_test.go
new file mode 100644
index 000000000..286b68cb1
--- /dev/null
+++ b/vendor/github.com/imdario/mergo/issue38_test.go
@@ -0,0 +1,59 @@
+package mergo
+
+import (
+ "testing"
+ "time"
+)
+
+type structWithoutTimePointer struct {
+ Created time.Time
+}
+
+func TestIssue38Merge(t *testing.T) {
+ dst := structWithoutTimePointer{
+ time.Now(),
+ }
+
+ expected := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)
+ src := structWithoutTimePointer{
+ expected,
+ }
+ if err := Merge(&dst, src); err != nil {
+ t.Errorf("Error while merging %s", err)
+ }
+ if dst.Created == src.Created {
+ t.Fatalf("Created merged unexpectedly: dst.Created(%v) == src.Created(%v)", dst.Created, src.Created)
+ }
+}
+
+func TestIssue38MergeEmptyStruct(t *testing.T) {
+ dst := structWithoutTimePointer{}
+
+ expected := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)
+ src := structWithoutTimePointer{
+ expected,
+ }
+ if err := Merge(&dst, src); err != nil {
+ t.Errorf("Error while merging %s", err)
+ }
+ if dst.Created == src.Created {
+ t.Fatalf("Created merged unexpectedly: dst.Created(%v) == src.Created(%v)", dst.Created, src.Created)
+ }
+}
+
+func TestIssue38MergeWithOverwrite(t *testing.T) {
+ dst := structWithoutTimePointer{
+ time.Now(),
+ }
+
+ expected := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)
+ src := structWithoutTimePointer{
+ expected,
+ }
+ if err := MergeWithOverwrite(&dst, src); err != nil {
+ t.Errorf("Error while merging %s", err)
+ }
+ if dst.Created != src.Created {
+ t.Fatalf("Created not merged in properly: dst.Created(%v) != src.Created(%v)", dst.Created, src.Created)
+ }
+}
diff --git a/vendor/github.com/imdario/mergo/map.go b/vendor/github.com/imdario/mergo/map.go
index 8e8c4ba8e..99002565f 100644
--- a/vendor/github.com/imdario/mergo/map.go
+++ b/vendor/github.com/imdario/mergo/map.go
@@ -61,6 +61,13 @@ func deepMap(dst, src reflect.Value, visited map[uintptr]*visit, depth int, over
dstMap[fieldName] = src.Field(i).Interface()
}
}
+ case reflect.Ptr:
+ if dst.IsNil() {
+ v := reflect.New(dst.Type().Elem())
+ dst.Set(v)
+ }
+ dst = dst.Elem()
+ fallthrough
case reflect.Struct:
srcMap := src.Interface().(map[string]interface{})
for key := range srcMap {
@@ -85,6 +92,7 @@ func deepMap(dst, src reflect.Value, visited map[uintptr]*visit, depth int, over
srcKind = reflect.Ptr
}
}
+
if !srcElement.IsValid() {
continue
}
@@ -92,14 +100,16 @@ func deepMap(dst, src reflect.Value, visited map[uintptr]*visit, depth int, over
if err = deepMerge(dstElement, srcElement, visited, depth+1, overwrite); err != nil {
return
}
- } else {
- if srcKind == reflect.Map {
- if err = deepMap(dstElement, srcElement, visited, depth+1, overwrite); err != nil {
- return
- }
- } else {
- return fmt.Errorf("type mismatch on %s field: found %v, expected %v", fieldName, srcKind, dstKind)
+ } else if dstKind == reflect.Interface && dstElement.Kind() == reflect.Interface {
+ if err = deepMerge(dstElement, srcElement, visited, depth+1, overwrite); err != nil {
+ return
+ }
+ } else if srcKind == reflect.Map {
+ if err = deepMap(dstElement, srcElement, visited, depth+1, overwrite); err != nil {
+ return
}
+ } else {
+ return fmt.Errorf("type mismatch on %s field: found %v, expected %v", fieldName, srcKind, dstKind)
}
}
}
diff --git a/vendor/github.com/imdario/mergo/merge.go b/vendor/github.com/imdario/mergo/merge.go
index 11e55b1e2..052b9fe78 100644
--- a/vendor/github.com/imdario/mergo/merge.go
+++ b/vendor/github.com/imdario/mergo/merge.go
@@ -12,6 +12,18 @@ 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 {
+ exported = exported || hasExportedField(dst.Field(i))
+ } else {
+ exported = exported || len(field.PkgPath) == 0
+ }
+ }
+ return
+}
+
// 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.
@@ -34,12 +46,22 @@ func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, ov
}
switch dst.Kind() {
case reflect.Struct:
- for i, n := 0, dst.NumField(); i < n; i++ {
- if err = deepMerge(dst.Field(i), src.Field(i), visited, depth+1, overwrite); err != nil {
- return
+ 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 {
+ return
+ }
+ }
+ } else {
+ if dst.CanSet() && !isEmptyValue(src) && (overwrite || isEmptyValue(dst)) {
+ dst.Set(src)
}
}
case reflect.Map:
+ if len(src.MapKeys()) == 0 && !src.IsNil() && len(dst.MapKeys()) == 0 {
+ dst.Set(reflect.MakeMap(dst.Type()))
+ return
+ }
for _, key := range src.MapKeys() {
srcElement := src.MapIndex(key)
if !srcElement.IsValid() {
@@ -67,6 +89,10 @@ func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, ov
}
}
}
+ if dstElement.IsValid() && reflect.TypeOf(srcElement.Interface()).Kind() == reflect.Map {
+ continue
+ }
+
if !isEmptyValue(srcElement) && (overwrite || (!dstElement.IsValid() || isEmptyValue(dst))) {
if dst.IsNil() {
dst.Set(reflect.MakeMap(dst.Type()))
@@ -77,9 +103,27 @@ func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, ov
case reflect.Ptr:
fallthrough
case reflect.Interface:
+ 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 {
+ return
+ }
+ } else if dst.Elem().Type() == src.Type() {
+ if err = deepMerge(dst.Elem(), src, visited, depth+1, overwrite); err != nil {
+ return
+ }
+ } else {
+ return ErrDifferentArgumentsTypes
+ }
+ break
+ }
if src.IsNil() {
break
- } else if dst.IsNil() {
+ } else if dst.IsNil() || overwrite {
if dst.CanSet() && (overwrite || isEmptyValue(dst)) {
dst.Set(src)
}
diff --git a/vendor/github.com/imdario/mergo/mergo.go b/vendor/github.com/imdario/mergo/mergo.go
index f8a0991ec..79ccdf5cb 100644
--- a/vendor/github.com/imdario/mergo/mergo.go
+++ b/vendor/github.com/imdario/mergo/mergo.go
@@ -45,7 +45,7 @@ func isEmptyValue(v reflect.Value) bool {
return v.Uint() == 0
case reflect.Float32, reflect.Float64:
return v.Float() == 0
- case reflect.Interface, reflect.Ptr:
+ case reflect.Interface, reflect.Ptr, reflect.Func:
return v.IsNil()
}
return false
diff --git a/vendor/github.com/imdario/mergo/mergo_test.go b/vendor/github.com/imdario/mergo/mergo_test.go
index dd2651b31..e167c332a 100644
--- a/vendor/github.com/imdario/mergo/mergo_test.go
+++ b/vendor/github.com/imdario/mergo/mergo_test.go
@@ -6,12 +6,11 @@
package mergo
import (
+ "gopkg.in/yaml.v2"
"io/ioutil"
"reflect"
"testing"
"time"
-
- "gopkg.in/yaml.v1"
)
type simpleTest struct {
@@ -24,6 +23,14 @@ type complexTest struct {
ID string
}
+type mapTest struct {
+ M map[int]int
+}
+
+type ifcTest struct {
+ I interface{}
+}
+
type moreComplextText struct {
Ct complexTest
St simpleTest
@@ -244,6 +251,50 @@ func TestSliceStruct(t *testing.T) {
}
}
+func TestEmptyMaps(t *testing.T) {
+ a := mapTest{}
+ b := mapTest{
+ map[int]int{},
+ }
+ if err := Merge(&a, b); err != nil {
+ t.Fail()
+ }
+ if !reflect.DeepEqual(a, b) {
+ t.FailNow()
+ }
+}
+
+func TestEmptyToEmptyMaps(t *testing.T) {
+ a := mapTest{}
+ b := mapTest{}
+ if err := Merge(&a, b); err != nil {
+ t.Fail()
+ }
+ if !reflect.DeepEqual(a, b) {
+ t.FailNow()
+ }
+}
+
+func TestEmptyToNotEmptyMaps(t *testing.T) {
+ a := mapTest{map[int]int{
+ 1: 2,
+ 3: 4,
+ }}
+ aa := mapTest{map[int]int{
+ 1: 2,
+ 3: 4,
+ }}
+ b := mapTest{
+ map[int]int{},
+ }
+ if err := Merge(&a, b); err != nil {
+ t.Fail()
+ }
+ if !reflect.DeepEqual(a, aa) {
+ t.FailNow()
+ }
+}
+
func TestMapsWithOverwrite(t *testing.T) {
m := map[string]simpleTest{
"a": {}, // overwritten by 16
@@ -318,7 +369,8 @@ func TestYAMLMaps(t *testing.T) {
license := loadYAML("testdata/license.yml")
ft := thing["fields"].(map[interface{}]interface{})
fl := license["fields"].(map[interface{}]interface{})
- expectedLength := len(ft) + len(fl)
+ // license has one extra field (site) and another already existing in thing (author) that Mergo won't override.
+ expectedLength := len(ft) + len(fl) - 1
if err := Merge(&license, thing); err != nil {
t.Fatal(err.Error())
}
@@ -393,6 +445,45 @@ func TestSimpleMap(t *testing.T) {
}
}
+func TestIfcMap(t *testing.T) {
+ a := ifcTest{}
+ b := ifcTest{42}
+ if err := Map(&a, b); err != nil {
+ t.FailNow()
+ }
+ if a.I != 42 {
+ t.Fatalf("b not merged in properly: a.I(%d) != b.I(%d)", a.I, b.I)
+ }
+ if !reflect.DeepEqual(a, b) {
+ t.FailNow()
+ }
+}
+
+func TestIfcMapNoOverwrite(t *testing.T) {
+ a := ifcTest{13}
+ b := ifcTest{42}
+ if err := Map(&a, b); err != nil {
+ t.FailNow()
+ }
+ if a.I != 13 {
+ t.Fatalf("a not left alone: a.I(%d) == b.I(%d)", a.I, b.I)
+ }
+}
+
+func TestIfcMapWithOverwrite(t *testing.T) {
+ a := ifcTest{13}
+ b := ifcTest{42}
+ if err := MapWithOverwrite(&a, b); err != nil {
+ t.FailNow()
+ }
+ if a.I != 42 {
+ t.Fatalf("b not merged in properly: a.I(%d) != b.I(%d)", a.I, b.I)
+ }
+ if !reflect.DeepEqual(a, b) {
+ t.FailNow()
+ }
+}
+
type pointerMapTest struct {
A int
hidden int
@@ -434,6 +525,29 @@ func TestBackAndForth(t *testing.T) {
}
}
+func TestEmbeddedPointerUnpacking(t *testing.T) {
+ tests := []struct{ input pointerMapTest }{
+ {pointerMapTest{42, 1, nil}},
+ {pointerMapTest{42, 1, &simpleTest{66}}},
+ }
+ newValue := 77
+ m := map[string]interface{}{
+ "b": map[string]interface{}{
+ "value": newValue,
+ },
+ }
+ for _, test := range tests {
+ pt := test.input
+ if err := MapWithOverwrite(&pt, m); err != nil {
+ t.FailNow()
+ }
+ if pt.B.Value != newValue {
+ t.Fatalf("pt not mapped properly: pt.A.Value(%d) != m[`b`][`value`](%d)", pt.B.Value, newValue)
+ }
+
+ }
+}
+
type structWithTimePointer struct {
Birth *time.Time
}
@@ -523,3 +637,26 @@ func TestUnexportedProperty(t *testing.T) {
}()
Merge(&a, b)
}
+
+type structWithBoolPointer struct {
+ C *bool
+}
+
+func TestBooleanPointer(t *testing.T) {
+ bt, bf := true, false
+ src := structWithBoolPointer{
+ &bt,
+ }
+ dst := structWithBoolPointer{
+ &bf,
+ }
+ if err := Merge(&dst, src); err != nil {
+ t.FailNow()
+ }
+ if dst.C == src.C {
+ t.Fatalf("dst.C should be a different pointer than src.C")
+ }
+ if *dst.C != *src.C {
+ t.Fatalf("dst.C should be true")
+ }
+}