From 42928de09f0a3ddc401aeea3a32e0b802d0bba76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Pedersen?= Date: Sun, 11 Mar 2018 18:59:11 +0100 Subject: [PATCH] Refactor the GitInfo into the date handlers Fixes #4495 --- hugolib/gitinfo.go | 40 +++++++++++ hugolib/hugo_sites.go | 12 ++++ hugolib/page.go | 7 ++ hugolib/pagemeta/page_frontmatter.go | 20 +++++- hugolib/pagemeta/page_frontmatter_test.go | 86 +++++++++-------------- 5 files changed, 112 insertions(+), 53 deletions(-) diff --git a/hugolib/gitinfo.go b/hugolib/gitinfo.go index bfcfa9a42fe..1132f0b1a85 100644 --- a/hugolib/gitinfo.go +++ b/hugolib/gitinfo.go @@ -19,10 +19,50 @@ import ( "strings" "github.com/bep/gitmap" + "github.com/gohugoio/hugo/config" "github.com/gohugoio/hugo/helpers" ) +type gitInfo struct { + contentDir string + repo *gitmap.GitRepo +} + +func (g *gitInfo) forPage(p *Page) (*gitmap.GitInfo, bool) { + if g == nil { + return nil, false + } + name := path.Join(g.contentDir, filepath.ToSlash(p.Path())) + return g.repo.Files[name], true +} + +func newGitInfo(cfg config.Provider) (*gitInfo, error) { + var ( + workingDir = cfg.GetString("workingDir") + contentDir = cfg.GetString("contentDir") + ) + + gitRepo, err := gitmap.Map(workingDir, "") + if err != nil { + return nil, err + } + + repoPath := filepath.FromSlash(gitRepo.TopLevelAbsPath) + // The Hugo site may be placed in a sub folder in the Git repo, + // one example being the Hugo docs. + // We have to find the root folder to the Hugo site below the Git root. + contentRoot := strings.TrimPrefix(workingDir, repoPath) + contentRoot = strings.TrimPrefix(contentRoot, helpers.FilePathSeparator) + contentDir = path.Join(filepath.ToSlash(contentRoot), contentDir) + + return &gitInfo{contentDir: contentDir, repo: gitRepo}, nil +} + func (h *HugoSites) assembleGitInfo() { + // TODO(bep) gitinfo remove this + if true { + return + } if !h.Cfg.GetBool("enableGitInfo") { return } diff --git a/hugolib/hugo_sites.go b/hugolib/hugo_sites.go index 6c2a5c1538f..0ed7f10c4ae 100644 --- a/hugolib/hugo_sites.go +++ b/hugolib/hugo_sites.go @@ -47,6 +47,9 @@ type HugoSites struct { // Keeps track of bundle directories and symlinks to enable partial rebuilding. ContentChanges *contentChangeMap + + // If enabled, keeps a revision map for all content. + gitInfo *gitInfo } func (h *HugoSites) IsMultihost() bool { @@ -146,6 +149,15 @@ func newHugoSites(cfg deps.DepsCfg, sites ...*Site) (*HugoSites, error) { h.Deps = sites[0].Deps + if cfg.Cfg.GetBool("enableGitInfo") { + gi, err := newGitInfo(cfg.Cfg) + if err != nil { + h.Log.ERROR.Println("Failed to read Git log:", err) + } else { + h.gitInfo = gi + } + } + return h, nil } diff --git a/hugolib/page.go b/hugolib/page.go index 2274aa84ae8..e64e5281c5e 100644 --- a/hugolib/page.go +++ b/hugolib/page.go @@ -1579,6 +1579,13 @@ func (p *Page) parse(reader io.Reader) error { meta = map[string]interface{}{} } + gi, enabled := p.s.owner.gitInfo.forPage(p) + if gi != nil { + p.GitInfo = gi + } else if enabled { + p.s.Log.WARN.Println("Failed to find GitInfo for page %q", p.Path()) + } + return p.update(meta) } diff --git a/hugolib/pagemeta/page_frontmatter.go b/hugolib/pagemeta/page_frontmatter.go index 5e60a47d028..8bfc4e837e8 100644 --- a/hugolib/pagemeta/page_frontmatter.go +++ b/hugolib/pagemeta/page_frontmatter.go @@ -56,6 +56,9 @@ type FrontMatterDescriptor struct { // The content file's mod time. ModTime time.Time + // May be set from the author date in Git. + GitAuthorDate time.Time + // The below are pointers to values on Page and will be modified. // This is the Page's params. @@ -175,13 +178,16 @@ const ( // Gets date from file OS mod time. fmModTime = ":filemodtime" + + // Gets date from Git + fmGitAuthorDate = ":git" ) // This is the config you get when doing nothing. func newDefaultFrontmatterConfig() frontmatterConfig { return frontmatterConfig{ date: []string{fmDate, fmPubDate, fmLastmod}, - lastmod: []string{fmLastmod, fmDate, fmPubDate}, + lastmod: []string{fmGitAuthorDate, fmLastmod, fmDate, fmPubDate}, publishDate: []string{fmPubDate, fmDate}, expiryDate: []string{fmExpiryDate}, } @@ -348,6 +354,8 @@ func (f FrontMatterHandler) createDateHandler(identifiers []string, setter func( handlers = append(handlers, h.newDateFilenameHandler(setter)) case fmModTime: handlers = append(handlers, h.newDateModTimeHandler(setter)) + case fmGitAuthorDate: + handlers = append(handlers, h.newDateGitAuthorDateHandler(setter)) default: handlers = append(handlers, h.newDateFieldHandler(identifier, setter)) } @@ -410,3 +418,13 @@ func (f *frontmatterFieldHandlers) newDateModTimeHandler(setter func(d *FrontMat return true, nil } } + +func (f *frontmatterFieldHandlers) newDateGitAuthorDateHandler(setter func(d *FrontMatterDescriptor, t time.Time)) frontMatterFieldHandler { + return func(d *FrontMatterDescriptor) (bool, error) { + if d.GitAuthorDate.IsZero() { + return false, nil + } + setter(d, d.GitAuthorDate) + return true, nil + } +} diff --git a/hugolib/pagemeta/page_frontmatter_test.go b/hugolib/pagemeta/page_frontmatter_test.go index 5372a4f3af0..03f4c2f84a4 100644 --- a/hugolib/pagemeta/page_frontmatter_test.go +++ b/hugolib/pagemeta/page_frontmatter_test.go @@ -15,6 +15,7 @@ package pagemeta import ( "fmt" + "strings" "testing" "time" @@ -94,7 +95,7 @@ func TestFrontMatterNewConfig(t *testing.T) { fc, err = newFrontmatterConfig(cfg) assert.NoError(err) assert.Equal([]string{"date", "publishdate", "pubdate", "published", "lastmod", "modified"}, fc.date) - assert.Equal([]string{"lastmod", "modified", "date", "publishdate", "pubdate", "published"}, fc.lastmod) + assert.Equal([]string{":git", "lastmod", "modified", "date", "publishdate", "pubdate", "published"}, fc.lastmod) assert.Equal([]string{"expirydate", "unpublishdate"}, fc.expiryDate) assert.Equal([]string{"publishdate", "pubdate", "published", "date"}, fc.publishDate) @@ -108,69 +109,50 @@ func TestFrontMatterNewConfig(t *testing.T) { fc, err = newFrontmatterConfig(cfg) assert.NoError(err) assert.Equal([]string{"d1", "date", "publishdate", "pubdate", "published", "lastmod", "modified"}, fc.date) - assert.Equal([]string{"d2", "lastmod", "modified", "date", "publishdate", "pubdate", "published"}, fc.lastmod) + assert.Equal([]string{"d2", ":git", "lastmod", "modified", "date", "publishdate", "pubdate", "published"}, fc.lastmod) assert.Equal([]string{"d3", "expirydate", "unpublishdate"}, fc.expiryDate) assert.Equal([]string{"d4", "publishdate", "pubdate", "published", "date"}, fc.publishDate) } -func TestFrontMatterDatesFilenameModTime(t *testing.T) { +func TestFrontMatterDatesHandlers(t *testing.T) { assert := require.New(t) - cfg := viper.New() - - cfg.Set("frontmatter", map[string]interface{}{ - "date": []string{":fileModTime", "date"}, - }) - - handler, err := NewFrontmatterHandler(nil, cfg) - assert.NoError(err) - - d1, _ := time.Parse("2006-01-02", "2018-02-01") - d2, _ := time.Parse("2006-01-02", "2018-02-02") - - d := newTestFd() - d.ModTime = d1 - d.Frontmatter["date"] = d2 - assert.NoError(handler.HandleDates(d)) - assert.Equal(d1, d.Dates.Date) - assert.Equal(d2, d.Params["date"]) - - d = newTestFd() - d.Frontmatter["date"] = d2 - assert.NoError(handler.HandleDates(d)) - assert.Equal(d2, d.Dates.Date) - assert.Equal(d2, d.Params["date"]) - -} - -func TestFrontMatterDatesFilename(t *testing.T) { - assert := require.New(t) + for _, handlerID := range []string{":filename", ":fileModTime", ":git"} { - cfg := viper.New() - - cfg.Set("frontmatter", map[string]interface{}{ - "date": []string{":filename", "date"}, - }) + cfg := viper.New() - handler, err := NewFrontmatterHandler(nil, cfg) - assert.NoError(err) + cfg.Set("frontmatter", map[string]interface{}{ + "date": []string{handlerID, "date"}, + }) - d1, _ := time.Parse("2006-01-02", "2018-02-01") - d2, _ := time.Parse("2006-01-02", "2018-02-02") + handler, err := NewFrontmatterHandler(nil, cfg) + assert.NoError(err) - d := newTestFd() - d.BaseFilename = "2018-02-01-page.md" - d.Frontmatter["date"] = d2 - assert.NoError(handler.HandleDates(d)) - assert.Equal(d1, d.Dates.Date) - assert.Equal(d2, d.Params["date"]) + d1, _ := time.Parse("2006-01-02", "2018-02-01") + d2, _ := time.Parse("2006-01-02", "2018-02-02") + + d := newTestFd() + switch strings.ToLower(handlerID) { + case ":filename": + d.BaseFilename = "2018-02-01-page.md" + case ":filemodtime": + d.ModTime = d1 + case ":git": + d.GitAuthorDate = d1 + } + d.Frontmatter["date"] = d2 + assert.NoError(handler.HandleDates(d)) + assert.Equal(d1, d.Dates.Date) + assert.Equal(d2, d.Params["date"]) + + d = newTestFd() + d.Frontmatter["date"] = d2 + assert.NoError(handler.HandleDates(d)) + assert.Equal(d2, d.Dates.Date) + assert.Equal(d2, d.Params["date"]) - d = newTestFd() - d.Frontmatter["date"] = d2 - assert.NoError(handler.HandleDates(d)) - assert.Equal(d2, d.Dates.Date) - assert.Equal(d2, d.Params["date"]) + } } func TestFrontMatterDatesCustomConfig(t *testing.T) {