summaryrefslogtreecommitdiff
path: root/vendor/k8s.io/apimachinery/pkg/util/strategicpatch/meta.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/k8s.io/apimachinery/pkg/util/strategicpatch/meta.go')
-rw-r--r--vendor/k8s.io/apimachinery/pkg/util/strategicpatch/meta.go194
1 files changed, 194 insertions, 0 deletions
diff --git a/vendor/k8s.io/apimachinery/pkg/util/strategicpatch/meta.go b/vendor/k8s.io/apimachinery/pkg/util/strategicpatch/meta.go
new file mode 100644
index 000000000..c31de15e7
--- /dev/null
+++ b/vendor/k8s.io/apimachinery/pkg/util/strategicpatch/meta.go
@@ -0,0 +1,194 @@
+/*
+Copyright 2017 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 strategicpatch
+
+import (
+ "errors"
+ "fmt"
+ "reflect"
+
+ "k8s.io/apimachinery/pkg/util/mergepatch"
+ forkedjson "k8s.io/apimachinery/third_party/forked/golang/json"
+ openapi "k8s.io/kube-openapi/pkg/util/proto"
+)
+
+type PatchMeta struct {
+ patchStrategies []string
+ patchMergeKey string
+}
+
+func (pm PatchMeta) GetPatchStrategies() []string {
+ if pm.patchStrategies == nil {
+ return []string{}
+ }
+ return pm.patchStrategies
+}
+
+func (pm PatchMeta) SetPatchStrategies(ps []string) {
+ pm.patchStrategies = ps
+}
+
+func (pm PatchMeta) GetPatchMergeKey() string {
+ return pm.patchMergeKey
+}
+
+func (pm PatchMeta) SetPatchMergeKey(pmk string) {
+ pm.patchMergeKey = pmk
+}
+
+type LookupPatchMeta interface {
+ // LookupPatchMetadataForStruct gets subschema and the patch metadata (e.g. patch strategy and merge key) for map.
+ LookupPatchMetadataForStruct(key string) (LookupPatchMeta, PatchMeta, error)
+ // LookupPatchMetadataForSlice get subschema and the patch metadata for slice.
+ LookupPatchMetadataForSlice(key string) (LookupPatchMeta, PatchMeta, error)
+ // Get the type name of the field
+ Name() string
+}
+
+type PatchMetaFromStruct struct {
+ T reflect.Type
+}
+
+func NewPatchMetaFromStruct(dataStruct interface{}) (PatchMetaFromStruct, error) {
+ t, err := getTagStructType(dataStruct)
+ return PatchMetaFromStruct{T: t}, err
+}
+
+var _ LookupPatchMeta = PatchMetaFromStruct{}
+
+func (s PatchMetaFromStruct) LookupPatchMetadataForStruct(key string) (LookupPatchMeta, PatchMeta, error) {
+ fieldType, fieldPatchStrategies, fieldPatchMergeKey, err := forkedjson.LookupPatchMetadataForStruct(s.T, key)
+ if err != nil {
+ return nil, PatchMeta{}, err
+ }
+
+ return PatchMetaFromStruct{T: fieldType},
+ PatchMeta{
+ patchStrategies: fieldPatchStrategies,
+ patchMergeKey: fieldPatchMergeKey,
+ }, nil
+}
+
+func (s PatchMetaFromStruct) LookupPatchMetadataForSlice(key string) (LookupPatchMeta, PatchMeta, error) {
+ subschema, patchMeta, err := s.LookupPatchMetadataForStruct(key)
+ if err != nil {
+ return nil, PatchMeta{}, err
+ }
+ elemPatchMetaFromStruct := subschema.(PatchMetaFromStruct)
+ t := elemPatchMetaFromStruct.T
+
+ var elemType reflect.Type
+ switch t.Kind() {
+ // If t is an array or a slice, get the element type.
+ // If element is still an array or a slice, return an error.
+ // Otherwise, return element type.
+ case reflect.Array, reflect.Slice:
+ elemType = t.Elem()
+ if elemType.Kind() == reflect.Array || elemType.Kind() == reflect.Slice {
+ return nil, PatchMeta{}, errors.New("unexpected slice of slice")
+ }
+ // If t is an pointer, get the underlying element.
+ // If the underlying element is neither an array nor a slice, the pointer is pointing to a slice,
+ // e.g. https://github.com/kubernetes/kubernetes/blob/bc22e206c79282487ea0bf5696d5ccec7e839a76/staging/src/k8s.io/apimachinery/pkg/util/strategicpatch/patch_test.go#L2782-L2822
+ // If the underlying element is either an array or a slice, return its element type.
+ case reflect.Ptr:
+ t = t.Elem()
+ if t.Kind() == reflect.Array || t.Kind() == reflect.Slice {
+ t = t.Elem()
+ }
+ elemType = t
+ default:
+ return nil, PatchMeta{}, fmt.Errorf("expected slice or array type, but got: %s", s.T.Kind().String())
+ }
+
+ return PatchMetaFromStruct{T: elemType}, patchMeta, nil
+}
+
+func (s PatchMetaFromStruct) Name() string {
+ return s.T.Kind().String()
+}
+
+func getTagStructType(dataStruct interface{}) (reflect.Type, error) {
+ if dataStruct == nil {
+ return nil, mergepatch.ErrBadArgKind(struct{}{}, nil)
+ }
+
+ t := reflect.TypeOf(dataStruct)
+ // Get the underlying type for pointers
+ if t.Kind() == reflect.Ptr {
+ t = t.Elem()
+ }
+
+ if t.Kind() != reflect.Struct {
+ return nil, mergepatch.ErrBadArgKind(struct{}{}, dataStruct)
+ }
+
+ return t, nil
+}
+
+func GetTagStructTypeOrDie(dataStruct interface{}) reflect.Type {
+ t, err := getTagStructType(dataStruct)
+ if err != nil {
+ panic(err)
+ }
+ return t
+}
+
+type PatchMetaFromOpenAPI struct {
+ Schema openapi.Schema
+}
+
+func NewPatchMetaFromOpenAPI(s openapi.Schema) PatchMetaFromOpenAPI {
+ return PatchMetaFromOpenAPI{Schema: s}
+}
+
+var _ LookupPatchMeta = PatchMetaFromOpenAPI{}
+
+func (s PatchMetaFromOpenAPI) LookupPatchMetadataForStruct(key string) (LookupPatchMeta, PatchMeta, error) {
+ if s.Schema == nil {
+ return nil, PatchMeta{}, nil
+ }
+ kindItem := NewKindItem(key, s.Schema.GetPath())
+ s.Schema.Accept(kindItem)
+
+ err := kindItem.Error()
+ if err != nil {
+ return nil, PatchMeta{}, err
+ }
+ return PatchMetaFromOpenAPI{Schema: kindItem.subschema},
+ kindItem.patchmeta, nil
+}
+
+func (s PatchMetaFromOpenAPI) LookupPatchMetadataForSlice(key string) (LookupPatchMeta, PatchMeta, error) {
+ if s.Schema == nil {
+ return nil, PatchMeta{}, nil
+ }
+ sliceItem := NewSliceItem(key, s.Schema.GetPath())
+ s.Schema.Accept(sliceItem)
+
+ err := sliceItem.Error()
+ if err != nil {
+ return nil, PatchMeta{}, err
+ }
+ return PatchMetaFromOpenAPI{Schema: sliceItem.subschema},
+ sliceItem.patchmeta, nil
+}
+
+func (s PatchMetaFromOpenAPI) Name() string {
+ schema := s.Schema
+ return schema.GetName()
+}