mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-04 04:08:16 +00:00 
			
		
		
		
	Merge pull request #37343 from ymqytw/revert_branch
Revert list of primitives fix
This commit is contained in:
		@@ -591,11 +591,11 @@ func patchResource(
 | 
				
			|||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return nil, err
 | 
									return nil, err
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			currentPatch, err := strategicpatch.CreateStrategicMergePatch(originalObjJS, currentObjectJS, versionedObj, strategicpatch.SMPatchVersionLatest)
 | 
								currentPatch, err := strategicpatch.CreateStrategicMergePatch(originalObjJS, currentObjectJS, versionedObj)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return nil, err
 | 
									return nil, err
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			originalPatch, err := strategicpatch.CreateStrategicMergePatch(originalObjJS, originalPatchedObjJS, versionedObj, strategicpatch.SMPatchVersionLatest)
 | 
								originalPatch, err := strategicpatch.CreateStrategicMergePatch(originalObjJS, originalPatchedObjJS, versionedObj)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return nil, err
 | 
									return nil, err
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -213,7 +213,7 @@ func (tc *patchTestCase) Run(t *testing.T) {
 | 
				
			|||||||
			continue
 | 
								continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		case api.StrategicMergePatchType:
 | 
							case api.StrategicMergePatchType:
 | 
				
			||||||
			patch, err = strategicpatch.CreateStrategicMergePatch(originalObjJS, changedJS, versionedObj, strategicpatch.SMPatchVersionLatest)
 | 
								patch, err = strategicpatch.CreateStrategicMergePatch(originalObjJS, changedJS, versionedObj)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				t.Errorf("%s: unexpected error: %v", tc.name, err)
 | 
									t.Errorf("%s: unexpected error: %v", tc.name, err)
 | 
				
			||||||
				return
 | 
									return
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -244,8 +244,7 @@ func (e *eventLogger) eventObserve(newEvent *api.Event) (*api.Event, []byte, err
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		newData, _ := json.Marshal(event)
 | 
							newData, _ := json.Marshal(event)
 | 
				
			||||||
		oldData, _ := json.Marshal(eventCopy2)
 | 
							oldData, _ := json.Marshal(eventCopy2)
 | 
				
			||||||
		// Defaulting to SMPatchVersion_1_5 is safe, since we only update Count and LastTimestamp, and none of them has list of primitives
 | 
							patch, err = strategicpatch.CreateStrategicMergePatch(oldData, newData, event)
 | 
				
			||||||
		patch, err = strategicpatch.CreateStrategicMergePatch(oldData, newData, event, strategicpatch.SMPatchVersion_1_5)
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// record our new observation
 | 
						// record our new observation
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -107,9 +107,8 @@ func (nsu *nodeStatusUpdater) UpdateNodeStatuses() error {
 | 
				
			|||||||
				err)
 | 
									err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Defaulting to SMPatchVersion_1_5 is safe, since updateNodeStatus doesn't update any lists of primitives
 | 
					 | 
				
			||||||
		patchBytes, err :=
 | 
							patchBytes, err :=
 | 
				
			||||||
			strategicpatch.CreateStrategicMergePatch(oldData, newData, node, strategicpatch.SMPatchVersion_1_5)
 | 
								strategicpatch.CreateStrategicMergePatch(oldData, newData, node)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return fmt.Errorf(
 | 
								return fmt.Errorf(
 | 
				
			||||||
				"failed to CreateStrategicMergePatch for node %q. %v",
 | 
									"failed to CreateStrategicMergePatch for node %q. %v",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -191,11 +191,9 @@ go_test(
 | 
				
			|||||||
        "//pkg/runtime/serializer/streaming:go_default_library",
 | 
					        "//pkg/runtime/serializer/streaming:go_default_library",
 | 
				
			||||||
        "//pkg/types:go_default_library",
 | 
					        "//pkg/types:go_default_library",
 | 
				
			||||||
        "//pkg/util/intstr:go_default_library",
 | 
					        "//pkg/util/intstr:go_default_library",
 | 
				
			||||||
        "//pkg/util/strategicpatch:go_default_library",
 | 
					 | 
				
			||||||
        "//pkg/util/strings:go_default_library",
 | 
					        "//pkg/util/strings:go_default_library",
 | 
				
			||||||
        "//pkg/util/term:go_default_library",
 | 
					        "//pkg/util/term:go_default_library",
 | 
				
			||||||
        "//pkg/util/wait:go_default_library",
 | 
					        "//pkg/util/wait:go_default_library",
 | 
				
			||||||
        "//pkg/version:go_default_library",
 | 
					 | 
				
			||||||
        "//pkg/watch:go_default_library",
 | 
					        "//pkg/watch:go_default_library",
 | 
				
			||||||
        "//pkg/watch/versioned:go_default_library",
 | 
					        "//pkg/watch/versioned:go_default_library",
 | 
				
			||||||
        "//vendor:github.com/spf13/cobra",
 | 
					        "//vendor:github.com/spf13/cobra",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -239,8 +239,7 @@ func (o AnnotateOptions) RunAnnotate(f cmdutil.Factory, cmd *cobra.Command) erro
 | 
				
			|||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return err
 | 
									return err
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			// Defaulting to SMPatchVersion_1_5 is safe, since it just update the annotation which is a map[string]string
 | 
								patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, obj)
 | 
				
			||||||
			patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, obj, strategicpatch.SMPatchVersion_1_5)
 | 
					 | 
				
			||||||
			createdPatch := err == nil
 | 
								createdPatch := err == nil
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				glog.V(2).Infof("couldn't compute patch: %v", err)
 | 
									glog.V(2).Infof("couldn't compute patch: %v", err)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,6 +24,8 @@ import (
 | 
				
			|||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/api"
 | 
						"k8s.io/kubernetes/pkg/api"
 | 
				
			||||||
 | 
						"k8s.io/kubernetes/pkg/apimachinery/registered"
 | 
				
			||||||
 | 
						"k8s.io/kubernetes/pkg/client/restclient"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/client/restclient/fake"
 | 
						"k8s.io/kubernetes/pkg/client/restclient/fake"
 | 
				
			||||||
	cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
 | 
						cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/runtime"
 | 
						"k8s.io/kubernetes/pkg/runtime"
 | 
				
			||||||
@@ -392,7 +394,7 @@ func TestAnnotateErrors(t *testing.T) {
 | 
				
			|||||||
		f, tf, _, _ := cmdtesting.NewAPIFactory()
 | 
							f, tf, _, _ := cmdtesting.NewAPIFactory()
 | 
				
			||||||
		tf.Printer = &testPrinter{}
 | 
							tf.Printer = &testPrinter{}
 | 
				
			||||||
		tf.Namespace = "test"
 | 
							tf.Namespace = "test"
 | 
				
			||||||
		tf.ClientConfig = defaultClientConfig()
 | 
							tf.ClientConfig = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		buf := bytes.NewBuffer([]byte{})
 | 
							buf := bytes.NewBuffer([]byte{})
 | 
				
			||||||
		cmd := NewCmdAnnotate(f, buf)
 | 
							cmd := NewCmdAnnotate(f, buf)
 | 
				
			||||||
@@ -430,12 +432,6 @@ func TestAnnotateObject(t *testing.T) {
 | 
				
			|||||||
			switch req.Method {
 | 
								switch req.Method {
 | 
				
			||||||
			case "GET":
 | 
								case "GET":
 | 
				
			||||||
				switch req.URL.Path {
 | 
									switch req.URL.Path {
 | 
				
			||||||
				case "/version":
 | 
					 | 
				
			||||||
					resp, err := genResponseWithJsonEncodedBody(serverVersion_1_5_0)
 | 
					 | 
				
			||||||
					if err != nil {
 | 
					 | 
				
			||||||
						t.Fatalf("error: failed to generate server version response: %#v\n", serverVersion_1_5_0)
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
					return resp, nil
 | 
					 | 
				
			||||||
				case "/namespaces/test/pods/foo":
 | 
									case "/namespaces/test/pods/foo":
 | 
				
			||||||
					return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &pods.Items[0])}, nil
 | 
										return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &pods.Items[0])}, nil
 | 
				
			||||||
				default:
 | 
									default:
 | 
				
			||||||
@@ -457,7 +453,7 @@ func TestAnnotateObject(t *testing.T) {
 | 
				
			|||||||
		}),
 | 
							}),
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	tf.Namespace = "test"
 | 
						tf.Namespace = "test"
 | 
				
			||||||
	tf.ClientConfig = defaultClientConfig()
 | 
						tf.ClientConfig = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	buf := bytes.NewBuffer([]byte{})
 | 
						buf := bytes.NewBuffer([]byte{})
 | 
				
			||||||
	cmd := NewCmdAnnotate(f, buf)
 | 
						cmd := NewCmdAnnotate(f, buf)
 | 
				
			||||||
@@ -486,12 +482,6 @@ func TestAnnotateObjectFromFile(t *testing.T) {
 | 
				
			|||||||
			switch req.Method {
 | 
								switch req.Method {
 | 
				
			||||||
			case "GET":
 | 
								case "GET":
 | 
				
			||||||
				switch req.URL.Path {
 | 
									switch req.URL.Path {
 | 
				
			||||||
				case "/version":
 | 
					 | 
				
			||||||
					resp, err := genResponseWithJsonEncodedBody(serverVersion_1_5_0)
 | 
					 | 
				
			||||||
					if err != nil {
 | 
					 | 
				
			||||||
						t.Fatalf("error: failed to generate server version response: %#v\n", serverVersion_1_5_0)
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
					return resp, nil
 | 
					 | 
				
			||||||
				case "/namespaces/test/replicationcontrollers/cassandra":
 | 
									case "/namespaces/test/replicationcontrollers/cassandra":
 | 
				
			||||||
					return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &pods.Items[0])}, nil
 | 
										return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &pods.Items[0])}, nil
 | 
				
			||||||
				default:
 | 
									default:
 | 
				
			||||||
@@ -513,7 +503,7 @@ func TestAnnotateObjectFromFile(t *testing.T) {
 | 
				
			|||||||
		}),
 | 
							}),
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	tf.Namespace = "test"
 | 
						tf.Namespace = "test"
 | 
				
			||||||
	tf.ClientConfig = defaultClientConfig()
 | 
						tf.ClientConfig = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	buf := bytes.NewBuffer([]byte{})
 | 
						buf := bytes.NewBuffer([]byte{})
 | 
				
			||||||
	cmd := NewCmdAnnotate(f, buf)
 | 
						cmd := NewCmdAnnotate(f, buf)
 | 
				
			||||||
@@ -542,7 +532,7 @@ func TestAnnotateLocal(t *testing.T) {
 | 
				
			|||||||
		}),
 | 
							}),
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	tf.Namespace = "test"
 | 
						tf.Namespace = "test"
 | 
				
			||||||
	tf.ClientConfig = defaultClientConfig()
 | 
						tf.ClientConfig = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	buf := bytes.NewBuffer([]byte{})
 | 
						buf := bytes.NewBuffer([]byte{})
 | 
				
			||||||
	cmd := NewCmdAnnotate(f, buf)
 | 
						cmd := NewCmdAnnotate(f, buf)
 | 
				
			||||||
@@ -572,12 +562,6 @@ func TestAnnotateMultipleObjects(t *testing.T) {
 | 
				
			|||||||
			switch req.Method {
 | 
								switch req.Method {
 | 
				
			||||||
			case "GET":
 | 
								case "GET":
 | 
				
			||||||
				switch req.URL.Path {
 | 
									switch req.URL.Path {
 | 
				
			||||||
				case "/version":
 | 
					 | 
				
			||||||
					resp, err := genResponseWithJsonEncodedBody(serverVersion_1_5_0)
 | 
					 | 
				
			||||||
					if err != nil {
 | 
					 | 
				
			||||||
						t.Fatalf("error: failed to generate server version response: %#v\n", serverVersion_1_5_0)
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
					return resp, nil
 | 
					 | 
				
			||||||
				case "/namespaces/test/pods":
 | 
									case "/namespaces/test/pods":
 | 
				
			||||||
					return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, pods)}, nil
 | 
										return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, pods)}, nil
 | 
				
			||||||
				default:
 | 
									default:
 | 
				
			||||||
@@ -601,7 +585,7 @@ func TestAnnotateMultipleObjects(t *testing.T) {
 | 
				
			|||||||
		}),
 | 
							}),
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	tf.Namespace = "test"
 | 
						tf.Namespace = "test"
 | 
				
			||||||
	tf.ClientConfig = defaultClientConfig()
 | 
						tf.ClientConfig = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	buf := bytes.NewBuffer([]byte{})
 | 
						buf := bytes.NewBuffer([]byte{})
 | 
				
			||||||
	cmd := NewCmdAnnotate(f, buf)
 | 
						cmd := NewCmdAnnotate(f, buf)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -531,23 +531,13 @@ func (p *patcher) patchSimple(obj runtime.Object, modified []byte, source, names
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Compute a three way strategic merge patch to send to server.
 | 
						// Compute a three way strategic merge patch to send to server.
 | 
				
			||||||
	patch, err := strategicpatch.CreateThreeWayMergePatch(original, modified, current, versionedObject, p.overwrite, strategicpatch.SMPatchVersion_1_5)
 | 
						patch, err := strategicpatch.CreateThreeWayMergePatch(original, modified, current, versionedObject, p.overwrite)
 | 
				
			||||||
	// If creating a patch fails, retrying with SMPatchVersion_1_0 is not helpful. So we return the error.
 | 
					 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		format := "creating patch with:\noriginal:\n%s\nmodified:\n%s\ncurrent:\n%s\nfor:"
 | 
							format := "creating patch with:\noriginal:\n%s\nmodified:\n%s\ncurrent:\n%s\nfor:"
 | 
				
			||||||
		return nil, cmdutil.AddSourceToErr(fmt.Sprintf(format, original, modified, current), source, err)
 | 
							return nil, cmdutil.AddSourceToErr(fmt.Sprintf(format, original, modified, current), source, err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	_, err = p.helper.Patch(namespace, name, api.StrategicMergePatchType, patch)
 | 
						_, err = p.helper.Patch(namespace, name, api.StrategicMergePatchType, patch)
 | 
				
			||||||
	if errors.IsInternalError(err) {
 | 
					 | 
				
			||||||
		// Retry SMPatchVersion_1_0 when applying the SMPatchVersion_1_5 patch returns an Internal Error (500).
 | 
					 | 
				
			||||||
		// Because the failure may be due to the server not supporting the SMPatchVersion_1_5 patch.
 | 
					 | 
				
			||||||
		patch, err = strategicpatch.CreateThreeWayMergePatch(original, modified, current, versionedObject, p.overwrite, strategicpatch.SMPatchVersion_1_0)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			format := "creating patch with:\noriginal:\n%s\nmodified:\n%s\ncurrent:\n%s\nfor:"
 | 
					 | 
				
			||||||
			return nil, cmdutil.AddSourceToErr(fmt.Sprintf(format, original, modified, current), source, err)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		_, err = p.helper.Patch(namespace, name, api.StrategicMergePatchType, patch)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return patch, err
 | 
						return patch, err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,7 +23,6 @@ import (
 | 
				
			|||||||
	"io/ioutil"
 | 
						"io/ioutil"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"strings"
 | 
					 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/spf13/cobra"
 | 
						"github.com/spf13/cobra"
 | 
				
			||||||
@@ -38,7 +37,6 @@ import (
 | 
				
			|||||||
	cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
 | 
						cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
 | 
				
			||||||
	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
 | 
						cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/runtime"
 | 
						"k8s.io/kubernetes/pkg/runtime"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/util/strategicpatch"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestApplyExtraArgsFail(t *testing.T) {
 | 
					func TestApplyExtraArgsFail(t *testing.T) {
 | 
				
			||||||
@@ -144,58 +142,6 @@ func readAndAnnotateService(t *testing.T, filename string) (string, []byte) {
 | 
				
			|||||||
	return annotateRuntimeObject(t, svc1, svc2, "Service")
 | 
						return annotateRuntimeObject(t, svc1, svc2, "Service")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func setFinalizersRuntimeObject(t *testing.T, originalObj, currentObj runtime.Object) (string, []byte) {
 | 
					 | 
				
			||||||
	originalAccessor, err := meta.Accessor(originalObj)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	originalFinalizers := []string{"a/a"}
 | 
					 | 
				
			||||||
	originalAccessor.SetFinalizers(originalFinalizers)
 | 
					 | 
				
			||||||
	original, err := runtime.Encode(testapi.Default.Codec(), originalObj)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	currentAccessor, err := meta.Accessor(currentObj)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	currentFinalizers := []string{"b/b"}
 | 
					 | 
				
			||||||
	currentAccessor.SetFinalizers(currentFinalizers)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	currentAnnotations := currentAccessor.GetAnnotations()
 | 
					 | 
				
			||||||
	if currentAnnotations == nil {
 | 
					 | 
				
			||||||
		currentAnnotations = make(map[string]string)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	currentAnnotations[annotations.LastAppliedConfigAnnotation] = string(original)
 | 
					 | 
				
			||||||
	currentAccessor.SetAnnotations(currentAnnotations)
 | 
					 | 
				
			||||||
	current, err := runtime.Encode(testapi.Default.Codec(), currentObj)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return currentAccessor.GetName(), current
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func readAndSetFinalizersReplicationController(t *testing.T, filename string) (string, []byte) {
 | 
					 | 
				
			||||||
	rc1 := readReplicationControllerFromFile(t, filename)
 | 
					 | 
				
			||||||
	rc2 := readReplicationControllerFromFile(t, filename)
 | 
					 | 
				
			||||||
	name, rcBytes := setFinalizersRuntimeObject(t, rc1, rc2)
 | 
					 | 
				
			||||||
	return name, rcBytes
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func isSMPatchVersion_1_5(t *testing.T, req *http.Request) bool {
 | 
					 | 
				
			||||||
	patch, err := ioutil.ReadAll(req.Body)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// SMPatchVersion_1_5 patch should has string "mergeprimitiveslist"
 | 
					 | 
				
			||||||
	return strings.Contains(string(patch), strategicpatch.MergePrimitivesListDirective)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func validatePatchApplication(t *testing.T, req *http.Request) {
 | 
					func validatePatchApplication(t *testing.T, req *http.Request) {
 | 
				
			||||||
	patch, err := ioutil.ReadAll(req.Body)
 | 
						patch, err := ioutil.ReadAll(req.Body)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
@@ -242,12 +188,6 @@ func TestApplyObject(t *testing.T) {
 | 
				
			|||||||
		NegotiatedSerializer: ns,
 | 
							NegotiatedSerializer: ns,
 | 
				
			||||||
		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
 | 
							Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
 | 
				
			||||||
			switch p, m := req.URL.Path, req.Method; {
 | 
								switch p, m := req.URL.Path, req.Method; {
 | 
				
			||||||
			case p == "/version" && m == "GET":
 | 
					 | 
				
			||||||
				resp, err := genResponseWithJsonEncodedBody(serverVersion_1_5_0)
 | 
					 | 
				
			||||||
				if err != nil {
 | 
					 | 
				
			||||||
					t.Fatalf("error: failed to generate server version response: %#v\n", serverVersion_1_5_0)
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				return resp, nil
 | 
					 | 
				
			||||||
			case p == pathRC && m == "GET":
 | 
								case p == pathRC && m == "GET":
 | 
				
			||||||
				bodyRC := ioutil.NopCloser(bytes.NewReader(currentRC))
 | 
									bodyRC := ioutil.NopCloser(bytes.NewReader(currentRC))
 | 
				
			||||||
				return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: bodyRC}, nil
 | 
									return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: bodyRC}, nil
 | 
				
			||||||
@@ -262,7 +202,6 @@ func TestApplyObject(t *testing.T) {
 | 
				
			|||||||
		}),
 | 
							}),
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	tf.Namespace = "test"
 | 
						tf.Namespace = "test"
 | 
				
			||||||
	tf.ClientConfig = defaultClientConfig()
 | 
					 | 
				
			||||||
	buf := bytes.NewBuffer([]byte{})
 | 
						buf := bytes.NewBuffer([]byte{})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cmd := NewCmdApply(f, buf)
 | 
						cmd := NewCmdApply(f, buf)
 | 
				
			||||||
@@ -277,65 +216,6 @@ func TestApplyObject(t *testing.T) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestApplyRetryWithSMPatchVersion_1_5(t *testing.T) {
 | 
					 | 
				
			||||||
	initTestErrorHandler(t)
 | 
					 | 
				
			||||||
	nameRC, currentRC := readAndSetFinalizersReplicationController(t, filenameRC)
 | 
					 | 
				
			||||||
	pathRC := "/namespaces/test/replicationcontrollers/" + nameRC
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	firstPatch := true
 | 
					 | 
				
			||||||
	retry := false
 | 
					 | 
				
			||||||
	f, tf, _, ns := cmdtesting.NewAPIFactory()
 | 
					 | 
				
			||||||
	tf.Printer = &testPrinter{}
 | 
					 | 
				
			||||||
	tf.Client = &fake.RESTClient{
 | 
					 | 
				
			||||||
		NegotiatedSerializer: ns,
 | 
					 | 
				
			||||||
		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
 | 
					 | 
				
			||||||
			switch p, m := req.URL.Path, req.Method; {
 | 
					 | 
				
			||||||
			case p == pathRC && m == "GET":
 | 
					 | 
				
			||||||
				bodyRC := ioutil.NopCloser(bytes.NewReader(currentRC))
 | 
					 | 
				
			||||||
				return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: bodyRC}, nil
 | 
					 | 
				
			||||||
			case p == pathRC && m == "PATCH":
 | 
					 | 
				
			||||||
				if firstPatch {
 | 
					 | 
				
			||||||
					if !isSMPatchVersion_1_5(t, req) {
 | 
					 | 
				
			||||||
						t.Fatalf("apply didn't try to send SMPatchVersion_1_5 for the first time")
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
					firstPatch = false
 | 
					 | 
				
			||||||
					statusErr := kubeerr.NewInternalError(fmt.Errorf("Server encountered internal error."))
 | 
					 | 
				
			||||||
					bodyBytes, _ := json.Marshal(statusErr)
 | 
					 | 
				
			||||||
					bodyErr := ioutil.NopCloser(bytes.NewReader(bodyBytes))
 | 
					 | 
				
			||||||
					return &http.Response{StatusCode: http.StatusInternalServerError, Header: defaultHeader(), Body: bodyErr}, nil
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				retry = true
 | 
					 | 
				
			||||||
				if isSMPatchVersion_1_5(t, req) {
 | 
					 | 
				
			||||||
					t.Fatalf("apply didn't try to send SMPatchVersion_1_0 after SMPatchVersion_1_5 patch encounter an Internal Error (500)")
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				bodyRC := ioutil.NopCloser(bytes.NewReader(currentRC))
 | 
					 | 
				
			||||||
				return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: bodyRC}, nil
 | 
					 | 
				
			||||||
			default:
 | 
					 | 
				
			||||||
				t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
 | 
					 | 
				
			||||||
				return nil, nil
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}),
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	tf.Namespace = "test"
 | 
					 | 
				
			||||||
	tf.ClientConfig = defaultClientConfig()
 | 
					 | 
				
			||||||
	buf := bytes.NewBuffer([]byte{})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	cmd := NewCmdApply(f, buf)
 | 
					 | 
				
			||||||
	cmd.Flags().Set("filename", filenameRC)
 | 
					 | 
				
			||||||
	cmd.Flags().Set("output", "name")
 | 
					 | 
				
			||||||
	cmd.Run(cmd, []string{})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if !retry {
 | 
					 | 
				
			||||||
		t.Fatalf("apply didn't retry when get Internal Error (500)")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// uses the name from the file, not the response
 | 
					 | 
				
			||||||
	expectRC := "replicationcontroller/" + nameRC + "\n"
 | 
					 | 
				
			||||||
	if buf.String() != expectRC {
 | 
					 | 
				
			||||||
		t.Fatalf("unexpected output: %s\nexpected: %s", buf.String(), expectRC)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestApplyRetry(t *testing.T) {
 | 
					func TestApplyRetry(t *testing.T) {
 | 
				
			||||||
	initTestErrorHandler(t)
 | 
						initTestErrorHandler(t)
 | 
				
			||||||
	nameRC, currentRC := readAndAnnotateReplicationController(t, filenameRC)
 | 
						nameRC, currentRC := readAndAnnotateReplicationController(t, filenameRC)
 | 
				
			||||||
@@ -350,12 +230,6 @@ func TestApplyRetry(t *testing.T) {
 | 
				
			|||||||
		NegotiatedSerializer: ns,
 | 
							NegotiatedSerializer: ns,
 | 
				
			||||||
		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
 | 
							Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
 | 
				
			||||||
			switch p, m := req.URL.Path, req.Method; {
 | 
								switch p, m := req.URL.Path, req.Method; {
 | 
				
			||||||
			case p == "/version" && m == "GET":
 | 
					 | 
				
			||||||
				resp, err := genResponseWithJsonEncodedBody(serverVersion_1_5_0)
 | 
					 | 
				
			||||||
				if err != nil {
 | 
					 | 
				
			||||||
					t.Fatalf("error: failed to generate server version response: %#v\n", serverVersion_1_5_0)
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				return resp, nil
 | 
					 | 
				
			||||||
			case p == pathRC && m == "GET":
 | 
								case p == pathRC && m == "GET":
 | 
				
			||||||
				getCount++
 | 
									getCount++
 | 
				
			||||||
				bodyRC := ioutil.NopCloser(bytes.NewReader(currentRC))
 | 
									bodyRC := ioutil.NopCloser(bytes.NewReader(currentRC))
 | 
				
			||||||
@@ -379,7 +253,6 @@ func TestApplyRetry(t *testing.T) {
 | 
				
			|||||||
		}),
 | 
							}),
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	tf.Namespace = "test"
 | 
						tf.Namespace = "test"
 | 
				
			||||||
	tf.ClientConfig = defaultClientConfig()
 | 
					 | 
				
			||||||
	buf := bytes.NewBuffer([]byte{})
 | 
						buf := bytes.NewBuffer([]byte{})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cmd := NewCmdApply(f, buf)
 | 
						cmd := NewCmdApply(f, buf)
 | 
				
			||||||
@@ -409,12 +282,6 @@ func TestApplyNonExistObject(t *testing.T) {
 | 
				
			|||||||
		NegotiatedSerializer: ns,
 | 
							NegotiatedSerializer: ns,
 | 
				
			||||||
		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
 | 
							Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
 | 
				
			||||||
			switch p, m := req.URL.Path, req.Method; {
 | 
								switch p, m := req.URL.Path, req.Method; {
 | 
				
			||||||
			case p == "/version" && m == "GET":
 | 
					 | 
				
			||||||
				resp, err := genResponseWithJsonEncodedBody(serverVersion_1_5_0)
 | 
					 | 
				
			||||||
				if err != nil {
 | 
					 | 
				
			||||||
					t.Fatalf("error: failed to generate server version response: %#v\n", serverVersion_1_5_0)
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				return resp, nil
 | 
					 | 
				
			||||||
			case p == "/api/v1/namespaces/test" && m == "GET":
 | 
								case p == "/api/v1/namespaces/test" && m == "GET":
 | 
				
			||||||
				return &http.Response{StatusCode: 404, Header: defaultHeader(), Body: ioutil.NopCloser(bytes.NewReader(nil))}, nil
 | 
									return &http.Response{StatusCode: 404, Header: defaultHeader(), Body: ioutil.NopCloser(bytes.NewReader(nil))}, nil
 | 
				
			||||||
			case p == pathNameRC && m == "GET":
 | 
								case p == pathNameRC && m == "GET":
 | 
				
			||||||
@@ -429,7 +296,6 @@ func TestApplyNonExistObject(t *testing.T) {
 | 
				
			|||||||
		}),
 | 
							}),
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	tf.Namespace = "test"
 | 
						tf.Namespace = "test"
 | 
				
			||||||
	tf.ClientConfig = defaultClientConfig()
 | 
					 | 
				
			||||||
	buf := bytes.NewBuffer([]byte{})
 | 
						buf := bytes.NewBuffer([]byte{})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cmd := NewCmdApply(f, buf)
 | 
						cmd := NewCmdApply(f, buf)
 | 
				
			||||||
@@ -465,12 +331,6 @@ func testApplyMultipleObjects(t *testing.T, asList bool) {
 | 
				
			|||||||
		NegotiatedSerializer: ns,
 | 
							NegotiatedSerializer: ns,
 | 
				
			||||||
		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
 | 
							Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
 | 
				
			||||||
			switch p, m := req.URL.Path, req.Method; {
 | 
								switch p, m := req.URL.Path, req.Method; {
 | 
				
			||||||
			case p == "/version" && m == "GET":
 | 
					 | 
				
			||||||
				resp, err := genResponseWithJsonEncodedBody(serverVersion_1_5_0)
 | 
					 | 
				
			||||||
				if err != nil {
 | 
					 | 
				
			||||||
					t.Fatalf("error: failed to generate server version response: %#v\n", serverVersion_1_5_0)
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				return resp, nil
 | 
					 | 
				
			||||||
			case p == pathRC && m == "GET":
 | 
								case p == pathRC && m == "GET":
 | 
				
			||||||
				bodyRC := ioutil.NopCloser(bytes.NewReader(currentRC))
 | 
									bodyRC := ioutil.NopCloser(bytes.NewReader(currentRC))
 | 
				
			||||||
				return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: bodyRC}, nil
 | 
									return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: bodyRC}, nil
 | 
				
			||||||
@@ -492,7 +352,6 @@ func testApplyMultipleObjects(t *testing.T, asList bool) {
 | 
				
			|||||||
		}),
 | 
							}),
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	tf.Namespace = "test"
 | 
						tf.Namespace = "test"
 | 
				
			||||||
	tf.ClientConfig = defaultClientConfig()
 | 
					 | 
				
			||||||
	buf := bytes.NewBuffer([]byte{})
 | 
						buf := bytes.NewBuffer([]byte{})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cmd := NewCmdApply(f, buf)
 | 
						cmd := NewCmdApply(f, buf)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -39,13 +39,8 @@ import (
 | 
				
			|||||||
	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
 | 
						cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/runtime"
 | 
						"k8s.io/kubernetes/pkg/runtime"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/util/strings"
 | 
						"k8s.io/kubernetes/pkg/util/strings"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/version"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var serverVersion_1_5_0 = version.Info{
 | 
					 | 
				
			||||||
	GitVersion: "v1.5.0",
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func initTestErrorHandler(t *testing.T) {
 | 
					func initTestErrorHandler(t *testing.T) {
 | 
				
			||||||
	cmdutil.BehaviorOnFatal(func(str string, code int) {
 | 
						cmdutil.BehaviorOnFatal(func(str string, code int) {
 | 
				
			||||||
		t.Errorf("Error running command (exit code %d): %s", code, str)
 | 
							t.Errorf("Error running command (exit code %d): %s", code, str)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -291,7 +291,7 @@ func runEdit(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
			switch editMode {
 | 
								switch editMode {
 | 
				
			||||||
			case NormalEditMode:
 | 
								case NormalEditMode:
 | 
				
			||||||
				err = visitToPatch(originalObj, updates, f, mapper, resourceMapper, encoder, out, errOut, defaultVersion, &results, file)
 | 
									err = visitToPatch(originalObj, updates, mapper, resourceMapper, encoder, out, errOut, defaultVersion, &results, file)
 | 
				
			||||||
			case EditBeforeCreateMode:
 | 
								case EditBeforeCreateMode:
 | 
				
			||||||
				err = visitToCreate(updates, mapper, resourceMapper, out, errOut, defaultVersion, &results, file)
 | 
									err = visitToCreate(updates, mapper, resourceMapper, out, errOut, defaultVersion, &results, file)
 | 
				
			||||||
			default:
 | 
								default:
 | 
				
			||||||
@@ -415,15 +415,7 @@ func getMapperAndResult(f cmdutil.Factory, args []string, options *resource.File
 | 
				
			|||||||
	return mapper, resourceMapper, r, cmdNamespace, err
 | 
						return mapper, resourceMapper, r, cmdNamespace, err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func visitToPatch(originalObj runtime.Object, updates *resource.Info,
 | 
					func visitToPatch(originalObj runtime.Object, updates *resource.Info, mapper meta.RESTMapper, resourceMapper *resource.Mapper, encoder runtime.Encoder, out, errOut io.Writer, defaultVersion unversioned.GroupVersion, results *editResults, file string) error {
 | 
				
			||||||
	f cmdutil.Factory,
 | 
					 | 
				
			||||||
	mapper meta.RESTMapper, resourceMapper *resource.Mapper,
 | 
					 | 
				
			||||||
	encoder runtime.Encoder,
 | 
					 | 
				
			||||||
	out, errOut io.Writer,
 | 
					 | 
				
			||||||
	defaultVersion unversioned.GroupVersion,
 | 
					 | 
				
			||||||
	results *editResults,
 | 
					 | 
				
			||||||
	file string) error {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	patchVisitor := resource.NewFlattenListVisitor(updates, resourceMapper)
 | 
						patchVisitor := resource.NewFlattenListVisitor(updates, resourceMapper)
 | 
				
			||||||
	err := patchVisitor.Visit(func(info *resource.Info, incomingErr error) error {
 | 
						err := patchVisitor.Visit(func(info *resource.Info, incomingErr error) error {
 | 
				
			||||||
		currOriginalObj := originalObj
 | 
							currOriginalObj := originalObj
 | 
				
			||||||
@@ -486,8 +478,7 @@ func visitToPatch(originalObj runtime.Object, updates *resource.Info,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		preconditions := []strategicpatch.PreconditionFunc{strategicpatch.RequireKeyUnchanged("apiVersion"),
 | 
							preconditions := []strategicpatch.PreconditionFunc{strategicpatch.RequireKeyUnchanged("apiVersion"),
 | 
				
			||||||
			strategicpatch.RequireKeyUnchanged("kind"), strategicpatch.RequireMetadataKeyUnchanged("name")}
 | 
								strategicpatch.RequireKeyUnchanged("kind"), strategicpatch.RequireMetadataKeyUnchanged("name")}
 | 
				
			||||||
		patch, err := strategicpatch.CreateTwoWayMergePatch(originalJS, editedJS, currOriginalObj, strategicpatch.SMPatchVersion_1_5, preconditions...)
 | 
							patch, err := strategicpatch.CreateTwoWayMergePatch(originalJS, editedJS, currOriginalObj, preconditions...)
 | 
				
			||||||
		// If creating a patch fails, retrying with SMPatchVersion_1_0 is not helpful. So we return the error.
 | 
					 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			glog.V(4).Infof("Unable to calculate diff, no merge is possible: %v", err)
 | 
								glog.V(4).Infof("Unable to calculate diff, no merge is possible: %v", err)
 | 
				
			||||||
			if strategicpatch.IsPreconditionFailed(err) {
 | 
								if strategicpatch.IsPreconditionFailed(err) {
 | 
				
			||||||
@@ -498,22 +489,10 @@ func visitToPatch(originalObj runtime.Object, updates *resource.Info,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		results.version = defaultVersion
 | 
							results.version = defaultVersion
 | 
				
			||||||
		patched, err := resource.NewHelper(info.Client, info.Mapping).Patch(info.Namespace, info.Name, api.StrategicMergePatchType, patch)
 | 
							patched, err := resource.NewHelper(info.Client, info.Mapping).Patch(info.Namespace, info.Name, api.StrategicMergePatchType, patch)
 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			// Retry SMPatchVersion_1_0 when applying the SMPatchVersion_1_5 patch returns an Internal Error (500).
 | 
					 | 
				
			||||||
			// Because the failure may be due to the server not supporting the SMPatchVersion_1_5 patch.
 | 
					 | 
				
			||||||
			if errors.IsInternalError(err) {
 | 
					 | 
				
			||||||
				patch, err = strategicpatch.CreateTwoWayMergePatch(originalJS, editedJS, currOriginalObj, strategicpatch.SMPatchVersion_1_0)
 | 
					 | 
				
			||||||
				if err != nil {
 | 
					 | 
				
			||||||
					glog.V(4).Infof("Unable to calculate diff, no merge is possible: %v", err)
 | 
					 | 
				
			||||||
					return err
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				patched, err = resource.NewHelper(info.Client, info.Mapping).Patch(info.Namespace, info.Name, api.StrategicMergePatchType, patch)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			fmt.Fprintln(out, results.addError(err, info))
 | 
								fmt.Fprintln(out, results.addError(err, info))
 | 
				
			||||||
			return nil
 | 
								return nil
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		info.Refresh(patched, true)
 | 
							info.Refresh(patched, true)
 | 
				
			||||||
		cmdutil.PrintSuccess(mapper, false, out, info.Mapping.Resource, info.Name, false, "edited")
 | 
							cmdutil.PrintSuccess(mapper, false, out, info.Mapping.Resource, info.Name, false, "edited")
 | 
				
			||||||
		return nil
 | 
							return nil
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -246,8 +246,7 @@ func (o *LabelOptions) RunLabel(f cmdutil.Factory, cmd *cobra.Command) error {
 | 
				
			|||||||
			if !reflect.DeepEqual(oldData, newData) {
 | 
								if !reflect.DeepEqual(oldData, newData) {
 | 
				
			||||||
				dataChangeMsg = "labeled"
 | 
									dataChangeMsg = "labeled"
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			// Defaulting to SMPatchVersion_1_5 is safe, since we only update labels and change cause, and none of them has list of primitives
 | 
								patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, obj)
 | 
				
			||||||
			patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, obj, strategicpatch.SMPatchVersion_1_5)
 | 
					 | 
				
			||||||
			createdPatch := err == nil
 | 
								createdPatch := err == nil
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				glog.V(2).Infof("couldn't compute patch: %v", err)
 | 
									glog.V(2).Infof("couldn't compute patch: %v", err)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -354,12 +354,6 @@ func TestLabelForResourceFromFile(t *testing.T) {
 | 
				
			|||||||
			switch req.Method {
 | 
								switch req.Method {
 | 
				
			||||||
			case "GET":
 | 
								case "GET":
 | 
				
			||||||
				switch req.URL.Path {
 | 
									switch req.URL.Path {
 | 
				
			||||||
				case "/version":
 | 
					 | 
				
			||||||
					resp, err := genResponseWithJsonEncodedBody(serverVersion_1_5_0)
 | 
					 | 
				
			||||||
					if err != nil {
 | 
					 | 
				
			||||||
						t.Fatalf("error: failed to generate server version response: %#v\n", serverVersion_1_5_0)
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
					return resp, nil
 | 
					 | 
				
			||||||
				case "/namespaces/test/replicationcontrollers/cassandra":
 | 
									case "/namespaces/test/replicationcontrollers/cassandra":
 | 
				
			||||||
					return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &pods.Items[0])}, nil
 | 
										return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &pods.Items[0])}, nil
 | 
				
			||||||
				default:
 | 
									default:
 | 
				
			||||||
@@ -381,7 +375,7 @@ func TestLabelForResourceFromFile(t *testing.T) {
 | 
				
			|||||||
		}),
 | 
							}),
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	tf.Namespace = "test"
 | 
						tf.Namespace = "test"
 | 
				
			||||||
	tf.ClientConfig = defaultClientConfig()
 | 
						tf.ClientConfig = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	buf := bytes.NewBuffer([]byte{})
 | 
						buf := bytes.NewBuffer([]byte{})
 | 
				
			||||||
	cmd := NewCmdLabel(f, buf)
 | 
						cmd := NewCmdLabel(f, buf)
 | 
				
			||||||
@@ -443,12 +437,6 @@ func TestLabelMultipleObjects(t *testing.T) {
 | 
				
			|||||||
			switch req.Method {
 | 
								switch req.Method {
 | 
				
			||||||
			case "GET":
 | 
								case "GET":
 | 
				
			||||||
				switch req.URL.Path {
 | 
									switch req.URL.Path {
 | 
				
			||||||
				case "/version":
 | 
					 | 
				
			||||||
					resp, err := genResponseWithJsonEncodedBody(serverVersion_1_5_0)
 | 
					 | 
				
			||||||
					if err != nil {
 | 
					 | 
				
			||||||
						t.Fatalf("error: failed to generate server version response: %#v\n", serverVersion_1_5_0)
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
					return resp, nil
 | 
					 | 
				
			||||||
				case "/namespaces/test/pods":
 | 
									case "/namespaces/test/pods":
 | 
				
			||||||
					return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, pods)}, nil
 | 
										return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, pods)}, nil
 | 
				
			||||||
				default:
 | 
									default:
 | 
				
			||||||
@@ -472,7 +460,7 @@ func TestLabelMultipleObjects(t *testing.T) {
 | 
				
			|||||||
		}),
 | 
							}),
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	tf.Namespace = "test"
 | 
						tf.Namespace = "test"
 | 
				
			||||||
	tf.ClientConfig = defaultClientConfig()
 | 
						tf.ClientConfig = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	buf := bytes.NewBuffer([]byte{})
 | 
						buf := bytes.NewBuffer([]byte{})
 | 
				
			||||||
	cmd := NewCmdLabel(f, buf)
 | 
						cmd := NewCmdLabel(f, buf)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -34,12 +34,6 @@ func TestPatchObject(t *testing.T) {
 | 
				
			|||||||
		NegotiatedSerializer: ns,
 | 
							NegotiatedSerializer: ns,
 | 
				
			||||||
		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
 | 
							Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
 | 
				
			||||||
			switch p, m := req.URL.Path, req.Method; {
 | 
								switch p, m := req.URL.Path, req.Method; {
 | 
				
			||||||
			case p == "/version" && m == "GET":
 | 
					 | 
				
			||||||
				resp, err := genResponseWithJsonEncodedBody(serverVersion_1_5_0)
 | 
					 | 
				
			||||||
				if err != nil {
 | 
					 | 
				
			||||||
					t.Fatalf("error: failed to generate server version response: %#v\n", serverVersion_1_5_0)
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				return resp, nil
 | 
					 | 
				
			||||||
			case p == "/namespaces/test/services/frontend" && (m == "PATCH" || m == "GET"):
 | 
								case p == "/namespaces/test/services/frontend" && (m == "PATCH" || m == "GET"):
 | 
				
			||||||
				return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &svc.Items[0])}, nil
 | 
									return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &svc.Items[0])}, nil
 | 
				
			||||||
			default:
 | 
								default:
 | 
				
			||||||
@@ -49,7 +43,6 @@ func TestPatchObject(t *testing.T) {
 | 
				
			|||||||
		}),
 | 
							}),
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	tf.Namespace = "test"
 | 
						tf.Namespace = "test"
 | 
				
			||||||
	tf.ClientConfig = defaultClientConfig()
 | 
					 | 
				
			||||||
	buf := bytes.NewBuffer([]byte{})
 | 
						buf := bytes.NewBuffer([]byte{})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cmd := NewCmdPatch(f, buf)
 | 
						cmd := NewCmdPatch(f, buf)
 | 
				
			||||||
@@ -73,12 +66,6 @@ func TestPatchObjectFromFile(t *testing.T) {
 | 
				
			|||||||
		NegotiatedSerializer: ns,
 | 
							NegotiatedSerializer: ns,
 | 
				
			||||||
		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
 | 
							Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
 | 
				
			||||||
			switch p, m := req.URL.Path, req.Method; {
 | 
								switch p, m := req.URL.Path, req.Method; {
 | 
				
			||||||
			case p == "/version" && m == "GET":
 | 
					 | 
				
			||||||
				resp, err := genResponseWithJsonEncodedBody(serverVersion_1_5_0)
 | 
					 | 
				
			||||||
				if err != nil {
 | 
					 | 
				
			||||||
					t.Fatalf("error: failed to generate server version response: %#v\n", serverVersion_1_5_0)
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				return resp, nil
 | 
					 | 
				
			||||||
			case p == "/namespaces/test/services/frontend" && (m == "PATCH" || m == "GET"):
 | 
								case p == "/namespaces/test/services/frontend" && (m == "PATCH" || m == "GET"):
 | 
				
			||||||
				return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &svc.Items[0])}, nil
 | 
									return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &svc.Items[0])}, nil
 | 
				
			||||||
			default:
 | 
								default:
 | 
				
			||||||
@@ -88,7 +75,6 @@ func TestPatchObjectFromFile(t *testing.T) {
 | 
				
			|||||||
		}),
 | 
							}),
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	tf.Namespace = "test"
 | 
						tf.Namespace = "test"
 | 
				
			||||||
	tf.ClientConfig = defaultClientConfig()
 | 
					 | 
				
			||||||
	buf := bytes.NewBuffer([]byte{})
 | 
						buf := bytes.NewBuffer([]byte{})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cmd := NewCmdPatch(f, buf)
 | 
						cmd := NewCmdPatch(f, buf)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -32,7 +32,6 @@ go_library(
 | 
				
			|||||||
        "//pkg/runtime:go_default_library",
 | 
					        "//pkg/runtime:go_default_library",
 | 
				
			||||||
        "//pkg/util/errors:go_default_library",
 | 
					        "//pkg/util/errors:go_default_library",
 | 
				
			||||||
        "//pkg/util/interrupt:go_default_library",
 | 
					        "//pkg/util/interrupt:go_default_library",
 | 
				
			||||||
        "//pkg/util/strategicpatch:go_default_library",
 | 
					 | 
				
			||||||
        "//pkg/watch:go_default_library",
 | 
					        "//pkg/watch:go_default_library",
 | 
				
			||||||
        "//vendor:github.com/renstrom/dedent",
 | 
					        "//vendor:github.com/renstrom/dedent",
 | 
				
			||||||
        "//vendor:github.com/spf13/cobra",
 | 
					        "//vendor:github.com/spf13/cobra",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -31,7 +31,6 @@ import (
 | 
				
			|||||||
	"k8s.io/kubernetes/pkg/kubectl/resource"
 | 
						"k8s.io/kubernetes/pkg/kubectl/resource"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/runtime"
 | 
						"k8s.io/kubernetes/pkg/runtime"
 | 
				
			||||||
	utilerrors "k8s.io/kubernetes/pkg/util/errors"
 | 
						utilerrors "k8s.io/kubernetes/pkg/util/errors"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/util/strategicpatch"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// PauseConfig is the start of the data required to perform the operation.  As new fields are added, add them here instead of
 | 
					// PauseConfig is the start of the data required to perform the operation.  As new fields are added, add them here instead of
 | 
				
			||||||
@@ -39,7 +38,6 @@ import (
 | 
				
			|||||||
type PauseConfig struct {
 | 
					type PauseConfig struct {
 | 
				
			||||||
	resource.FilenameOptions
 | 
						resource.FilenameOptions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	f       cmdutil.Factory
 | 
					 | 
				
			||||||
	Pauser  func(info *resource.Info) (bool, error)
 | 
						Pauser  func(info *resource.Info) (bool, error)
 | 
				
			||||||
	Mapper  meta.RESTMapper
 | 
						Mapper  meta.RESTMapper
 | 
				
			||||||
	Typer   runtime.ObjectTyper
 | 
						Typer   runtime.ObjectTyper
 | 
				
			||||||
@@ -101,7 +99,6 @@ func (o *PauseConfig) CompletePause(f cmdutil.Factory, cmd *cobra.Command, out i
 | 
				
			|||||||
		return cmdutil.UsageError(cmd, cmd.Use)
 | 
							return cmdutil.UsageError(cmd, cmd.Use)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	o.f = f
 | 
					 | 
				
			||||||
	o.Mapper, o.Typer = f.Object()
 | 
						o.Mapper, o.Typer = f.Object()
 | 
				
			||||||
	o.Encoder = f.JSONEncoder()
 | 
						o.Encoder = f.JSONEncoder()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -135,8 +132,7 @@ func (o *PauseConfig) CompletePause(f cmdutil.Factory, cmd *cobra.Command, out i
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func (o PauseConfig) RunPause() error {
 | 
					func (o PauseConfig) RunPause() error {
 | 
				
			||||||
	allErrs := []error{}
 | 
						allErrs := []error{}
 | 
				
			||||||
	// Defaulting to SMPatchVersion_1_5 is safe, since Pauser only update a boolean variable
 | 
						for _, patch := range set.CalculatePatches(o.Infos, o.Encoder, o.Pauser) {
 | 
				
			||||||
	for _, patch := range set.CalculatePatches(o.f, o.Infos, o.Encoder, strategicpatch.SMPatchVersion_1_5, o.Pauser) {
 | 
					 | 
				
			||||||
		info := patch.Info
 | 
							info := patch.Info
 | 
				
			||||||
		if patch.Err != nil {
 | 
							if patch.Err != nil {
 | 
				
			||||||
			allErrs = append(allErrs, fmt.Errorf("error: %s %q %v", info.Mapping.Resource, info.Name, patch.Err))
 | 
								allErrs = append(allErrs, fmt.Errorf("error: %s %q %v", info.Mapping.Resource, info.Name, patch.Err))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -31,7 +31,6 @@ import (
 | 
				
			|||||||
	"k8s.io/kubernetes/pkg/kubectl/resource"
 | 
						"k8s.io/kubernetes/pkg/kubectl/resource"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/runtime"
 | 
						"k8s.io/kubernetes/pkg/runtime"
 | 
				
			||||||
	utilerrors "k8s.io/kubernetes/pkg/util/errors"
 | 
						utilerrors "k8s.io/kubernetes/pkg/util/errors"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/util/strategicpatch"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ResumeConfig is the start of the data required to perform the operation.  As new fields are added, add them here instead of
 | 
					// ResumeConfig is the start of the data required to perform the operation.  As new fields are added, add them here instead of
 | 
				
			||||||
@@ -39,7 +38,6 @@ import (
 | 
				
			|||||||
type ResumeConfig struct {
 | 
					type ResumeConfig struct {
 | 
				
			||||||
	resource.FilenameOptions
 | 
						resource.FilenameOptions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	f       cmdutil.Factory
 | 
					 | 
				
			||||||
	Resumer func(object *resource.Info) (bool, error)
 | 
						Resumer func(object *resource.Info) (bool, error)
 | 
				
			||||||
	Mapper  meta.RESTMapper
 | 
						Mapper  meta.RESTMapper
 | 
				
			||||||
	Typer   runtime.ObjectTyper
 | 
						Typer   runtime.ObjectTyper
 | 
				
			||||||
@@ -99,7 +97,6 @@ func (o *ResumeConfig) CompleteResume(f cmdutil.Factory, cmd *cobra.Command, out
 | 
				
			|||||||
		return cmdutil.UsageError(cmd, cmd.Use)
 | 
							return cmdutil.UsageError(cmd, cmd.Use)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	o.f = f
 | 
					 | 
				
			||||||
	o.Mapper, o.Typer = f.Object()
 | 
						o.Mapper, o.Typer = f.Object()
 | 
				
			||||||
	o.Encoder = f.JSONEncoder()
 | 
						o.Encoder = f.JSONEncoder()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -139,8 +136,7 @@ func (o *ResumeConfig) CompleteResume(f cmdutil.Factory, cmd *cobra.Command, out
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func (o ResumeConfig) RunResume() error {
 | 
					func (o ResumeConfig) RunResume() error {
 | 
				
			||||||
	allErrs := []error{}
 | 
						allErrs := []error{}
 | 
				
			||||||
	// Defaulting to SMPatchVersion_1_5 is safe, since Resumer only update a boolean variable
 | 
						for _, patch := range set.CalculatePatches(o.Infos, o.Encoder, o.Resumer) {
 | 
				
			||||||
	for _, patch := range set.CalculatePatches(o.f, o.Infos, o.Encoder, strategicpatch.SMPatchVersion_1_5, o.Resumer) {
 | 
					 | 
				
			||||||
		info := patch.Info
 | 
							info := patch.Info
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if patch.Err != nil {
 | 
							if patch.Err != nil {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,7 +23,7 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/api"
 | 
						"k8s.io/kubernetes/pkg/api"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/api/errors"
 | 
						"k8s.io/kubernetes/pkg/api/errors"
 | 
				
			||||||
	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
 | 
						kcmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/kubectl/resource"
 | 
						"k8s.io/kubernetes/pkg/kubectl/resource"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/runtime"
 | 
						"k8s.io/kubernetes/pkg/runtime"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/util/strategicpatch"
 | 
						"k8s.io/kubernetes/pkg/util/strategicpatch"
 | 
				
			||||||
@@ -61,7 +61,7 @@ func handlePodUpdateError(out io.Writer, err error, resource string) {
 | 
				
			|||||||
				return
 | 
									return
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			if ok := cmdutil.PrintErrorWithCauses(err, out); ok {
 | 
								if ok := kcmdutil.PrintErrorWithCauses(err, out); ok {
 | 
				
			||||||
				return
 | 
									return
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -120,10 +120,7 @@ type Patch struct {
 | 
				
			|||||||
// CalculatePatches calls the mutation function on each provided info object, and generates a strategic merge patch for
 | 
					// CalculatePatches calls the mutation function on each provided info object, and generates a strategic merge patch for
 | 
				
			||||||
// the changes in the object. Encoder must be able to encode the info into the appropriate destination type. If mutateFn
 | 
					// the changes in the object. Encoder must be able to encode the info into the appropriate destination type. If mutateFn
 | 
				
			||||||
// returns false, the object is not included in the final list of patches.
 | 
					// returns false, the object is not included in the final list of patches.
 | 
				
			||||||
// If local is true, it will be default to use SMPatchVersionLatest to calculate a patch without contacting the server to
 | 
					func CalculatePatches(infos []*resource.Info, encoder runtime.Encoder, mutateFn func(*resource.Info) (bool, error)) []*Patch {
 | 
				
			||||||
// get the server supported SMPatchVersion. If you are using a patch's Patch field generated in local mode, be careful.
 | 
					 | 
				
			||||||
// If local is false, it will talk to the server to check which StategicMergePatchVersion to use.
 | 
					 | 
				
			||||||
func CalculatePatches(f cmdutil.Factory, infos []*resource.Info, encoder runtime.Encoder, smPatchVersion strategicpatch.StrategicMergePatchVersion, mutateFn func(*resource.Info) (bool, error)) []*Patch {
 | 
					 | 
				
			||||||
	var patches []*Patch
 | 
						var patches []*Patch
 | 
				
			||||||
	for _, info := range infos {
 | 
						for _, info := range infos {
 | 
				
			||||||
		patch := &Patch{Info: info}
 | 
							patch := &Patch{Info: info}
 | 
				
			||||||
@@ -159,7 +156,7 @@ func CalculatePatches(f cmdutil.Factory, infos []*resource.Info, encoder runtime
 | 
				
			|||||||
			continue
 | 
								continue
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		patch.Patch, patch.Err = strategicpatch.CreateTwoWayMergePatch(patch.Before, patch.After, versioned, smPatchVersion)
 | 
							patch.Patch, patch.Err = strategicpatch.CreateTwoWayMergePatch(patch.Before, patch.After, versioned)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return patches
 | 
						return patches
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -28,7 +28,6 @@ import (
 | 
				
			|||||||
	"k8s.io/kubernetes/pkg/kubectl/resource"
 | 
						"k8s.io/kubernetes/pkg/kubectl/resource"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/runtime"
 | 
						"k8s.io/kubernetes/pkg/runtime"
 | 
				
			||||||
	utilerrors "k8s.io/kubernetes/pkg/util/errors"
 | 
						utilerrors "k8s.io/kubernetes/pkg/util/errors"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/util/strategicpatch"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ImageOptions is the start of the data required to perform the operation.  As new fields are added, add them here instead of
 | 
					// ImageOptions is the start of the data required to perform the operation.  As new fields are added, add them here instead of
 | 
				
			||||||
@@ -36,7 +35,6 @@ import (
 | 
				
			|||||||
type ImageOptions struct {
 | 
					type ImageOptions struct {
 | 
				
			||||||
	resource.FilenameOptions
 | 
						resource.FilenameOptions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	f           cmdutil.Factory
 | 
					 | 
				
			||||||
	Mapper      meta.RESTMapper
 | 
						Mapper      meta.RESTMapper
 | 
				
			||||||
	Typer       runtime.ObjectTyper
 | 
						Typer       runtime.ObjectTyper
 | 
				
			||||||
	Infos       []*resource.Info
 | 
						Infos       []*resource.Info
 | 
				
			||||||
@@ -110,7 +108,6 @@ func NewCmdImage(f cmdutil.Factory, out, err io.Writer) *cobra.Command {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (o *ImageOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
 | 
					func (o *ImageOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
 | 
				
			||||||
	o.f = f
 | 
					 | 
				
			||||||
	o.Mapper, o.Typer = f.Object()
 | 
						o.Mapper, o.Typer = f.Object()
 | 
				
			||||||
	o.UpdatePodSpecForObject = f.UpdatePodSpecForObject
 | 
						o.UpdatePodSpecForObject = f.UpdatePodSpecForObject
 | 
				
			||||||
	o.Encoder = f.JSONEncoder()
 | 
						o.Encoder = f.JSONEncoder()
 | 
				
			||||||
@@ -164,8 +161,8 @@ func (o *ImageOptions) Validate() error {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func (o *ImageOptions) Run() error {
 | 
					func (o *ImageOptions) Run() error {
 | 
				
			||||||
	allErrs := []error{}
 | 
						allErrs := []error{}
 | 
				
			||||||
	// Defauting to SMPatchVersion_1_5, since the func passed in doesn't update any lists of primitive
 | 
					
 | 
				
			||||||
	patches := CalculatePatches(o.f, o.Infos, o.Encoder, strategicpatch.SMPatchVersion_1_5, func(info *resource.Info) (bool, error) {
 | 
						patches := CalculatePatches(o.Infos, o.Encoder, func(info *resource.Info) (bool, error) {
 | 
				
			||||||
		transformed := false
 | 
							transformed := false
 | 
				
			||||||
		_, err := o.UpdatePodSpecForObject(info.Object, func(spec *api.PodSpec) error {
 | 
							_, err := o.UpdatePodSpecForObject(info.Object, func(spec *api.PodSpec) error {
 | 
				
			||||||
			for name, image := range o.ContainerImages {
 | 
								for name, image := range o.ContainerImages {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -31,7 +31,6 @@ import (
 | 
				
			|||||||
	"k8s.io/kubernetes/pkg/kubectl/resource"
 | 
						"k8s.io/kubernetes/pkg/kubectl/resource"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/runtime"
 | 
						"k8s.io/kubernetes/pkg/runtime"
 | 
				
			||||||
	utilerrors "k8s.io/kubernetes/pkg/util/errors"
 | 
						utilerrors "k8s.io/kubernetes/pkg/util/errors"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/util/strategicpatch"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var (
 | 
					var (
 | 
				
			||||||
@@ -61,7 +60,6 @@ var (
 | 
				
			|||||||
type ResourcesOptions struct {
 | 
					type ResourcesOptions struct {
 | 
				
			||||||
	resource.FilenameOptions
 | 
						resource.FilenameOptions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	f                 cmdutil.Factory
 | 
					 | 
				
			||||||
	Mapper            meta.RESTMapper
 | 
						Mapper            meta.RESTMapper
 | 
				
			||||||
	Typer             runtime.ObjectTyper
 | 
						Typer             runtime.ObjectTyper
 | 
				
			||||||
	Infos             []*resource.Info
 | 
						Infos             []*resource.Info
 | 
				
			||||||
@@ -126,7 +124,6 @@ func NewCmdResources(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (o *ResourcesOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
 | 
					func (o *ResourcesOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
 | 
				
			||||||
	o.f = f
 | 
					 | 
				
			||||||
	o.Mapper, o.Typer = f.Object()
 | 
						o.Mapper, o.Typer = f.Object()
 | 
				
			||||||
	o.UpdatePodSpecForObject = f.UpdatePodSpecForObject
 | 
						o.UpdatePodSpecForObject = f.UpdatePodSpecForObject
 | 
				
			||||||
	o.Encoder = f.JSONEncoder()
 | 
						o.Encoder = f.JSONEncoder()
 | 
				
			||||||
@@ -177,8 +174,7 @@ func (o *ResourcesOptions) Validate() error {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func (o *ResourcesOptions) Run() error {
 | 
					func (o *ResourcesOptions) Run() error {
 | 
				
			||||||
	allErrs := []error{}
 | 
						allErrs := []error{}
 | 
				
			||||||
	// Defauting to SMPatchVersion_1_5, since the func passed in doesn't update any lists of primitive
 | 
						patches := CalculatePatches(o.Infos, o.Encoder, func(info *resource.Info) (bool, error) {
 | 
				
			||||||
	patches := CalculatePatches(o.f, o.Infos, o.Encoder, strategicpatch.SMPatchVersion_1_5, func(info *resource.Info) (bool, error) {
 | 
					 | 
				
			||||||
		transformed := false
 | 
							transformed := false
 | 
				
			||||||
		_, err := o.UpdatePodSpecForObject(info.Object, func(spec *api.PodSpec) error {
 | 
							_, err := o.UpdatePodSpecForObject(info.Object, func(spec *api.PodSpec) error {
 | 
				
			||||||
			containers, _ := selectContainers(spec.Containers, o.ContainerSelector)
 | 
								containers, _ := selectContainers(spec.Containers, o.ContainerSelector)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -343,8 +343,7 @@ func (o TaintOptions) RunTaint() error {
 | 
				
			|||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		// Defaulting to SMPatchVersion_1_5 is safe, since we don't update list of primitives.
 | 
							patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, obj)
 | 
				
			||||||
		patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, obj, strategicpatch.SMPatchVersion_1_5)
 | 
					 | 
				
			||||||
		createdPatch := err == nil
 | 
							createdPatch := err == nil
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			glog.V(2).Infof("couldn't compute patch: %v", err)
 | 
								glog.V(2).Infof("couldn't compute patch: %v", err)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -252,6 +252,7 @@ func TestTaint(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	for _, test := range tests {
 | 
						for _, test := range tests {
 | 
				
			||||||
		oldNode, expectNewNode := generateNodeAndTaintedNode(test.oldTaints, test.newTaints)
 | 
							oldNode, expectNewNode := generateNodeAndTaintedNode(test.oldTaints, test.newTaints)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		new_node := &api.Node{}
 | 
							new_node := &api.Node{}
 | 
				
			||||||
		tainted := false
 | 
							tainted := false
 | 
				
			||||||
		f, tf, codec, ns := cmdtesting.NewAPIFactory()
 | 
							f, tf, codec, ns := cmdtesting.NewAPIFactory()
 | 
				
			||||||
@@ -261,12 +262,6 @@ func TestTaint(t *testing.T) {
 | 
				
			|||||||
			Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
 | 
								Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
 | 
				
			||||||
				m := &MyReq{req}
 | 
									m := &MyReq{req}
 | 
				
			||||||
				switch {
 | 
									switch {
 | 
				
			||||||
				case m.isFor("GET", "/version"):
 | 
					 | 
				
			||||||
					resp, err := genResponseWithJsonEncodedBody(serverVersion_1_5_0)
 | 
					 | 
				
			||||||
					if err != nil {
 | 
					 | 
				
			||||||
						t.Fatalf("error: failed to generate server version response: %#v\n", serverVersion_1_5_0)
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
					return resp, nil
 | 
					 | 
				
			||||||
				case m.isFor("GET", "/nodes/node-name"):
 | 
									case m.isFor("GET", "/nodes/node-name"):
 | 
				
			||||||
					return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, oldNode)}, nil
 | 
										return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, oldNode)}, nil
 | 
				
			||||||
				case m.isFor("PATCH", "/nodes/node-name"), m.isFor("PUT", "/nodes/node-name"):
 | 
									case m.isFor("PATCH", "/nodes/node-name"), m.isFor("PUT", "/nodes/node-name"):
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -427,12 +427,8 @@ func (f *fakeAPIFactory) UnstructuredObject() (meta.RESTMapper, runtime.ObjectTy
 | 
				
			|||||||
	return cmdutil.NewShortcutExpander(mapper, nil), typer, nil
 | 
						return cmdutil.NewShortcutExpander(mapper, nil), typer, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (f *fakeAPIFactory) Decoder(toInternal bool) runtime.Decoder {
 | 
					func (f *fakeAPIFactory) Decoder(bool) runtime.Decoder {
 | 
				
			||||||
	if toInternal {
 | 
						return testapi.Default.Codec()
 | 
				
			||||||
		return api.Codecs.UniversalDecoder()
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		return api.Codecs.UniversalDeserializer()
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (f *fakeAPIFactory) JSONEncoder() runtime.Encoder {
 | 
					func (f *fakeAPIFactory) JSONEncoder() runtime.Encoder {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -533,8 +533,7 @@ func ChangeResourcePatch(info *resource.Info, changeCause string) ([]byte, error
 | 
				
			|||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	// Using SMPatchVersion_1_5, since RecordChangeCause() just update the annotation which is a map[string]string
 | 
						return strategicpatch.CreateTwoWayMergePatch(oldData, newData, info.Object)
 | 
				
			||||||
	return strategicpatch.CreateTwoWayMergePatch(oldData, newData, info.Object, strategicpatch.SMPatchVersion_1_5)
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// containsChangeCause checks if input resource info contains change-cause annotation.
 | 
					// containsChangeCause checks if input resource info contains change-cause annotation.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -38,20 +38,11 @@ import (
 | 
				
			|||||||
// Some of the content of this package was borrowed with minor adaptations from
 | 
					// Some of the content of this package was borrowed with minor adaptations from
 | 
				
			||||||
// evanphx/json-patch and openshift/origin.
 | 
					// evanphx/json-patch and openshift/origin.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type StrategicMergePatchVersion string
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	directiveMarker  = "$patch"
 | 
						directiveMarker  = "$patch"
 | 
				
			||||||
	deleteDirective  = "delete"
 | 
						deleteDirective  = "delete"
 | 
				
			||||||
	replaceDirective = "replace"
 | 
						replaceDirective = "replace"
 | 
				
			||||||
	mergeDirective   = "merge"
 | 
						mergeDirective   = "merge"
 | 
				
			||||||
	MergePrimitivesListDirective = "mergeprimitiveslist"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// different versions of StrategicMergePatch
 | 
					 | 
				
			||||||
	SMPatchVersion_1_0   StrategicMergePatchVersion = "v1.0.0"
 | 
					 | 
				
			||||||
	SMPatchVersion_1_5   StrategicMergePatchVersion = "v1.5.0"
 | 
					 | 
				
			||||||
	Unknown              StrategicMergePatchVersion = "Unknown"
 | 
					 | 
				
			||||||
	SMPatchVersionLatest                            = SMPatchVersion_1_5
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// IsPreconditionFailed returns true if the provided error indicates
 | 
					// IsPreconditionFailed returns true if the provided error indicates
 | 
				
			||||||
@@ -96,7 +87,6 @@ func IsConflict(err error) bool {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
var errBadJSONDoc = fmt.Errorf("Invalid JSON document")
 | 
					var errBadJSONDoc = fmt.Errorf("Invalid JSON document")
 | 
				
			||||||
var errNoListOfLists = fmt.Errorf("Lists of lists are not supported")
 | 
					var errNoListOfLists = fmt.Errorf("Lists of lists are not supported")
 | 
				
			||||||
var errNoElementsInSlice = fmt.Errorf("no elements in any of the given slices")
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
// The following code is adapted from github.com/openshift/origin/pkg/util/jsonmerge.
 | 
					// The following code is adapted from github.com/openshift/origin/pkg/util/jsonmerge.
 | 
				
			||||||
// Instead of defining a Delta that holds an original, a patch and a set of preconditions,
 | 
					// Instead of defining a Delta that holds an original, a patch and a set of preconditions,
 | 
				
			||||||
@@ -143,15 +133,15 @@ func RequireMetadataKeyUnchanged(key string) PreconditionFunc {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Deprecated: Use the synonym CreateTwoWayMergePatch, instead.
 | 
					// Deprecated: Use the synonym CreateTwoWayMergePatch, instead.
 | 
				
			||||||
func CreateStrategicMergePatch(original, modified []byte, dataStruct interface{}, smPatchVersion StrategicMergePatchVersion) ([]byte, error) {
 | 
					func CreateStrategicMergePatch(original, modified []byte, dataStruct interface{}) ([]byte, error) {
 | 
				
			||||||
	return CreateTwoWayMergePatch(original, modified, dataStruct, smPatchVersion)
 | 
						return CreateTwoWayMergePatch(original, modified, dataStruct)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// CreateTwoWayMergePatch creates a patch that can be passed to StrategicMergePatch from an original
 | 
					// CreateTwoWayMergePatch creates a patch that can be passed to StrategicMergePatch from an original
 | 
				
			||||||
// document and a modified document, which are passed to the method as json encoded content. It will
 | 
					// document and a modified document, which are passed to the method as json encoded content. It will
 | 
				
			||||||
// return a patch that yields the modified document when applied to the original document, or an error
 | 
					// return a patch that yields the modified document when applied to the original document, or an error
 | 
				
			||||||
// if either of the two documents is invalid.
 | 
					// if either of the two documents is invalid.
 | 
				
			||||||
func CreateTwoWayMergePatch(original, modified []byte, dataStruct interface{}, smPatchVersion StrategicMergePatchVersion, fns ...PreconditionFunc) ([]byte, error) {
 | 
					func CreateTwoWayMergePatch(original, modified []byte, dataStruct interface{}, fns ...PreconditionFunc) ([]byte, error) {
 | 
				
			||||||
	originalMap := map[string]interface{}{}
 | 
						originalMap := map[string]interface{}{}
 | 
				
			||||||
	if len(original) > 0 {
 | 
						if len(original) > 0 {
 | 
				
			||||||
		if err := json.Unmarshal(original, &originalMap); err != nil {
 | 
							if err := json.Unmarshal(original, &originalMap); err != nil {
 | 
				
			||||||
@@ -171,7 +161,7 @@ func CreateTwoWayMergePatch(original, modified []byte, dataStruct interface{}, s
 | 
				
			|||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	patchMap, err := diffMaps(originalMap, modifiedMap, t, false, false, smPatchVersion)
 | 
						patchMap, err := diffMaps(originalMap, modifiedMap, t, false, false)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -187,7 +177,7 @@ func CreateTwoWayMergePatch(original, modified []byte, dataStruct interface{}, s
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Returns a (recursive) strategic merge patch that yields modified when applied to original.
 | 
					// Returns a (recursive) strategic merge patch that yields modified when applied to original.
 | 
				
			||||||
func diffMaps(original, modified map[string]interface{}, t reflect.Type, ignoreChangesAndAdditions, ignoreDeletions bool, smPatchVersion StrategicMergePatchVersion) (map[string]interface{}, error) {
 | 
					func diffMaps(original, modified map[string]interface{}, t reflect.Type, ignoreChangesAndAdditions, ignoreDeletions bool) (map[string]interface{}, error) {
 | 
				
			||||||
	patch := map[string]interface{}{}
 | 
						patch := map[string]interface{}{}
 | 
				
			||||||
	if t.Kind() == reflect.Ptr {
 | 
						if t.Kind() == reflect.Ptr {
 | 
				
			||||||
		t = t.Elem()
 | 
							t = t.Elem()
 | 
				
			||||||
@@ -240,7 +230,7 @@ func diffMaps(original, modified map[string]interface{}, t reflect.Type, ignoreC
 | 
				
			|||||||
				return nil, err
 | 
									return nil, err
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			patchValue, err := diffMaps(originalValueTyped, modifiedValueTyped, fieldType, ignoreChangesAndAdditions, ignoreDeletions, smPatchVersion)
 | 
								patchValue, err := diffMaps(originalValueTyped, modifiedValueTyped, fieldType, ignoreChangesAndAdditions, ignoreDeletions)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return nil, err
 | 
									return nil, err
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -258,25 +248,13 @@ func diffMaps(original, modified map[string]interface{}, t reflect.Type, ignoreC
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if fieldPatchStrategy == mergeDirective {
 | 
								if fieldPatchStrategy == mergeDirective {
 | 
				
			||||||
				patchValue, err := diffLists(originalValueTyped, modifiedValueTyped, fieldType.Elem(), fieldPatchMergeKey, ignoreChangesAndAdditions, ignoreDeletions, smPatchVersion)
 | 
									patchValue, err := diffLists(originalValueTyped, modifiedValueTyped, fieldType.Elem(), fieldPatchMergeKey, ignoreChangesAndAdditions, ignoreDeletions)
 | 
				
			||||||
				if err != nil {
 | 
									if err != nil {
 | 
				
			||||||
					return nil, err
 | 
										return nil, err
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				if patchValue == nil {
 | 
					 | 
				
			||||||
					continue
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
				switch typedPatchValue := patchValue.(type) {
 | 
									if len(patchValue) > 0 {
 | 
				
			||||||
				case []interface{}:
 | 
										patch[key] = patchValue
 | 
				
			||||||
					if len(typedPatchValue) > 0 {
 | 
					 | 
				
			||||||
						patch[key] = typedPatchValue
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
				case map[string]interface{}:
 | 
					 | 
				
			||||||
					if len(typedPatchValue) > 0 {
 | 
					 | 
				
			||||||
						patch[key] = typedPatchValue
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
				default:
 | 
					 | 
				
			||||||
					return nil, fmt.Errorf("invalid type of patch: %v", reflect.TypeOf(patchValue))
 | 
					 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				continue
 | 
									continue
 | 
				
			||||||
@@ -306,7 +284,7 @@ func diffMaps(original, modified map[string]interface{}, t reflect.Type, ignoreC
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// Returns a (recursive) strategic merge patch that yields modified when applied to original,
 | 
					// Returns a (recursive) strategic merge patch that yields modified when applied to original,
 | 
				
			||||||
// for a pair of lists with merge semantics.
 | 
					// for a pair of lists with merge semantics.
 | 
				
			||||||
func diffLists(original, modified []interface{}, t reflect.Type, mergeKey string, ignoreChangesAndAdditions, ignoreDeletions bool, smPatchVersion StrategicMergePatchVersion) (interface{}, error) {
 | 
					func diffLists(original, modified []interface{}, t reflect.Type, mergeKey string, ignoreChangesAndAdditions, ignoreDeletions bool) ([]interface{}, error) {
 | 
				
			||||||
	if len(original) == 0 {
 | 
						if len(original) == 0 {
 | 
				
			||||||
		if len(modified) == 0 || ignoreChangesAndAdditions {
 | 
							if len(modified) == 0 || ignoreChangesAndAdditions {
 | 
				
			||||||
			return nil, nil
 | 
								return nil, nil
 | 
				
			||||||
@@ -320,14 +298,12 @@ func diffLists(original, modified []interface{}, t reflect.Type, mergeKey string
 | 
				
			|||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var patch interface{}
 | 
						var patch []interface{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if elementType.Kind() == reflect.Map {
 | 
						if elementType.Kind() == reflect.Map {
 | 
				
			||||||
		patch, err = diffListsOfMaps(original, modified, t, mergeKey, ignoreChangesAndAdditions, ignoreDeletions, smPatchVersion)
 | 
							patch, err = diffListsOfMaps(original, modified, t, mergeKey, ignoreChangesAndAdditions, ignoreDeletions)
 | 
				
			||||||
	} else if elementType.Kind() == reflect.Slice {
 | 
						} else if !ignoreChangesAndAdditions {
 | 
				
			||||||
		err = errNoListOfLists
 | 
							patch, err = diffListsOfScalars(original, modified)
 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		patch, err = diffListsOfScalars(original, modified, ignoreChangesAndAdditions, ignoreDeletions, smPatchVersion)
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
@@ -339,23 +315,8 @@ func diffLists(original, modified []interface{}, t reflect.Type, mergeKey string
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// Returns a (recursive) strategic merge patch that yields modified when applied to original,
 | 
					// Returns a (recursive) strategic merge patch that yields modified when applied to original,
 | 
				
			||||||
// for a pair of lists of scalars with merge semantics.
 | 
					// for a pair of lists of scalars with merge semantics.
 | 
				
			||||||
func diffListsOfScalars(original, modified []interface{}, ignoreChangesAndAdditions, ignoreDeletions bool, smPatchVersion StrategicMergePatchVersion) (interface{}, error) {
 | 
					func diffListsOfScalars(original, modified []interface{}) ([]interface{}, error) {
 | 
				
			||||||
	originalScalars := uniqifyAndSortScalars(original)
 | 
						if len(modified) == 0 {
 | 
				
			||||||
	modifiedScalars := uniqifyAndSortScalars(modified)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	switch smPatchVersion {
 | 
					 | 
				
			||||||
	case SMPatchVersion_1_5:
 | 
					 | 
				
			||||||
		return diffListsOfScalarsIntoMap(originalScalars, modifiedScalars, ignoreChangesAndAdditions, ignoreDeletions)
 | 
					 | 
				
			||||||
	case SMPatchVersion_1_0:
 | 
					 | 
				
			||||||
		return diffListsOfScalarsIntoSlice(originalScalars, modifiedScalars, ignoreChangesAndAdditions, ignoreDeletions)
 | 
					 | 
				
			||||||
	default:
 | 
					 | 
				
			||||||
		return nil, fmt.Errorf("Unknown StrategicMergePatchVersion: %v", smPatchVersion)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func diffListsOfScalarsIntoSlice(originalScalars, modifiedScalars []interface{}, ignoreChangesAndAdditions, ignoreDeletions bool) ([]interface{}, error) {
 | 
					 | 
				
			||||||
	originalIndex, modifiedIndex := 0, 0
 | 
					 | 
				
			||||||
	if len(modifiedScalars) == 0 {
 | 
					 | 
				
			||||||
		// There is no need to check the length of original because there is no way to create
 | 
							// There is no need to check the length of original because there is no way to create
 | 
				
			||||||
		// a patch that deletes a scalar from a list of scalars with merge semantics.
 | 
							// a patch that deletes a scalar from a list of scalars with merge semantics.
 | 
				
			||||||
		return nil, nil
 | 
							return nil, nil
 | 
				
			||||||
@@ -363,14 +324,18 @@ func diffListsOfScalarsIntoSlice(originalScalars, modifiedScalars []interface{},
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	patch := []interface{}{}
 | 
						patch := []interface{}{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						originalScalars := uniqifyAndSortScalars(original)
 | 
				
			||||||
 | 
						modifiedScalars := uniqifyAndSortScalars(modified)
 | 
				
			||||||
 | 
						originalIndex, modifiedIndex := 0, 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
loopB:
 | 
					loopB:
 | 
				
			||||||
	for ; modifiedIndex < len(modifiedScalars); modifiedIndex++ {
 | 
						for ; modifiedIndex < len(modifiedScalars); modifiedIndex++ {
 | 
				
			||||||
		for ; originalIndex < len(originalScalars); originalIndex++ {
 | 
							for ; originalIndex < len(originalScalars); originalIndex++ {
 | 
				
			||||||
			originalString := fmt.Sprintf("%v", originalScalars[originalIndex])
 | 
								originalString := fmt.Sprintf("%v", original[originalIndex])
 | 
				
			||||||
			modifiedString := fmt.Sprintf("%v", modifiedScalars[modifiedIndex])
 | 
								modifiedString := fmt.Sprintf("%v", modified[modifiedIndex])
 | 
				
			||||||
			if originalString >= modifiedString {
 | 
								if originalString >= modifiedString {
 | 
				
			||||||
				if originalString != modifiedString {
 | 
									if originalString != modifiedString {
 | 
				
			||||||
					patch = append(patch, modifiedScalars[modifiedIndex])
 | 
										patch = append(patch, modified[modifiedIndex])
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				continue loopB
 | 
									continue loopB
 | 
				
			||||||
@@ -384,57 +349,7 @@ loopB:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	// Add any remaining items found only in modified
 | 
						// Add any remaining items found only in modified
 | 
				
			||||||
	for ; modifiedIndex < len(modifiedScalars); modifiedIndex++ {
 | 
						for ; modifiedIndex < len(modifiedScalars); modifiedIndex++ {
 | 
				
			||||||
		patch = append(patch, modifiedScalars[modifiedIndex])
 | 
							patch = append(patch, modified[modifiedIndex])
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return patch, nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func diffListsOfScalarsIntoMap(originalScalars, modifiedScalars []interface{}, ignoreChangesAndAdditions, ignoreDeletions bool) (map[string]interface{}, error) {
 | 
					 | 
				
			||||||
	originalIndex, modifiedIndex := 0, 0
 | 
					 | 
				
			||||||
	patch := map[string]interface{}{}
 | 
					 | 
				
			||||||
	patch[directiveMarker] = MergePrimitivesListDirective
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for originalIndex < len(originalScalars) && modifiedIndex < len(modifiedScalars) {
 | 
					 | 
				
			||||||
		originalString := fmt.Sprintf("%v", originalScalars[originalIndex])
 | 
					 | 
				
			||||||
		modifiedString := fmt.Sprintf("%v", modifiedScalars[modifiedIndex])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// objects are identical
 | 
					 | 
				
			||||||
		if originalString == modifiedString {
 | 
					 | 
				
			||||||
			originalIndex++
 | 
					 | 
				
			||||||
			modifiedIndex++
 | 
					 | 
				
			||||||
			continue
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if originalString > modifiedString {
 | 
					 | 
				
			||||||
			if !ignoreChangesAndAdditions {
 | 
					 | 
				
			||||||
				modifiedValue := modifiedScalars[modifiedIndex]
 | 
					 | 
				
			||||||
				patch[modifiedString] = modifiedValue
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			modifiedIndex++
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			if !ignoreDeletions {
 | 
					 | 
				
			||||||
				patch[originalString] = nil
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			originalIndex++
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Delete any remaining items found only in original
 | 
					 | 
				
			||||||
	if !ignoreDeletions {
 | 
					 | 
				
			||||||
		for ; originalIndex < len(originalScalars); originalIndex++ {
 | 
					 | 
				
			||||||
			originalString := fmt.Sprintf("%v", originalScalars[originalIndex])
 | 
					 | 
				
			||||||
			patch[originalString] = nil
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Add any remaining items found only in modified
 | 
					 | 
				
			||||||
	if !ignoreChangesAndAdditions {
 | 
					 | 
				
			||||||
		for ; modifiedIndex < len(modifiedScalars); modifiedIndex++ {
 | 
					 | 
				
			||||||
			modifiedString := fmt.Sprintf("%v", modifiedScalars[modifiedIndex])
 | 
					 | 
				
			||||||
			modifiedValue := modifiedScalars[modifiedIndex]
 | 
					 | 
				
			||||||
			patch[modifiedString] = modifiedValue
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return patch, nil
 | 
						return patch, nil
 | 
				
			||||||
@@ -445,7 +360,7 @@ var errBadArgTypeFmt = "expected a %s, but received a %s"
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// Returns a (recursive) strategic merge patch that yields modified when applied to original,
 | 
					// Returns a (recursive) strategic merge patch that yields modified when applied to original,
 | 
				
			||||||
// for a pair of lists of maps with merge semantics.
 | 
					// for a pair of lists of maps with merge semantics.
 | 
				
			||||||
func diffListsOfMaps(original, modified []interface{}, t reflect.Type, mergeKey string, ignoreChangesAndAdditions, ignoreDeletions bool, smPatchVersion StrategicMergePatchVersion) ([]interface{}, error) {
 | 
					func diffListsOfMaps(original, modified []interface{}, t reflect.Type, mergeKey string, ignoreChangesAndAdditions, ignoreDeletions bool) ([]interface{}, error) {
 | 
				
			||||||
	patch := make([]interface{}, 0)
 | 
						patch := make([]interface{}, 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	originalSorted, err := sortMergeListsByNameArray(original, t, mergeKey, false)
 | 
						originalSorted, err := sortMergeListsByNameArray(original, t, mergeKey, false)
 | 
				
			||||||
@@ -491,7 +406,7 @@ loopB:
 | 
				
			|||||||
			if originalString >= modifiedString {
 | 
								if originalString >= modifiedString {
 | 
				
			||||||
				if originalString == modifiedString {
 | 
									if originalString == modifiedString {
 | 
				
			||||||
					// Merge key values are equal, so recurse
 | 
										// Merge key values are equal, so recurse
 | 
				
			||||||
					patchValue, err := diffMaps(originalMap, modifiedMap, t, ignoreChangesAndAdditions, ignoreDeletions, smPatchVersion)
 | 
										patchValue, err := diffMaps(originalMap, modifiedMap, t, ignoreChangesAndAdditions, ignoreDeletions)
 | 
				
			||||||
					if err != nil {
 | 
										if err != nil {
 | 
				
			||||||
						return nil, err
 | 
											return nil, err
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
@@ -627,16 +542,8 @@ func mergeMap(original, patch map[string]interface{}, t reflect.Type) (map[strin
 | 
				
			|||||||
			return map[string]interface{}{}, nil
 | 
								return map[string]interface{}{}, nil
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if v == MergePrimitivesListDirective {
 | 
					 | 
				
			||||||
			// delete the directiveMarker's key-value pair to avoid delta map and delete map
 | 
					 | 
				
			||||||
			// overlaping with each other when calculating a ThreeWayDiff for list of Primitives.
 | 
					 | 
				
			||||||
			// Otherwise, the overlaping will cause it calling LookupPatchMetadata() which will
 | 
					 | 
				
			||||||
			// return an error since the metadata shows it's a slice but it is actually a map.
 | 
					 | 
				
			||||||
			delete(original, directiveMarker)
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
		return nil, fmt.Errorf(errBadPatchTypeFmt, v, patch)
 | 
							return nil, fmt.Errorf(errBadPatchTypeFmt, v, patch)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// nil is an accepted value for original to simplify logic in other places.
 | 
						// nil is an accepted value for original to simplify logic in other places.
 | 
				
			||||||
	// If original is nil, replace it with an empty map and then apply the patch.
 | 
						// If original is nil, replace it with an empty map and then apply the patch.
 | 
				
			||||||
@@ -671,9 +578,7 @@ func mergeMap(original, patch map[string]interface{}, t reflect.Type) (map[strin
 | 
				
			|||||||
		// If they're both maps or lists, recurse into the value.
 | 
							// If they're both maps or lists, recurse into the value.
 | 
				
			||||||
		originalType := reflect.TypeOf(original[k])
 | 
							originalType := reflect.TypeOf(original[k])
 | 
				
			||||||
		patchType := reflect.TypeOf(patchV)
 | 
							patchType := reflect.TypeOf(patchV)
 | 
				
			||||||
		// check if we are trying to merge a slice with a map for list of primitives
 | 
							if originalType == patchType {
 | 
				
			||||||
		isMergeSliceOfPrimitivesWithAPatchMap := originalType != nil && patchType != nil && originalType.Kind() == reflect.Slice && patchType.Kind() == reflect.Map
 | 
					 | 
				
			||||||
		if originalType == patchType || isMergeSliceOfPrimitivesWithAPatchMap {
 | 
					 | 
				
			||||||
			// First find the fieldPatchStrategy and fieldPatchMergeKey.
 | 
								// First find the fieldPatchStrategy and fieldPatchMergeKey.
 | 
				
			||||||
			fieldType, fieldPatchStrategy, fieldPatchMergeKey, err := forkedjson.LookupPatchMetadata(t, k)
 | 
								fieldType, fieldPatchStrategy, fieldPatchMergeKey, err := forkedjson.LookupPatchMetadata(t, k)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
@@ -695,8 +600,9 @@ func mergeMap(original, patch map[string]interface{}, t reflect.Type) (map[strin
 | 
				
			|||||||
			if originalType.Kind() == reflect.Slice && fieldPatchStrategy == mergeDirective {
 | 
								if originalType.Kind() == reflect.Slice && fieldPatchStrategy == mergeDirective {
 | 
				
			||||||
				elemType := fieldType.Elem()
 | 
									elemType := fieldType.Elem()
 | 
				
			||||||
				typedOriginal := original[k].([]interface{})
 | 
									typedOriginal := original[k].([]interface{})
 | 
				
			||||||
 | 
									typedPatch := patchV.([]interface{})
 | 
				
			||||||
				var err error
 | 
									var err error
 | 
				
			||||||
				original[k], err = mergeSlice(typedOriginal, patchV, elemType, fieldPatchMergeKey)
 | 
									original[k], err = mergeSlice(typedOriginal, typedPatch, elemType, fieldPatchMergeKey)
 | 
				
			||||||
				if err != nil {
 | 
									if err != nil {
 | 
				
			||||||
					return nil, err
 | 
										return nil, err
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
@@ -717,34 +623,13 @@ func mergeMap(original, patch map[string]interface{}, t reflect.Type) (map[strin
 | 
				
			|||||||
// Merge two slices together. Note: This may modify both the original slice and
 | 
					// Merge two slices together. Note: This may modify both the original slice and
 | 
				
			||||||
// the patch because getting a deep copy of a slice in golang is highly
 | 
					// the patch because getting a deep copy of a slice in golang is highly
 | 
				
			||||||
// non-trivial.
 | 
					// non-trivial.
 | 
				
			||||||
// The patch could be a map[string]interface{} representing a slice of primitives.
 | 
					func mergeSlice(original, patch []interface{}, elemType reflect.Type, mergeKey string) ([]interface{}, error) {
 | 
				
			||||||
// If the patch map doesn't has the specific directiveMarker (MergePrimitivesListDirective),
 | 
						if len(original) == 0 && len(patch) == 0 {
 | 
				
			||||||
// it returns an error. Please check patch_test.go and find the test case named
 | 
					 | 
				
			||||||
// "merge lists of scalars for list of primitives" to see what the patch looks like.
 | 
					 | 
				
			||||||
// Patch is still []interface{} for all the other types.
 | 
					 | 
				
			||||||
func mergeSlice(original []interface{}, patch interface{}, elemType reflect.Type, mergeKey string) ([]interface{}, error) {
 | 
					 | 
				
			||||||
	t, err := sliceElementType(original)
 | 
					 | 
				
			||||||
	if err != nil && err != errNoElementsInSlice {
 | 
					 | 
				
			||||||
		return nil, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if patchMap, ok := patch.(map[string]interface{}); ok {
 | 
					 | 
				
			||||||
		// We try to merge the original slice with a patch map only when the map has
 | 
					 | 
				
			||||||
		// a specific directiveMarker. Otherwise, this patch will be treated as invalid.
 | 
					 | 
				
			||||||
		if directiveValue, ok := patchMap[directiveMarker]; ok && directiveValue == MergePrimitivesListDirective {
 | 
					 | 
				
			||||||
			return mergeSliceOfScalarsWithPatchMap(original, patchMap)
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			return nil, fmt.Errorf("Unable to merge a slice with an invalid map")
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	typedPatch := patch.([]interface{})
 | 
					 | 
				
			||||||
	if len(original) == 0 && len(typedPatch) == 0 {
 | 
					 | 
				
			||||||
		return original, nil
 | 
							return original, nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// All the values must be of the same type, but not a list.
 | 
						// All the values must be of the same type, but not a list.
 | 
				
			||||||
	t, err = sliceElementType(original, typedPatch)
 | 
						t, err := sliceElementType(original, patch)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -753,7 +638,7 @@ func mergeSlice(original []interface{}, patch interface{}, elemType reflect.Type
 | 
				
			|||||||
	if t.Kind() != reflect.Map {
 | 
						if t.Kind() != reflect.Map {
 | 
				
			||||||
		// Maybe in the future add a "concat" mode that doesn't
 | 
							// Maybe in the future add a "concat" mode that doesn't
 | 
				
			||||||
		// uniqify.
 | 
							// uniqify.
 | 
				
			||||||
		both := append(original, typedPatch...)
 | 
							both := append(original, patch...)
 | 
				
			||||||
		return uniqifyScalars(both), nil
 | 
							return uniqifyScalars(both), nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -764,7 +649,7 @@ func mergeSlice(original []interface{}, patch interface{}, elemType reflect.Type
 | 
				
			|||||||
	// First look for any special $patch elements.
 | 
						// First look for any special $patch elements.
 | 
				
			||||||
	patchWithoutSpecialElements := []interface{}{}
 | 
						patchWithoutSpecialElements := []interface{}{}
 | 
				
			||||||
	replace := false
 | 
						replace := false
 | 
				
			||||||
	for _, v := range typedPatch {
 | 
						for _, v := range patch {
 | 
				
			||||||
		typedV := v.(map[string]interface{})
 | 
							typedV := v.(map[string]interface{})
 | 
				
			||||||
		patchType, ok := typedV[directiveMarker]
 | 
							patchType, ok := typedV[directiveMarker]
 | 
				
			||||||
		if ok {
 | 
							if ok {
 | 
				
			||||||
@@ -800,10 +685,10 @@ func mergeSlice(original []interface{}, patch interface{}, elemType reflect.Type
 | 
				
			|||||||
		return patchWithoutSpecialElements, nil
 | 
							return patchWithoutSpecialElements, nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	typedPatch = patchWithoutSpecialElements
 | 
						patch = patchWithoutSpecialElements
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Merge patch into original.
 | 
						// Merge patch into original.
 | 
				
			||||||
	for _, v := range typedPatch {
 | 
						for _, v := range patch {
 | 
				
			||||||
		// Because earlier we confirmed that all the elements are maps.
 | 
							// Because earlier we confirmed that all the elements are maps.
 | 
				
			||||||
		typedV := v.(map[string]interface{})
 | 
							typedV := v.(map[string]interface{})
 | 
				
			||||||
		mergeValue, ok := typedV[mergeKey]
 | 
							mergeValue, ok := typedV[mergeKey]
 | 
				
			||||||
@@ -836,36 +721,6 @@ func mergeSlice(original []interface{}, patch interface{}, elemType reflect.Type
 | 
				
			|||||||
	return original, nil
 | 
						return original, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// mergeSliceOfScalarsWithPatchMap merges the original slice with a patch map and
 | 
					 | 
				
			||||||
// returns an uniqified and sorted slice of primitives.
 | 
					 | 
				
			||||||
// The patch map must have the specific directiveMarker (MergePrimitivesListDirective).
 | 
					 | 
				
			||||||
func mergeSliceOfScalarsWithPatchMap(original []interface{}, patch map[string]interface{}) ([]interface{}, error) {
 | 
					 | 
				
			||||||
	// make sure the patch has the specific directiveMarker ()
 | 
					 | 
				
			||||||
	if directiveValue, ok := patch[directiveMarker]; ok && directiveValue != MergePrimitivesListDirective {
 | 
					 | 
				
			||||||
		return nil, fmt.Errorf("Unable to merge a slice with an invalid map")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	delete(patch, directiveMarker)
 | 
					 | 
				
			||||||
	output := make([]interface{}, 0, len(original)+len(patch))
 | 
					 | 
				
			||||||
	for _, value := range original {
 | 
					 | 
				
			||||||
		valueString := fmt.Sprintf("%v", value)
 | 
					 | 
				
			||||||
		if v, ok := patch[valueString]; ok {
 | 
					 | 
				
			||||||
			if v != nil {
 | 
					 | 
				
			||||||
				output = append(output, v)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			delete(patch, valueString)
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			output = append(output, value)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	for _, value := range patch {
 | 
					 | 
				
			||||||
		if value != nil {
 | 
					 | 
				
			||||||
			output = append(output, value)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		// No action required to delete items that missing from the original slice.
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return uniqifyAndSortScalars(output), nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// This method no longer panics if any element of the slice is not a map.
 | 
					// This method no longer panics if any element of the slice is not a map.
 | 
				
			||||||
func findMapInSliceBasedOnKeyValue(m []interface{}, key string, value interface{}) (map[string]interface{}, int, bool, error) {
 | 
					func findMapInSliceBasedOnKeyValue(m []interface{}, key string, value interface{}) (map[string]interface{}, int, bool, error) {
 | 
				
			||||||
	for k, v := range m {
 | 
						for k, v := range m {
 | 
				
			||||||
@@ -1091,7 +946,7 @@ func sliceElementType(slices ...[]interface{}) (reflect.Type, error) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if prevType == nil {
 | 
						if prevType == nil {
 | 
				
			||||||
		return nil, errNoElementsInSlice
 | 
							return nil, fmt.Errorf("no elements in any of the given slices")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return prevType, nil
 | 
						return prevType, nil
 | 
				
			||||||
@@ -1180,10 +1035,6 @@ func mergingMapFieldsHaveConflicts(
 | 
				
			|||||||
				if leftMarker != rightMarker {
 | 
									if leftMarker != rightMarker {
 | 
				
			||||||
					return true, nil
 | 
										return true, nil
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					 | 
				
			||||||
				if leftMarker == MergePrimitivesListDirective && rightMarker == MergePrimitivesListDirective {
 | 
					 | 
				
			||||||
					return false, nil
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Check the individual keys.
 | 
								// Check the individual keys.
 | 
				
			||||||
@@ -1206,30 +1057,13 @@ func mergingMapFieldsHaveConflicts(
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func mapsHaveConflicts(typedLeft, typedRight map[string]interface{}, structType reflect.Type) (bool, error) {
 | 
					func mapsHaveConflicts(typedLeft, typedRight map[string]interface{}, structType reflect.Type) (bool, error) {
 | 
				
			||||||
	isForListOfPrimitives := false
 | 
					 | 
				
			||||||
	if leftDirective, ok := typedLeft[directiveMarker]; ok {
 | 
					 | 
				
			||||||
		if rightDirective, ok := typedRight[directiveMarker]; ok {
 | 
					 | 
				
			||||||
			if leftDirective == MergePrimitivesListDirective && rightDirective == rightDirective {
 | 
					 | 
				
			||||||
				isForListOfPrimitives = true
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	for key, leftValue := range typedLeft {
 | 
						for key, leftValue := range typedLeft {
 | 
				
			||||||
		if key != directiveMarker {
 | 
							if key != directiveMarker {
 | 
				
			||||||
			if rightValue, ok := typedRight[key]; ok {
 | 
								if rightValue, ok := typedRight[key]; ok {
 | 
				
			||||||
				var fieldType reflect.Type
 | 
									fieldType, fieldPatchStrategy, fieldPatchMergeKey, err := forkedjson.LookupPatchMetadata(structType, key)
 | 
				
			||||||
				var fieldPatchStrategy, fieldPatchMergeKey string
 | 
					 | 
				
			||||||
				var err error
 | 
					 | 
				
			||||||
				if isForListOfPrimitives {
 | 
					 | 
				
			||||||
					fieldType = reflect.TypeOf(leftValue)
 | 
					 | 
				
			||||||
					fieldPatchStrategy = ""
 | 
					 | 
				
			||||||
					fieldPatchMergeKey = ""
 | 
					 | 
				
			||||||
				} else {
 | 
					 | 
				
			||||||
					fieldType, fieldPatchStrategy, fieldPatchMergeKey, err = forkedjson.LookupPatchMetadata(structType, key)
 | 
					 | 
				
			||||||
				if err != nil {
 | 
									if err != nil {
 | 
				
			||||||
					return true, err
 | 
										return true, err
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if hasConflicts, err := mergingMapFieldsHaveConflicts(leftValue, rightValue,
 | 
									if hasConflicts, err := mergingMapFieldsHaveConflicts(leftValue, rightValue,
 | 
				
			||||||
					fieldType, fieldPatchStrategy, fieldPatchMergeKey); hasConflicts {
 | 
										fieldType, fieldPatchStrategy, fieldPatchMergeKey); hasConflicts {
 | 
				
			||||||
@@ -1338,7 +1172,7 @@ func mapsOfMapsHaveConflicts(typedLeft, typedRight map[string]interface{}, struc
 | 
				
			|||||||
// than from original to current. In other words, a conflict occurs if modified changes any key
 | 
					// than from original to current. In other words, a conflict occurs if modified changes any key
 | 
				
			||||||
// in a way that is different from how it is changed in current (e.g., deleting it, changing its
 | 
					// in a way that is different from how it is changed in current (e.g., deleting it, changing its
 | 
				
			||||||
// value).
 | 
					// value).
 | 
				
			||||||
func CreateThreeWayMergePatch(original, modified, current []byte, dataStruct interface{}, overwrite bool, smPatchVersion StrategicMergePatchVersion, fns ...PreconditionFunc) ([]byte, error) {
 | 
					func CreateThreeWayMergePatch(original, modified, current []byte, dataStruct interface{}, overwrite bool, fns ...PreconditionFunc) ([]byte, error) {
 | 
				
			||||||
	originalMap := map[string]interface{}{}
 | 
						originalMap := map[string]interface{}{}
 | 
				
			||||||
	if len(original) > 0 {
 | 
						if len(original) > 0 {
 | 
				
			||||||
		if err := json.Unmarshal(original, &originalMap); err != nil {
 | 
							if err := json.Unmarshal(original, &originalMap); err != nil {
 | 
				
			||||||
@@ -1369,12 +1203,12 @@ func CreateThreeWayMergePatch(original, modified, current []byte, dataStruct int
 | 
				
			|||||||
	// from original to modified. To find it, we compute deletions, which are the deletions from
 | 
						// from original to modified. To find it, we compute deletions, which are the deletions from
 | 
				
			||||||
	// original to modified, and delta, which is the difference from current to modified without
 | 
						// original to modified, and delta, which is the difference from current to modified without
 | 
				
			||||||
	// deletions, and then apply delta to deletions as a patch, which should be strictly additive.
 | 
						// deletions, and then apply delta to deletions as a patch, which should be strictly additive.
 | 
				
			||||||
	deltaMap, err := diffMaps(currentMap, modifiedMap, t, false, true, smPatchVersion)
 | 
						deltaMap, err := diffMaps(currentMap, modifiedMap, t, false, true)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	deletionsMap, err := diffMaps(originalMap, modifiedMap, t, true, false, smPatchVersion)
 | 
						deletionsMap, err := diffMaps(originalMap, modifiedMap, t, true, false)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -1394,7 +1228,7 @@ func CreateThreeWayMergePatch(original, modified, current []byte, dataStruct int
 | 
				
			|||||||
	// If overwrite is false, and the patch contains any keys that were changed differently,
 | 
						// If overwrite is false, and the patch contains any keys that were changed differently,
 | 
				
			||||||
	// then return a conflict error.
 | 
						// then return a conflict error.
 | 
				
			||||||
	if !overwrite {
 | 
						if !overwrite {
 | 
				
			||||||
		changedMap, err := diffMaps(originalMap, currentMap, t, false, false, smPatchVersion)
 | 
							changedMap, err := diffMaps(originalMap, currentMap, t, false, false)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return nil, err
 | 
								return nil, err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 
 | 
				
			|||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										2
									
								
								test/fixtures/pkg/kubectl/cmd/apply/rc.yaml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								test/fixtures/pkg/kubectl/cmd/apply/rc.yaml
									
									
									
									
										vendored
									
									
								
							@@ -1,8 +1,6 @@
 | 
				
			|||||||
apiVersion: v1
 | 
					apiVersion: v1
 | 
				
			||||||
kind: ReplicationController
 | 
					kind: ReplicationController
 | 
				
			||||||
metadata:
 | 
					metadata:
 | 
				
			||||||
  finalizers:
 | 
					 | 
				
			||||||
  - b/b
 | 
					 | 
				
			||||||
  name: test-rc
 | 
					  name: test-rc
 | 
				
			||||||
  labels:
 | 
					  labels:
 | 
				
			||||||
    name: test-rc
 | 
					    name: test-rc
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user