From e625088ef5a970388ad50e464e87db56b358dac4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Pedersen?= Date: Wed, 27 Nov 2019 13:42:36 +0100 Subject: Add render template hooks for links and images This commit also * revises the change detection for templates used by content files in server mode. * Adds a Page.RenderString method Fixes #6545 Fixes #4663 Closes #6043 --- hugolib/site.go | 120 +++++++++++++++++++++++++++++--------------------------- 1 file changed, 63 insertions(+), 57 deletions(-) (limited to 'hugolib/site.go') diff --git a/hugolib/site.go b/hugolib/site.go index 67ddff4d9..866ff5624 100644 --- a/hugolib/site.go +++ b/hugolib/site.go @@ -28,6 +28,12 @@ import ( "strings" "time" + "github.com/gohugoio/hugo/resources" + + "github.com/gohugoio/hugo/identity" + + "github.com/gohugoio/hugo/markup/converter/hooks" + "github.com/gohugoio/hugo/resources/resource" "github.com/gohugoio/hugo/markup/converter" @@ -60,7 +66,6 @@ import ( "github.com/gohugoio/hugo/navigation" "github.com/gohugoio/hugo/output" "github.com/gohugoio/hugo/related" - "github.com/gohugoio/hugo/resources" "github.com/gohugoio/hugo/resources/page/pagemeta" "github.com/gohugoio/hugo/source" "github.com/gohugoio/hugo/tpl" @@ -801,7 +806,6 @@ func (s *Site) multilingual() *Multilingual { type whatChanged struct { source bool - other bool files map[string]bool } @@ -888,10 +892,11 @@ func (s *Site) translateFileEvents(events []fsnotify.Event) []fsnotify.Event { // It returns whetever the content source was changed. // TODO(bep) clean up/rewrite this method. func (s *Site) processPartial(config *BuildCfg, init func(config *BuildCfg) error, events []fsnotify.Event) error { - events = s.filterFileEvents(events) events = s.translateFileEvents(events) + changeIdentities := make(identity.Identities) + s.Log.DEBUG.Printf("Rebuild for events %q", events) h := s.h @@ -902,11 +907,12 @@ func (s *Site) processPartial(config *BuildCfg, init func(config *BuildCfg) erro sourceChanged = []fsnotify.Event{} sourceReallyChanged = []fsnotify.Event{} contentFilesChanged []string - tmplChanged = []fsnotify.Event{} - dataChanged = []fsnotify.Event{} - i18nChanged = []fsnotify.Event{} - shortcodesChanged = make(map[string]bool) - sourceFilesChanged = make(map[string]bool) + + tmplChanged bool + dataChanged bool + i18nChanged bool + + sourceFilesChanged = make(map[string]bool) // prevent spamming the log on changes logger = helpers.NewDistinctFeedbackLogger() @@ -919,33 +925,30 @@ func (s *Site) processPartial(config *BuildCfg, init func(config *BuildCfg) erro cachePartitions = append(cachePartitions, resources.ResourceKeyPartitions(assetsFilename)...) } - if s.isContentDirEvent(ev) { - logger.Println("Source changed", ev) - sourceChanged = append(sourceChanged, ev) - } - if s.isLayoutDirEvent(ev) { - logger.Println("Template changed", ev) - tmplChanged = append(tmplChanged, ev) - - if strings.Contains(ev.Name, "shortcodes") { - shortcode := filepath.Base(ev.Name) - shortcode = strings.TrimSuffix(shortcode, filepath.Ext(shortcode)) - shortcodesChanged[shortcode] = true + id, found := s.eventToIdentity(ev) + if found { + changeIdentities[id] = id + + switch id.Type { + case files.ComponentFolderContent: + logger.Println("Source changed", ev) + sourceChanged = append(sourceChanged, ev) + case files.ComponentFolderLayouts: + logger.Println("Template changed", ev) + tmplChanged = true + case files.ComponentFolderData: + logger.Println("Data changed", ev) + dataChanged = true + case files.ComponentFolderI18n: + logger.Println("i18n changed", ev) + i18nChanged = true + } } - if s.isDataDirEvent(ev) { - logger.Println("Data changed", ev) - dataChanged = append(dataChanged, ev) - } - if s.isI18nEvent(ev) { - logger.Println("i18n changed", ev) - i18nChanged = append(dataChanged, ev) - } } changed := &whatChanged{ - source: len(sourceChanged) > 0 || len(shortcodesChanged) > 0, - other: len(tmplChanged) > 0 || len(i18nChanged) > 0 || len(dataChanged) > 0, + source: len(sourceChanged) > 0, files: sourceFilesChanged, } @@ -960,7 +963,7 @@ func (s *Site) processPartial(config *BuildCfg, init func(config *BuildCfg) erro s.ResourceSpec.ResourceCache.DeletePartitions(cachePartitions...) } - if len(tmplChanged) > 0 || len(i18nChanged) > 0 { + if tmplChanged || i18nChanged { sites := s.h.Sites first := sites[0] @@ -989,7 +992,7 @@ func (s *Site) processPartial(config *BuildCfg, init func(config *BuildCfg) erro } } - if len(dataChanged) > 0 { + if dataChanged { s.h.init.data.Reset() } @@ -1018,18 +1021,7 @@ func (s *Site) processPartial(config *BuildCfg, init func(config *BuildCfg) erro sourceFilesChanged[ev.Name] = true } - for shortcode := range shortcodesChanged { - // There are certain scenarios that, when a shortcode changes, - // it isn't sufficient to just rerender the already parsed shortcode. - // One example is if the user adds a new shortcode to the content file first, - // and then creates the shortcode on the file system. - // To handle these scenarios, we must do a full reprocessing of the - // pages that keeps a reference to the changed shortcode. - pagesWithShortcode := h.findPagesByShortcode(shortcode) - for _, p := range pagesWithShortcode { - contentFilesChanged = append(contentFilesChanged, p.File().Filename()) - } - } + h.resetPageStateFromEvents(changeIdentities) if len(sourceReallyChanged) > 0 || len(contentFilesChanged) > 0 { var filenamesChanged []string @@ -1218,20 +1210,14 @@ func (s *Site) initializeSiteInfo() error { return nil } -func (s *Site) isI18nEvent(e fsnotify.Event) bool { - return s.BaseFs.SourceFilesystems.IsI18n(e.Name) -} - -func (s *Site) isDataDirEvent(e fsnotify.Event) bool { - return s.BaseFs.SourceFilesystems.IsData(e.Name) -} - -func (s *Site) isLayoutDirEvent(e fsnotify.Event) bool { - return s.BaseFs.SourceFilesystems.IsLayout(e.Name) -} +func (s *Site) eventToIdentity(e fsnotify.Event) (identity.PathIdentity, bool) { + for _, fs := range s.BaseFs.SourceFilesystems.FileSystems() { + if p := fs.Path(e.Name); p != "" { + return identity.NewPathIdentity(fs.Name, p), true + } + } -func (s *Site) isContentDirEvent(e fsnotify.Event) bool { - return s.BaseFs.IsContent(e.Name) + return identity.PathIdentity{}, false } func (s *Site) readAndProcessContent(filenames ...string) error { @@ -1562,6 +1548,26 @@ var infoOnMissingLayout = map[string]bool{ "404": true, } +type contentLinkRenderer struct { + templateHandler tpl.TemplateHandler + identity.Provider + templ tpl.Template +} + +func (r contentLinkRenderer) Render(w io.Writer, ctx hooks.LinkContext) error { + return r.templateHandler.Execute(r.templ, w, ctx) +} + +func (s *Site) lookupTemplate(layouts ...string) (tpl.Template, bool) { + for _, l := range layouts { + if templ, found := s.Tmpl.Lookup(l); found { + return templ, true + } + } + + return nil, false +} + func (s *Site) renderForLayouts(name, outputFormat string, d interface{}, w io.Writer, layouts ...string) (err error) { templ := s.findFirstTemplate(layouts...) if templ == nil { -- cgit v1.2.3