mirror of
https://github.com/opentofu/opentofu.git
synced 2025-01-08 15:13:56 -06:00
cfa299d2ee
Nomad was manually updated, so revert that to the version in master, remove it from vendor.json and add it to the ignore list. Update all packages that were in an unknown state to their latest master commits.
124 lines
3.4 KiB
Go
124 lines
3.4 KiB
Go
// 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 (
|
|
"reflect"
|
|
)
|
|
|
|
// 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) {
|
|
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}
|
|
}
|
|
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
|
|
}
|
|
}
|
|
case reflect.Map:
|
|
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.Ptr, 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:
|
|
if err = deepMerge(dstElement, srcElement, visited, depth+1, overwrite); err != nil {
|
|
return
|
|
}
|
|
}
|
|
}
|
|
if !isEmptyValue(srcElement) && (overwrite || (!dstElement.IsValid() || isEmptyValue(dst))) {
|
|
if dst.IsNil() {
|
|
dst.Set(reflect.MakeMap(dst.Type()))
|
|
}
|
|
dst.SetMapIndex(key, srcElement)
|
|
}
|
|
}
|
|
case reflect.Ptr:
|
|
fallthrough
|
|
case reflect.Interface:
|
|
if src.IsNil() {
|
|
break
|
|
} else 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 {
|
|
return
|
|
}
|
|
default:
|
|
if dst.CanSet() && !isEmptyValue(src) && (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{}) error {
|
|
return merge(dst, src, false)
|
|
}
|
|
|
|
// 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)
|
|
}
|
|
|
|
func merge(dst, src interface{}, overwrite bool) error {
|
|
var (
|
|
vDst, vSrc reflect.Value
|
|
err error
|
|
)
|
|
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)
|
|
}
|