diff options
41 files changed, 1103 insertions, 1807 deletions
diff --git a/commands/server.go b/commands/server.go index 709181507..7d884096c 100644 --- a/commands/server.go +++ b/commands/server.go @@ -16,6 +16,7 @@ package commands import ( "bytes" "fmt" + "io" "net" "net/http" "net/url" @@ -33,7 +34,6 @@ import ( "github.com/pkg/errors" "github.com/gohugoio/hugo/livereload" - "github.com/gohugoio/hugo/tpl" "github.com/gohugoio/hugo/config" "github.com/gohugoio/hugo/helpers" @@ -287,7 +287,7 @@ func getRootWatchDirsStr(baseDir string, watchDirs []string) string { type fileServer struct { baseURLs []string roots []string - errorTemplate tpl.Template + errorTemplate func(err interface{}) (io.Reader, error) c *commandeer s *serverCmd } @@ -335,8 +335,7 @@ func (f *fileServer) createEndpoint(i int) (*http.ServeMux, string, string, erro err := f.c.getErrorWithContext() if err != nil { w.WriteHeader(500) - var b bytes.Buffer - err := f.errorTemplate.Execute(&b, err) + r, err := f.errorTemplate(err) if err != nil { f.c.logger.ERROR.Println(err) } @@ -344,7 +343,7 @@ func (f *fileServer) createEndpoint(i int) (*http.ServeMux, string, string, erro if !f.c.paused { port = f.c.Cfg.GetInt("liveReloadPort") } - fmt.Fprint(w, injectLiveReloadScript(&b, port)) + fmt.Fprint(w, injectLiveReloadScript(r, port)) return } @@ -422,11 +421,15 @@ func (c *commandeer) serve(s *serverCmd) error { } srv := &fileServer{ - baseURLs: baseURLs, - roots: roots, - c: c, - s: s, - errorTemplate: templ, + baseURLs: baseURLs, + roots: roots, + c: c, + s: s, + errorTemplate: func(ctx interface{}) (io.Reader, error) { + b := &bytes.Buffer{} + err := c.hugo().Tmpl.Execute(templ, b, ctx) + return b, err + }, } doLiveReload := !c.Cfg.GetBool("disableLiveReload") diff --git a/create/content_template_handler.go b/create/content_template_handler.go index 1576fabdb..b70cf02eb 100644 --- a/create/content_template_handler.go +++ b/create/content_template_handler.go @@ -129,7 +129,7 @@ func executeArcheTypeAsTemplate(s *hugolib.Site, name, kind, targetPath, archety archetypeTemplate = []byte(archetypeShortcodeReplacementsPre.Replace(string(archetypeTemplate))) // Reuse the Hugo template setup to get the template funcs properly set up. - templateHandler := s.Deps.Tmpl.(tpl.TemplateHandler) + templateHandler := s.Deps.Tmpl.(tpl.TemplateManager) templateName := "_text/" + helpers.Filename(archetypeFilename) if err := templateHandler.AddTemplate(templateName, string(archetypeTemplate)); err != nil { return nil, errors.Wrapf(err, "Failed to parse archetype file %q:", archetypeFilename) @@ -138,7 +138,7 @@ func executeArcheTypeAsTemplate(s *hugolib.Site, name, kind, targetPath, archety templ, _ := templateHandler.Lookup(templateName) var buff bytes.Buffer - if err := templ.Execute(&buff, data); err != nil { + if err := templateHandler.Execute(templ, &buff, data); err != nil { return nil, errors.Wrapf(err, "Failed to process archetype file %q:", archetypeFilename) } diff --git a/deps/deps.go b/deps/deps.go index d7b381ce9..ecbba2e56 100644 --- a/deps/deps.go +++ b/deps/deps.go @@ -37,8 +37,8 @@ type Deps struct { // Used to log warnings that may repeat itself many times. DistinctWarningLog *helpers.DistinctLogger - // The templates to use. This will usually implement the full tpl.TemplateHandler. - Tmpl tpl.TemplateFinder `json:"-"` + // The templates to use. This will usually implement the full tpl.TemplateManager. + Tmpl tpl.TemplateHandler `json:"-"` // We use this to parse and execute ad-hoc text templates. TextTmpl tpl.TemplateParseFinder `json:"-"` @@ -77,7 +77,10 @@ type Deps struct { OutputFormatsConfig output.Formats templateProvider ResourceProvider - WithTemplate func(templ tpl.TemplateHandler) error `json:"-"` + WithTemplate func(templ tpl.TemplateManager) error `json:"-"` + + // Used in tests + OverloadedTemplateFuncs map[string]interface{} translationProvider ResourceProvider @@ -151,8 +154,8 @@ type ResourceProvider interface { } // TemplateHandler returns the used tpl.TemplateFinder as tpl.TemplateHandler. -func (d *Deps) TemplateHandler() tpl.TemplateHandler { - return d.Tmpl.(tpl.TemplateHandler) +func (d *Deps) TemplateHandler() tpl.TemplateManager { + return d.Tmpl.(tpl.TemplateManager) } // LoadResources loads translations and templates. @@ -239,24 +242,25 @@ func New(cfg DepsCfg) (*Deps, error) { distinctWarnLogger := helpers.NewDistinctLogger(logger.WARN) d := &Deps{ - Fs: fs, - Log: logger, - DistinctErrorLog: distinctErrorLogger, - DistinctWarningLog: distinctWarnLogger, - templateProvider: cfg.TemplateProvider, - translationProvider: cfg.TranslationProvider, - WithTemplate: cfg.WithTemplate, - PathSpec: ps, - ContentSpec: contentSpec, - SourceSpec: sp, - ResourceSpec: resourceSpec, - Cfg: cfg.Language, - Language: cfg.Language, - Site: cfg.Site, - FileCaches: fileCaches, - BuildStartListeners: &Listeners{}, - Timeout: time.Duration(timeoutms) * time.Millisecond, - globalErrHandler: &globalErrHandler{}, + Fs: fs, + Log: logger, + DistinctErrorLog: distinctErrorLogger, + DistinctWarningLog: distinctWarnLogger, + templateProvider: cfg.TemplateProvider, + translationProvider: cfg.TranslationProvider, + WithTemplate: cfg.WithTemplate, + OverloadedTemplateFuncs: cfg.OverloadedTemplateFuncs, + PathSpec: ps, + ContentSpec: contentSpec, + SourceSpec: sp, + ResourceSpec: resourceSpec, + Cfg: cfg.Language, + Language: cfg.Language, + Site: cfg.Site, + FileCaches: fileCaches, + BuildStartListeners: &Listeners{}, + Timeout: time.Duration(timeoutms) * time.Millisecond, + globalErrHandler: &globalErrHandler{}, } if cfg.Cfg.GetBool("templateMetrics") { @@ -344,7 +348,9 @@ type DepsCfg struct { // Template handling. TemplateProvider ResourceProvider - WithTemplate func(templ tpl.TemplateHandler) error + WithTemplate func(templ tpl.TemplateManager) error + // Used in tests + OverloadedTemplateFuncs map[string]interface{} // i18n handling. TranslationProvider ResourceProvider diff --git a/hugolib/alias.go b/hugolib/alias.go index 972f7b01c..c80e7d0d2 100644 --- a/hugolib/alias.go +++ b/hugolib/alias.go @@ -15,6 +15,7 @@ package hugolib import ( "bytes" + "errors" "fmt" "html/template" "io" @@ -31,27 +32,15 @@ import ( "github.com/gohugoio/hugo/tpl" ) -const ( - alias = "<!DOCTYPE html><html><head><title>{{ .Permalink }}</title><link rel=\"canonical\" href=\"{{ .Permalink }}\"/><meta name=\"robots\" content=\"noindex\"><meta charset=\"utf-8\" /><meta http-equiv=\"refresh\" content=\"0; url={{ .Permalink }}\" /></head></html>" - aliasXHtml = "<!DOCTYPE html><html xmlns=\"http://www.w3.org/1999/xhtml\"><head><title>{{ .Permalink }}</title><link rel=\"canonical\" href=\"{{ .Permalink }}\"/><meta name=\"robots\" content=\"noindex\"><meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\" /><meta http-equiv=\"refresh\" content=\"0; url={{ .Permalink }}\" /></head></html>" -) - var defaultAliasTemplates *template.Template -func init() { - //TODO(bep) consolidate - defaultAliasTemplates = template.New("") - template.Must(defaultAliasTemplates.New("alias").Parse(alias)) - template.Must(defaultAliasTemplates.New("alias-xhtml").Parse(aliasXHtml)) -} - type aliasHandler struct { - t tpl.TemplateFinder + t tpl.TemplateHandler log *loggers.Logger allowRoot bool } -func newAliasHandler(t tpl.TemplateFinder, l *loggers.Logger, allowRoot bool) aliasHandler { +func newAliasHandler(t tpl.TemplateHandler, l *loggers.Logger, allowRoot bool) aliasHandler { return aliasHandler{t, l, allowRoot} } @@ -60,33 +49,27 @@ type aliasPage struct { page.Page } -func (a aliasHandler) renderAlias(isXHTML bool, permalink string, p page.Page) (io.Reader, error) { - t := "alias" - if isXHTML { - t = "alias-xhtml" - } +func (a aliasHandler) renderAlias(permalink string, p page.Page) (io.Reader, error) { var templ tpl.Template var found bool - if a.t != nil { - templ, found = a.t.Lookup("alias.html") - } - + templ, found = a.t.Lookup("alias.html") if !found { - def := defaultAliasTemplates.Lookup(t) - if def != nil { - templ = &tpl.TemplateAdapter{Template: def} + // TODO(bep) consolidate + templ, found = a.t.Lookup("_internal/alias.html") + if !found { + return nil, errors.New("no alias template found") } - } + data := aliasPage{ permalink, p, } buffer := new(bytes.Buffer) - err := templ.Execute(buffer, data) + err := a.t.Execute(templ, buffer, data) if err != nil { return nil, err } @@ -100,8 +83,6 @@ func (s *Site) writeDestAlias(path, permalink string, outputFormat output.Format func (s *Site) publishDestAlias(allowRoot bool, path, permalink string, outputFormat output.Format, p page.Page) (err error) { handler := newAliasHandler(s.Tmpl, s.Log, allowRoot) - isXHTML := strings.HasSuffix(path, ".xhtml") - s.Log.DEBUG.Println("creating alias:", path, "redirecting to", permalink) targetPath, err := handler.targetPathAlias(path) @@ -109,7 +90,7 @@ func (s *Site) publishDestAlias(allowRoot bool, path, permalink string, outputFo return err } - aliasContent, err := handler.renderAlias(isXHTML, permalink, p) + aliasContent, err := handler.renderAlias(permalink, p) if err != nil { return err } diff --git a/hugolib/case_insensitive_test.go b/hugolib/case_insensitive_test.go index a8616ab06..42b9d7ef6 100644 --- a/hugolib/case_insensitive_test.go +++ b/hugolib/case_insensitive_test.go @@ -14,7 +14,6 @@ package hugolib import ( - "fmt" "path/filepath" "testing" @@ -232,76 +231,3 @@ Page2: {{ $page2.Params.ColoR }} "index2|Site: yellow|", ) } - -// TODO1 -func TestCaseInsensitiveConfigurationForAllTemplateEngines(t *testing.T) { - t.Parallel() - - noOp := func(s string) string { - return s - } - - for _, config := range []struct { - suffix string - templateFixer func(s string) string - }{ - //{"amber", amberFixer}, - {"html", noOp}, - //{"ace", noOp}, - } { - doTestCaseInsensitiveConfigurationForTemplateEngine(t, config.suffix, config.templateFixer) - - } - -} - -func doTestCaseInsensitiveConfigurationForTemplateEngine(t *testing.T, suffix string, templateFixer func(s string) string) { - c := qt.New(t) - mm := afero.NewMemMapFs() - - caseMixingTestsWriteCommonSources(t, mm) - - cfg, err := LoadConfigDefault(mm) - c.Assert(err, qt.IsNil) - - fs := hugofs.NewFrom(mm, cfg) - - th := newTestHelper(cfg, fs, t) - - t.Log("Testing", suffix) - - templTemplate := ` -p - | - | Page Colors: {{ .Params.CoLOR }}|{{ .Params.Colors.Blue }} - | Site Colors: {{ .Site.Params.COlOR }}|{{ .Site.Params.COLORS.YELLOW }} - | {{ .Content }} - -` - - templ := templateFixer(templTemplate) - - t.Log(templ) - - writeSource(t, fs, filepath.Join("layouts", "_default", fmt.Sprintf("single.%s", suffix)), templ) - - sites, err := NewHugoSites(deps.DepsCfg{Fs: fs, Cfg: cfg}) - - if err != nil { - t.Fatalf("Failed to create sites: %s", err) - } - - err = sites.Build(BuildCfg{}) - - if err != nil { - t.Fatalf("Failed to build sites: %s", err) - } - - th.assertFileContent(filepath.Join("public", "nn", "sect1", "page1", "index.html"), - "Page Colors: red|heavenly", - "Site Colors: green|yellow", - "Shortcode Page: red|heavenly", - "Shortcode Site: green|yellow", - ) - -} diff --git a/hugolib/embedded_shortcodes_test.go b/hugolib/embedded_shortcodes_test.go index 64f2203e9..a998b85b7 100644 --- a/hugolib/embedded_shortcodes_test.go +++ b/hugolib/embedded_shortcodes_test.go @@ -27,7 +27,6 @@ import ( "github.com/gohugoio/hugo/deps" qt "github.com/frankban/quicktest" - "github.com/gohugoio/hugo/tpl" ) const ( @@ -334,18 +333,13 @@ func TestShortcodeTweet(t *testing.T) { cfg.Set("privacy", this.privacy) - withTemplate := func(templ tpl.TemplateHandler) error { - templ.(tpl.TemplateTestMocker).SetFuncs(tweetFuncMap) - return nil - } - writeSource(t, fs, filepath.Join("content", "simple.md"), fmt.Sprintf(`--- title: Shorty --- %s`, this.in)) writeSource(t, fs, filepath.Join("layouts", "_default", "single.html"), `{{ .Content }}`) - buildSingleSite(t, deps.DepsCfg{Fs: fs, Cfg: cfg, WithTemplate: withTemplate}, BuildCfg{}) + buildSingleSite(t, deps.DepsCfg{Fs: fs, Cfg: cfg, OverloadedTemplateFuncs: tweetFuncMap}, BuildCfg{}) th.assertFileContentRegexp(filepath.Join("public", "simple", "index.html"), this.expected) @@ -389,18 +383,13 @@ func TestShortcodeInstagram(t *testing.T) { th = newTestHelper(cfg, fs, t) ) - withTemplate := func(templ tpl.TemplateHandler) error { - templ.(tpl.TemplateTestMocker).SetFuncs(instagramFuncMap) - return nil - } - writeSource(t, fs, filepath.Join("content", "simple.md"), fmt.Sprintf(`--- title: Shorty --- %s`, this.in)) writeSource(t, fs, filepath.Join("layouts", "_default", "single.html"), `{{ .Content | safeHTML }}`) - buildSingleSite(t, deps.DepsCfg{Fs: fs, Cfg: cfg, WithTemplate: withTemplate}, BuildCfg{}) + buildSingleSite(t, deps.DepsCfg{Fs: fs, Cfg: cfg, OverloadedTemplateFuncs: instagramFuncMap}, BuildCfg{}) th.assertFileContentRegexp(filepath.Join("public", "simple", "index.html"), this.expected) diff --git a/hugolib/hugo_modules_test.go b/hugolib/hugo_modules_test.go index 9ba039c74..40185e051 100644 --- a/hugolib/hugo_modules_test.go +++ b/hugolib/hugo_modules_test.go @@ -42,10 +42,10 @@ import ( func TestHugoModules(t *testing.T) { t.Parallel() - if hugo.GoMinorVersion() < 12 { + if !isCI() || hugo.GoMinorVersion() < 12 { // https://github.com/golang/go/issues/26794 // There were some concurrent issues with Go modules in < Go 12. - t.Skip("skip this for Go <= 1.11 due to a bug in Go's stdlib") + t.Skip("skip this on local host and for Go <= 1.11 due to a bug in Go's stdlib") } if testing.Short() { diff --git a/hugolib/hugo_sites.go b/hugolib/hugo_sites.go index c0d75c09f..c71dcaa59 100644 --- a/hugolib/hugo_sites.go +++ b/hugolib/hugo_sites.go @@ -426,8 +426,8 @@ func NewHugoSites(cfg deps.DepsCfg) (*HugoSites, error) { return newHugoSites(cfg, sites...) } -func (s *Site) withSiteTemplates(withTemplates ...func(templ tpl.TemplateHandler) error) func(templ tpl.TemplateHandler) error { - return func(templ tpl.TemplateHandler) error { +func (s *Site) withSiteTemplates(withTemplates ...func(templ tpl.TemplateManager) error) func(templ tpl.TemplateManager) error { + return func(templ tpl.TemplateManager) error { if err := templ.LoadTemplates(""); err != nil { return err } diff --git a/hugolib/hugo_smoke_test.go b/hugolib/hugo_smoke_test.go index 539e79729..406255d51 100644 --- a/hugolib/hugo_smoke_test.go +++ b/hugolib/hugo_smoke_test.go @@ -21,6 +21,27 @@ import ( qt "github.com/frankban/quicktest" ) +// The most basic build test. +func TestHello(t *testing.T) { + t.Parallel() + b := newTestSitesBuilder(t) + b.WithConfigFile("toml", ` +baseURL="https://example.org" +disableKinds = ["taxonomy", "taxonomyTerm", "section", "page"] +`) + b.WithContent("p1", ` +--- +title: Page +--- + +`) + b.WithTemplates("index.html", `Site: {{ .Site.Language.Lang | upper }}`) + + b.Build(BuildCfg{}) + + b.AssertFileContent("public/index.html", `Site: EN`) +} + func TestSmoke(t *testing.T) { t.Parallel() diff --git a/hugolib/page.go b/hugolib/page.go index b0e8c4359..56202f5e0 100644 --- a/hugolib/page.go +++ b/hugolib/page.go @@ -480,7 +480,7 @@ func (p *pageState) Render(layout ...string) template.HTML { templ, _ = p.s.Tmpl.Lookup(layout + ".html") } if templ != nil { - res, err := executeToString(templ, p) + res, err := executeToString(p.s.Tmpl, templ, p) if err != nil { p.s.SendError(p.wrapError(errors.Wrapf(err, ".Render: failed to execute template %q v", layout))) return "" diff --git a/hugolib/page__per_output.go b/hugolib/page__per_output.go index 9697468ff..d3a32e15c 100644 --- a/hugolib/page__per_output.go +++ b/hugolib/page__per_output.go @@ -411,10 +411,10 @@ func (t targetPathsHolder) targetPaths() page.TargetPaths { return t.paths } -func executeToString(templ tpl.Template, data interface{}) (string, error) { +func executeToString(h tpl.TemplateHandler, templ tpl.Template, data interface{}) (string, error) { b := bp.GetBuffer() defer bp.PutBuffer(b) - if err := templ.Execute(b, data); err != nil { + if err := h.Execute(templ, b, data); err != nil { return "", err } return b.String(), nil diff --git a/hugolib/page_test.go b/hugolib/page_test.go index ff037a3cc..dc8bc821c 100644 --- a/hugolib/page_test.go +++ b/hugolib/page_test.go @@ -459,7 +459,7 @@ func TestPageWithDelimiterForMarkdownThatCrossesBorder(t *testing.T) { } cnt := content(p) - if cnt != "<p>The <a href=\"http://gohugo.io/\">best static site generator</a>.<sup id=\"fnref:1\"><a href=\"#fn:1\" class=\"footnote-ref\" role=\"doc-noteref\">1</a></sup></p>\n<section class=\"footnotes\" role=\"doc-endnotes\">\n<hr>\n<ol>\n<li id=\"fn:1\" role=\"doc-endnote\">\n<p>Many people say so. <a href=\"#fnref:1\" class=\"footnote-backref\" role=\"doc-backlink\">↩︎</a></p>\n</li>\n</ol>\n</section>" { + if cnt != "<p>The <a href=\"http://gohugo.io/\">best static site generator</a>.<sup id=\"fnref:1\"><a href=\"#fn:1\" class=\"footnote-ref\" role=\"doc-noteref\">1</a></sup></p>\n<section class=\"footnotes\" role=\"doc-endnotes\">\n<hr>\n<ol>\n<li id=\"fn:1\" role=\"doc-endnote\">\n<p>Many people say so.<a href=\"#fnref:1\" class=\"footnote-backref\" role=\"doc-backlink\">↩</a></p>\n</li>\n</ol>\n</section>" { t.Fatalf("Got content:\n%q", cnt) } } diff --git a/hugolib/shortcode.go b/hugolib/shortcode.go index 5e916aeec..69bcb6d4f 100644 --- a/hugolib/shortcode.go +++ b/hugolib/shortcode.go @@ -393,7 +393,7 @@ func renderShortcode( } - result, err := renderShortcodeWithPage(tmpl, data) + result, err := renderShortcodeWithPage(s.Tmpl, tmpl, data) if err != nil && sc.isInline { fe := herrors.ToFileError("html", err) @@ -634,11 +634,11 @@ func replaceShortcodeTokens(source []byte, replacements map[string]string) ([]by return source, nil } |