diff --git a/common/paths/pathparser.go b/common/paths/pathparser.go index 40297735ced..65399819b69 100644 --- a/common/paths/pathparser.go +++ b/common/paths/pathparser.go @@ -25,9 +25,10 @@ import ( "github.com/gohugoio/hugo/identity" ) -var defaultPathParser PathParser = PathParser{ +var DefaultPathParser = &PathParser{ IsContentExt: func(ext string) bool { - return false + // TODO1 + return ext == "md" }, } @@ -44,9 +45,8 @@ type PathParser struct { } // Parse parses component c with path s into Path using the default path parser. -// Only used in tests. TODO1 func Parse(c, s string) *Path { - return defaultPathParser.Parse(c, s) + return DefaultPathParser.Parse(c, s) } // NormalizePathString returns a normalized path string using the very basic Hugo rules. diff --git a/hugofs/files/classifier_test.go b/hugofs/files/classifier_test.go index f2fad56ca0f..b1a92faadd7 100644 --- a/hugofs/files/classifier_test.go +++ b/hugofs/files/classifier_test.go @@ -14,22 +14,11 @@ package files import ( - "path/filepath" "testing" qt "github.com/frankban/quicktest" ) -func TestIsContentFile(t *testing.T) { - c := qt.New(t) - - c.Assert(IsContentFile(filepath.FromSlash("my/file.md")), qt.Equals, true) - c.Assert(IsContentFile(filepath.FromSlash("my/file.ad")), qt.Equals, true) - c.Assert(IsContentFile(filepath.FromSlash("textfile.txt")), qt.Equals, false) - c.Assert(IsContentExt("md"), qt.Equals, true) - c.Assert(IsContentExt("json"), qt.Equals, false) -} - func TestComponentFolders(t *testing.T) { c := qt.New(t) diff --git a/hugofs/walk.go b/hugofs/walk.go index 3bb2f49233a..252cf997067 100644 --- a/hugofs/walk.go +++ b/hugofs/walk.go @@ -73,6 +73,10 @@ func NewWalkway(cfg WalkwayConfig) *Walkway { panic("fs must be set") } + if cfg.PathParser == nil { + cfg.PathParser = paths.DefaultPathParser + } + logger := cfg.Logger if logger == nil { logger = loggers.NewDefault() @@ -161,8 +165,7 @@ func (w *Walkway) walk(path string, info FileMetaInfo, dirEntries []FileMetaInfo dirEntries = DirEntriesToFileMetaInfos(fis) for _, fi := range dirEntries { - if fi.Meta().PathInfo == nil && w.cfg.PathParser != nil { - // TODO1 + if fi.Meta().PathInfo == nil { fi.Meta().PathInfo = w.cfg.PathParser.Parse("", filepath.Join(pathRel, fi.Name())) } } diff --git a/hugolib/content_map.go b/hugolib/content_map.go index f89547ee8bf..fd387d0a172 100644 --- a/hugolib/content_map.go +++ b/hugolib/content_map.go @@ -164,7 +164,7 @@ func (cfg contentMapConfig) getTaxonomyConfig(s string) (v viewName) { return } -func (m *pageMap) AddFi(fi hugofs.FileMetaInfo, whatChanged *whatChanged) (pageCount uint64, resourceCount uint64, addErr error) { +func (m *pageMap) AddFi(fi hugofs.FileMetaInfo, buildConfig *BuildCfg) (pageCount uint64, resourceCount uint64, addErr error) { if fi.IsDir() { return } @@ -227,147 +227,14 @@ func (m *pageMap) AddFi(fi hugofs.FileMetaInfo, whatChanged *whatChanged) (pageC return } case paths.PathTypeContentData: - m.s.Log.Trace(logg.StringFunc( - func() string { - return fmt.Sprintf("insert pages from data file: %q", fi.Meta().Filename) - }, - )) - - if !files.IsGoTmplExt(pi.Ext()) { - addErr = fmt.Errorf("unsupported data file extension %q", pi.Ext()) - return - } - // TODO1 disabled languages. - - s := m.s.h.resolveSite(fi.Meta().Lang) - f := source.NewFileInfo(fi) - h := s.h - - // Make sure the layouts are initialized. - if _, err := h.init.layouts.Do(context.Background()); err != nil { + pc, rc, err := m.addPagesFromGoTmplFi(fi, buildConfig) + pageCount += pc + resourceCount += rc + if err != nil { addErr = err return } - if err := func() error { - contentAdapter := s.pageMap.treePagesFromTemplateOptions.Get(pi.Base()) - var rebuild bool - if contentAdapter != nil { - // Rebuild - contentAdapter = contentAdapter.CloneForGoTmpl(fi) - rebuild = true - } else { - contentAdapter = pagesfromdata.NewPagesFromTemplate( - pagesfromdata.PagesFromTemplateOptions{ - GoTmplFi: fi, - Site: s, - DepsFromSite: func(s page.Site) pagesfromdata.PagesFromTemplateDeps { - ss := s.(*Site) - return pagesfromdata.PagesFromTemplateDeps{ - TmplFinder: ss.TextTmpl(), - TmplExec: ss.Tmpl(), - } - }, - DependencyManager: s.Conf.NewIdentityManager("pagesfromdata"), - Watching: s.Conf.Watching(), - HandlePage: func(pt *pagesfromdata.PagesFromTemplate, pc *pagemeta.PageConfig) error { - s := pt.Site.(*Site) - pc.Path = path.Join(pt.GoTmplFi.Meta().PathInfo.Base(), pc.Path) - if err := pc.Compile(true, "", s.conf.MediaTypes.Config); err != nil { - return err - } - - ps, pi, err := h.newPage( - &pageMeta{ - f: f, - s: s, - pageMetaParams: &pageMetaParams{ - pageConfig: pc, - }, - }, - ) - if err != nil { - return err - } - - if ps == nil { - // Disabled page. - return nil - } - - u, n, replaced := s.pageMap.treePages.InsertIntoValuesDimensionWithLock(pi.Base(), ps) - - if h.isRebuild() { - if replaced { - pt.AddChange(n.GetIdentity()) - } else { - pt.AddChange(u.GetIdentity()) - } - } - - return nil - }, - HandleResource: func(pt *pagesfromdata.PagesFromTemplate, rc *pagemeta.ResourceConfig) error { - s := pt.Site.(*Site) - rc.Path = path.Join(pt.GoTmplFi.Meta().PathInfo.Base(), rc.Path) - if err := rc.Compile(s.Conf.PathParser()); err != nil { - return err - } - rs := &resourceSource{path: rc.PathInfo, rc: rc, opener: nil, fi: nil, langIndex: s.languagei} - - _, n, replaced := s.pageMap.treeResources.InsertIntoValuesDimensionWithLock(rc.Path, rs) - - if h.isRebuild() && replaced { - pt.AddChange(n.GetIdentity()) - } - return nil - }, - }, - ) - - s.pageMap.treePagesFromTemplateOptions.Insert(pi.Base(), contentAdapter) - - } - - handleBuildInfo := func(s *Site, bi pagesfromdata.BuildInfo) { - resourceCount += bi.NumResourcesAdded - pageCount += bi.NumPagesAdded - s.handleContentAdapterChanges(bi, whatChanged) - } - - // TODO1 do we need a mutex? - bi, err := contentAdapter.Execute(context.Background()) - if err != nil { - return err - } - handleBuildInfo(s, bi) - - if !rebuild && bi.EnableAllLanguages { - // Clone and insert the adapter for the other sites. - for _, ss := range s.h.Sites { - if s == ss { - continue - } - - clone := contentAdapter.CloneForSite(ss) - - // Make sure it gets executed for the first time. - bi, err := clone.Execute(context.Background()) - if err != nil { - return err - } - handleBuildInfo(ss, bi) - // Insert into the correct language tree so it get rebuilt on changes. - ss.pageMap.treePagesFromTemplateOptions.Insert(pi.Base(), clone) - - } - } - - return nil - }(); err != nil { - addErr = err - return - } default: m.s.Log.Trace(logg.StringFunc( func() string { @@ -400,6 +267,151 @@ func (m *pageMap) AddFi(fi hugofs.FileMetaInfo, whatChanged *whatChanged) (pageC return } +func (m *pageMap) addPagesFromGoTmplFi(fi hugofs.FileMetaInfo, buildConfig *BuildCfg) (pageCount uint64, resourceCount uint64, addErr error) { + meta := fi.Meta() + pi := meta.PathInfo + + m.s.Log.Trace(logg.StringFunc( + func() string { + return fmt.Sprintf("insert pages from data file: %q", fi.Meta().Filename) + }, + )) + + if !files.IsGoTmplExt(pi.Ext()) { + addErr = fmt.Errorf("unsupported data file extension %q", pi.Ext()) + return + } + // TODO1 disabled languages. + + s := m.s.h.resolveSite(fi.Meta().Lang) + f := source.NewFileInfo(fi) + h := s.h + + // Make sure the layouts are initialized. + if _, err := h.init.layouts.Do(context.Background()); err != nil { + addErr = err + return + } + + contentAdapter := s.pageMap.treePagesFromTemplateOptions.Get(pi.Base()) + var rebuild bool + if contentAdapter != nil { + // Rebuild + contentAdapter = contentAdapter.CloneForGoTmpl(fi) + rebuild = true + } else { + contentAdapter = pagesfromdata.NewPagesFromTemplate( + pagesfromdata.PagesFromTemplateOptions{ + GoTmplFi: fi, + Site: s, + DepsFromSite: func(s page.Site) pagesfromdata.PagesFromTemplateDeps { + ss := s.(*Site) + return pagesfromdata.PagesFromTemplateDeps{ + TmplFinder: ss.TextTmpl(), + TmplExec: ss.Tmpl(), + } + }, + DependencyManager: s.Conf.NewIdentityManager("pagesfromdata"), + Watching: s.Conf.Watching(), + HandlePage: func(pt *pagesfromdata.PagesFromTemplate, pc *pagemeta.PageConfig) error { + s := pt.Site.(*Site) + pc.Path = path.Join(pt.GoTmplFi.Meta().PathInfo.Base(), pc.Path) + if err := pc.Compile(true, "", s.conf.MediaTypes.Config); err != nil { + return err + } + + ps, pi, err := h.newPage( + &pageMeta{ + f: f, + s: s, + pageMetaParams: &pageMetaParams{ + pageConfig: pc, + }, + }, + ) + if err != nil { + return err + } + + if ps == nil { + // Disabled page. + return nil + } + + u, n, replaced := s.pageMap.treePages.InsertIntoValuesDimensionWithLock(pi.Base(), ps) + + if h.isRebuild() { + if replaced { + pt.AddChange(n.GetIdentity()) + } else { + pt.AddChange(u.GetIdentity()) + } + } + + return nil + }, + HandleResource: func(pt *pagesfromdata.PagesFromTemplate, rc *pagemeta.ResourceConfig) error { + s := pt.Site.(*Site) + rc.Path = path.Join(pt.GoTmplFi.Meta().PathInfo.Base(), rc.Path) + if err := rc.Compile(s.Conf.PathParser()); err != nil { + return err + } + rs := &resourceSource{path: rc.PathInfo, rc: rc, opener: nil, fi: nil, langIndex: s.languagei} + + _, n, replaced := s.pageMap.treeResources.InsertIntoValuesDimensionWithLock(rc.Path, rs) + + if h.isRebuild() && replaced { + pt.AddChange(n.GetIdentity()) + } + return nil + }, + }, + ) + + s.pageMap.treePagesFromTemplateOptions.Insert(pi.Base(), contentAdapter) + + } + + handleBuildInfo := func(s *Site, bi pagesfromdata.BuildInfo) { + resourceCount += bi.NumResourcesAdded + pageCount += bi.NumPagesAdded + s.handleContentAdapterChanges(bi, buildConfig) + } + + // TODO1 do we need a mutex? + bi, err := contentAdapter.Execute(context.Background()) + if err != nil { + addErr = err + return + } + handleBuildInfo(s, bi) + + if !rebuild && bi.EnableAllLanguages { + // Clone and insert the adapter for the other sites. + for _, ss := range s.h.Sites { + if s == ss { + continue + } + + clone := contentAdapter.CloneForSite(ss) + + // Make sure it gets executed for the first time. + bi, err := clone.Execute(context.Background()) + if err != nil { + addErr = err + return + } + handleBuildInfo(ss, bi) + + // Insert into the correct language tree so it get rebuilt on changes. + ss.pageMap.treePagesFromTemplateOptions.Insert(pi.Base(), clone) + + } + } + + return +} + // The home page is represented with the zero string. // All other keys starts with a leading slash. No trailing slash. // Slashes are Unix-style. diff --git a/hugolib/hugo_sites_build.go b/hugolib/hugo_sites_build.go index 43ac2bedb82..ba7c65e6eee 100644 --- a/hugolib/hugo_sites_build.go +++ b/hugolib/hugo_sites_build.go @@ -116,7 +116,7 @@ func (h *HugoSites) Build(config BuildCfg, events ...fsnotify.Event) error { conf := &config if conf.whatChanged == nil { // Assume everything has changed - conf.whatChanged = &whatChanged{needsPagesAssemble: true} + conf.whatChanged = &whatChanged{needsPagesAssembly: true} } var prepareErr error @@ -224,7 +224,7 @@ func (h *HugoSites) initRebuild(config *BuildCfg) error { }) for _, s := range h.Sites { - s.resetBuildState(config.whatChanged.needsPagesAssemble) + s.resetBuildState(config.whatChanged.needsPagesAssembly) } h.reset(config) @@ -243,7 +243,7 @@ func (h *HugoSites) process(ctx context.Context, l logg.LevelLogger, config *Bui // This is a rebuild return h.processPartial(ctx, l, config, init, events) } - return h.processFull(ctx, l, *config) + return h.processFull(ctx, l, config) } // assemble creates missing sections, applies aggregate values (e.g. dates, cascading params), @@ -252,11 +252,9 @@ func (h *HugoSites) assemble(ctx context.Context, l logg.LevelLogger, bcfg *Buil l = l.WithField("step", "assemble") defer loggers.TimeTrackf(l, time.Now(), nil, "") - if !bcfg.whatChanged.needsPagesAssemble { - changes := bcfg.whatChanged.Changes() - + if !bcfg.whatChanged.needsPagesAssembly { + changes := bcfg.whatChanged.Drain() if len(changes) > 0 { - // TODO1 consolidate. if err := h.resolveAndClearStateForIdentities(ctx, l, nil, changes); err != nil { return err } @@ -287,7 +285,7 @@ func (h *HugoSites) assemble(ctx context.Context, l logg.LevelLogger, bcfg *Buil return err } - changes := bcfg.whatChanged.Changes() + changes := bcfg.whatChanged.Drain() // Changes from the assemble step (e.g. lastMod, cascade) needs a re-calculation // of what needs to be re-built. @@ -794,7 +792,6 @@ func (h *HugoSites) processPartial(ctx context.Context, l logg.LevelLogger, conf case files.ComponentFolderAssets: logger.Println("Asset changed", pathInfo.Path()) changes = append(changes, pathInfo) - needsPagesAssemble = true case files.ComponentFolderData: logger.Println("Data changed", pathInfo.Path()) @@ -802,7 +799,6 @@ func (h *HugoSites) processPartial(ctx context.Context, l logg.LevelLogger, conf // Currently very coarse grained. changes = append(changes, siteidentities.Data) h.init.data.Reset() - needsPagesAssemble = true case files.ComponentFolderI18n: logger.Println("i18n changed", pathInfo.Path()) i18nChanged = true @@ -886,7 +882,7 @@ func (h *HugoSites) processPartial(ctx context.Context, l logg.LevelLogger, conf resourceFiles := h.fileEventsContentPaths(addedOrChangedContent) changed := &whatChanged{ - needsPagesAssemble: needsPagesAssemble, + needsPagesAssembly: needsPagesAssemble, identitySet: make(identity.Identities), } changed.Add(changes...) @@ -909,10 +905,7 @@ func (h *HugoSites) processPartial(ctx context.Context, l logg.LevelLogger, conf } } - // Removes duplicates. - changes = changed.identitySet.AsSlice() - - if err := h.resolveAndClearStateForIdentities(ctx, l, cacheBusterOr, changes); err != nil { + if err := h.resolveAndClearStateForIdentities(ctx, l, cacheBusterOr, changed.Drain()); err != nil { return err } @@ -940,7 +933,7 @@ func (h *HugoSites) processPartial(ctx context.Context, l logg.LevelLogger, conf } if resourceFiles != nil { - if err := h.processFiles(ctx, l, *config, resourceFiles...); err != nil { + if err := h.processFiles(ctx, l, config, resourceFiles...); err != nil { return err } } @@ -965,7 +958,7 @@ func (h *HugoSites) LogServerAddresses() { } } -func (h *HugoSites) processFull(ctx context.Context, l logg.LevelLogger, config BuildCfg) (err error) { +func (h *HugoSites) processFull(ctx context.Context, l logg.LevelLogger, config *BuildCfg) (err error) { if err = h.processFiles(ctx, l, config); err != nil { err = fmt.Errorf("readAndProcessContent: %w", err) return @@ -973,19 +966,20 @@ func (h *HugoSites) processFull(ctx context.Context, l logg.LevelLogger, config return err } -func (s *Site) handleContentAdapterChanges(bi pagesfromdata.BuildInfo, whatChanged *whatChanged) { +func (s *Site) handleContentAdapterChanges(bi pagesfromdata.BuildInfo, buildConfig *BuildCfg) { if !s.h.isRebuild() { return } if len(bi.ChangedIdentities) > 0 { - whatChanged.Add(bi.ChangedIdentities...) + buildConfig.whatChanged.Add(bi.ChangedIdentities...) + buildConfig.whatChanged.needsPagesAssembly = true } for _, p := range bi.DeletedPaths { pp := path.Join(bi.Path.Base(), p) if v, ok := s.pageMap.treePages.Delete(pp); ok { - whatChanged.Add(v.GetIdentity()) + buildConfig.whatChanged.Add(v.GetIdentity()) } } } @@ -999,7 +993,7 @@ func (h *HugoSites) processContentAdaptersOnRebuild(ctx context.Context, buildCo return err } s := p.Site.(*Site) - s.handleContentAdapterChanges(bi, buildConfig.whatChanged) + s.handleContentAdapterChanges(bi, buildConfig) return nil }, }) @@ -1014,7 +1008,7 @@ func (h *HugoSites) processContentAdaptersOnRebuild(ctx context.Context, buildCo return g.Wait() } -func (s *HugoSites) processFiles(ctx context.Context, l logg.LevelLogger, buildConfig BuildCfg, filenames ...pathChange) error { +func (s *HugoSites) processFiles(ctx context.Context, l logg.LevelLogger, buildConfig *BuildCfg, filenames ...pathChange) error { if s.Deps == nil { panic("nil deps on site") } @@ -1024,7 +1018,7 @@ func (s *HugoSites) processFiles(ctx context.Context, l logg.LevelLogger, buildC // For inserts, we can pick an arbitrary pageMap. pageMap := s.Sites[0].pageMap - c := newPagesCollector(ctx, s.h, sourceSpec, s.Log, l, pageMap, buildConfig.whatChanged, filenames) + c := newPagesCollector(ctx, s.h, sourceSpec, s.Log, l, pageMap, buildConfig, filenames) if err := c.Collect(); err != nil { return err diff --git a/hugolib/pages_capture.go b/hugolib/pages_capture.go index 10e813fab8f..96c2c0f96e2 100644 --- a/hugolib/pages_capture.go +++ b/hugolib/pages_capture.go @@ -42,7 +42,7 @@ func newPagesCollector( logger loggers.Logger, infoLogger logg.LevelLogger, m *pageMap, - whatChanged *whatChanged, + buildConfig *BuildCfg, ids []pathChange, ) *pagesCollector { return &pagesCollector{ @@ -53,7 +53,7 @@ func newPagesCollector( sp: sp, logger: logger, infoLogger: infoLogger, - whatChanged: whatChanged, + buildConfig: buildConfig, ids: ids, seenDirs: make(map[string]bool), } @@ -70,7 +70,7 @@ type pagesCollector struct { fs afero.Fs - whatChanged *whatChanged + buildConfig *BuildCfg // List of paths that have changed. Used in partial builds. ids []pathChange @@ -121,7 +121,7 @@ func (c *pagesCollector) Collect() (collectErr error) { c.g = rungroup.Run[hugofs.FileMetaInfo](c.ctx, rungroup.Config[hugofs.FileMetaInfo]{ NumWorkers: numWorkers, Handle: func(ctx context.Context, fi hugofs.FileMetaInfo) error { - numPages, numResources, err := c.m.AddFi(fi, c.whatChanged) + numPages, numResources, err := c.m.AddFi(fi, c.buildConfig) if err != nil { return hugofs.AddFileInfoToError(err, fi, c.fs) } diff --git a/hugolib/pagesfromdata/pagesfromgotmpl_integration_test.go b/hugolib/pagesfromdata/pagesfromgotmpl_integration_test.go index 55e7c3334d2..eaec99f0bc4 100644 --- a/hugolib/pagesfromdata/pagesfromgotmpl_integration_test.go +++ b/hugolib/pagesfromdata/pagesfromgotmpl_integration_test.go @@ -106,7 +106,7 @@ func TestPagesFromGoTmplBasic(t *testing.T) { // Dates "Dates: Date: 2023-03-01|Lastmod: 2023-03-01|PublishDate: 2023-03-01|ExpiryDate: 0001-01-01|", ) - b.AssertFileContent("public/docs/p2/index.html", "Single: p2|", "Hello World! No **markdown** here.") + b.AssertFileContent("public/docs/p2/index.html", "Single: p2title|", "Hello World! No **markdown** here.") b.AssertFileContent("public/docs/p3/index.html", "Hello World Default") } @@ -231,15 +231,15 @@ baseURL = "https://example.com" func TestPagesFromGoTmplEditGoTmpl(t *testing.T) { t.Parallel() b := hugolib.TestRunning(t, filesPagesFromDataTempleBasic) - b.EditFileReplaceAll("content/docs/_content.gotmpl", `"title" "p2"`, `"title" "p2edited"`).Build() - b.AssertFileContent("public/docs/p2/index.html", "Single: p2edited|") - b.AssertFileContent("public/docs/index.html", "p2edited") + b.EditFileReplaceAll("content/docs/_content.gotmpl", `"title" "p2title"`, `"title" "p2titleedited"`).Build() + b.AssertFileContent("public/docs/p2/index.html", "Single: p2titleedited|") + b.AssertFileContent("public/docs/index.html", "p2titleedited") } func TestPagesFromGoTmplEditDataResource(t *testing.T) { t.Parallel() b := hugolib.TestRunning(t, filesPagesFromDataTempleBasic) - b.AssertRenderCountPage(6) + b.AssertRenderCountPage(7) b.EditFileReplaceAll("assets/mydata.yaml", "p1: \"p1\"", "p1: \"p1edited\"").Build() b.AssertFileContent("public/docs/p1/index.html", "Single: p1edited:p1|") b.AssertFileContent("public/docs/index.html", "p1edited") @@ -257,9 +257,8 @@ func TestPagesFromGoTmplEditPartial(t *testing.T) { func TestPagesFromGoTmplRemovePage(t *testing.T) { t.Parallel() b := hugolib.TestRunning(t, filesPagesFromDataTempleBasic) - // RegularPagesRecursive: p1:p1:/docs/p1|p1:p1:/docs/p3|p2:/docs/p2|pfile:/docs/pfile|$ b.EditFileReplaceAll("content/docs/_content.gotmpl", `{{ $.AddPage (dict "kind" "page" "path" "p2" "title" "p2title" "dates" $dates "content" $contentHTML ) }}`, "").Build() - b.AssertFileContent("public/index.html", "RegularPagesRecursive: p1:p1:/docs/p1|p3title:/docs/p3|pfile:/docs/pfile|$") + b.AssertFileContent("public/index.html", "RegularPagesRecursive: p1:p1:/docs/p1|p3title:/docs/p3|p4title:/docs/p4|pfile:/docs/pfile|$") } func TestPagesFromGoTmplDraftPage(t *testing.T) { @@ -281,9 +280,9 @@ func TestPagesFromGoTmplDraftFlagFromResource(t *testing.T) { func TestPagesFromGoTmplMovePage(t *testing.T) { t.Parallel() b := hugolib.TestRunning(t, filesPagesFromDataTempleBasic) - b.AssertFileContent("public/index.html", "RegularPagesRecursive: p1:p1:/docs/p1|p1:p1:/docs/p3|p2:/docs/p2|pfile:/docs/pfile|$") + b.AssertFileContent("public/index.html", "RegularPagesRecursive: p1:p1:/docs/p1|p2title:/docs/p2|p3title:/docs/p3|p4title:/docs/p4|pfile:/docs/pfile|$") b.EditFileReplaceAll("content/docs/_content.gotmpl", `"path" "p2"`, `"path" "p2moved"`).Build() - b.AssertFileContent("public/index.html", "RegularPagesRecursive: p1:p1:/docs/p1|p1:p1:/docs/p3|p2:/docs/p2moved|pfile:/docs/pfile|$") + b.AssertFileContent("public/index.html", "RegularPagesRecursive: p1:p1:/docs/p1|p2title:/docs/p2moved|p3title:/docs/p3|p4title:/docs/p4|pfile:/docs/pfile|$") } func TestPagesFromGoTmplEnableAllLanguages(t *testing.T) { diff --git a/hugolib/site.go b/hugolib/site.go index 13a1fce124a..d9103e73790 100644 --- a/hugolib/site.go +++ b/hugolib/site.go @@ -374,7 +374,7 @@ func (s *Site) watching() bool { type whatChanged struct { mu sync.Mutex - needsPagesAssemble bool + needsPagesAssembly bool identitySet identity.Identities } @@ -394,6 +394,10 @@ func (w *whatChanged) Add(ids ...identity.Identity) { func (w *whatChanged) Clear() { w.mu.Lock() defer w.mu.Unlock() + w.clear() +} + +func (w *whatChanged) clear() { w.identitySet = identity.Identities{} } @@ -404,6 +408,14 @@ func (w *whatChanged) Changes() []identity.Identity { return w.identitySet.AsSlice() } +func (w *whatChanged) Drain() []identity.Identity { + w.mu.Lock() + defer w.mu.Unlock() + ids := w.identitySet.AsSlice() + w.clear() + return ids +} + // RegisterMediaTypes will register the Site's media types in the mime // package, so it will behave correctly with Hugo's built-in server. func (s *Site) RegisterMediaTypes() { diff --git a/media/mediaType_test.go b/media/mediaType_test.go index 3b8e099b897..abf0ed91ea9 100644 --- a/media/mediaType_test.go +++ b/media/mediaType_test.go @@ -214,3 +214,11 @@ func BenchmarkTypeOps(b *testing.B) { } } + +func TestIsContentFile(t *testing.T) { + c := qt.New(t) + + c.Assert(IsContentFile(filepath.FromSlash("my/file.md")), qt.Equals, true) + c.Assert(IsContentFile(filepath.FromSlash("my/file.ad")), qt.Equals, true) + c.Assert(IsContentFile(filepath.FromSlash("textfile.txt")), qt.Equals, false) +} diff --git a/resources/postpub/fields_test.go b/resources/postpub/fields_test.go index 336da1f0e3e..53875cb346b 100644 --- a/resources/postpub/fields_test.go +++ b/resources/postpub/fields_test.go @@ -36,6 +36,8 @@ func TestCreatePlaceholders(t *testing.T) { "SuffixesCSV": "pre_foo.SuffixesCSV_post", "Delimiter": "pre_foo.Delimiter_post", "FirstSuffix": "pre_foo.FirstSuffix_post", + "IsHTML": "pre_foo.IsHTML_post", + "IsMarkdown": "pre_foo.IsMarkdown_post", "IsText": "pre_foo.IsText_post", "String": "pre_foo.String_post", "Type": "pre_foo.Type_post",