Skip to content
This repository was archived by the owner on Jan 21, 2020. It is now read-only.

Commit afdd155

Browse files
author
David Chung
authored
Simplify template variables with a single 'var' function (#472)
Signed-off-by: David Chung <[email protected]>
1 parent 0a99d03 commit afdd155

File tree

7 files changed

+52
-153
lines changed

7 files changed

+52
-153
lines changed

cmd/cli/base/template.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ func TemplateProcessor(plugins func() discovery.Plugins) (*pflag.FlagSet, ToJSON
5555

5656
fs := pflag.NewFlagSet("template", pflag.ExitOnError)
5757

58-
globals := fs.StringSliceP("global", "g", []string{}, "key=value pairs of 'global' values in template")
58+
globals := fs.StringSliceP("var", "v", []string{}, "key=value pairs of globally scoped variagbles")
5959
yamlDoc := fs.BoolP("yaml", "y", false, "True if input is in yaml format; json is the default")
6060
dump := fs.BoolP("dump", "x", false, "True to dump to output instead of executing")
6161

cmd/cli/info/info.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ func Command(plugins func() discovery.Plugins) *cobra.Command {
6767
return err
6868
}
6969

70-
view, err := renderer.Def("plugin", *name, "Plugin name").Render(info)
70+
view, err := renderer.Global("plugin", *name).Render(info)
7171
if err != nil {
7272
return err
7373
}
@@ -103,7 +103,7 @@ func Command(plugins func() discovery.Plugins) *cobra.Command {
103103
return err
104104
}
105105

106-
view, err := renderer.Def("plugin", *name, "Plugin name").Render(info)
106+
view, err := renderer.Global("plugin", *name).Render(info)
107107
if err != nil {
108108
return err
109109
}
@@ -117,7 +117,7 @@ func Command(plugins func() discovery.Plugins) *cobra.Command {
117117

118118
const (
119119
apiViewTemplate = `
120-
Plugin: {{ref "plugin"}}
120+
Plugin: {{var "plugin"}}
121121
Implements: {{range $spi := .Implements}}{{$spi.Name}}/{{$spi.Version}} {{end}}
122122
Interfaces: {{range $iface := .Interfaces}}
123123
SPI: {{$iface.Name}}/{{$iface.Version}}
@@ -136,7 +136,7 @@ Interfaces: {{range $iface := .Interfaces}}
136136

137137
funcsViewTemplate = `
138138
{{range $category, $functions := .}}
139-
{{ref "plugin"}}/{{$category}} _________________________________________________________________________________________
139+
{{var "plugin"}}/{{$category}} _________________________________________________________________________________________
140140
{{range $f := $functions}}
141141
Name: {{$f.Name}}
142142
Description: {{join "\n " $f.Description}}

examples/flavor/swarm/templates.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ set -o xtrace
1212
mkdir -p /etc/docker
1313
cat << EOF > /etc/docker/daemon.json
1414
{
15-
"labels": {{ INFRAKIT_LABELS | to_json }}
15+
"labels": {{ INFRAKIT_LABELS | jsonEncode }}
1616
}
1717
EOF
1818
@@ -50,7 +50,7 @@ set -o xtrace
5050
mkdir -p /etc/docker
5151
cat << EOF > /etc/docker/daemon.json
5252
{
53-
"labels": {{ INFRAKIT_LABELS | to_json }}
53+
"labels": {{ INFRAKIT_LABELS | jsonEncode }}
5454
}
5555
EOF
5656

pkg/template/funcs.go

Lines changed: 16 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -317,57 +317,37 @@ func (t *Template) DefaultFuncs() []Function {
317317
},
318318
},
319319
{
320-
Name: "global",
320+
Name: "var",
321321
Description: []string{
322-
"Sets a global variable named after the first argument, with the value as the second argument.",
323-
"This is similar to def (which sets the default value).",
324-
"Global variables are propagated to all templates that are rendered via the 'include' function.",
322+
"References or sets a variable. If single argument, returns the value.",
323+
"If second argument is provided, sets the variable. The scope is global.",
325324
},
326-
Func: func(n string, v interface{}) Void {
327-
t.Global(n, v)
325+
Func: func(n string, optional ...interface{}) interface{} {
326+
if len(optional) == 0 {
327+
return t.Ref(n)
328+
}
329+
t.Global(n, optional[len(optional)-1])
328330
return voidValue
329331
},
330332
},
331333
{
332-
Name: "def",
334+
Name: "k",
333335
Description: []string{
334-
"Defines a variable with the first argument as name and last argument value as the default.",
335-
"It's also ok to pass a third optional parameter, in the middle, as the documentation string.",
336-
},
337-
Func: func(name string, args ...interface{}) (Void, error) {
338-
if _, has := t.defaults[name]; has {
339-
// not sure if this is good, but should complain loudly
340-
return voidValue, fmt.Errorf("already defined: %v", name)
341-
}
342-
var doc string
343-
var value interface{}
344-
switch len(args) {
345-
case 1:
346-
// just value, no docs
347-
value = args[0]
348-
case 2:
349-
// docs and value
350-
doc = fmt.Sprintf("%v", args[0])
351-
value = args[1]
352-
}
353-
t.Def(name, value, doc)
354-
return voidValue, nil
336+
"Get value from dictionary by key.",
337+
"First arg is the key, second must be a map[string]interface{}",
355338
},
356-
},
357-
{
358-
Name: "ref",
359-
Description: []string{
360-
"References / gets the variable named after the first argument.",
361-
"The values must be set first by either def or global.",
339+
Func: // MapIndex gets the value of key from map
340+
func(k interface{}, m map[string]interface{}) interface{} {
341+
return m[fmt.Sprintf("%v", k)]
362342
},
363-
Func: t.Ref,
364343
},
365344
{
366345
Name: "q",
367346
Description: []string{
368347
"Runs a JMESPath (http://jmespath.org/) query (first arg) on the object (second arg).",
369348
"The return value is an object which needs to be rendered properly for the format of the document.",
370-
"Example: {{ include \"https://httpbin.org/get\" | from_json | q \"origin\" }} returns the origin of http request.",
349+
"Example: {{ include \"https://httpbin.org/get\" | from_json | q \"origin\" }}",
350+
"returns the origin of http request.",
371351
},
372352
Func: QueryObject,
373353
},
@@ -451,16 +431,6 @@ func (t *Template) DefaultFuncs() []Function {
451431
},
452432
Func: FromINI,
453433
},
454-
{
455-
Name: "k",
456-
Description: []string{
457-
"Get value from dictionary by key. First arg is the key, second must be a map[string]interface{}",
458-
},
459-
Func: // MapIndex gets the value of key from map
460-
func(k interface{}, m map[string]interface{}) interface{} {
461-
return m[fmt.Sprintf("%v", k)]
462-
},
463-
},
464434
{
465435
Name: "echo",
466436
Description: []string{
@@ -478,32 +448,5 @@ func (t *Template) DefaultFuncs() []Function {
478448
return ""
479449
},
480450
},
481-
482-
// Deprecated
483-
{
484-
Name: "to_json",
485-
Description: []string{
486-
"Encodes the input as a JSON string",
487-
"This is useful for taking an object (interface{}) and render it inline as proper JSON.",
488-
"Example: {{ include \"https://httpbin.org/get\" | from_json | to_json }}",
489-
},
490-
Func: ToJSON,
491-
},
492-
{
493-
Name: "to_json_format",
494-
Description: []string{
495-
"Encodes the input as a JSON string with first arg as prefix, second arg the indentation, then the object",
496-
},
497-
Func: ToJSONFormat,
498-
},
499-
{
500-
Name: "from_json",
501-
Description: []string{
502-
"Decodes the input (first arg) into a structure (a map[string]interface{} or []interface{}).",
503-
"This is useful for parsing arbitrary resources in JSON format as object. The object is the queryable via 'q'",
504-
"For example: {{ include \"https://httpbin.org/get\" | from_json | q \"origin\" }} returns the origin of request.",
505-
},
506-
Func: FromJSON,
507-
},
508451
}
509452
}

pkg/template/integration_test.go

Lines changed: 16 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,10 @@ import (
88
"sync"
99
"testing"
1010

11-
"github.com/docker/infrakit/pkg/log"
1211
"github.com/docker/infrakit/pkg/types"
1312
"github.com/stretchr/testify/require"
1413
)
1514

16-
var logger = log.New("module", "template")
17-
1815
func TestTemplateInclusionFromDifferentSources(t *testing.T) {
1916
prefix := testSetupTemplates(t, testFiles)
2017

@@ -88,11 +85,11 @@ echo "this is common/setup.sh"
8885
"test" : "test1",
8986
"description" : "simple template to test the various template functions",
9087
{{/* Load from from ./ using relative path notation. Then split into lines and json encode */}}
91-
"userData" : {{ include "script.tpl" . | lines | to_json }},
88+
"userData" : {{ include "script.tpl" . | lines | jsonEncode }},
9289
{{/* Load from an URL */}}
9390
"sample" : {{ include "https://httpbin.org/get" }},
9491
{{/* Load from URL and then parse as JSON then select an attribute */}}
95-
"originIp" : "{{ include "https://httpbin.org/get" | from_json | q "origin" }}"
92+
"originIp" : "{{ include "https://httpbin.org/get" | jsonDecode | q "origin" }}"
9693
}`,
9794

9895
"plugin/script.tpl": `
@@ -164,7 +161,7 @@ The message is {{str}}
164161
}
165162

166163
func TestMissingGlobal(t *testing.T) {
167-
s := `{{ if not (ref "/not/exist")}}none{{else}}here{{end}}`
164+
s := `{{ if not (var "/not/exist")}}none{{else}}here{{end}}`
168165
tt, err := NewTemplate("str://"+s, Options{})
169166
require.NoError(t, err)
170167
view, err := tt.Render(nil)
@@ -173,28 +170,18 @@ func TestMissingGlobal(t *testing.T) {
173170
}
174171

175172
func TestSourceAndDef(t *testing.T) {
176-
r := `{{ def \"foo\" 100 }}`
177-
s := `{{ source "str://` + r + `" }}foo={{ref "foo"}}`
173+
r := `{{ var \"foo\" 100 }}`
174+
s := `{{ source "str://` + r + `" }}foo={{var "foo"}}`
178175
tt, err := NewTemplate("str://"+s, Options{})
179176
require.NoError(t, err)
180177
view, err := tt.Render(nil)
181178
require.NoError(t, err)
182179
require.Equal(t, "foo=100", view)
183180
}
184181

185-
func TestAddDef(t *testing.T) {
186-
s := `{{ ref "message" }}: x + y = {{ add (ref "x") (ref "y") }}`
187-
tt, err := NewTemplate("str://"+s, Options{})
188-
require.NoError(t, err)
189-
190-
view, err := tt.Def("x", 25, "Default value for x").Def("y", 100, "no doc").Def("message", "hello", "").Render(nil)
191-
require.NoError(t, err)
192-
require.Equal(t, "hello: x + y = 125", view)
193-
}
194-
195182
func TestSourceAndGlobal(t *testing.T) {
196-
r := `{{ global \"foo\" 100 }}`
197-
s := `{{ source "str://` + r + `" }}foo={{ref "foo"}}`
183+
r := `{{ var \"foo\" 100 }}`
184+
s := `{{ source "str://` + r + `" }}foo={{var "foo"}}`
198185
tt, err := NewTemplate("str://"+s, Options{})
199186
require.NoError(t, err)
200187
view, err := tt.Render(nil)
@@ -203,8 +190,8 @@ func TestSourceAndGlobal(t *testing.T) {
203190
}
204191

205192
func TestIncludeAndGlobal(t *testing.T) {
206-
r := `{{ global \"foo\" 100 }}` // the child template tries to mutate the global
207-
s := `{{ include "str://` + r + `" }}foo={{ref "foo"}}`
193+
r := `{{ var \"foo\" 100 }}` // the child template tries to mutate the global
194+
s := `{{ include "str://` + r + `" }}foo={{var "foo"}}`
208195
tt, err := NewTemplate("str://"+s, Options{})
209196
require.NoError(t, err)
210197
tt.Global("foo", 200) // set the global of the calling / parent template
@@ -218,7 +205,7 @@ func TestSourceAndGlobalWithContext(t *testing.T) {
218205
"a": 1,
219206
"b": 2,
220207
}
221-
r := `{{ global \"foo\" 100 }}{{$void := set . \"a\" 100}}` // sourced mutates the context
208+
r := `{{ var \"foo\" 100 }}{{$void := set . \"a\" 100}}` // sourced mutates the context
222209
s := `{{ source "str://` + r + `" }}a={{.a}}`
223210
tt, err := NewTemplate("str://"+s, Options{})
224211
require.NoError(t, err)
@@ -232,7 +219,7 @@ func TestIncludeAndGlobalWithContext(t *testing.T) {
232219
"a": 1,
233220
"b": 2,
234221
}
235-
r := `{{ global \"foo\" 100 }}{{$void := set . \"a\" 100}}` // included tries to mutate the context
222+
r := `{{ var \"foo\" 100 }}{{$void := set . \"a\" 100}}` // included tries to mutate the context
236223
s := `{{ include "str://` + r + `" }}a={{.a}}`
237224
tt, err := NewTemplate("str://"+s, Options{})
238225
require.NoError(t, err)
@@ -264,27 +251,27 @@ func TestWithFunctions(t *testing.T) {
264251
func TestSourceWithHeaders(t *testing.T) {
265252

266253
h, context := headersAndContext("foo=bar")
267-
logger.Info("result", "context", context, "headers", h)
254+
log.Info("result", "context", context, "headers", h)
268255
require.Equal(t, interface{}(nil), context)
269256
require.Equal(t, map[string][]string{"foo": {"bar"}}, h)
270257

271258
h, context = headersAndContext("foo=bar", "bar=baz", 224)
272-
logger.Info("result", "context", context, "headers", h)
259+
log.Info("result", "context", context, "headers", h)
273260
require.Equal(t, 224, context)
274261
require.Equal(t, map[string][]string{"foo": {"bar"}, "bar": {"baz"}}, h)
275262

276263
h, context = headersAndContext("foo=bar", "bar=baz")
277-
logger.Info("result", "context", context, "headers", h)
264+
log.Info("result", "context", context, "headers", h)
278265
require.Equal(t, nil, context)
279266
require.Equal(t, map[string][]string{"foo": {"bar"}, "bar": {"baz"}}, h)
280267

281268
h, context = headersAndContext("foo")
282-
logger.Info("result", "context", context, "headers", h)
269+
log.Info("result", "context", context, "headers", h)
283270
require.Equal(t, "foo", context)
284271
require.Equal(t, map[string][]string{}, h)
285272

286273
h, context = headersAndContext("foo=bar", map[string]string{"hello": "world"})
287-
logger.Info("result", "context", context, "headers", h)
274+
log.Info("result", "context", context, "headers", h)
288275
require.Equal(t, map[string]string{"hello": "world"}, context)
289276
require.Equal(t, map[string][]string{"foo": {"bar"}}, h)
290277

0 commit comments

Comments
 (0)