@@ -57,7 +57,7 @@ func applyTemplateStruct(l Lookuper, p setter, v reflect.Value) error {
57
57
return nil
58
58
}
59
59
60
- // applyTemplateByType applies the template string to a generic type.
60
+ // applyTemplateByType (recursively) applies the template string to a generic type.
61
61
func applyTemplateByType (l Lookuper , p setter , v reflect.Value ) error {
62
62
switch v .Kind () {
63
63
case reflect .Array , reflect .Slice :
@@ -119,31 +119,34 @@ func applyTemplateString(l Lookuper, p setter, v reflect.Value) error {
119
119
panic ("called applyTemplateString on non string type" )
120
120
}
121
121
s := v .String ()
122
- tmpl , is := isTemplate (s )
123
- if ! is {
122
+ tmpl , more := isTemplate (s )
123
+ if ! more {
124
124
// nothing to do
125
125
return nil
126
126
}
127
127
128
- key := keyFromTemplate (tmpl )
129
- val , err := l .Lookup (key )
130
- if err != nil {
131
- return err
132
- }
133
- if val == nil {
134
- return nil
135
- }
128
+ for more {
129
+ key := keyFromTemplate (tmpl )
130
+ val , err := l .Lookup (key )
131
+ if err != nil {
132
+ return err
133
+ }
134
+ if val == nil {
135
+ val = ""
136
+ }
136
137
137
- new , err := replaceTemplate (s , tmpl , val )
138
- if err != nil {
139
- return err
140
- }
141
- str , ok := convertToString (new )
142
- if ! ok {
143
- return fmt .Errorf ("value %v cannot be converted as string in the template %s" , val , new )
138
+ new , err := replaceTemplate (s , tmpl , val )
139
+ if err != nil {
140
+ return err
141
+ }
142
+ str , ok := convertToString (new )
143
+ if ! ok {
144
+ return fmt .Errorf ("value %v cannot be converted as string in the template %s" , val , new )
145
+ }
146
+ s = str
147
+ tmpl , more = isTemplate (s )
144
148
}
145
-
146
- p .SetValue (str )
149
+ p .SetValue (s )
147
150
return nil
148
151
}
149
152
@@ -159,32 +162,49 @@ func applyTemplateInterface(l Lookuper, p setter, v reflect.Value) error {
159
162
return applyTemplateByType (l , p , v .Elem ())
160
163
}
161
164
162
- tmpl , is := isTemplate (s )
163
- if ! is {
165
+ tmpl , more := isTemplate (s )
166
+ if ! more {
164
167
// nothing to do
165
168
return nil
166
169
}
170
+ replaced := 0
171
+ for more {
172
+ key := keyFromTemplate (tmpl )
173
+ val , err := l .Lookup (key )
174
+ if err != nil {
175
+ return err
176
+ }
177
+ if val == nil {
178
+ val = ""
179
+ }
167
180
168
- key := keyFromTemplate ( tmpl )
169
- val , err := l . Lookup ( key )
170
- if err != nil {
171
- return err
172
- }
173
- if val == nil {
174
- return nil
175
- }
181
+ new , err := replaceTemplate ( s , tmpl , val )
182
+ if err != nil {
183
+ return err
184
+ }
185
+
186
+ replaced ++
187
+ str , ok := convertToString ( new )
188
+ tmpl , more = isTemplate ( str )
176
189
177
- new , err := replaceTemplate (s , tmpl , val )
178
- if err != nil {
179
- return err
190
+ if ! more && replaced == 1 {
191
+ // a single template was to be replaced, preserve type
192
+ p .SetValue (new )
193
+ return nil
194
+ }
195
+ // if more than one template is to be replaced, use the string representation
196
+ if ! ok {
197
+ return fmt .Errorf ("value %v cannot be converted as string in the template %s" , val , new )
198
+ }
199
+ s = str
180
200
}
181
- p .SetValue (new )
201
+ p .SetValue (s )
182
202
return nil
183
203
}
184
204
185
205
func replaceTemplate (original , tmpl string , val any ) (any , error ) {
186
206
if strings .TrimSpace (original ) == tmpl {
187
- // the value was directly a template, i.e . "{{ grpc.services.gateway.address }}"
207
+ // the value was directly a template, e.g . "{{ grpc.services.gateway.address }}"
188
208
return val , nil
189
209
}
190
210
// the value is of something like "something {{ template }} something else"
@@ -227,7 +247,7 @@ func convertToString(val any) (string, bool) {
227
247
return "" , false
228
248
}
229
249
230
- var templateRegex = regexp .MustCompile ("{{.{1,} }}" )
250
+ var templateRegex = regexp .MustCompile ("{{[^{}]+ }}" )
231
251
232
252
func isTemplate (s string ) (string , bool ) {
233
253
m := templateRegex .FindString (s )
@@ -237,7 +257,10 @@ func isTemplate(s string) (string, bool) {
237
257
func keyFromTemplate (s string ) string {
238
258
s = strings .TrimSpace (s )
239
259
s = strings .TrimPrefix (s , "{{" )
240
- s = strings .TrimSuffix (s , "}}" )
260
+ for strings .Index (s , "}}" ) > 0 {
261
+ //nolint: gocritic
262
+ s = s [:strings .Index (s , "}}" )] // this is not offBy1
263
+ }
241
264
return "." + strings .TrimSpace (s )
242
265
}
243
266
0 commit comments