Vendor github.com/imdario/mergo
Signed-off-by: Maksym Pavlenko <makpav@amazon.com>
This commit is contained in:
parent
8333d98c2b
commit
6e2228df72
@ -46,6 +46,7 @@ github.com/hashicorp/errwrap 7554cd9344cec97297fa6649b055a8c98c2a1e55
|
|||||||
github.com/hashicorp/go-multierror ed905158d87462226a13fe39ddf685ea65f1c11f
|
github.com/hashicorp/go-multierror ed905158d87462226a13fe39ddf685ea65f1c11f
|
||||||
github.com/hashicorp/golang-lru v0.5.1
|
github.com/hashicorp/golang-lru v0.5.1
|
||||||
go.opencensus.io v0.22.0
|
go.opencensus.io v0.22.0
|
||||||
|
github.com/imdario/mergo v0.3.7
|
||||||
|
|
||||||
# cri dependencies
|
# cri dependencies
|
||||||
github.com/containerd/cri f1d492b0cdd14e76476ee4dd024696ce3634e501 # master
|
github.com/containerd/cri f1d492b0cdd14e76476ee4dd024696ce3634e501 # master
|
||||||
|
28
vendor/github.com/imdario/mergo/LICENSE
generated
vendored
Normal file
28
vendor/github.com/imdario/mergo/LICENSE
generated
vendored
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
Copyright (c) 2013 Dario Castañé. All rights reserved.
|
||||||
|
Copyright (c) 2012 The Go Authors. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following disclaimer
|
||||||
|
in the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
* Neither the name of Google Inc. nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
238
vendor/github.com/imdario/mergo/README.md
generated
vendored
Normal file
238
vendor/github.com/imdario/mergo/README.md
generated
vendored
Normal file
@ -0,0 +1,238 @@
|
|||||||
|
# Mergo
|
||||||
|
|
||||||
|
A helper to merge structs and maps in Golang. Useful for configuration default values, avoiding messy if-statements.
|
||||||
|
|
||||||
|
Also a lovely [comune](http://en.wikipedia.org/wiki/Mergo) (municipality) in the Province of Ancona in the Italian region of Marche.
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
It is ready for production use. [It is used in several projects by Docker, Google, The Linux Foundation, VMWare, Shopify, etc](https://github.com/imdario/mergo#mergo-in-the-wild).
|
||||||
|
|
||||||
|
[![GoDoc][3]][4]
|
||||||
|
[![GoCard][5]][6]
|
||||||
|
[![Build Status][1]][2]
|
||||||
|
[![Coverage Status][7]][8]
|
||||||
|
[![Sourcegraph][9]][10]
|
||||||
|
[](https://app.fossa.io/projects/git%2Bgithub.com%2Fimdario%2Fmergo?ref=badge_shield)
|
||||||
|
|
||||||
|
[1]: https://travis-ci.org/imdario/mergo.png
|
||||||
|
[2]: https://travis-ci.org/imdario/mergo
|
||||||
|
[3]: https://godoc.org/github.com/imdario/mergo?status.svg
|
||||||
|
[4]: https://godoc.org/github.com/imdario/mergo
|
||||||
|
[5]: https://goreportcard.com/badge/imdario/mergo
|
||||||
|
[6]: https://goreportcard.com/report/github.com/imdario/mergo
|
||||||
|
[7]: https://coveralls.io/repos/github/imdario/mergo/badge.svg?branch=master
|
||||||
|
[8]: https://coveralls.io/github/imdario/mergo?branch=master
|
||||||
|
[9]: https://sourcegraph.com/github.com/imdario/mergo/-/badge.svg
|
||||||
|
[10]: https://sourcegraph.com/github.com/imdario/mergo?badge
|
||||||
|
|
||||||
|
### Latest release
|
||||||
|
|
||||||
|
[Release v0.3.7](https://github.com/imdario/mergo/releases/tag/v0.3.7).
|
||||||
|
|
||||||
|
### Important note
|
||||||
|
|
||||||
|
Please keep in mind that in [0.3.2](//github.com/imdario/mergo/releases/tag/0.3.2) Mergo changed `Merge()`and `Map()` signatures to support [transformers](#transformers). An optional/variadic argument has been added, so it won't break existing code.
|
||||||
|
|
||||||
|
If you were using Mergo **before** April 6th 2015, please check your project works as intended after updating your local copy with ```go get -u github.com/imdario/mergo```. I apologize for any issue caused by its previous behavior and any future bug that Mergo could cause (I hope it won't!) in existing projects after the change (release 0.2.0).
|
||||||
|
|
||||||
|
### Donations
|
||||||
|
|
||||||
|
If Mergo is useful to you, consider buying me a coffee, a beer or making a monthly donation so I can keep building great free software. :heart_eyes:
|
||||||
|
|
||||||
|
<a href='https://ko-fi.com/B0B58839' target='_blank'><img height='36' style='border:0px;height:36px;' src='https://az743702.vo.msecnd.net/cdn/kofi1.png?v=0' border='0' alt='Buy Me a Coffee at ko-fi.com' /></a>
|
||||||
|
[](https://beerpay.io/imdario/mergo)
|
||||||
|
[](https://beerpay.io/imdario/mergo)
|
||||||
|
<a href="https://liberapay.com/dario/donate"><img alt="Donate using Liberapay" src="https://liberapay.com/assets/widgets/donate.svg"></a>
|
||||||
|
|
||||||
|
### Mergo in the wild
|
||||||
|
|
||||||
|
- [moby/moby](https://github.com/moby/moby)
|
||||||
|
- [kubernetes/kubernetes](https://github.com/kubernetes/kubernetes)
|
||||||
|
- [vmware/dispatch](https://github.com/vmware/dispatch)
|
||||||
|
- [Shopify/themekit](https://github.com/Shopify/themekit)
|
||||||
|
- [imdario/zas](https://github.com/imdario/zas)
|
||||||
|
- [matcornic/hermes](https://github.com/matcornic/hermes)
|
||||||
|
- [OpenBazaar/openbazaar-go](https://github.com/OpenBazaar/openbazaar-go)
|
||||||
|
- [kataras/iris](https://github.com/kataras/iris)
|
||||||
|
- [michaelsauter/crane](https://github.com/michaelsauter/crane)
|
||||||
|
- [go-task/task](https://github.com/go-task/task)
|
||||||
|
- [sensu/uchiwa](https://github.com/sensu/uchiwa)
|
||||||
|
- [ory/hydra](https://github.com/ory/hydra)
|
||||||
|
- [sisatech/vcli](https://github.com/sisatech/vcli)
|
||||||
|
- [dairycart/dairycart](https://github.com/dairycart/dairycart)
|
||||||
|
- [projectcalico/felix](https://github.com/projectcalico/felix)
|
||||||
|
- [resin-os/balena](https://github.com/resin-os/balena)
|
||||||
|
- [go-kivik/kivik](https://github.com/go-kivik/kivik)
|
||||||
|
- [Telefonica/govice](https://github.com/Telefonica/govice)
|
||||||
|
- [supergiant/supergiant](supergiant/supergiant)
|
||||||
|
- [SergeyTsalkov/brooce](https://github.com/SergeyTsalkov/brooce)
|
||||||
|
- [soniah/dnsmadeeasy](https://github.com/soniah/dnsmadeeasy)
|
||||||
|
- [ohsu-comp-bio/funnel](https://github.com/ohsu-comp-bio/funnel)
|
||||||
|
- [EagerIO/Stout](https://github.com/EagerIO/Stout)
|
||||||
|
- [lynndylanhurley/defsynth-api](https://github.com/lynndylanhurley/defsynth-api)
|
||||||
|
- [russross/canvasassignments](https://github.com/russross/canvasassignments)
|
||||||
|
- [rdegges/cryptly-api](https://github.com/rdegges/cryptly-api)
|
||||||
|
- [casualjim/exeggutor](https://github.com/casualjim/exeggutor)
|
||||||
|
- [divshot/gitling](https://github.com/divshot/gitling)
|
||||||
|
- [RWJMurphy/gorl](https://github.com/RWJMurphy/gorl)
|
||||||
|
- [andrerocker/deploy42](https://github.com/andrerocker/deploy42)
|
||||||
|
- [elwinar/rambler](https://github.com/elwinar/rambler)
|
||||||
|
- [tmaiaroto/gopartman](https://github.com/tmaiaroto/gopartman)
|
||||||
|
- [jfbus/impressionist](https://github.com/jfbus/impressionist)
|
||||||
|
- [Jmeyering/zealot](https://github.com/Jmeyering/zealot)
|
||||||
|
- [godep-migrator/rigger-host](https://github.com/godep-migrator/rigger-host)
|
||||||
|
- [Dronevery/MultiwaySwitch-Go](https://github.com/Dronevery/MultiwaySwitch-Go)
|
||||||
|
- [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)
|
||||||
|
- [bukalapak/snowboard](https://github.com/bukalapak/snowboard)
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
go get github.com/imdario/mergo
|
||||||
|
|
||||||
|
// use in your .go code
|
||||||
|
import (
|
||||||
|
"github.com/imdario/mergo"
|
||||||
|
)
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
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. It won't merge empty structs value as [they are not considered zero values](https://golang.org/ref/spec#The_zero_value) either. Also maps will be merged recursively except for structs inside maps (because they are not addressable using Go reflection).
|
||||||
|
|
||||||
|
```go
|
||||||
|
if err := mergo.Merge(&dst, src); err != nil {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Also, you can merge overwriting values using the transformer `WithOverride`.
|
||||||
|
|
||||||
|
```go
|
||||||
|
if err := mergo.Merge(&dst, src, mergo.WithOverride); 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.
|
||||||
|
|
||||||
|
```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.
|
||||||
|
|
||||||
|
More information and examples in [godoc documentation](http://godoc.org/github.com/imdario/mergo).
|
||||||
|
|
||||||
|
### Nice example
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/imdario/mergo"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Foo struct {
|
||||||
|
A string
|
||||||
|
B int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
src := Foo{
|
||||||
|
A: "one",
|
||||||
|
B: 2,
|
||||||
|
}
|
||||||
|
dest := Foo{
|
||||||
|
A: "two",
|
||||||
|
}
|
||||||
|
mergo.Merge(&dest, src)
|
||||||
|
fmt.Println(dest)
|
||||||
|
// Will print
|
||||||
|
// {two 2}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Note: if test are failing due missing package, please execute:
|
||||||
|
|
||||||
|
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"
|
||||||
|
"github.com/imdario/mergo"
|
||||||
|
"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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type Snapshot struct {
|
||||||
|
Time time.Time
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
src := Snapshot{time.Now()}
|
||||||
|
dest := Snapshot{}
|
||||||
|
mergo.Merge(&dest, src, mergo.WithTransformers(timeTransfomer{}))
|
||||||
|
fmt.Println(dest)
|
||||||
|
// Will print
|
||||||
|
// { 2018-01-12 01:15:00 +0000 UTC m=+0.000000001 }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Contact me
|
||||||
|
|
||||||
|
If I can help you, you have an idea or you are using Mergo in your projects, don't hesitate to drop me a line (or a pull request): [@im_dario](https://twitter.com/im_dario)
|
||||||
|
|
||||||
|
## About
|
||||||
|
|
||||||
|
Written by [Dario Castañé](http://dario.im).
|
||||||
|
|
||||||
|
## Top Contributors
|
||||||
|
|
||||||
|
[](https://sourcerer.io/fame/imdario/imdario/mergo/links/0)
|
||||||
|
[](https://sourcerer.io/fame/imdario/imdario/mergo/links/1)
|
||||||
|
[](https://sourcerer.io/fame/imdario/imdario/mergo/links/2)
|
||||||
|
[](https://sourcerer.io/fame/imdario/imdario/mergo/links/3)
|
||||||
|
[](https://sourcerer.io/fame/imdario/imdario/mergo/links/4)
|
||||||
|
[](https://sourcerer.io/fame/imdario/imdario/mergo/links/5)
|
||||||
|
[](https://sourcerer.io/fame/imdario/imdario/mergo/links/6)
|
||||||
|
[](https://sourcerer.io/fame/imdario/imdario/mergo/links/7)
|
||||||
|
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
[BSD 3-Clause](http://opensource.org/licenses/BSD-3-Clause) license, as [Go language](http://golang.org/LICENSE).
|
||||||
|
|
||||||
|
|
||||||
|
[](https://app.fossa.io/projects/git%2Bgithub.com%2Fimdario%2Fmergo?ref=badge_large)
|
44
vendor/github.com/imdario/mergo/doc.go
generated
vendored
Normal file
44
vendor/github.com/imdario/mergo/doc.go
generated
vendored
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
// Copyright 2013 Dario Castañé. All rights reserved.
|
||||||
|
// Copyright 2009 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package mergo merges same-type structs and maps by setting default values in zero-value fields.
|
||||||
|
|
||||||
|
Mergo won't merge unexported (private) fields but will do recursively any exported one. It also won't merge structs inside maps (because they are not addressable using Go reflection).
|
||||||
|
|
||||||
|
Usage
|
||||||
|
|
||||||
|
From my own work-in-progress project:
|
||||||
|
|
||||||
|
type networkConfig struct {
|
||||||
|
Protocol string
|
||||||
|
Address string
|
||||||
|
ServerType string `json: "server_type"`
|
||||||
|
Port uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
type FssnConfig struct {
|
||||||
|
Network networkConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
var fssnDefault = FssnConfig {
|
||||||
|
networkConfig {
|
||||||
|
"tcp",
|
||||||
|
"127.0.0.1",
|
||||||
|
"http",
|
||||||
|
31560,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inside a function [...]
|
||||||
|
|
||||||
|
if err := mergo.Merge(&config, fssnDefault); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// More code [...]
|
||||||
|
|
||||||
|
*/
|
||||||
|
package mergo
|
175
vendor/github.com/imdario/mergo/map.go
generated
vendored
Normal file
175
vendor/github.com/imdario/mergo/map.go
generated
vendored
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
// Copyright 2014 Dario Castañé. All rights reserved.
|
||||||
|
// Copyright 2009 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Based on src/pkg/reflect/deepequal.go from official
|
||||||
|
// golang's stdlib.
|
||||||
|
|
||||||
|
package mergo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"unicode"
|
||||||
|
"unicode/utf8"
|
||||||
|
)
|
||||||
|
|
||||||
|
func changeInitialCase(s string, mapper func(rune) rune) string {
|
||||||
|
if s == "" {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
r, n := utf8.DecodeRuneInString(s)
|
||||||
|
return string(mapper(r)) + s[n:]
|
||||||
|
}
|
||||||
|
|
||||||
|
func isExported(field reflect.StructField) bool {
|
||||||
|
r, _ := utf8.DecodeRuneInString(field.Name)
|
||||||
|
return r >= 'A' && r <= 'Z'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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, config *Config) (err error) {
|
||||||
|
overwrite := config.Overwrite
|
||||||
|
if dst.CanAddr() {
|
||||||
|
addr := dst.UnsafeAddr()
|
||||||
|
h := 17 * addr
|
||||||
|
seen := visited[h]
|
||||||
|
typ := dst.Type()
|
||||||
|
for p := seen; p != nil; p = p.next {
|
||||||
|
if p.ptr == addr && p.typ == typ {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Remember, remember...
|
||||||
|
visited[h] = &visit{addr, typ, seen}
|
||||||
|
}
|
||||||
|
zeroValue := reflect.Value{}
|
||||||
|
switch dst.Kind() {
|
||||||
|
case reflect.Map:
|
||||||
|
dstMap := dst.Interface().(map[string]interface{})
|
||||||
|
for i, n := 0, src.NumField(); i < n; i++ {
|
||||||
|
srcType := src.Type()
|
||||||
|
field := srcType.Field(i)
|
||||||
|
if !isExported(field) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fieldName := field.Name
|
||||||
|
fieldName = changeInitialCase(fieldName, unicode.ToLower)
|
||||||
|
if v, ok := dstMap[fieldName]; !ok || (isEmptyValue(reflect.ValueOf(v)) || overwrite) {
|
||||||
|
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 {
|
||||||
|
config.overwriteWithEmptyValue = true
|
||||||
|
srcValue := srcMap[key]
|
||||||
|
fieldName := changeInitialCase(key, unicode.ToUpper)
|
||||||
|
dstElement := dst.FieldByName(fieldName)
|
||||||
|
if dstElement == zeroValue {
|
||||||
|
// We discard it because the field doesn't exist.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
srcElement := reflect.ValueOf(srcValue)
|
||||||
|
dstKind := dstElement.Kind()
|
||||||
|
srcKind := srcElement.Kind()
|
||||||
|
if srcKind == reflect.Ptr && dstKind != reflect.Ptr {
|
||||||
|
srcElement = srcElement.Elem()
|
||||||
|
srcKind = reflect.TypeOf(srcElement.Interface()).Kind()
|
||||||
|
} else if dstKind == reflect.Ptr {
|
||||||
|
// Can this work? I guess it can't.
|
||||||
|
if srcKind != reflect.Ptr && srcElement.CanAddr() {
|
||||||
|
srcPtr := srcElement.Addr()
|
||||||
|
srcElement = reflect.ValueOf(srcPtr)
|
||||||
|
srcKind = reflect.Ptr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !srcElement.IsValid() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if srcKind == dstKind {
|
||||||
|
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, config); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else if srcKind == reflect.Map {
|
||||||
|
if err = deepMap(dstElement, srcElement, visited, depth+1, config); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return fmt.Errorf("type mismatch on %s field: found %v, expected %v", fieldName, srcKind, dstKind)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map sets fields' values in dst from src.
|
||||||
|
// src can be a map with string keys or a struct. dst must be the opposite:
|
||||||
|
// if src is a map, dst must be a valid pointer to struct. If src is a struct,
|
||||||
|
// dst must be map[string]interface{}.
|
||||||
|
// It won't merge unexported (private) fields and will do recursively
|
||||||
|
// any exported field.
|
||||||
|
// If dst is a map, keys will be src fields' names in lower camel case.
|
||||||
|
// Missing key in src that doesn't match a field in dst will be skipped. This
|
||||||
|
// 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{}, opts ...func(*Config)) error {
|
||||||
|
return _map(dst, src, opts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MapWithOverwrite will do the same as Map except that non-empty dst attributes will be overridden by
|
||||||
|
// non-empty src attribute values.
|
||||||
|
// 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{}, 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, config)
|
||||||
|
}
|
||||||
|
switch vSrc.Kind() {
|
||||||
|
case reflect.Struct:
|
||||||
|
if vDst.Kind() != reflect.Map {
|
||||||
|
return ErrExpectedMapAsDestination
|
||||||
|
}
|
||||||
|
case reflect.Map:
|
||||||
|
if vDst.Kind() != reflect.Struct {
|
||||||
|
return ErrExpectedStructAsDestination
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return ErrNotSupported
|
||||||
|
}
|
||||||
|
return deepMap(vDst, vSrc, make(map[uintptr]*visit), 0, config)
|
||||||
|
}
|
255
vendor/github.com/imdario/mergo/merge.go
generated
vendored
Normal file
255
vendor/github.com/imdario/mergo/merge.go
generated
vendored
Normal file
@ -0,0 +1,255 @@
|
|||||||
|
// Copyright 2013 Dario Castañé. All rights reserved.
|
||||||
|
// Copyright 2009 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Based on src/pkg/reflect/deepequal.go from official
|
||||||
|
// golang's stdlib.
|
||||||
|
|
||||||
|
package mergo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"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 && dst.Field(i).Kind() == reflect.Struct {
|
||||||
|
exported = exported || hasExportedField(dst.Field(i))
|
||||||
|
} else {
|
||||||
|
exported = exported || len(field.PkgPath) == 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
Overwrite bool
|
||||||
|
AppendSlice bool
|
||||||
|
Transformers Transformers
|
||||||
|
overwriteWithEmptyValue bool
|
||||||
|
}
|
||||||
|
|
||||||
|
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, config *Config) (err error) {
|
||||||
|
overwrite := config.Overwrite
|
||||||
|
overwriteWithEmptySrc := config.overwriteWithEmptyValue
|
||||||
|
config.overwriteWithEmptyValue = false
|
||||||
|
|
||||||
|
if !src.IsValid() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if dst.CanAddr() {
|
||||||
|
addr := dst.UnsafeAddr()
|
||||||
|
h := 17 * addr
|
||||||
|
seen := visited[h]
|
||||||
|
typ := dst.Type()
|
||||||
|
for p := seen; p != nil; p = p.next {
|
||||||
|
if p.ptr == addr && p.typ == typ {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Remember, remember...
|
||||||
|
visited[h] = &visit{addr, typ, seen}
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.Transformers != nil && !isEmptyValue(dst) {
|
||||||
|
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, config); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if dst.CanSet() && (!isEmptyValue(src) || overwriteWithEmptySrc) && (overwrite || isEmptyValue(dst)) {
|
||||||
|
dst.Set(src)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case reflect.Map:
|
||||||
|
if dst.IsNil() && !src.IsNil() {
|
||||||
|
dst.Set(reflect.MakeMap(dst.Type()))
|
||||||
|
}
|
||||||
|
for _, key := range src.MapKeys() {
|
||||||
|
srcElement := src.MapIndex(key)
|
||||||
|
if !srcElement.IsValid() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
dstElement := dst.MapIndex(key)
|
||||||
|
switch srcElement.Kind() {
|
||||||
|
case reflect.Chan, reflect.Func, reflect.Map, reflect.Interface, reflect.Slice:
|
||||||
|
if srcElement.IsNil() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fallthrough
|
||||||
|
default:
|
||||||
|
if !srcElement.CanInterface() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
switch reflect.TypeOf(srcElement.Interface()).Kind() {
|
||||||
|
case reflect.Struct:
|
||||||
|
fallthrough
|
||||||
|
case reflect.Ptr:
|
||||||
|
fallthrough
|
||||||
|
case reflect.Map:
|
||||||
|
srcMapElm := srcElement
|
||||||
|
dstMapElm := dstElement
|
||||||
|
if srcMapElm.CanInterface() {
|
||||||
|
srcMapElm = reflect.ValueOf(srcMapElm.Interface())
|
||||||
|
if dstMapElm.IsValid() {
|
||||||
|
dstMapElm = reflect.ValueOf(dstMapElm.Interface())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err = deepMerge(dstMapElm, srcMapElm, 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())
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isEmptyValue(src) || overwriteWithEmptySrc) && (overwrite || isEmptyValue(dst)) && !config.AppendSlice {
|
||||||
|
dstSlice = srcSlice
|
||||||
|
} else if config.AppendSlice {
|
||||||
|
if srcSlice.Type() != dstSlice.Type() {
|
||||||
|
return fmt.Errorf("cannot append two slice with different type (%s, %s)", srcSlice.Type(), dstSlice.Type())
|
||||||
|
}
|
||||||
|
dstSlice = reflect.AppendSlice(dstSlice, srcSlice)
|
||||||
|
}
|
||||||
|
dst.SetMapIndex(key, dstSlice)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if dstElement.IsValid() && !isEmptyValue(dstElement) && (reflect.TypeOf(srcElement.Interface()).Kind() == reflect.Map || reflect.TypeOf(srcElement.Interface()).Kind() == reflect.Slice) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if srcElement.IsValid() && (overwrite || (!dstElement.IsValid() || isEmptyValue(dstElement))) {
|
||||||
|
if dst.IsNil() {
|
||||||
|
dst.Set(reflect.MakeMap(dst.Type()))
|
||||||
|
}
|
||||||
|
dst.SetMapIndex(key, srcElement)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case reflect.Slice:
|
||||||
|
if !dst.CanSet() {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if (!isEmptyValue(src) || overwriteWithEmptySrc) && (overwrite || isEmptyValue(dst)) && !config.AppendSlice {
|
||||||
|
dst.Set(src)
|
||||||
|
} else if config.AppendSlice {
|
||||||
|
if src.Type() != dst.Type() {
|
||||||
|
return fmt.Errorf("cannot append two slice with different type (%s, %s)", src.Type(), dst.Type())
|
||||||
|
}
|
||||||
|
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, config); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else if dst.Elem().Type() == src.Type() {
|
||||||
|
if err = deepMerge(dst.Elem(), src, visited, depth+1, config); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return ErrDifferentArgumentsTypes
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if dst.IsNil() || overwrite {
|
||||||
|
if dst.CanSet() && (overwrite || isEmptyValue(dst)) {
|
||||||
|
dst.Set(src)
|
||||||
|
}
|
||||||
|
} else if err = deepMerge(dst.Elem(), src.Elem(), visited, depth+1, config); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
if dst.CanSet() && (!isEmptyValue(src) || overwriteWithEmptySrc) && (overwrite || isEmptyValue(dst)) {
|
||||||
|
dst.Set(src)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge will fill any empty for value type attributes on the dst struct using corresponding
|
||||||
|
// 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{}, 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.
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithOverride will make merge override non-empty dst attributes with non-empty src attributes values.
|
||||||
|
func WithOverride(config *Config) {
|
||||||
|
config.Overwrite = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithAppendSlice will make merge append slices instead of overwriting it
|
||||||
|
func WithAppendSlice(config *Config) {
|
||||||
|
config.AppendSlice = 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, config)
|
||||||
|
}
|
97
vendor/github.com/imdario/mergo/mergo.go
generated
vendored
Normal file
97
vendor/github.com/imdario/mergo/mergo.go
generated
vendored
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
// Copyright 2013 Dario Castañé. All rights reserved.
|
||||||
|
// Copyright 2009 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Based on src/pkg/reflect/deepequal.go from official
|
||||||
|
// golang's stdlib.
|
||||||
|
|
||||||
|
package mergo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Errors reported by Mergo when it finds invalid arguments.
|
||||||
|
var (
|
||||||
|
ErrNilArguments = errors.New("src and dst must not be nil")
|
||||||
|
ErrDifferentArgumentsTypes = errors.New("src and dst must be of same type")
|
||||||
|
ErrNotSupported = errors.New("only structs and maps are supported")
|
||||||
|
ErrExpectedMapAsDestination = errors.New("dst was expected to be a map")
|
||||||
|
ErrExpectedStructAsDestination = errors.New("dst was expected to be a struct")
|
||||||
|
)
|
||||||
|
|
||||||
|
// During deepMerge, must keep track of checks that are
|
||||||
|
// in progress. The comparison algorithm assumes that all
|
||||||
|
// checks in progress are true when it reencounters them.
|
||||||
|
// Visited are stored in a map indexed by 17 * a1 + a2;
|
||||||
|
type visit struct {
|
||||||
|
ptr uintptr
|
||||||
|
typ reflect.Type
|
||||||
|
next *visit
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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:
|
||||||
|
return v.Len() == 0
|
||||||
|
case reflect.Bool:
|
||||||
|
return !v.Bool()
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
|
return v.Int() == 0
|
||||||
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||||
|
return v.Uint() == 0
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
return v.Float() == 0
|
||||||
|
case reflect.Interface, reflect.Ptr:
|
||||||
|
if v.IsNil() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return isEmptyValue(v.Elem())
|
||||||
|
case reflect.Func:
|
||||||
|
return v.IsNil()
|
||||||
|
case reflect.Invalid:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func resolveValues(dst, src interface{}) (vDst, vSrc reflect.Value, err error) {
|
||||||
|
if dst == nil || src == nil {
|
||||||
|
err = ErrNilArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
vDst = reflect.ValueOf(dst).Elem()
|
||||||
|
if vDst.Kind() != reflect.Struct && vDst.Kind() != reflect.Map {
|
||||||
|
err = ErrNotSupported
|
||||||
|
return
|
||||||
|
}
|
||||||
|
vSrc = reflect.ValueOf(src)
|
||||||
|
// We check if vSrc is a pointer to dereference it.
|
||||||
|
if vSrc.Kind() == reflect.Ptr {
|
||||||
|
vSrc = vSrc.Elem()
|
||||||
|
}
|
||||||
|
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.
|
||||||
|
func deeper(dst, src reflect.Value, visited map[uintptr]*visit, depth int) (err error) {
|
||||||
|
if dst.CanAddr() {
|
||||||
|
addr := dst.UnsafeAddr()
|
||||||
|
h := 17 * addr
|
||||||
|
seen := visited[h]
|
||||||
|
typ := dst.Type()
|
||||||
|
for p := seen; p != nil; p = p.next {
|
||||||
|
if p.ptr == addr && p.typ == typ {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Remember, remember...
|
||||||
|
visited[h] = &visit{addr, typ, seen}
|
||||||
|
}
|
||||||
|
return // TODO refactor
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user