Skip to content

Commit

Permalink
Merge pull request #673 from marwan-at-work/tpl
Browse files Browse the repository at this point in the history
codegen/templates: allow templates to be passed in options instead of…
  • Loading branch information
vektah authored Apr 15, 2019
2 parents 8cae895 + 37fd067 commit 5aa6a20
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 25 deletions.
77 changes: 52 additions & 25 deletions codegen/templates/templates.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,36 @@ import (
"github.com/pkg/errors"
)

// CurrentImports keeps track of all the import declarations that are needed during the execution of a plugin.
// this is done with a global because subtemplates currently get called in functions. Lets aim to remove this eventually.
var CurrentImports *Imports

// Options specify various parameters to rendering a template.
type Options struct {
PackageName string
// PackageName is a helper that specifies the package header declaration.
// In other words, when you write the template you don't need to specify `package X`
// at the top of the file. By providing PackageName in the Options, the Render
// function will do that for you.
PackageName string
// Template is a string of the entire template that
// will be parsed and rendered. If it's empty,
// the plugin processor will look for .gotpl files
// in the same directory of where you wrote the plugin.
Template string
// Filename is the name of the file that will be
// written to the system disk once the template is rendered.
Filename string
RegionTags bool
GeneratedHeader bool
Data interface{}
Funcs template.FuncMap
// Data will be passed to the template execution.
Data interface{}
Funcs template.FuncMap
}

// Render renders a gql plugin template from the given Options. Render is an
// abstraction of the text/template package that makes it easier to write gqlgen
// plugins. If Options.Template is empty, the Render function will look for `.gotpl`
// files inside the directory where you wrote the plugin.
func Render(cfg Options) error {
if CurrentImports != nil {
panic(fmt.Errorf("recursive or concurrent call to RenderToFile detected"))
Expand All @@ -48,31 +66,40 @@ func Render(cfg Options) error {
t := template.New("").Funcs(funcs)

var roots []string
// load all the templates in the directory
err := filepath.Walk(rootDir, func(path string, info os.FileInfo, err error) error {
if cfg.Template != "" {
var err error
t, err = t.New("template.gotpl").Parse(cfg.Template)
if err != nil {
return err
}
name := filepath.ToSlash(strings.TrimPrefix(path, rootDir+string(os.PathSeparator)))
if !strings.HasSuffix(info.Name(), ".gotpl") {
return nil
}
b, err := ioutil.ReadFile(path)
if err != nil {
return err
return errors.Wrap(err, "error with provided template")
}
roots = append(roots, "template.gotpl")
} else {
// load all the templates in the directory
err := filepath.Walk(rootDir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
name := filepath.ToSlash(strings.TrimPrefix(path, rootDir+string(os.PathSeparator)))
if !strings.HasSuffix(info.Name(), ".gotpl") {
return nil
}
b, err := ioutil.ReadFile(path)
if err != nil {
return err
}

t, err = t.New(name).Parse(string(b))
if err != nil {
return errors.Wrap(err, cfg.Filename)
}
t, err = t.New(name).Parse(string(b))
if err != nil {
return errors.Wrap(err, cfg.Filename)
}

roots = append(roots, name)
roots = append(roots, name)

return nil
})
if err != nil {
return errors.Wrap(err, "locating templates")
return nil
})
if err != nil {
return errors.Wrap(err, "locating templates")
}
}

// then execute all the important looking ones in order, adding them to the same file
Expand All @@ -91,7 +118,7 @@ func Render(cfg Options) error {
if cfg.RegionTags {
buf.WriteString("\n// region " + center(70, "*", " "+root+" ") + "\n")
}
err = t.Lookup(root).Execute(&buf, cfg.Data)
err := t.Lookup(root).Execute(&buf, cfg.Data)
if err != nil {
return errors.Wrap(err, root)
}
Expand All @@ -110,7 +137,7 @@ func Render(cfg Options) error {
result.WriteString("import (\n")
result.WriteString(CurrentImports.String())
result.WriteString(")\n")
_, err = buf.WriteTo(&result)
_, err := buf.WriteTo(&result)
if err != nil {
return err
}
Expand Down
15 changes: 15 additions & 0 deletions codegen/templates/templates_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package templates

import (
"io/ioutil"
"os"
"testing"

"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -100,3 +102,16 @@ func TestCenter(t *testing.T) {
require.Equal(t, "##fffff###", center(10, "#", "fffff"))
require.Equal(t, "###fffff###", center(11, "#", "fffff"))
}

func TestTemplateOverride(t *testing.T) {
f, err := ioutil.TempFile("", "gqlgen")
if err != nil {
t.Fatal(err)
}
defer f.Close()
defer os.RemoveAll(f.Name())
err = Render(Options{Template: "hello", Filename: f.Name()})
if err != nil {
t.Fatal(err)
}
}

0 comments on commit 5aa6a20

Please sign in to comment.