interpolation.go 1.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. package interpolation
  2. import (
  3. "fmt"
  4. "github.com/docker/docker/cli/compose/template"
  5. )
  6. // Interpolate replaces variables in a string with the values from a mapping
  7. func Interpolate(config map[string]interface{}, section string, mapping template.Mapping) (map[string]interface{}, error) {
  8. out := map[string]interface{}{}
  9. for name, item := range config {
  10. if item == nil {
  11. out[name] = nil
  12. continue
  13. }
  14. interpolatedItem, err := interpolateSectionItem(name, item.(map[string]interface{}), section, mapping)
  15. if err != nil {
  16. return nil, err
  17. }
  18. out[name] = interpolatedItem
  19. }
  20. return out, nil
  21. }
  22. func interpolateSectionItem(
  23. name string,
  24. item map[string]interface{},
  25. section string,
  26. mapping template.Mapping,
  27. ) (map[string]interface{}, error) {
  28. out := map[string]interface{}{}
  29. for key, value := range item {
  30. interpolatedValue, err := recursiveInterpolate(value, mapping)
  31. if err != nil {
  32. return nil, fmt.Errorf(
  33. "Invalid interpolation format for %#v option in %s %#v: %#v. You may need to escape any $ with another $.",
  34. key, section, name, err.Template,
  35. )
  36. }
  37. out[key] = interpolatedValue
  38. }
  39. return out, nil
  40. }
  41. func recursiveInterpolate(
  42. value interface{},
  43. mapping template.Mapping,
  44. ) (interface{}, *template.InvalidTemplateError) {
  45. switch value := value.(type) {
  46. case string:
  47. return template.Substitute(value, mapping)
  48. case map[string]interface{}:
  49. out := map[string]interface{}{}
  50. for key, elem := range value {
  51. interpolatedElem, err := recursiveInterpolate(elem, mapping)
  52. if err != nil {
  53. return nil, err
  54. }
  55. out[key] = interpolatedElem
  56. }
  57. return out, nil
  58. case []interface{}:
  59. out := make([]interface{}, len(value))
  60. for i, elem := range value {
  61. interpolatedElem, err := recursiveInterpolate(elem, mapping)
  62. if err != nil {
  63. return nil, err
  64. }
  65. out[i] = interpolatedElem
  66. }
  67. return out, nil
  68. default:
  69. return value, nil
  70. }
  71. }