summaryrefslogtreecommitdiffstats
path: root/tpl
diff options
context:
space:
mode:
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2017-01-10 10:55:03 +0100
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2017-02-04 11:37:25 +0700
commitc71e1b106e6011d148cac899f83c4685dee33a22 (patch)
treec5c7090f0c2398c7771e4908ebcc97aa7714ffd2 /tpl
parent0ada40591216572b0e4c6a8ab986b0aa4fb13c13 (diff)
all: Refactor to nonglobal file systems
Updates #2701 Fixes #2951
Diffstat (limited to 'tpl')
-rw-r--r--tpl/amber_compiler.go42
-rw-r--r--tpl/template.go170
-rw-r--r--tpl/template_funcs.go92
-rw-r--r--tpl/template_funcs_test.go189
-rw-r--r--tpl/template_i18n.go1
-rw-r--r--tpl/template_resources.go19
-rw-r--r--tpl/template_resources_test.go32
-rw-r--r--tpl/template_test.go110
8 files changed, 399 insertions, 256 deletions
diff --git a/tpl/amber_compiler.go b/tpl/amber_compiler.go
new file mode 100644
index 000000000..4477f6ac0
--- /dev/null
+++ b/tpl/amber_compiler.go
@@ -0,0 +1,42 @@
+// Copyright 2017 The Hugo Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package tpl
+
+import (
+ "html/template"
+
+ "github.com/eknkc/amber"
+)
+
+func (gt *GoHTMLTemplate) CompileAmberWithTemplate(b []byte, path string, t *template.Template) (*template.Template, error) {
+ c := amber.New()
+
+ if err := c.ParseData(b, path); err != nil {
+ return nil, err
+ }
+
+ data, err := c.CompileString()
+
+ if err != nil {
+ return nil, err
+ }
+
+ tpl, err := t.Funcs(gt.amberFuncMap).Parse(data)
+
+ if err != nil {
+ return nil, err
+ }
+
+ return tpl, nil
+}
diff --git a/tpl/template.go b/tpl/template.go
index 867c0a2ef..1c71989f4 100644
--- a/tpl/template.go
+++ b/tpl/template.go
@@ -24,33 +24,12 @@ import (
"github.com/eknkc/amber"
"github.com/spf13/afero"
bp "github.com/spf13/hugo/bufferpool"
+ "github.com/spf13/hugo/deps"
"github.com/spf13/hugo/helpers"
- "github.com/spf13/hugo/hugofs"
- jww "github.com/spf13/jwalterweatherman"
"github.com/yosssi/ace"
)
// TODO(bep) globals get rid of the rest of the jww.ERR etc.
-//var tmpl *GoHTMLTemplate
-
-// TODO(bep) an interface with hundreds of methods ... remove it.
-// And unexport most of these methods.
-type Template interface {
- ExecuteTemplate(wr io.Writer, name string, data interface{}) error
- Lookup(name string) *template.Template
- Templates() []*template.Template
- New(name string) *template.Template
- GetClone() *template.Template
- LoadTemplates(absPath string)
- LoadTemplatesWithPrefix(absPath, prefix string)
- AddTemplate(name, tpl string) error
- AddTemplateFileWithMaster(name, overlayFilename, masterFilename string) error
- AddAceTemplate(name, basePath, innerPath string, baseContent, innerContent []byte) error
- AddInternalTemplate(prefix, name, tpl string) error
- AddInternalShortcode(name, tpl string) error
- PrintErrors()
- Funcs(funcMap template.FuncMap)
-}
type templateErr struct {
name string
@@ -70,52 +49,105 @@ type GoHTMLTemplate struct {
funcster *templateFuncster
- // TODO(bep) globals template
- log *jww.Notepad
+ amberFuncMap template.FuncMap
+
+ *deps.Deps
}
-// New returns a new Hugo Template System
+type TemplateProvider struct{}
+
+var DefaultTemplateProvider *TemplateProvider
+
+// Update updates the Hugo Template System in the provided Deps.
// with all the additional features, templates & functions
-func New(logger *jww.Notepad, withTemplate ...func(templ Template) error) *GoHTMLTemplate {
+func (*TemplateProvider) Update(deps *deps.Deps) error {
+ // TODO(bep) check that this isn't called too many times.
tmpl := &GoHTMLTemplate{
Template: template.New(""),
overlays: make(map[string]*template.Template),
errors: make([]*templateErr, 0),
- log: logger,
+ Deps: deps,
}
- tmpl.funcster = newTemplateFuncster(tmpl)
+ deps.Tmpl = tmpl
- // The URL funcs in the funcMap is somewhat language dependent,
- // so we need to wait until the language and site config is loaded.
- // TODO(bep) globals
- tmpl.funcster.initFuncMap()
-
- // TODO(bep) globals
- for k, v := range tmpl.funcster.funcMap {
- amber.FuncMap[k] = v
- }
+ tmpl.initFuncs(deps)
tmpl.LoadEmbedded()
- for _, wt := range withTemplate {
- err := wt(tmpl)
+ if deps.WithTemplate != nil {
+ err := deps.WithTemplate(tmpl)
if err != nil {
tmpl.errors = append(tmpl.errors, &templateErr{"init", err})
}
}
- tmpl.markReady()
+ tmpl.MarkReady()
+
+ return nil
+
+}
+
+// Clone clones
+func (*TemplateProvider) Clone(d *deps.Deps) error {
+
+ t := d.Tmpl.(*GoHTMLTemplate)
+
+ // 1. Clone the clone with new template funcs
+ // 2. Clone any overlays with new template funcs
+
+ tmpl := &GoHTMLTemplate{
+ Template: template.Must(t.Template.Clone()),
+ overlays: make(map[string]*template.Template),
+ errors: make([]*templateErr, 0),
+ Deps: d,
+ }
+
+ d.Tmpl = tmpl
+ tmpl.initFuncs(d)
+
+ for k, v := range t.overlays {
+ vc := template.Must(v.Clone())
+ vc.Funcs(tmpl.funcster.funcMap)
+ tmpl.overlays[k] = vc
+ }
+
+ tmpl.MarkReady()
+
+ return nil
+}
+
+func (t *GoHTMLTemplate) initFuncs(d *deps.Deps) {
+
+ t.funcster = newTemplateFuncster(d)
+
+ // The URL funcs in the funcMap is somewhat language dependent,
+ // so we need to wait until the language and site config is loaded.
+ t.funcster.initFuncMap()
+
+ t.amberFuncMap = template.FuncMap{}
+
+ for k, v := range amber.FuncMap {
+ t.amberFuncMap[k] = v
+ }
+
+ for k, v := range t.funcster.funcMap {
+ t.amberFuncMap[k] = v
+ // Hacky, but we need to make sure that the func names are in the global map.
+ amber.FuncMap[k] = func() string {
+ panic("should never be invoked")
+ return ""
+ }
+ }
- return tmpl
}
func (t *GoHTMLTemplate) Funcs(funcMap template.FuncMap) {
t.Template.Funcs(funcMap)
}
-func (t *GoHTMLTemplate) partial(name string, contextList ...interface{}) template.HTML {
+func (t *GoHTMLTemplate) Partial(name string, contextList ...interface{}) template.HTML {
if strings.HasPrefix("partials/", name) {
name = name[8:]
}
@@ -147,8 +179,8 @@ func (t *GoHTMLTemplate) executeTemplate(context interface{}, w io.Writer, layou
}
}
if !worked {
- t.log.ERROR.Println("Unable to render", layouts)
- t.log.ERROR.Println("Expecting to find a template in either the theme/layouts or /layouts in one of the following relative locations", layouts)
+ t.Log.ERROR.Println("Unable to render", layouts)
+ t.Log.ERROR.Println("Expecting to find a template in either the theme/layouts or /layouts in one of the following relative locations", layouts)
}
}
@@ -186,9 +218,9 @@ func (t *GoHTMLTemplate) LoadEmbedded() {
t.EmbedTemplates()
}
-// markReady marks the template as "ready for execution". No changes allowed
+// MarkReady marks the template as "ready for execution". No changes allowed
// after this is set.
-func (t *GoHTMLTemplate) markReady() {
+func (t *GoHTMLTemplate) MarkReady() {
if t.clone == nil {
t.clone = template.Must(t.Template.Clone())
}
@@ -244,7 +276,7 @@ func (t *GoHTMLTemplate) AddTemplateFileWithMaster(name, overlayFilename, master
masterTpl := t.Lookup(masterFilename)
if masterTpl == nil {
- b, err := afero.ReadFile(hugofs.Source(), masterFilename)
+ b, err := afero.ReadFile(t.Fs.Source, masterFilename)
if err != nil {
return err
}
@@ -257,7 +289,7 @@ func (t *GoHTMLTemplate) AddTemplateFileWithMaster(name, overlayFilename, master
}
}
- b, err := afero.ReadFile(hugofs.Source(), overlayFilename)
+ b, err := afero.ReadFile(t.Fs.Source, overlayFilename)
if err != nil {
return err
}
@@ -315,19 +347,13 @@ func (t *GoHTMLTemplate) AddTemplateFile(name, baseTemplatePath, path string) er
switch ext {
case ".amber":
templateName := strings.TrimSuffix(name, filepath.Ext(name)) + ".html"
- compiler := amber.New()
- b, err := afero.ReadFile(hugofs.Source(), path)
+ b, err := afero.ReadFile(t.Fs.Source, path)
if err != nil {
return err
}
- // Parse the input data
- if err := compiler.ParseData(b, path); err != nil {
- return err
- }
-
- templ, err := compiler.CompileWithTemplate(t.New(templateName))
+ templ, err := t.CompileAmberWithTemplate(b, path, t.New(templateName))
if err != nil {
return err
}
@@ -335,14 +361,14 @@ func (t *GoHTMLTemplate) AddTemplateFile(name, baseTemplatePath, path string) er
return applyTemplateTransformers(templ)
case ".ace":
var innerContent, baseContent []byte
- innerContent, err := afero.ReadFile(hugofs.Source(), path)
+ innerContent, err := afero.ReadFile(t.Fs.Source, path)
if err != nil {
return err
}
if baseTemplatePath != "" {
- baseContent, err = afero.ReadFile(hugofs.Source(), baseTemplatePath)
+ baseContent, err = afero.ReadFile(t.Fs.Source, baseTemplatePath)
if err != nil {
return err
}
@@ -355,13 +381,13 @@ func (t *GoHTMLTemplate) AddTemplateFile(name, baseTemplatePath, path string) er
return t.AddTemplateFileWithMaster(name, path, baseTemplatePath)
}
- b, err := afero.ReadFile(hugofs.Source(), path)
+ b, err := afero.ReadFile(t.Fs.Source, path)
if err != nil {
return err
}
- t.log.DEBUG.Printf("Add template file from path %s", path)
+ t.Log.DEBUG.Printf("Add template file from path %s", path)
return t.AddTemplate(name, string(b))
}
@@ -391,25 +417,25 @@ func isBaseTemplate(path string) bool {
}
func (t *GoHTMLTemplate) loadTemplates(absPath string, prefix string) {
- t.log.DEBUG.Printf("Load templates from path %q prefix %q", absPath, prefix)
+ t.Log.DEBUG.Printf("Load templates from path %q prefix %q", absPath, prefix)
walker := func(path string, fi os.FileInfo, err error) error {
if err != nil {
return nil
}
- t.log.DEBUG.Println("Template path", path)
+ t.Log.DEBUG.Println("Template path", path)
if fi.Mode()&os.ModeSymlink == os.ModeSymlink {
link, err := filepath.EvalSymlinks(absPath)
if err != nil {
- t.log.ERROR.Printf("Cannot read symbolic link '%s', error was: %s", absPath, err)
+ t.Log.ERROR.Printf("Cannot read symbolic link '%s', error was: %s", absPath, err)
return nil
}
- linkfi, err := hugofs.Source().Stat(link)
+ linkfi, err := t.Fs.Source.Stat(link)
if err != nil {
- t.log.ERROR.Printf("Cannot stat '%s', error was: %s", link, err)
+ t.Log.ERROR.Printf("Cannot stat '%s', error was: %s", link, err)
return nil
}
if !linkfi.Mode().IsRegular() {
- t.log.ERROR.Printf("Symbolic links for directories not supported, skipping '%s'", absPath)
+ t.Log.ERROR.Printf("Symbolic links for directories not supported, skipping '%s'", absPath)
}
return nil
}
@@ -441,7 +467,7 @@ func (t *GoHTMLTemplate) loadTemplates(absPath string, prefix string) {
// This may be a view that shouldn't have base template
// Have to look inside it to make sure
- needsBase, err := helpers.FileContainsAny(path, innerMarkers, hugofs.Source())
+ needsBase, err := helpers.FileContainsAny(path, innerMarkers, t.Fs.Source)
if err != nil {
return err
}
@@ -482,7 +508,7 @@ func (t *GoHTMLTemplate) loadTemplates(absPath string, prefix string) {
for _, pair := range pairsToCheck {
pathsToCheck := basePathsToCheck(pair, layoutDir, themeDir)
for _, pathToCheck := range pathsToCheck {
- if ok, err := helpers.Exists(pathToCheck, hugofs.Source()); err == nil && ok {
+ if ok, err := helpers.Exists(pathToCheck, t.Fs.Source); err == nil && ok {
baseTemplatePath = pathToCheck
break Loop
}
@@ -492,14 +518,14 @@ func (t *GoHTMLTemplate) loadTemplates(absPath string, prefix string) {
}
if err := t.AddTemplateFile(tplName, baseTemplatePath, path); err != nil {
- t.log.ERROR.Printf("Failed to add template %s in path %s: %s", tplName, path, err)
+ t.Log.ERROR.Printf("Failed to add template %s in path %s: %s", tplName, path, err)
}
}
return nil
}
- if err := helpers.SymbolicWalk(hugofs.Source(), absPath, walker); err != nil {
- t.log.ERROR.Printf("Failed to load templates: %s", err)
+ if err := helpers.SymbolicWalk(t.Fs.Source, absPath, walker); err != nil {
+ t.Log.ERROR.Printf("Failed to load templates: %s", err)
}
}
@@ -526,6 +552,6 @@ func (t *GoHTMLTemplate) LoadTemplates(absPath string) {
func (t *GoHTMLTemplate) PrintErrors() {
for i, e := range t.errors {
- t.log.ERROR.Println(i, ":", e.err)
+ t.Log.ERROR.Println(i, ":", e.err)
}
}
diff --git a/tpl/template_funcs.go b/tpl/template_funcs.go
index 8f653808b..5db5e54ac 100644
--- a/tpl/template_funcs.go
+++ b/tpl/template_funcs.go
@@ -43,8 +43,8 @@ import (
"github.com/bep/inflect"
"github.com/spf13/afero"
"github.com/spf13/cast"
+ "github.com/spf13/hugo/deps"
"github.com/spf13/hugo/helpers"
- "github.com/spf13/hugo/hugofs"
jww "github.com/spf13/jwalterweatherman"
"github.com/spf13/viper"
@@ -56,14 +56,15 @@ import (
// Some of the template funcs are'nt entirely stateless.
type templateFuncster struct {
- t *GoHTMLTemplate
funcMap template.FuncMap
cachedPartials partialCache
+
+ *deps.Deps
}
-func newTemplateFuncster(t *GoHTMLTemplate) *templateFuncster {
+func newTemplateFuncster(deps *deps.Deps) *templateFuncster {
return &templateFuncster{
- t: t,
+ Deps: deps,
cachedPartials: partialCache{p: make(map[string]template.HTML)},
}
}
@@ -424,7 +425,7 @@ func resetImageConfigCache() {
// imageConfig returns the image.Config for the specified path relative to the
// working directory. resetImageConfigCache must be run beforehand.
-func imageConfig(path interface{}) (image.Config, error) {
+func (t *templateFuncster) imageConfig(path interface{}) (image.Config, error) {
filename, err := cast.ToStringE(path)
if err != nil {
return image.Config{}, err
@@ -443,7 +444,7 @@ func imageConfig(path interface{}) (image.Config, error) {
return config, nil
}
- f, err := hugofs.WorkingDir().Open(filename)
+ f, err := t.Fs.WorkingDir.Open(filename)
if err != nil {
return image.Config{}, err
}
@@ -1013,7 +1014,7 @@ func where(seq, key interface{}, args ...interface{}) (interface{}, error) {
}
// apply takes a map, array, or slice and returns a new slice with the function fname applied over it.
-func (tf *templateFuncster) apply(seq interface{}, fname string, args ...interface{}) (interface{}, error) {
+func (t *templateFuncster) apply(seq interface{}, fname string, args ...interface{}) (interface{}, error) {
if seq == nil {
return make([]interface{}, 0), nil
}
@@ -1028,7 +1029,7 @@ func (tf *templateFuncster) apply(seq interface{}, fname string, args ...interfa
return nil, errors.New("can't iterate over a nil value")
}
- fn, found := tf.funcMap[fname]
+ fn, found := t.funcMap[fname]
if !found {
return nil, errors.New("can't find function " + fname)
}
@@ -1528,26 +1529,27 @@ type partialCache struct {
// Get retrieves partial output from the cache based upon the partial name.
// If the partial is not found in the cache, the partial is rendered and added
// to the cache.
-func (tf *templateFuncster) Get(key, name string, context interface{}) (p template.HTML) {
+func (t *templateFuncster) Get(key, name string, context interface{}) (p template.HTML) {
var ok bool
- tf.cachedPartials.RLock()
- p, ok = tf.cachedPartials.p[key]
- tf.cachedPartials.RUnlock()
+ t.cachedPartials.RLock()
+ p, ok = t.cachedPartials.p[key]
+ t.cachedPartials.RUnlock()
if ok {
return p
}
- tf.cachedPartials.Lock()
- if p, ok = tf.cachedPartials.p[key]; !ok {
- tf.cachedPartials.Unlock()
- p = tf.t.partial(name, context)
+ t.cachedPartials.Lock()
+ if p, ok = t.cachedPartials.p[key]; !ok {
+ t.cachedPartials.Unlock()
+ p = t.Tmpl.Partial(name, context)
+
+ t.cachedPartials.Lock()
+ t.cachedPartials.p[key] = p
- tf.cachedPartials.Lock()
- tf.cachedPartials.p[key] = p
}
- tf.cachedPartials.Unlock()
+ t.cachedPartials.Unlock()
return p
}
@@ -1556,14 +1558,14 @@ func (tf *templateFuncster) Get(key, name string, context interface{}) (p templa
// string parameter (a string slice actually, but be only use a variadic
// argument to make it optional) can be passed so that a given partial can have
// multiple uses. The cache is created with name+variant as the key.
-func (tf *templateFuncster) partialCached(name string, context interface{}, variant ...string) template.HTML {
+func (t *templateFuncster) partialCached(name string, context interface{}, variant ...string) template.HTML {
key := name
if len(variant) > 0 {
for i := 0; i < len(variant); i++ {
key += variant[i]
}
}
- return tf.Get(key, name, context)
+ return t.Get(key, name, context)
}
// regexpCache represents a cache of regexp objects protected by a mutex.
@@ -1814,23 +1816,23 @@ func readFile(fs *afero.BasePathFs, filename string) (string, error) {
// configured WorkingDir.
// It returns the contents as a string.
// There is a upper size limit set at 1 megabytes.
-func readFileFromWorkingDir(i interface{}) (string, error) {
+func (t *templateFuncster) readFileFromWorkingDir(i interface{}) (string, error) {
s, err := cast.ToStringE(i)
if err != nil {
return "", err
}
- return readFile(hugofs.WorkingDir(), s)
+ return readFile(t.Fs.WorkingDir, s)
}
// readDirFromWorkingDir listst the directory content relative to the
// configured WorkingDir.
-func readDirFromWorkingDir(i interface{}) ([]os.FileInfo, error) {
+func (t *templateFuncster) readDirFromWorkingDir(i interface{}) ([]os.FileInfo, error) {
path, err := cast.ToStringE(i)
if err != nil {
return nil, err
}
- list, err := afero.ReadDir(hugofs.WorkingDir(), path)
+ list, err := afero.ReadDir(t.Fs.WorkingDir, path)
if err != nil {
return nil, fmt.Errorf("Failed to read Directory %s with error message %s", path, err)
@@ -2074,20 +2076,20 @@ func htmlUnescape(in interface{}) (string, error) {
return html.UnescapeString(conv), nil
}
-func absURL(a interface{}) (template.HTML, error) {
+func (t *templateFuncster) absURL(a interface{}) (template.HTML, error) {
s, err := cast.ToStringE(a)
if err != nil {
return "", nil
}
- return template.HTML(helpers.CurrentPathSpec().AbsURL(s, false)), nil
+ return template.HTML(t.PathSpec.AbsURL(s, false)), nil
}
-func relURL(a interface{}) (template.HTML, error) {
+func (t *templateFuncster) relURL(a interface{}) (template.HTML, error) {
s, err := cast.ToStringE(a)
if err != nil {
return "", nil
}
- return template.HTML(helpers.CurrentPathSpec().RelURL(s, false)), nil
+ return template.HTML(t.PathSpec.RelURL(s, false)), nil
}
// getenv retrieves the value of the environment variable named by the key.
@@ -2101,19 +2103,19 @@ func getenv(key interface{}) (string, error) {
return os.Getenv(skey), nil
}
-func (tf *templateFuncster) initFuncMap() {
+func (t *templateFuncster) initFuncMap() {
funcMap := template.FuncMap{
- "absURL": absURL,
+ "absURL": t.absURL,
"absLangURL": func(i interface{}) (template.HTML, error) {
s, err := cast.ToStringE(i)
if err != nil {
return "", err
}
- return template.HTML(helpers.CurrentPathSpec().AbsURL(s, true)), nil
+ return template.HTML(t.PathSpec.AbsURL(s, true)), nil
},
"add": func(a, b interface{}) (interface{}, error) { return helpers.DoArithmetic(a, b, '+') },
"after": after,
- "apply": tf.apply,
+ "apply": t.apply,
"base64Decode": base64Decode,
"base64Encode": base64Encode,
"chomp": chomp,
@@ -2130,8 +2132,8 @@ func (tf *templateFuncster) initFuncMap() {
"findRE": findRE,
"first": first,
"ge": ge,
- "getCSV": getCSV,
- "getJSON": getJSON,
+ "getCSV": t.getCSV,
+ "getJSON": t.getJSON,
"getenv": getenv,
"gt": gt,
"hasPrefix": hasPrefix,
@@ -2139,7 +2141,7 @@ func (tf *templateFuncster) initFuncMap() {
"htmlEscape": htmlEscape,
"htmlUnescape": htmlUnescape,
"humanize": humanize,
- "imageConfig": imageConfig,
+ "imageConfig": t.imageConfig,
"in": in,
"index": index,
"int": func(v interface{}) (int, error) { return cast.ToIntE(v) },
@@ -2158,21 +2160,21 @@ func (tf *templateFuncster) initFuncMap() {
"mul": func(a, b interface{}) (interface{}, error) { return helpers.DoArithmetic(a, b, '*') },
"ne": ne,
"now": func() time.Time { return time.Now() },
- "partial": tf.t.partial,
- "partialCached": tf.partialCached,
+ "partial": t.Tmpl.Partial,
+ "partialCached": t.partialCached,
"plainify": plainify,
"pluralize": pluralize,
"querify": querify,
- "readDir": readDirFromWorkingDir,
- "readFile": readFileFromWorkingDir,
+ "readDir": t.readDirFromWorkingDir,
+ "readFile": t.readFileFromWorkingDir,
"ref": ref,
- "relURL": relURL,
+ "relURL": t.relURL,
"relLangURL": func(i interface{}) (template.HTML, error) {
s, err := cast.ToStringE(i)
if err != nil {
return "", err
}
- return template.HTML(helpers.CurrentPathSpec().RelURL(s, true)), nil
+ return template.HTML(t.PathSpec.RelURL(s, true)), nil
},
"relref": relRef,
"replace": replace,
@@ -2201,12 +2203,12 @@ func (tf *templateFuncster) initFuncMap() {
"trim": trim,
"truncate": truncate,
"upper": upper,
- "urlize": helpers.CurrentPathSpec().URLize,
+ "urlize": t.PathSpec.URLize,
"where": where,
"i18n": i18nTranslate,
"T": i18nTranslate,
}
- tf.funcMap = funcMap
- tf.t.Funcs(funcMap)
+ t.funcMap = funcMap
+ t.Tmpl.Funcs(funcMap)
}
diff --git a/tpl/template_funcs_test.go b/tpl/template_funcs_test.go
index e0c185092..e5d0193a6 100644
--- a/tpl/template_funcs_test.go
+++ b/tpl/template_funcs_test.go
@@ -31,6 +31,9 @@ import (
"testing"
"time"
+ "github.com/spf13/hugo/tplapi"
+
+ "github.com/spf13/hugo/deps"
"github.com/spf13/hugo/helpers"
"io/ioutil"
@@ -43,9 +46,17 @@ import (
jww "github.com/spf13/jwalterweatherman"
"github.com/spf13/viper"
"github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
)
-var logger = jww.NewNotepad(jww.LevelFatal, jww.LevelFatal, os.Stdout, ioutil.Discard, "", log.Ldate|log.Ltime)
+var (
+ logger = jww.NewNotepad(jww.LevelFatal, jww.LevelFatal, os.Stdout, ioutil.Discard, "", log.Ldate|log.Ltime)
+ defaultDepsConfig = deps.DepsCfg{
+ Language: helpers.NewLanguage("en"),
+ Logger: logger,
+ TemplateProvider: DefaultTemplateProvider,
+ }
+)
type tstNoStringer struct {
}
@@ -80,8 +91,7 @@ func tstInitTemplates() {
func TestFuncsInTemplate(t *testing.T) {
- viper.Reset()
- defer viper.Reset()
+ testReset()
workingDir := "/home/hugo"
@@ -89,10 +99,9 @@ func TestFuncsInTemplate(t *testing.T) {
viper.Set("currentContentLanguage", helpers.NewDefaultLanguage())
viper.Set("multilingual", true)
- fs := &afero.MemMapFs{}
- hugofs.InitFs(fs)
+ fs := hugofs.NewMem()
- afero.WriteFile(fs, filepath.Join(workingDir, "README.txt"), []byte("Hugo Rocks!"), 0755)
+ afero.WriteFile(fs.Source, filepath.Join(workingDir, "README.txt"), []byte("Hugo Rocks!"), 0755)
// Add the examples from the docs: As a smoke test and to make sure the examples work.
// TODO(bep): docs: fix title example
@@ -244,7 +253,7 @@ urlize: bat-man
`
var b bytes.Buffer
- templ, err := New(logger).New("test").Parse(in)
+
var data struct {
Title string
Section string
@@ -259,11 +268,21 @@ urlize: bat-man
tstInitTemplates()
- if err != nil {
- t.Fatal("Got error on parse", err)
+ config := defaultDepsConfig
+ config.WithTemplate = func(templ tplapi.Template) error {
+ if _, err := templ.New("test").Parse(in); err != nil {
+ t.Fatal("Got error on parse", err)
+ }
+ return nil
+ }
+ config.Fs = fs
+
+ d := deps.New(config)
+ if err := d.LoadTemplates(); err != nil {
+ t.Fatal(err)
}
- err = templ.Execute(&b, &data)
+ err := d.Tmpl.Lookup("test").Execute(&b, &data)
if err != nil {
t.Fatal("Got error on execute", err)
@@ -624,15 +643,13 @@ func blankImage(width, height int) []byte {
}
func TestImageConfig(t *testing.T) {
- viper.Reset()
- defer viper.Reset()
+ testReset()
workingDir := "/home/hugo"
viper.Set("workingDir", workingDir)
- fs := &afero.MemMapFs{}
- hugofs.InitFs(fs)
+ f := newTestFuncster()
for i, this := range []struct {
resetCache bool
@@ -692,13 +709,13 @@ func TestImageConfig(t *testing.T) {
},
},
} {
- afero.WriteFile(fs, filepath.Join(workingDir, this.path), this.input, 0755)
+ afero.WriteFile(f.Fs.Source, filepath.Join(workingDir, this.path), this.input, 0755)
if this.resetCache {
resetImageConfigCache()
}
- result, err := imageConfig(this.path)
+ result, err := f.imageConfig(this.path)
if err != nil {
t.Errorf("imageConfig returned error: %s", err)
}
@@ -712,15 +729,15 @@ func TestImageConfig(t *testing.T) {
}
}
- if _, err := imageConfig(t); err == nil {
+ if _, err := f.imageConfig(t); err == nil {
t.Error("Expected error from imageConfig when passed invalid path")
}
- if _, err := imageConfig("non-existent.png"); err == nil {
+ if _, err := f.imageConfig("non-existent.png"); err == nil {
t.Error("Expected error from imageConfig when passed non-existent file")
}
- if _, err := imageConfig(""); err == nil {
+ if _, err := f.imageConfig(""); err == nil {
t.Error("Expected error from imageConfig when passed empty path")
}
@@ -2381,14 +2398,11 @@ func TestDefault(t *testing.T) {
{map[string]string{"foo": "dog"}, `{{ default "nope" .foo "extra" }}`, ``, false},
{map[string]interface{}{"images": []string{}}, `{{ default "default.jpg" (index .images 0) }}`, `default.jpg`, true},
} {
- tmpl, err := New(logger).New("test").Parse(this.tpl)
- if err != nil {
- t.Errorf("[%d] unable to create new html template %q: %s", i, this.tpl, err)
- continue
- }
+
+ tmpl := newTestTemplate(t, "test", this.tpl)
buf := new(bytes.Buffer)
- err = tmpl.Execute(buf, this.input)
+ err := tmpl.Execute(buf, this.input)
if (err == nil) != this.ok {
t.Errorf("[%d] execute template returned unexpected error: %s", i, err)
continue
@@ -2520,6 +2534,7 @@ func TestSafeCSS(t *testing.T) {
}
}
+// TODO(bep) what is this? Also look above.
func TestSafeJS(t *testing.T) {
for i, this := range []struct {
str string
@@ -2560,6 +2575,7 @@ func TestSafeJS(t *testing.T) {
}
}
+// TODO(bep) what is this?
func TestSafeURL(t *testing.T) {
for i, this := range []struct {
str string
@@ -2716,18 +2732,16 @@ func TestSHA256(t *testing.T) {
}
func TestReadFile(t *testing.T) {
- viper.Reset()
- defer viper.Reset()
+ testReset()
workingDir := "/home/hugo"
viper.Set("workingDir", workingDir)
- fs := &afero.MemMapFs{}
- hugofs.InitFs(fs)
+ f := newTestFuncster()
- afero.WriteFile(fs, filepath.Join(workingDir, "/f/f1.txt"), []byte("f1-content"), 0755)
- afero.WriteFile(fs, filepath.Join("/home", "f2.txt"), []byte("f2-content"), 0755)
+ afero.WriteFile(f.Fs.Source, filepath.Join(workingDir, "/f/f1.txt"), []byte("f1-content"), 0755)
+ afero.WriteFile(f.Fs.Source, filepath.Join("/home", "f2.txt"), []byte("f2-content"), 0755)