values.go 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. package utils
  2. import "sigs.k8s.io/yaml"
  3. // MergeYAML merges raw yaml, with preference given to override
  4. func MergeYAML(base, override []byte) (map[string]interface{}, error) {
  5. baseVals := map[string]interface{}{}
  6. overrideVals := map[string]interface{}{}
  7. err := yaml.Unmarshal(base, &baseVals)
  8. if err != nil {
  9. return nil, err
  10. }
  11. err = yaml.Unmarshal(override, &overrideVals)
  12. if err != nil {
  13. return nil, err
  14. }
  15. return CoalesceValues(baseVals, overrideVals), nil
  16. }
  17. // CoalesceValues replaces arrays and scalar values, merges maps
  18. func CoalesceValues(base, override map[string]interface{}) map[string]interface{} {
  19. for key, val := range base {
  20. if oVal, ok := override[key]; ok {
  21. if oVal == nil {
  22. delete(override, key)
  23. } else if isYAMLTable(oVal) && isYAMLTable(val) {
  24. oMapVal, _ := oVal.(map[string]interface{})
  25. bMapVal, _ := val.(map[string]interface{})
  26. override[key] = mergeMaps(bMapVal, oMapVal)
  27. }
  28. } else {
  29. override[key] = val
  30. }
  31. }
  32. return override
  33. }
  34. func isYAMLTable(v interface{}) bool {
  35. _, ok := v.(map[string]interface{})
  36. return ok
  37. }
  38. // mergeMaps merges any number of maps together, with maps later in the slice taking
  39. // precedent
  40. func mergeMaps(maps ...map[string]interface{}) map[string]interface{} {
  41. // merge bottom-up
  42. if len(maps) > 2 {
  43. mLen := len(maps)
  44. newMaps := maps[0 : mLen-2]
  45. // reduce length of maps by 1 and merge again
  46. newMaps = append(newMaps, mergeMaps(maps[mLen-2], maps[mLen-1]))
  47. return mergeMaps(newMaps...)
  48. } else if len(maps) == 2 {
  49. if maps[0] == nil {
  50. return maps[1]
  51. }
  52. if maps[1] == nil {
  53. return maps[0]
  54. }
  55. for key, map0Val := range maps[0] {
  56. if map1Val, ok := maps[1][key]; ok && map1Val == nil {
  57. delete(maps[1], key)
  58. } else if !ok {
  59. maps[1][key] = map0Val
  60. } else if isYAMLTable(map0Val) {
  61. if isYAMLTable(map1Val) {
  62. mergeMaps(map0Val.(map[string]interface{}), map1Val.(map[string]interface{}))
  63. }
  64. }
  65. }
  66. return maps[1]
  67. } else if len(maps) == 1 {
  68. return maps[0]
  69. }
  70. return nil
  71. }