values.go 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  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 isYAMLTable(v interface{}) bool {
  40. _, ok := v.(map[string]interface{})
  41. return ok
  42. }
  43. // mergeMaps merges any number of maps together, with maps later in the slice taking
  44. // precedent
  45. func mergeMaps(maps ...map[string]interface{}) map[string]interface{} {
  46. // merge bottom-up
  47. if len(maps) > 2 {
  48. mLen := len(maps)
  49. newMaps := maps[0 : mLen-2]
  50. // reduce length of maps by 1 and merge again
  51. newMaps = append(newMaps, mergeMaps(maps[mLen-2], maps[mLen-1]))
  52. return mergeMaps(newMaps...)
  53. } else if len(maps) == 2 {
  54. if maps[0] == nil {
  55. return maps[1]
  56. }
  57. if maps[1] == nil {
  58. return maps[0]
  59. }
  60. for key, map0Val := range maps[0] {
  61. if map1Val, ok := maps[1][key]; ok && map1Val == nil {
  62. delete(maps[1], key)
  63. } else if !ok {
  64. maps[1][key] = map0Val
  65. } else if isYAMLTable(map0Val) {
  66. if isYAMLTable(map1Val) {
  67. mergeMaps(map0Val.(map[string]interface{}), map1Val.(map[string]interface{}))
  68. }
  69. }
  70. }
  71. return maps[1]
  72. } else if len(maps) == 1 {
  73. return maps[0]
  74. }
  75. return nil
  76. }