values.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  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. if base == nil && override != nil {
  20. return override
  21. } else if override == nil {
  22. return base
  23. }
  24. for key, val := range base {
  25. if oVal, ok := override[key]; ok {
  26. if oVal == nil {
  27. delete(override, key)
  28. } else if isYAMLTable(oVal) && isYAMLTable(val) {
  29. oMapVal, _ := oVal.(map[string]interface{})
  30. bMapVal, _ := val.(map[string]interface{})
  31. override[key] = mergeMaps(bMapVal, oMapVal)
  32. }
  33. } else {
  34. override[key] = val
  35. }
  36. }
  37. return override
  38. }
  39. func DeepCoalesceValues(base, override map[string]interface{}) map[string]interface{} {
  40. if base == nil && override != nil {
  41. return override
  42. } else if override == nil {
  43. return base
  44. }
  45. for key, val := range base {
  46. if oVal, ok := override[key]; ok {
  47. if oVal == nil {
  48. delete(override, key)
  49. } else if isYAMLTable(oVal) && isYAMLTable(val) {
  50. oMapVal, _ := oVal.(map[string]interface{})
  51. bMapVal, _ := val.(map[string]interface{})
  52. override[key] = mergeMaps(bMapVal, oMapVal)
  53. } else if _, ok := val.(map[string]interface{}); ok {
  54. override[key] = CoalesceValues(val.(map[string]interface{}), oVal.(map[string]interface{}))
  55. } else {
  56. override[key] = oVal
  57. }
  58. } else {
  59. override[key] = val
  60. }
  61. }
  62. return override
  63. }
  64. func isYAMLTable(v interface{}) bool {
  65. _, ok := v.(map[string]interface{})
  66. return ok
  67. }
  68. // mergeMaps merges any number of maps together, with maps later in the slice taking
  69. // precedent
  70. func mergeMaps(maps ...map[string]interface{}) map[string]interface{} {
  71. // merge bottom-up
  72. if len(maps) > 2 {
  73. mLen := len(maps)
  74. newMaps := maps[0 : mLen-2]
  75. // reduce length of maps by 1 and merge again
  76. newMaps = append(newMaps, mergeMaps(maps[mLen-2], maps[mLen-1]))
  77. return mergeMaps(newMaps...)
  78. } else if len(maps) == 2 {
  79. if maps[0] == nil {
  80. return maps[1]
  81. }
  82. if maps[1] == nil {
  83. return maps[0]
  84. }
  85. for key, map0Val := range maps[0] {
  86. if map1Val, ok := maps[1][key]; ok && map1Val == nil {
  87. delete(maps[1], key)
  88. } else if !ok {
  89. maps[1][key] = map0Val
  90. } else if isYAMLTable(map0Val) {
  91. if isYAMLTable(map1Val) {
  92. mergeMaps(map0Val.(map[string]interface{}), map1Val.(map[string]interface{}))
  93. }
  94. }
  95. }
  96. return maps[1]
  97. } else if len(maps) == 1 {
  98. return maps[0]
  99. }
  100. return nil
  101. }