github.com/timstclair/heapster@v0.20.0-alpha1/Godeps/_workspace/src/k8s.io/kubernetes/pkg/util/strategicpatch/patch.go (about) 1 /* 2 Copyright 2014 The Kubernetes Authors All rights reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package strategicpatch 18 19 import ( 20 "encoding/json" 21 "fmt" 22 "reflect" 23 "sort" 24 25 forkedjson "k8s.io/kubernetes/third_party/forked/json" 26 ) 27 28 // An alternate implementation of JSON Merge Patch 29 // (https://tools.ietf.org/html/rfc7386) which supports the ability to annotate 30 // certain fields with metadata that indicates whether the elements of JSON 31 // lists should be merged or replaced. 32 // 33 // For more information, see the PATCH section of docs/devel/api-conventions.md. 34 // 35 // Some of the content of this package was borrowed with minor adaptations from 36 // evanphx/json-patch and openshift/origin. 37 38 const ( 39 directiveMarker = "$patch" 40 deleteDirective = "delete" 41 replaceDirective = "replace" 42 mergeDirective = "merge" 43 ) 44 45 // IsPreconditionFailed returns true if the provided error indicates 46 // a precondition failed. 47 func IsPreconditionFailed(err error) bool { 48 _, ok := err.(errPreconditionFailed) 49 return ok 50 } 51 52 type errPreconditionFailed struct { 53 message string 54 } 55 56 func newErrPreconditionFailed(target map[string]interface{}) errPreconditionFailed { 57 s := fmt.Sprintf("precondition failed for: %v", target) 58 return errPreconditionFailed{s} 59 } 60 61 func (err errPreconditionFailed) Error() string { 62 return err.message 63 } 64 65 type errConflict struct { 66 message string 67 } 68 69 func newErrConflict(patch, current []byte) errConflict { 70 s := fmt.Sprintf("patch:\n%s\nconflicts with current:\n%s\n", patch, current) 71 return errConflict{s} 72 } 73 74 func (err errConflict) Error() string { 75 return err.message 76 } 77 78 // IsConflict returns true if the provided error indicates 79 // a conflict between the patch and the current configuration. 80 func IsConflict(err error) bool { 81 _, ok := err.(errConflict) 82 return ok 83 } 84 85 var errBadJSONDoc = fmt.Errorf("Invalid JSON document") 86 var errNoListOfLists = fmt.Errorf("Lists of lists are not supported") 87 88 // The following code is adapted from github.com/openshift/origin/pkg/util/jsonmerge. 89 // Instead of defining a Delta that holds an original, a patch and a set of preconditions, 90 // the reconcile method accepts a set of preconditions as an argument. 91 92 // PreconditionFunc asserts that an incompatible change is not present within a patch. 93 type PreconditionFunc func(interface{}) bool 94 95 // RequireKeyUnchanged returns a precondition function that fails if the provided key 96 // is present in the patch (indicating that its value has changed). 97 func RequireKeyUnchanged(key string) PreconditionFunc { 98 return func(patch interface{}) bool { 99 patchMap, ok := patch.(map[string]interface{}) 100 if !ok { 101 return true 102 } 103 104 // The presence of key means that its value has been changed, so the test fails. 105 _, ok = patchMap[key] 106 return !ok 107 } 108 } 109 110 // Deprecated: Use the synonym CreateTwoWayMergePatch, instead. 111 func CreateStrategicMergePatch(original, modified []byte, dataStruct interface{}) ([]byte, error) { 112 return CreateTwoWayMergePatch(original, modified, dataStruct) 113 } 114 115 // CreateTwoWayMergePatch creates a patch that can be passed to StrategicMergePatch from an original 116 // document and a modified documernt, which are passed to the method as json encoded content. It will 117 // return a patch that yields the modified document when applied to the original document, or an error 118 // if either of the two documents is invalid. 119 func CreateTwoWayMergePatch(original, modified []byte, dataStruct interface{}, fns ...PreconditionFunc) ([]byte, error) { 120 originalMap := map[string]interface{}{} 121 if len(original) > 0 { 122 if err := json.Unmarshal(original, &originalMap); err != nil { 123 return nil, errBadJSONDoc 124 } 125 } 126 127 modifiedMap := map[string]interface{}{} 128 if len(modified) > 0 { 129 if err := json.Unmarshal(modified, &modifiedMap); err != nil { 130 return nil, errBadJSONDoc 131 } 132 } 133 134 t, err := getTagStructType(dataStruct) 135 if err != nil { 136 return nil, err 137 } 138 139 patchMap, err := diffMaps(originalMap, modifiedMap, t, false, false) 140 if err != nil { 141 return nil, err 142 } 143 144 // Apply the preconditions to the patch, and return an error if any of them fail. 145 for _, fn := range fns { 146 if !fn(patchMap) { 147 return nil, newErrPreconditionFailed(patchMap) 148 } 149 } 150 151 return json.Marshal(patchMap) 152 } 153 154 // Returns a (recursive) strategic merge patch that yields modified when applied to original. 155 func diffMaps(original, modified map[string]interface{}, t reflect.Type, ignoreChangesAndAdditions, ignoreDeletions bool) (map[string]interface{}, error) { 156 patch := map[string]interface{}{} 157 if t.Kind() == reflect.Ptr { 158 t = t.Elem() 159 } 160 161 for key, modifiedValue := range modified { 162 originalValue, ok := original[key] 163 if !ok { 164 // Key was added, so add to patch 165 if !ignoreChangesAndAdditions { 166 patch[key] = modifiedValue 167 } 168 169 continue 170 } 171 172 if key == directiveMarker { 173 originalString, ok := originalValue.(string) 174 if !ok { 175 return nil, fmt.Errorf("invalid value for special key: %s", directiveMarker) 176 } 177 178 modifiedString, ok := modifiedValue.(string) 179 if !ok { 180 return nil, fmt.Errorf("invalid value for special key: %s", directiveMarker) 181 } 182 183 if modifiedString != originalString { 184 patch[directiveMarker] = modifiedValue 185 } 186 187 continue 188 } 189 190 if reflect.TypeOf(originalValue) != reflect.TypeOf(modifiedValue) { 191 // Types have changed, so add to patch 192 if !ignoreChangesAndAdditions { 193 patch[key] = modifiedValue 194 } 195 196 continue 197 } 198 199 // Types are the same, so compare values 200 switch originalValueTyped := originalValue.(type) { 201 case map[string]interface{}: 202 modifiedValueTyped := modifiedValue.(map[string]interface{}) 203 fieldType, _, _, err := forkedjson.LookupPatchMetadata(t, key) 204 if err != nil { 205 return nil, err 206 } 207 208 patchValue, err := diffMaps(originalValueTyped, modifiedValueTyped, fieldType, ignoreChangesAndAdditions, ignoreDeletions) 209 if err != nil { 210 return nil, err 211 } 212 213 if len(patchValue) > 0 { 214 patch[key] = patchValue 215 } 216 217 continue 218 case []interface{}: 219 modifiedValueTyped := modifiedValue.([]interface{}) 220 fieldType, fieldPatchStrategy, fieldPatchMergeKey, err := forkedjson.LookupPatchMetadata(t, key) 221 if err != nil { 222 return nil, err 223 } 224 225 if fieldPatchStrategy == mergeDirective { 226 patchValue, err := diffLists(originalValueTyped, modifiedValueTyped, fieldType.Elem(), fieldPatchMergeKey, ignoreChangesAndAdditions, ignoreDeletions) 227 if err != nil { 228 return nil, err 229 } 230 231 if len(patchValue) > 0 { 232 patch[key] = patchValue 233 } 234 235 continue 236 } 237 } 238 239 if !ignoreChangesAndAdditions { 240 if !reflect.DeepEqual(originalValue, modifiedValue) { 241 // Values are different, so add to patch 242 patch[key] = modifiedValue 243 } 244 } 245 } 246 247 if !ignoreDeletions { 248 // Add nils for deleted values 249 for key := range original { 250 _, found := modified[key] 251 if !found { 252 patch[key] = nil 253 } 254 } 255 } 256 257 return patch, nil 258 } 259 260 // Returns a (recursive) strategic merge patch that yields modified when applied to original, 261 // for a pair of lists with merge semantics. 262 func diffLists(original, modified []interface{}, t reflect.Type, mergeKey string, ignoreChangesAndAdditions, ignoreDeletions bool) ([]interface{}, error) { 263 if len(original) == 0 { 264 if len(modified) == 0 || ignoreChangesAndAdditions { 265 return nil, nil 266 } 267 268 return modified, nil 269 } 270 271 elementType, err := sliceElementType(original, modified) 272 if err != nil { 273 return nil, err 274 } 275 276 var patch []interface{} 277 278 if elementType.Kind() == reflect.Map { 279 patch, err = diffListsOfMaps(original, modified, t, mergeKey, ignoreChangesAndAdditions, ignoreDeletions) 280 } else if !ignoreChangesAndAdditions { 281 patch, err = diffListsOfScalars(original, modified) 282 } 283 284 if err != nil { 285 return nil, err 286 } 287 288 return patch, nil 289 } 290 291 // Returns a (recursive) strategic merge patch that yields modified when applied to original, 292 // for a pair of lists of scalars with merge semantics. 293 func diffListsOfScalars(original, modified []interface{}) ([]interface{}, error) { 294 if len(modified) == 0 { 295 // There is no need to check the length of original because there is no way to create 296 // a patch that deletes a scalar from a list of scalars with merge semantics. 297 return nil, nil 298 } 299 300 patch := []interface{}{} 301 302 originalScalars := uniqifyAndSortScalars(original) 303 modifiedScalars := uniqifyAndSortScalars(modified) 304 originalIndex, modifiedIndex := 0, 0 305 306 loopB: 307 for ; modifiedIndex < len(modifiedScalars); modifiedIndex++ { 308 for ; originalIndex < len(originalScalars); originalIndex++ { 309 originalString := fmt.Sprintf("%v", original[originalIndex]) 310 modifiedString := fmt.Sprintf("%v", modified[modifiedIndex]) 311 if originalString >= modifiedString { 312 if originalString != modifiedString { 313 patch = append(patch, modified[modifiedIndex]) 314 } 315 316 continue loopB 317 } 318 // There is no else clause because there is no way to create a patch that deletes 319 // a scalar from a list of scalars with merge semantics. 320 } 321 322 break 323 } 324 325 // Add any remaining items found only in modified 326 for ; modifiedIndex < len(modifiedScalars); modifiedIndex++ { 327 patch = append(patch, modified[modifiedIndex]) 328 } 329 330 return patch, nil 331 } 332 333 var errNoMergeKeyFmt = "map: %v does not contain declared merge key: %s" 334 var errBadArgTypeFmt = "expected a %s, but received a %t" 335 336 // Returns a (recursive) strategic merge patch that yields modified when applied to original, 337 // for a pair of lists of maps with merge semantics. 338 func diffListsOfMaps(original, modified []interface{}, t reflect.Type, mergeKey string, ignoreChangesAndAdditions, ignoreDeletions bool) ([]interface{}, error) { 339 patch := make([]interface{}, 0) 340 341 originalSorted, err := sortMergeListsByNameArray(original, t, mergeKey, false) 342 if err != nil { 343 return nil, err 344 } 345 346 modifiedSorted, err := sortMergeListsByNameArray(modified, t, mergeKey, false) 347 if err != nil { 348 return nil, err 349 } 350 351 originalIndex, modifiedIndex := 0, 0 352 353 loopB: 354 for ; modifiedIndex < len(modifiedSorted); modifiedIndex++ { 355 modifiedMap, ok := modifiedSorted[modifiedIndex].(map[string]interface{}) 356 if !ok { 357 return nil, fmt.Errorf(errBadArgTypeFmt, "map[string]interface{}", modifiedSorted[modifiedIndex]) 358 } 359 360 modifiedValue, ok := modifiedMap[mergeKey] 361 if !ok { 362 return nil, fmt.Errorf(errNoMergeKeyFmt, modifiedMap, mergeKey) 363 } 364 365 for ; originalIndex < len(originalSorted); originalIndex++ { 366 originalMap, ok := originalSorted[originalIndex].(map[string]interface{}) 367 if !ok { 368 return nil, fmt.Errorf(errBadArgTypeFmt, "map[string]interface{}", originalSorted[originalIndex]) 369 } 370 371 originalValue, ok := originalMap[mergeKey] 372 if !ok { 373 return nil, fmt.Errorf(errNoMergeKeyFmt, originalMap, mergeKey) 374 } 375 376 // Assume that the merge key values are comparable strings 377 originalString := fmt.Sprintf("%v", originalValue) 378 modifiedString := fmt.Sprintf("%v", modifiedValue) 379 if originalString >= modifiedString { 380 if originalString == modifiedString { 381 // Merge key values are equal, so recurse 382 patchValue, err := diffMaps(originalMap, modifiedMap, t, ignoreChangesAndAdditions, ignoreDeletions) 383 if err != nil { 384 return nil, err 385 } 386 387 originalIndex++ 388 if len(patchValue) > 0 { 389 patchValue[mergeKey] = modifiedValue 390 patch = append(patch, patchValue) 391 } 392 } else if !ignoreChangesAndAdditions { 393 // Item was added, so add to patch 394 patch = append(patch, modifiedMap) 395 } 396 397 continue loopB 398 } 399 400 if !ignoreDeletions { 401 // Item was deleted, so add delete directive 402 patch = append(patch, map[string]interface{}{mergeKey: originalValue, directiveMarker: deleteDirective}) 403 } 404 } 405 406 break 407 } 408 409 if !ignoreDeletions { 410 // Delete any remaining items found only in original 411 for ; originalIndex < len(originalSorted); originalIndex++ { 412 originalMap, ok := originalSorted[originalIndex].(map[string]interface{}) 413 if !ok { 414 return nil, fmt.Errorf(errBadArgTypeFmt, "map[string]interface{}", originalSorted[originalIndex]) 415 } 416 417 originalValue, ok := originalMap[mergeKey] 418 if !ok { 419 return nil, fmt.Errorf(errNoMergeKeyFmt, originalMap, mergeKey) 420 } 421 422 patch = append(patch, map[string]interface{}{mergeKey: originalValue, directiveMarker: deleteDirective}) 423 } 424 } 425 426 if !ignoreChangesAndAdditions { 427 // Add any remaining items found only in modified 428 for ; modifiedIndex < len(modifiedSorted); modifiedIndex++ { 429 patch = append(patch, modified[modifiedIndex]) 430 } 431 } 432 433 return patch, nil 434 } 435 436 // Deprecated: StrategicMergePatchData is deprecated. Use the synonym StrategicMergePatch, 437 // instead, which follows the naming convention of evanphx/json-patch. 438 func StrategicMergePatchData(original, patch []byte, dataStruct interface{}) ([]byte, error) { 439 return StrategicMergePatch(original, patch, dataStruct) 440 } 441 442 // StrategicMergePatch applies a strategic merge patch. The patch and the original document 443 // must be json encoded content. A patch can be created from an original and a modified document 444 // by calling CreateStrategicMergePatch. 445 func StrategicMergePatch(original, patch []byte, dataStruct interface{}) ([]byte, error) { 446 if original == nil { 447 original = []byte{} 448 } 449 450 if patch == nil { 451 patch = []byte{} 452 } 453 454 originalMap := map[string]interface{}{} 455 err := json.Unmarshal(original, &originalMap) 456 if err != nil { 457 return nil, errBadJSONDoc 458 } 459 460 patchMap := map[string]interface{}{} 461 err = json.Unmarshal(patch, &patchMap) 462 if err != nil { 463 return nil, errBadJSONDoc 464 } 465 466 t, err := getTagStructType(dataStruct) 467 if err != nil { 468 return nil, err 469 } 470 471 result, err := mergeMap(originalMap, patchMap, t) 472 if err != nil { 473 return nil, err 474 } 475 476 return json.Marshal(result) 477 } 478 479 func getTagStructType(dataStruct interface{}) (reflect.Type, error) { 480 if dataStruct == nil { 481 return nil, fmt.Errorf(errBadArgTypeFmt, "struct", "nil") 482 } 483 484 t := reflect.TypeOf(dataStruct) 485 if t.Kind() == reflect.Ptr { 486 t = t.Elem() 487 } 488 489 if t.Kind() != reflect.Struct { 490 return nil, fmt.Errorf(errBadArgTypeFmt, "struct", t.Kind().String()) 491 } 492 493 return t, nil 494 } 495 496 var errBadPatchTypeFmt = "unknown patch type: %s in map: %v" 497 498 // Merge fields from a patch map into the original map. Note: This may modify 499 // both the original map and the patch because getting a deep copy of a map in 500 // golang is highly non-trivial. 501 func mergeMap(original, patch map[string]interface{}, t reflect.Type) (map[string]interface{}, error) { 502 if v, ok := patch[directiveMarker]; ok { 503 if v == replaceDirective { 504 // If the patch contains "$patch: replace", don't merge it, just use the 505 // patch directly. Later on, we can add a single level replace that only 506 // affects the map that the $patch is in. 507 delete(patch, directiveMarker) 508 return patch, nil 509 } 510 511 if v == deleteDirective { 512 // If the patch contains "$patch: delete", don't merge it, just return 513 // an empty map. 514 return map[string]interface{}{}, nil 515 } 516 517 return nil, fmt.Errorf(errBadPatchTypeFmt, v, patch) 518 } 519 520 // nil is an accepted value for original to simplify logic in other places. 521 // If original is nil, replace it with an empty map and then apply the patch. 522 if original == nil { 523 original = map[string]interface{}{} 524 } 525 526 // Start merging the patch into the original. 527 for k, patchV := range patch { 528 // If the value of this key is null, delete the key if it exists in the 529 // original. Otherwise, skip it. 530 if patchV == nil { 531 if _, ok := original[k]; ok { 532 delete(original, k) 533 } 534 535 continue 536 } 537 538 _, ok := original[k] 539 if !ok { 540 // If it's not in the original document, just take the patch value. 541 original[k] = patchV 542 continue 543 } 544 545 // If the data type is a pointer, resolve the element. 546 if t.Kind() == reflect.Ptr { 547 t = t.Elem() 548 } 549 550 // If they're both maps or lists, recurse into the value. 551 originalType := reflect.TypeOf(original[k]) 552 patchType := reflect.TypeOf(patchV) 553 if originalType == patchType { 554 // First find the fieldPatchStrategy and fieldPatchMergeKey. 555 fieldType, fieldPatchStrategy, fieldPatchMergeKey, err := forkedjson.LookupPatchMetadata(t, k) 556 if err != nil { 557 return nil, err 558 } 559 560 if originalType.Kind() == reflect.Map && fieldPatchStrategy != replaceDirective { 561 typedOriginal := original[k].(map[string]interface{}) 562 typedPatch := patchV.(map[string]interface{}) 563 var err error 564 original[k], err = mergeMap(typedOriginal, typedPatch, fieldType) 565 if err != nil { 566 return nil, err 567 } 568 569 continue 570 } 571 572 if originalType.Kind() == reflect.Slice && fieldPatchStrategy == mergeDirective { 573 elemType := fieldType.Elem() 574 typedOriginal := original[k].([]interface{}) 575 typedPatch := patchV.([]interface{}) 576 var err error 577 original[k], err = mergeSlice(typedOriginal, typedPatch, elemType, fieldPatchMergeKey) 578 if err != nil { 579 return nil, err 580 } 581 582 continue 583 } 584 } 585 586 // If originalType and patchType are different OR the types are both 587 // maps or slices but we're just supposed to replace them, just take 588 // the value from patch. 589 original[k] = patchV 590 } 591 592 return original, nil 593 } 594 595 // Merge two slices together. Note: This may modify both the original slice and 596 // the patch because getting a deep copy of a slice in golang is highly 597 // non-trivial. 598 func mergeSlice(original, patch []interface{}, elemType reflect.Type, mergeKey string) ([]interface{}, error) { 599 if len(original) == 0 && len(patch) == 0 { 600 return original, nil 601 } 602 603 // All the values must be of the same type, but not a list. 604 t, err := sliceElementType(original, patch) 605 if err != nil { 606 return nil, err 607 } 608 609 // If the elements are not maps, merge the slices of scalars. 610 if t.Kind() != reflect.Map { 611 // Maybe in the future add a "concat" mode that doesn't 612 // uniqify. 613 both := append(original, patch...) 614 return uniqifyScalars(both), nil 615 } 616 617 if mergeKey == "" { 618 return nil, fmt.Errorf("cannot merge lists without merge key for type %s", elemType.Kind().String()) 619 } 620 621 // First look for any special $patch elements. 622 patchWithoutSpecialElements := []interface{}{} 623 replace := false 624 for _, v := range patch { 625 typedV := v.(map[string]interface{}) 626 patchType, ok := typedV[directiveMarker] 627 if ok { 628 if patchType == deleteDirective { 629 mergeValue, ok := typedV[mergeKey] 630 if ok { 631 _, originalKey, found, err := findMapInSliceBasedOnKeyValue(original, mergeKey, mergeValue) 632 if err != nil { 633 return nil, err 634 } 635 636 if found { 637 // Delete the element at originalKey. 638 original = append(original[:originalKey], original[originalKey+1:]...) 639 } 640 } else { 641 return nil, fmt.Errorf("delete patch type with no merge key defined") 642 } 643 } else if patchType == replaceDirective { 644 replace = true 645 // Continue iterating through the array to prune any other $patch elements. 646 } else if patchType == mergeDirective { 647 return nil, fmt.Errorf("merging lists cannot yet be specified in the patch") 648 } else { 649 return nil, fmt.Errorf(errBadPatchTypeFmt, patchType, typedV) 650 } 651 } else { 652 patchWithoutSpecialElements = append(patchWithoutSpecialElements, v) 653 } 654 } 655 656 if replace { 657 return patchWithoutSpecialElements, nil 658 } 659 660 patch = patchWithoutSpecialElements 661 662 // Merge patch into original. 663 for _, v := range patch { 664 // Because earlier we confirmed that all the elements are maps. 665 typedV := v.(map[string]interface{}) 666 mergeValue, ok := typedV[mergeKey] 667 if !ok { 668 return nil, fmt.Errorf(errNoMergeKeyFmt, typedV, mergeKey) 669 } 670 671 // If we find a value with this merge key value in original, merge the 672 // maps. Otherwise append onto original. 673 originalMap, originalKey, found, err := findMapInSliceBasedOnKeyValue(original, mergeKey, mergeValue) 674 if err != nil { 675 return nil, err 676 } 677 678 if found { 679 var mergedMaps interface{} 680 var err error 681 // Merge into original. 682 mergedMaps, err = mergeMap(originalMap, typedV, elemType) 683 if err != nil { 684 return nil, err 685 } 686 687 original[originalKey] = mergedMaps 688 } else { 689 original = append(original, v) 690 } 691 } 692 693 return original, nil 694 } 695 696 // This method no longer panics if any element of the slice is not a map. 697 func findMapInSliceBasedOnKeyValue(m []interface{}, key string, value interface{}) (map[string]interface{}, int, bool, error) { 698 for k, v := range m { 699 typedV, ok := v.(map[string]interface{}) 700 if !ok { 701 return nil, 0, false, fmt.Errorf("value for key %v is not a map.", k) 702 } 703 704 valueToMatch, ok := typedV[key] 705 if ok && valueToMatch == value { 706 return typedV, k, true, nil 707 } 708 } 709 710 return nil, 0, false, nil 711 } 712 713 // This function takes a JSON map and sorts all the lists that should be merged 714 // by key. This is needed by tests because in JSON, list order is significant, 715 // but in Strategic Merge Patch, merge lists do not have significant order. 716 // Sorting the lists allows for order-insensitive comparison of patched maps. 717 func sortMergeListsByName(mapJSON []byte, dataStruct interface{}) ([]byte, error) { 718 var m map[string]interface{} 719 err := json.Unmarshal(mapJSON, &m) 720 if err != nil { 721 return nil, err 722 } 723 724 newM, err := sortMergeListsByNameMap(m, reflect.TypeOf(dataStruct)) 725 if err != nil { 726 return nil, err 727 } 728 729 return json.Marshal(newM) 730 } 731 732 func sortMergeListsByNameMap(s map[string]interface{}, t reflect.Type) (map[string]interface{}, error) { 733 newS := map[string]interface{}{} 734 for k, v := range s { 735 if k != directiveMarker { 736 fieldType, fieldPatchStrategy, fieldPatchMergeKey, err := forkedjson.LookupPatchMetadata(t, k) 737 if err != nil { 738 return nil, err 739 } 740 741 // If v is a map or a merge slice, recurse. 742 if typedV, ok := v.(map[string]interface{}); ok { 743 var err error 744 v, err = sortMergeListsByNameMap(typedV, fieldType) 745 if err != nil { 746 return nil, err 747 } 748 } else if typedV, ok := v.([]interface{}); ok { 749 if fieldPatchStrategy == mergeDirective { 750 var err error 751 v, err = sortMergeListsByNameArray(typedV, fieldType.Elem(), fieldPatchMergeKey, true) 752 if err != nil { 753 return nil, err 754 } 755 } 756 } 757 } 758 759 newS[k] = v 760 } 761 762 return newS, nil 763 } 764 765 func sortMergeListsByNameArray(s []interface{}, elemType reflect.Type, mergeKey string, recurse bool) ([]interface{}, error) { 766 if len(s) == 0 { 767 return s, nil 768 } 769 770 // We don't support lists of lists yet. 771 t, err := sliceElementType(s) 772 if err != nil { 773 return nil, err 774 } 775 776 // If the elements are not maps... 777 if t.Kind() != reflect.Map { 778 // Sort the elements, because they may have been merged out of order. 779 return uniqifyAndSortScalars(s), nil 780 } 781 782 // Elements are maps - if one of the keys of the map is a map or a 783 // list, we may need to recurse into it. 784 newS := []interface{}{} 785 for _, elem := range s { 786 if recurse { 787 typedElem := elem.(map[string]interface{}) 788 newElem, err := sortMergeListsByNameMap(typedElem, elemType) 789 if err != nil { 790 return nil, err 791 } 792 793 newS = append(newS, newElem) 794 } else { 795 newS = append(newS, elem) 796 } 797 } 798 799 // Sort the maps. 800 newS = sortMapsBasedOnField(newS, mergeKey) 801 return newS, nil 802 } 803 804 func sortMapsBasedOnField(m []interface{}, fieldName string) []interface{} { 805 mapM := mapSliceFromSlice(m) 806 ss := SortableSliceOfMaps{mapM, fieldName} 807 sort.Sort(ss) 808 newS := sliceFromMapSlice(ss.s) 809 return newS 810 } 811 812 func mapSliceFromSlice(m []interface{}) []map[string]interface{} { 813 newM := []map[string]interface{}{} 814 for _, v := range m { 815 vt := v.(map[string]interface{}) 816 newM = append(newM, vt) 817 } 818 819 return newM 820 } 821 822 func sliceFromMapSlice(s []map[string]interface{}) []interface{} { 823 newS := []interface{}{} 824 for _, v := range s { 825 newS = append(newS, v) 826 } 827 828 return newS 829 } 830 831 type SortableSliceOfMaps struct { 832 s []map[string]interface{} 833 k string // key to sort on 834 } 835 836 func (ss SortableSliceOfMaps) Len() int { 837 return len(ss.s) 838 } 839 840 func (ss SortableSliceOfMaps) Less(i, j int) bool { 841 iStr := fmt.Sprintf("%v", ss.s[i][ss.k]) 842 jStr := fmt.Sprintf("%v", ss.s[j][ss.k]) 843 return sort.StringsAreSorted([]string{iStr, jStr}) 844 } 845 846 func (ss SortableSliceOfMaps) Swap(i, j int) { 847 tmp := ss.s[i] 848 ss.s[i] = ss.s[j] 849 ss.s[j] = tmp 850 } 851 852 func uniqifyAndSortScalars(s []interface{}) []interface{} { 853 s = uniqifyScalars(s) 854 855 ss := SortableSliceOfScalars{s} 856 sort.Sort(ss) 857 return ss.s 858 } 859 860 func uniqifyScalars(s []interface{}) []interface{} { 861 // Clever algorithm to uniqify. 862 length := len(s) - 1 863 for i := 0; i < length; i++ { 864 for j := i + 1; j <= length; j++ { 865 if s[i] == s[j] { 866 s[j] = s[length] 867 s = s[0:length] 868 length-- 869 j-- 870 } 871 } 872 } 873 874 return s 875 } 876 877 type SortableSliceOfScalars struct { 878 s []interface{} 879 } 880 881 func (ss SortableSliceOfScalars) Len() int { 882 return len(ss.s) 883 } 884 885 func (ss SortableSliceOfScalars) Less(i, j int) bool { 886 iStr := fmt.Sprintf("%v", ss.s[i]) 887 jStr := fmt.Sprintf("%v", ss.s[j]) 888 return sort.StringsAreSorted([]string{iStr, jStr}) 889 } 890 891 func (ss SortableSliceOfScalars) Swap(i, j int) { 892 tmp := ss.s[i] 893 ss.s[i] = ss.s[j] 894 ss.s[j] = tmp 895 } 896 897 // Returns the type of the elements of N slice(s). If the type is different, 898 // another slice or undefined, returns an error. 899 func sliceElementType(slices ...[]interface{}) (reflect.Type, error) { 900 var prevType reflect.Type 901 for _, s := range slices { 902 // Go through elements of all given slices and make sure they are all the same type. 903 for _, v := range s { 904 currentType := reflect.TypeOf(v) 905 if prevType == nil { 906 prevType = currentType 907 // We don't support lists of lists yet. 908 if prevType.Kind() == reflect.Slice { 909 return nil, errNoListOfLists 910 } 911 } else { 912 if prevType != currentType { 913 return nil, fmt.Errorf("list element types are not identical: %v", fmt.Sprint(slices)) 914 } 915 prevType = currentType 916 } 917 } 918 } 919 920 if prevType == nil { 921 return nil, fmt.Errorf("no elements in any of the given slices") 922 } 923 924 return prevType, nil 925 } 926 927 // HasConflicts returns true if the left and right JSON interface objects overlap with 928 // different values in any key. All keys are required to be strings. Since patches of the 929 // same Type have congruent keys, this is valid for multiple patch types. 930 func HasConflicts(left, right interface{}) (bool, error) { 931 switch typedLeft := left.(type) { 932 case map[string]interface{}: 933 switch typedRight := right.(type) { 934 case map[string]interface{}: 935 for key, leftValue := range typedLeft { 936 rightValue, ok := typedRight[key] 937 if !ok { 938 return false, nil 939 } 940 return HasConflicts(leftValue, rightValue) 941 } 942 return false, nil 943 default: 944 return true, nil 945 } 946 case []interface{}: 947 switch typedRight := right.(type) { 948 case []interface{}: 949 if len(typedLeft) != len(typedRight) { 950 return true, nil 951 } 952 for i := range typedLeft { 953 return HasConflicts(typedLeft[i], typedRight[i]) 954 } 955 return false, nil 956 default: 957 return true, nil 958 } 959 case string, float64, bool, int, int64, nil: 960 return !reflect.DeepEqual(left, right), nil 961 default: 962 return true, fmt.Errorf("unknown type: %v", reflect.TypeOf(left)) 963 } 964 } 965 966 // CreateThreeWayMergePatch reconciles a modified configuration with an original configuration, 967 // while preserving any changes or deletions made to the original configuration in the interim, 968 // and not overridden by the current configuration. All three documents must be passed to the 969 // method as json encoded content. It will return a strategic merge patch, or an error if any 970 // of the documents is invalid, or if there are any preconditions that fail against the modified 971 // configuration, or, if force is false and there are conflicts between the modified and current 972 // configurations. 973 func CreateThreeWayMergePatch(original, modified, current []byte, dataStruct interface{}, force bool, fns ...PreconditionFunc) ([]byte, error) { 974 originalMap := map[string]interface{}{} 975 if len(original) > 0 { 976 if err := json.Unmarshal(original, &originalMap); err != nil { 977 return nil, errBadJSONDoc 978 } 979 } 980 981 modifiedMap := map[string]interface{}{} 982 if len(modified) > 0 { 983 if err := json.Unmarshal(modified, &modifiedMap); err != nil { 984 return nil, errBadJSONDoc 985 } 986 } 987 988 currentMap := map[string]interface{}{} 989 if len(current) > 0 { 990 if err := json.Unmarshal(current, ¤tMap); err != nil { 991 return nil, errBadJSONDoc 992 } 993 } 994 995 t, err := getTagStructType(dataStruct) 996 if err != nil { 997 return nil, err 998 } 999 1000 // The patch is the difference from current to modified without deletions, plus deletions 1001 // from original to modified. To find it, we compute deletions, which are the deletions from 1002 // original to modified, and delta, which is the difference from current to modified without 1003 // deletions, and then apply delta to deletions as a patch, which should be strictly additive. 1004 deltaMap, err := diffMaps(currentMap, modifiedMap, t, false, true) 1005 if err != nil { 1006 return nil, err 1007 } 1008 1009 deletionsMap, err := diffMaps(originalMap, modifiedMap, t, true, false) 1010 if err != nil { 1011 return nil, err 1012 } 1013 1014 patchMap, err := mergeMap(deletionsMap, deltaMap, t) 1015 if err != nil { 1016 return nil, err 1017 } 1018 1019 // Apply the preconditions to the patch, and return an error if any of them fail. 1020 for _, fn := range fns { 1021 if !fn(patchMap) { 1022 return nil, newErrPreconditionFailed(patchMap) 1023 } 1024 } 1025 1026 // TODO(jackgr): If force is false, and the patch contains any keys that are also in current, 1027 // then return a conflict error. 1028 1029 return json.Marshal(patchMap) 1030 }