1
16
17 package values
18
19 import (
20 "io"
21 "net/url"
22 "os"
23 "strings"
24
25 "github.com/pkg/errors"
26 "sigs.k8s.io/yaml"
27
28 "helm.sh/helm/v3/pkg/getter"
29 "helm.sh/helm/v3/pkg/strvals"
30 )
31
32
33 type Options struct {
34 ValueFiles []string
35 StringValues []string
36 Values []string
37 FileValues []string
38 JSONValues []string
39 LiteralValues []string
40 }
41
42
43
44 func (opts *Options) MergeValues(p getter.Providers) (map[string]interface{}, error) {
45 base := map[string]interface{}{}
46
47
48 for _, filePath := range opts.ValueFiles {
49 currentMap := map[string]interface{}{}
50
51 bytes, err := readFile(filePath, p)
52 if err != nil {
53 return nil, err
54 }
55
56 if err := yaml.Unmarshal(bytes, ¤tMap); err != nil {
57 return nil, errors.Wrapf(err, "failed to parse %s", filePath)
58 }
59
60 base = mergeMaps(base, currentMap)
61 }
62
63
64 for _, value := range opts.JSONValues {
65 if err := strvals.ParseJSON(value, base); err != nil {
66 return nil, errors.Errorf("failed parsing --set-json data %s", value)
67 }
68 }
69
70
71 for _, value := range opts.Values {
72 if err := strvals.ParseInto(value, base); err != nil {
73 return nil, errors.Wrap(err, "failed parsing --set data")
74 }
75 }
76
77
78 for _, value := range opts.StringValues {
79 if err := strvals.ParseIntoString(value, base); err != nil {
80 return nil, errors.Wrap(err, "failed parsing --set-string data")
81 }
82 }
83
84
85 for _, value := range opts.FileValues {
86 reader := func(rs []rune) (interface{}, error) {
87 bytes, err := readFile(string(rs), p)
88 if err != nil {
89 return nil, err
90 }
91 return string(bytes), err
92 }
93 if err := strvals.ParseIntoFile(value, base, reader); err != nil {
94 return nil, errors.Wrap(err, "failed parsing --set-file data")
95 }
96 }
97
98
99 for _, value := range opts.LiteralValues {
100 if err := strvals.ParseLiteralInto(value, base); err != nil {
101 return nil, errors.Wrap(err, "failed parsing --set-literal data")
102 }
103 }
104
105 return base, nil
106 }
107
108 func mergeMaps(a, b map[string]interface{}) map[string]interface{} {
109 out := make(map[string]interface{}, len(a))
110 for k, v := range a {
111 out[k] = v
112 }
113 for k, v := range b {
114 if v, ok := v.(map[string]interface{}); ok {
115 if bv, ok := out[k]; ok {
116 if bv, ok := bv.(map[string]interface{}); ok {
117 out[k] = mergeMaps(bv, v)
118 continue
119 }
120 }
121 }
122 out[k] = v
123 }
124 return out
125 }
126
127
128 func readFile(filePath string, p getter.Providers) ([]byte, error) {
129 if strings.TrimSpace(filePath) == "-" {
130 return io.ReadAll(os.Stdin)
131 }
132 u, err := url.Parse(filePath)
133 if err != nil {
134 return nil, err
135 }
136
137
138 g, err := p.ByScheme(u.Scheme)
139 if err != nil {
140 return os.ReadFile(filePath)
141 }
142 data, err := g.Get(filePath, getter.WithURL(filePath))
143 if err != nil {
144 return nil, err
145 }
146 return data.Bytes(), err
147 }
148
View as plain text