lang: funcs: Rename template functions to remove periods

Due to a limitation in the template library, we need to rename some
functions. It's probably worth looking into modifying this library or
finding an alternate version.
This commit is contained in:
James Shubin
2019-02-01 03:58:02 -05:00
parent ce8c8c8eea
commit f716a3a73b
4 changed files with 44 additions and 1 deletions

View File

@@ -21,6 +21,7 @@ import (
"bytes" "bytes"
"fmt" "fmt"
"reflect" "reflect"
"strings"
"text/template" "text/template"
"github.com/purpleidea/mgmt/lang/funcs" "github.com/purpleidea/mgmt/lang/funcs"
@@ -189,8 +190,8 @@ func (obj *TemplateFunc) run(templateText string, vars types.Value) (string, err
// function in the simple package? // function in the simple package?
// TODO: loop through this map in a sorted, deterministic order // TODO: loop through this map in a sorted, deterministic order
// XXX: should this use the scope instead (so imports are used properly) ? // XXX: should this use the scope instead (so imports are used properly) ?
// XXX: dots are not valid here, so maybe replace dots with underscores so we can do fmt_print???
for name, fn := range simple.RegisteredFuncs { for name, fn := range simple.RegisteredFuncs {
name = safename(name) // TODO: rename since we can't include dot
if _, exists := funcMap[name]; exists { if _, exists := funcMap[name]; exists {
obj.init.Logf("warning, existing function named: `%s` exists", name) obj.init.Logf("warning, existing function named: `%s` exists", name)
continue continue
@@ -326,6 +327,23 @@ func (obj *TemplateFunc) Close() error {
return nil return nil
} }
// safename renames the functions so they're valid inside the template. This is
// a limitation of the template library, and it might be worth moving to a new
// one.
func safename(name string) string {
// TODO: should we pick a different replacement char?
char := funcs.ReplaceChar // can't be any of: .-#
result := strings.Replace(name, funcs.ModuleSep, char, -1)
if result == name {
// No change, so add a prefix for package-less functions... This
// prevents conflicts from sys.func1 -> sys_func1 which would be
// a conflict with a top-level function named sys_func1 which is
// now renamed to _sys_func1.
return char + name
}
return result
}
// wrap builds a function in the format expected by the template engine, and // wrap builds a function in the format expected by the template engine, and
// returns it as an interface{}. It does so by wrapping our type system and // returns it as an interface{}. It does so by wrapping our type system and
// function API with what is expected from the reflection API. It returns a // function API with what is expected from the reflection API. It returns a

View File

@@ -30,6 +30,13 @@ const (
// example when using `fmt.printf` or `math.sin` this is the char used. // example when using `fmt.printf` or `math.sin` this is the char used.
// It is included here for convenience when importing this package. // It is included here for convenience when importing this package.
ModuleSep = interfaces.ModuleSep ModuleSep = interfaces.ModuleSep
// ReplaceChar is a special char that is used to replace ModuleSep when
// it can't be used for some reason. This currently only happens in the
// golang template library. Even with this limitation in that library,
// we don't want to allow this as the first or last character in a name.
// NOTE: the template library will panic if it is one of: .-#
ReplaceChar = "_"
) )
// registeredFuncs is a global map of all possible funcs which can be used. You // registeredFuncs is a global map of all possible funcs which can be used. You
@@ -56,6 +63,11 @@ func Register(name string, fn func() interfaces.Func) {
if strings.HasPrefix(name, ModuleSep) || strings.HasSuffix(name, ModuleSep) { if strings.HasPrefix(name, ModuleSep) || strings.HasSuffix(name, ModuleSep) {
panic(fmt.Sprintf("a func named %s is invalid", name)) panic(fmt.Sprintf("a func named %s is invalid", name))
} }
// TODO: this should be added but conflicts with our internal functions
// can't start or end with an underscore
//if strings.HasPrefix(name, ReplaceChar) || strings.HasSuffix(name, ReplaceChar) {
// panic(fmt.Sprintf("a func named %s is invalid", name))
//}
//gob.Register(fn()) //gob.Register(fn())
registeredFuncs[name] = fn registeredFuncs[name] = fn

View File

@@ -0,0 +1 @@
Vertex: print[template-0]

View File

@@ -0,0 +1,12 @@
import "datetime"
$secplus42 = 42 + $ayear
# note the order of the assignment (year can come later in the code)
$ayear = 60 * 60 * 24 * 365 # is a year in seconds (31536000)
$tmplvalues = struct{time => $secplus42, hello => "world",}
print "template-0" {
msg => template("Hello: {{ .hello }}, 42 sec + 1 year is: {{ .time }} seconds, aka: {{ datetime_print .time }}", $tmplvalues),
}