Skip to content

Commit

Permalink
tpl/tplimpl: Handle late transformation of templates
Browse files Browse the repository at this point in the history
  • Loading branch information
bep committed Apr 16, 2019
1 parent 56550d1 commit 6269c5c
Show file tree
Hide file tree
Showing 6 changed files with 125 additions and 60 deletions.
2 changes: 1 addition & 1 deletion tpl/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ type TemplateHandler interface {

NewTextTemplate() TemplateParseFinder

MarkReady()
MarkReady() error
RebuildClone()
}

Expand Down
6 changes: 3 additions & 3 deletions tpl/tplimpl/ace.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,15 @@ func (t *templateHandler) addAceTemplate(name, basePath, innerPath string, baseC

typ := resolveTemplateType(name)

info, err := applyTemplateTransformersToHMLTTemplate(typ, templ)
c, err := applyTemplateTransformersToHMLTTemplate(typ, templ)
if err != nil {
return err
}

if typ == templateShortcode {
t.addShortcodeVariant(name, info, templ)
t.addShortcodeVariant(name, c.Info, templ)
} else {
t.templateInfo[name] = info
t.templateInfo[name] = c.Info
}

return nil
Expand Down
128 changes: 89 additions & 39 deletions tpl/tplimpl/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"html/template"
"strings"
texttemplate "text/template"
"text/template/parse"

"github.com/gohugoio/hugo/hugofs"
"github.com/gohugoio/hugo/tpl/tplimpl/embedded"
Expand Down Expand Up @@ -51,7 +52,6 @@ var (
_ tpl.TemplateFinder = (*textTemplates)(nil)
_ templateLoader = (*htmlTemplates)(nil)
_ templateLoader = (*textTemplates)(nil)
_ templateLoader = (*templateHandler)(nil)
_ templateFuncsterTemplater = (*htmlTemplates)(nil)
_ templateFuncsterTemplater = (*textTemplates)(nil)
)
Expand All @@ -66,7 +66,7 @@ type templateErr struct {

type templateLoader interface {
handleMaster(name, overlayFilename, masterFilename string, onMissing func(filename string) (templateInfo, error)) error
addTemplate(name, tpl string) error
addTemplate(name, tpl string) (*templateContext, error)
addLateTemplate(name, tpl string) error
}

Expand Down Expand Up @@ -104,6 +104,10 @@ type templateHandler struct {

errors []*templateErr

// Holds names of the templates not found during the first AST transformation
// pass.
transformNotFound map[string]bool

// This is the filesystem to load the templates from. All the templates are
// stored in the root of this filesystem.
layoutsFs afero.Fs
Expand Down Expand Up @@ -278,13 +282,14 @@ func (t *templateHandler) setFuncMapInTemplate(in interface{}, funcs map[string]

func (t *templateHandler) clone(d *deps.Deps) *templateHandler {
c := &templateHandler{
Deps: d,
layoutsFs: d.BaseFs.Layouts.Fs,
shortcodes: make(map[string]*shortcodeTemplates),
templateInfo: t.templateInfo,
html: &htmlTemplates{t: template.Must(t.html.t.Clone()), overlays: make(map[string]*template.Template), templatesCommon: t.html.templatesCommon},
text: &textTemplates{textTemplate: &textTemplate{t: texttemplate.Must(t.text.t.Clone())}, overlays: make(map[string]*texttemplate.Template), templatesCommon: t.text.templatesCommon},
errors: make([]*templateErr, 0),
Deps: d,
layoutsFs: d.BaseFs.Layouts.Fs,
shortcodes: make(map[string]*shortcodeTemplates),
templateInfo: t.templateInfo,
html: &htmlTemplates{t: template.Must(t.html.t.Clone()), overlays: make(map[string]*template.Template), templatesCommon: t.html.templatesCommon},
text: &textTemplates{textTemplate: &textTemplate{t: texttemplate.Must(t.text.t.Clone())}, overlays: make(map[string]*texttemplate.Template), templatesCommon: t.text.templatesCommon},
transformNotFound: t.transformNotFound,
errors: make([]*templateErr, 0),
}

for k, v := range t.shortcodes {
Expand Down Expand Up @@ -342,13 +347,14 @@ func newTemplateAdapter(deps *deps.Deps) *templateHandler {
templatesCommon: common,
}
h := &templateHandler{
Deps: deps,
layoutsFs: deps.BaseFs.Layouts.Fs,
shortcodes: make(map[string]*shortcodeTemplates),
templateInfo: make(map[string]tpl.Info),
html: htmlT,
text: textT,
errors: make([]*templateErr, 0),
Deps: deps,
layoutsFs: deps.BaseFs.Layouts.Fs,
shortcodes: make(map[string]*shortcodeTemplates),
templateInfo: make(map[string]tpl.Info),
html: htmlT,
text: textT,
transformNotFound: make(map[string]bool),
errors: make([]*templateErr, 0),
}

common.handler = h
Expand Down Expand Up @@ -491,37 +497,38 @@ func (t *templateHandler) LoadTemplates(prefix string) error {

}

func (t *htmlTemplates) addTemplateIn(tt *template.Template, name, tpl string) error {
func (t *htmlTemplates) addTemplateIn(tt *template.Template, name, tpl string) (*templateContext, error) {
t.mu.Lock()
defer t.mu.Unlock()

templ, err := tt.New(name).Parse(tpl)
if err != nil {
return err
return nil, err
}

typ := resolveTemplateType(name)

info, err := applyTemplateTransformersToHMLTTemplate(typ, templ)
c, err := applyTemplateTransformersToHMLTTemplate(typ, templ)
if err != nil {
return err
return nil, err
}

if typ == templateShortcode {
t.handler.addShortcodeVariant(name, info, templ)
t.handler.addShortcodeVariant(name, c.Info, templ)
} else {
t.handler.templateInfo[name] = info
t.handler.templateInfo[name] = c.Info
}

return nil
return c, nil
}

func (t *htmlTemplates) addTemplate(name, tpl string) error {
func (t *htmlTemplates) addTemplate(name, tpl string) (*templateContext, error) {
return t.addTemplateIn(t.t, name, tpl)
}

func (t *htmlTemplates) addLateTemplate(name, tpl string) error {
return t.addTemplateIn(t.clone, name, tpl)
_, err := t.addTemplateIn(t.clone, name, tpl)
return err
}

type textTemplate struct {
Expand Down Expand Up @@ -556,41 +563,73 @@ func (t *textTemplate) parseIn(tt *texttemplate.Template, name, tpl string) (*te
return templ, nil
}

func (t *textTemplates) addTemplateIn(tt *texttemplate.Template, name, tpl string) error {
func (t *textTemplates) addTemplateIn(tt *texttemplate.Template, name, tpl string) (*templateContext, error) {
name = strings.TrimPrefix(name, textTmplNamePrefix)
templ, err := t.parseIn(tt, name, tpl)
if err != nil {
return err
return nil, err
}

typ := resolveTemplateType(name)

info, err := applyTemplateTransformersToTextTemplate(typ, templ)
c, err := applyTemplateTransformersToTextTemplate(typ, templ)
if err != nil {
return err
return nil, err
}

if typ == templateShortcode {
t.handler.addShortcodeVariant(name, info, templ)
t.handler.addShortcodeVariant(name, c.Info, templ)
} else {
t.handler.templateInfo[name] = info
t.handler.templateInfo[name] = c.Info
}

return nil
return c, nil
}

func (t *textTemplates) addTemplate(name, tpl string) error {
func (t *textTemplates) addTemplate(name, tpl string) (*templateContext, error) {
return t.addTemplateIn(t.t, name, tpl)
}

func (t *textTemplates) addLateTemplate(name, tpl string) error {
return t.addTemplateIn(t.clone, name, tpl)
_, err := t.addTemplateIn(t.clone, name, tpl)
return err
}

func (t *templateHandler) addTemplate(name, tpl string) error {
return t.AddTemplate(name, tpl)
}

func (t *templateHandler) postTransform() error {
if len(t.transformNotFound) == 0 {
return nil
}

lookupFn := func(name string) *parse.Tree {
templ := t.html.lookup(name)
if templ != nil {
return templ.Tree
}
templT := t.text.lookup(name)
if templT == nil {
return nil
}
return templT.Tree
}

for name, _ := range t.transformNotFound {
templ := lookupFn(name)
if templ != nil {
_, err := applyTemplateTransformers(templateUndefined, templ, lookupFn)
if err != nil {
return err
}
} else {
fmt.Println(">>> >>>", name)
}
}
return nil
}

func (t *templateHandler) addLateTemplate(name, tpl string) error {
return t.AddLateTemplate(name, tpl)
}
Expand All @@ -608,19 +647,28 @@ func (t *templateHandler) AddLateTemplate(name, tpl string) error {
// AddTemplate parses and adds a template to the collection.
// Templates with name prefixed with "_text" will be handled as plain
// text templates.
// TODO(bep) clean up these addTemplate variants
func (t *templateHandler) AddTemplate(name, tpl string) error {
h := t.getTemplateHandler(name)
if err := h.addTemplate(name, tpl); err != nil {
c, err := h.addTemplate(name, tpl)
if err != nil {
return err
}
for k, _ := range c.notFound {
t.transformNotFound[k] = true
}
return nil
}

// MarkReady marks the templates as "ready for execution". No changes allowed
// after this is set.
// TODO(bep) if this proves to be resource heavy, we could detect
// earlier if we really need this, or make it lazy.
func (t *templateHandler) MarkReady() {
func (t *templateHandler) MarkReady() error {
if err := t.postTransform(); err != nil {
return err
}

if t.html.clone == nil {
t.html.clone = template.Must(t.html.t.Clone())
t.html.cloneClone = template.Must(t.html.clone.Clone())
Expand All @@ -629,6 +677,8 @@ func (t *templateHandler) MarkReady() {
t.text.clone = texttemplate.Must(t.text.t.Clone())
t.text.cloneClone = texttemplate.Must(t.text.clone.Clone())
}

return nil
}

// RebuildClone rebuilds the cloned templates. Used for live-reloads.
Expand Down Expand Up @@ -890,15 +940,15 @@ func (t *templateHandler) addTemplateFile(name, baseTemplatePath, path string) e

typ := resolveTemplateType(name)

info, err := applyTemplateTransformersToHMLTTemplate(typ, templ)
c, err := applyTemplateTransformersToHMLTTemplate(typ, templ)
if err != nil {
return err
}

if typ == templateShortcode {
t.addShortcodeVariant(templateName, info, templ)
t.addShortcodeVariant(templateName, c.Info, templ)
} else {
t.templateInfo[name] = info
t.templateInfo[name] = c.Info
}

return nil
Expand Down
25 changes: 17 additions & 8 deletions tpl/tplimpl/template_ast_transformers.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ const (
type templateContext struct {
decl decl
visited map[string]bool
notFound map[string]bool
lookupFn func(name string) *parse.Tree

// The last error encountered.
Expand All @@ -72,16 +73,24 @@ func (c templateContext) getIfNotVisited(name string) *parse.Tree {
return nil
}
c.visited[name] = true
return c.lookupFn(name)
templ := c.lookupFn(name)
if templ == nil {
// This may be a inline template defined outside of this file
// and not yet parsed. Unusual, but it happens.
// Store the name to try again later.
c.notFound[name] = true
}

return templ
}

func newTemplateContext(lookupFn func(name string) *parse.Tree) *templateContext {
return &templateContext{
Info: tpl.Info{Config: tpl.DefaultConfig},
lookupFn: lookupFn,
decl: make(map[string]string),
visited: make(map[string]bool)}

visited: make(map[string]bool),
notFound: make(map[string]bool)}
}

func createParseTreeLookup(templ *template.Template) func(nn string) *parse.Tree {
Expand All @@ -94,11 +103,11 @@ func createParseTreeLookup(templ *template.Template) func(nn string) *parse.Tree
}
}

func applyTemplateTransformersToHMLTTemplate(typ templateType, templ *template.Template) (tpl.Info, error) {
func applyTemplateTransformersToHMLTTemplate(typ templateType, templ *template.Template) (*templateContext, error) {
return applyTemplateTransformers(typ, templ.Tree, createParseTreeLookup(templ))
}

func applyTemplateTransformersToTextTemplate(typ templateType, templ *texttemplate.Template) (tpl.Info, error) {
func applyTemplateTransformersToTextTemplate(typ templateType, templ *texttemplate.Template) (*templateContext, error) {
return applyTemplateTransformers(typ, templ.Tree,
func(nn string) *parse.Tree {
tt := templ.Lookup(nn)
Expand All @@ -109,9 +118,9 @@ func applyTemplateTransformersToTextTemplate(typ templateType, templ *texttempla
})
}

func applyTemplateTransformers(typ templateType, templ *parse.Tree, lookupFn func(name string) *parse.Tree) (tpl.Info, error) {
func applyTemplateTransformers(typ templateType, templ *parse.Tree, lookupFn func(name string) *parse.Tree) (*templateContext, error) {
if templ == nil {
return tpl.Info{}, errors.New("expected template, but none provided")
return nil, errors.New("expected template, but none provided")
}

c := newTemplateContext(lookupFn)
Expand All @@ -125,7 +134,7 @@ func applyTemplateTransformers(typ templateType, templ *parse.Tree, lookupFn fun
templ.Root = c.wrapInPartialReturnWrapper(templ.Root)
}

return c.Info, err
return c, err
}

const (
Expand Down
Loading

0 comments on commit 6269c5c

Please sign in to comment.