0
0
Fork 0
mirror of https://github.com/crazy-max/diun.git synced 2025-01-07 01:20:52 +00:00
crazy-max_diun/vendor/k8s.io/client-go/tools/clientcmd/merge.go
dependabot[bot] 1ac2dea65d
chore(deps): bump k8s.io/client-go from 0.29.3 to 0.32.0
Bumps [k8s.io/client-go](https://github.com/kubernetes/client-go) from 0.29.3 to 0.32.0.
- [Changelog](https://github.com/kubernetes/client-go/blob/master/CHANGELOG.md)
- [Commits](https://github.com/kubernetes/client-go/compare/v0.29.3...v0.32.0)

---
updated-dependencies:
- dependency-name: k8s.io/client-go
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-19 16:49:59 +00:00

121 lines
3.4 KiB
Go

/*
Copyright 2024 The Kubernetes Authors.
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 clientcmd
import (
"fmt"
"reflect"
"strings"
)
// recursively merges src into dst:
// - non-pointer struct fields with any exported fields are recursively merged
// - non-pointer struct fields with only unexported fields prefer src if the field is non-zero
// - maps are shallow merged with src keys taking priority over dst
// - non-zero src fields encountered during recursion that are not maps or structs overwrite and recursion stops
func merge[T any](dst, src *T) error {
if dst == nil {
return fmt.Errorf("cannot merge into nil pointer")
}
if src == nil {
return nil
}
return mergeValues(nil, reflect.ValueOf(dst).Elem(), reflect.ValueOf(src).Elem())
}
func mergeValues(fieldNames []string, dst, src reflect.Value) error {
dstType := dst.Type()
// no-op if we can't read the src
if !src.IsValid() {
return nil
}
// sanity check types match
if srcType := src.Type(); dstType != srcType {
return fmt.Errorf("cannot merge mismatched types (%s, %s) at %s", dstType, srcType, strings.Join(fieldNames, "."))
}
switch dstType.Kind() {
case reflect.Struct:
if hasExportedField(dstType) {
// recursively merge
for i, n := 0, dstType.NumField(); i < n; i++ {
if err := mergeValues(append(fieldNames, dstType.Field(i).Name), dst.Field(i), src.Field(i)); err != nil {
return err
}
}
} else if dst.CanSet() {
// If all fields are unexported, overwrite with src.
// Using src.IsZero() would make more sense but that's not what mergo did.
dst.Set(src)
}
case reflect.Map:
if dst.CanSet() && !src.IsZero() {
// initialize dst if needed
if dst.IsZero() {
dst.Set(reflect.MakeMap(dstType))
}
// shallow-merge overwriting dst keys with src keys
for _, mapKey := range src.MapKeys() {
dst.SetMapIndex(mapKey, src.MapIndex(mapKey))
}
}
case reflect.Slice:
if dst.CanSet() && src.Len() > 0 {
// overwrite dst with non-empty src slice
dst.Set(src)
}
case reflect.Pointer:
if dst.CanSet() && !src.IsZero() {
// overwrite dst with non-zero values for other types
if dstType.Elem().Kind() == reflect.Struct {
// use struct pointer as-is
dst.Set(src)
} else {
// shallow-copy non-struct pointer (interfaces, primitives, etc)
dst.Set(reflect.New(dstType.Elem()))
dst.Elem().Set(src.Elem())
}
}
default:
if dst.CanSet() && !src.IsZero() {
// overwrite dst with non-zero values for other types
dst.Set(src)
}
}
return nil
}
// hasExportedField returns true if the given type has any exported fields,
// or if it has any anonymous/embedded struct fields with exported fields
func hasExportedField(dstType reflect.Type) bool {
for i, n := 0, dstType.NumField(); i < n; i++ {
field := dstType.Field(i)
if field.Anonymous && field.Type.Kind() == reflect.Struct {
if hasExportedField(dstType.Field(i).Type) {
return true
}
} else if len(field.PkgPath) == 0 {
return true
}
}
return false
}