Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add ability to fill a Golang template from a Starlark transformer #1050

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions common/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -641,12 +641,10 @@ func GetStringFromTemplate(tpl string, config interface{}) (string, error) {
var tplbuffer bytes.Buffer
packageTemplate, err := template.New("").Funcs(sprig.TxtFuncMap()).Parse(tpl)
if err != nil {
logrus.Errorf("Unable to parse template : %s", err)
return "", err
return "", fmt.Errorf("failed to parse the template. Error: %w", err)
}
err = packageTemplate.Execute(&tplbuffer, config)
if err != nil {
return "", fmt.Errorf("unable to transform template to string using the data. Error: %q . Data: %+v Template: %q", err, config, tpl)
if err := packageTemplate.Execute(&tplbuffer, config); err != nil {
return "", fmt.Errorf("failed to transform the template to string using the data. Error: %w . Data: %+v Template: '%s'", err, config, tpl)
}
return tplbuffer.String(), nil
}
Expand Down
48 changes: 48 additions & 0 deletions transformer/external/starlarktransformer.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ const (
// Function names
qaFnName = "query"
// fs package
evalTemplate = "eval_template"
fsExistsFnName = "exists"
fsReadAsStringFnName = "read_as_string"
fsReadAsBinaryFnName = "read_as_binary"
Expand Down Expand Up @@ -330,6 +331,7 @@ func (t *Starlark) setDefaultGlobals() {
t.StarGlobals = starlark.StringDict{}
t.addStarlibModules()
t.addFSModules()
t.addTemplateModules()
t.addAppModules()
t.addCryptoModules()
t.addArchiveModules()
Expand Down Expand Up @@ -377,6 +379,15 @@ func (t *Starlark) addFSModules() {
}
}

func (t *Starlark) addTemplateModules() {
t.StarGlobals["template"] = &starlarkstruct.Module{
Name: "template",
Members: starlark.StringDict{
evalTemplate: t.getStarlarkEvalTemplate(),
},
}
}

func (t *Starlark) addCryptoModules() {
t.StarGlobals["crypto"] = &starlarkstruct.Module{
Name: "crypto",
Expand Down Expand Up @@ -557,6 +568,43 @@ func (t *Starlark) getStarlarkFSWrite() *starlark.Builtin {
})
}

func (t *Starlark) getStarlarkEvalTemplate() *starlark.Builtin {
return starlark.NewBuiltin(evalTemplate, func(thread *starlark.Thread, fn *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
templateContents := ""
data := starlark.NewDict(16)
if err := starlark.UnpackPositionalArgs(fsExistsFnName, args, kwargs, 2, &templateContents, &data); err != nil {
return nil, fmt.Errorf("failed to unpack the positional arguments. Error: %w", err)
}
logrus.Debugf("templateContents:\n%s\n---------------\n", templateContents)
dataMap := map[string]interface{}{}
for _, x := range data.Items() {
k, err := starutil.Unmarshal(x[0])
if err != nil {
logrus.Errorf("failed to unmarshal the Starlark value %#v as a Golang interface{} . Error: %q", x[0], err)
continue
}
v, err := starutil.Unmarshal(x[1])
if err != nil {
logrus.Errorf("failed to unmarshal the Starlark value %#v as a Golang interface{} . Error: %q", x[1], err)
continue
}
kStr, ok := k.(string)
if !ok {
logrus.Errorf("expected the key to be a string. actual type is %T and value is %#v", k, k)
continue
}
dataMap[kStr] = v
}
logrus.Debugf("dataMap:\n%#v\n---------------\n", dataMap)
filledTemplate, err := common.GetStringFromTemplate(templateContents, dataMap)
if err != nil {
return starlark.String(""), fmt.Errorf("failed to fill the template '%s' using the data %#v . Error: %w", templateContents, data, err)
}
logrus.Debugf("filledTemplate:\n%s\n---------------\n", filledTemplate)
return starlark.String(filledTemplate), nil
})
}

func (t *Starlark) getStarlarkFSExists() *starlark.Builtin {
return starlark.NewBuiltin(fsExistsFnName, func(thread *starlark.Thread, fn *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
var path string
Expand Down
Loading