1
2
3
4 package kv
5
6 import (
7 "bufio"
8 "bytes"
9 "fmt"
10 "strings"
11 "unicode"
12 "unicode/utf8"
13
14 "sigs.k8s.io/kustomize/api/ifc"
15 "sigs.k8s.io/kustomize/api/internal/generators"
16 "sigs.k8s.io/kustomize/api/types"
17 "sigs.k8s.io/kustomize/kyaml/errors"
18 )
19
20 var utf8bom = []byte{0xEF, 0xBB, 0xBF}
21
22
23 type loader struct {
24
25 ldr ifc.Loader
26
27
28 validator ifc.Validator
29 }
30
31 func NewLoader(ldr ifc.Loader, v ifc.Validator) ifc.KvLoader {
32 return &loader{ldr: ldr, validator: v}
33 }
34
35 func (kvl *loader) Validator() ifc.Validator {
36 return kvl.validator
37 }
38
39 func (kvl *loader) Load(
40 args types.KvPairSources) (all []types.Pair, err error) {
41 pairs, err := kvl.keyValuesFromEnvFiles(args.EnvSources)
42 if err != nil {
43 return nil, errors.WrapPrefixf(err,
44 "env source files: %v",
45 args.EnvSources)
46 }
47 all = append(all, pairs...)
48
49 pairs, err = keyValuesFromLiteralSources(args.LiteralSources)
50 if err != nil {
51 return nil, errors.WrapPrefixf(err,
52 "literal sources %v", args.LiteralSources)
53 }
54 all = append(all, pairs...)
55
56 pairs, err = kvl.keyValuesFromFileSources(args.FileSources)
57 if err != nil {
58 return nil, errors.WrapPrefixf(err,
59 "file sources: %v", args.FileSources)
60 }
61 return append(all, pairs...), nil
62 }
63
64 func keyValuesFromLiteralSources(sources []string) ([]types.Pair, error) {
65 var kvs []types.Pair
66 for _, s := range sources {
67 k, v, err := parseLiteralSource(s)
68 if err != nil {
69 return nil, err
70 }
71 kvs = append(kvs, types.Pair{Key: k, Value: v})
72 }
73 return kvs, nil
74 }
75
76 func (kvl *loader) keyValuesFromFileSources(sources []string) ([]types.Pair, error) {
77 var kvs []types.Pair
78 for _, s := range sources {
79 k, fPath, err := generators.ParseFileSource(s)
80 if err != nil {
81 return nil, err
82 }
83 content, err := kvl.ldr.Load(fPath)
84 if err != nil {
85 return nil, err
86 }
87 kvs = append(kvs, types.Pair{Key: k, Value: string(content)})
88 }
89 return kvs, nil
90 }
91
92 func (kvl *loader) keyValuesFromEnvFiles(paths []string) ([]types.Pair, error) {
93 var kvs []types.Pair
94 for _, p := range paths {
95 content, err := kvl.ldr.Load(p)
96 if err != nil {
97 return nil, err
98 }
99 more, err := kvl.keyValuesFromLines(content)
100 if err != nil {
101 return nil, err
102 }
103 kvs = append(kvs, more...)
104 }
105 return kvs, nil
106 }
107
108
109 func (kvl *loader) keyValuesFromLines(content []byte) ([]types.Pair, error) {
110 var kvs []types.Pair
111
112 scanner := bufio.NewScanner(bytes.NewReader(content))
113 currentLine := 0
114 for scanner.Scan() {
115
116
117 scannedBytes := scanner.Bytes()
118 kv, err := kvl.keyValuesFromLine(scannedBytes, currentLine)
119 if err != nil {
120 return nil, err
121 }
122 currentLine++
123
124 if len(kv.Key) == 0 {
125
126 continue
127 }
128
129 kvs = append(kvs, kv)
130 }
131 return kvs, nil
132 }
133
134
135 func (kvl *loader) keyValuesFromLine(line []byte, currentLine int) (types.Pair, error) {
136 kv := types.Pair{}
137
138 if !utf8.Valid(line) {
139 return kv, fmt.Errorf("line %d has invalid utf8 bytes : %v", line, string(line))
140 }
141
142
143 if currentLine == 0 {
144 line = bytes.TrimPrefix(line, utf8bom)
145 }
146
147
148 line = bytes.TrimLeftFunc(line, unicode.IsSpace)
149
150
151 if len(line) == 0 || line[0] == '#' {
152 return kv, nil
153 }
154
155 data := strings.SplitN(string(line), "=", 2)
156 key := data[0]
157 if err := kvl.validator.IsEnvVarName(key); err != nil {
158 return kv, err
159 }
160
161 if len(data) == 2 {
162 kv.Value = data[1]
163 } else {
164
165 kv.Value = ""
166 }
167 kv.Key = key
168 return kv, nil
169 }
170
171
172
173
174 func parseLiteralSource(source string) (keyName, value string, err error) {
175
176 if strings.Index(source, "=") == 0 {
177 return "", "", fmt.Errorf("invalid literal source %v, expected key=value", source)
178 }
179
180 items := strings.SplitN(source, "=", 2)
181 if len(items) != 2 {
182 return "", "", fmt.Errorf("invalid literal source %v, expected key=value", source)
183 }
184 return items[0], removeQuotes(items[1]), nil
185 }
186
187
188
189 func removeQuotes(str string) string {
190 if len(str) < 2 || str[0] != str[len(str)-1] {
191 return str
192 }
193 if str[0] == '"' || str[0] == '\'' {
194 return str[1 : len(str)-1]
195 }
196 return str
197 }
198
View as plain text