From c4261fe9f2551485817a354c16a4c52148231970 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Pedersen?= Date: Sat, 24 Feb 2018 15:17:14 +0100 Subject: [PATCH] Move to pagemeta package --- hugolib/page.go | 41 +++----- hugolib/page_paths.go | 2 +- hugolib/site.go | 5 +- {hugolib => pagemeta}/page_frontmatter.go | 96 +++++++++---------- .../page_frontmatter_test.go | 34 +++---- pagemeta/pagemeta.go | 30 ++++++ 6 files changed, 114 insertions(+), 94 deletions(-) rename {hugolib => pagemeta}/page_frontmatter.go (76%) rename {hugolib => pagemeta}/page_frontmatter_test.go (87%) create mode 100644 pagemeta/pagemeta.go diff --git a/hugolib/page.go b/hugolib/page.go index 9151a599013..a0eed5ddb8a 100644 --- a/hugolib/page.go +++ b/hugolib/page.go @@ -25,6 +25,7 @@ import ( "github.com/bep/gitmap" "github.com/gohugoio/hugo/helpers" + "github.com/gohugoio/hugo/pagemeta" "github.com/gohugoio/hugo/resource" "github.com/gohugoio/hugo/output" @@ -220,10 +221,12 @@ type Page struct { Keywords []string Data map[string]interface{} - PageDates + pagemeta.PageDates Sitemap Sitemap - URLPath + pagemeta.URLPath + frontMatterURL string + permalink string relPermalink string @@ -260,13 +263,6 @@ type Page struct { targetPathDescriptorPrototype *targetPathDescriptor } -type PageDates struct { - Date time.Time - Lastmod time.Time - PublishDate time.Time - ExpiryDate time.Time -} - // SearchKeywords implements the related.Document interface needed for fast page searches. func (p *Page) SearchKeywords(cfg related.IndexConfig) ([]related.Keyword, error) { @@ -1123,17 +1119,18 @@ func (p *Page) update(frontmatter map[string]interface{}) error { mtime = p.Source.FileInfo().ModTime() } - descriptor := frontMatterDescriptor{ - frontmatter: frontmatter, - params: p.params, - dates: &p.PageDates, - pageURLs: &p.URLPath, - baseFilename: p.BaseFileName(), modTime: mtime} + descriptor := pagemeta.FrontMatterDescriptor{ + Frontmatter: frontmatter, + Params: p.params, + Dates: &p.PageDates, + PageURLs: &p.URLPath, + BaseFilename: p.BaseFileName(), + ModTime: mtime} // Handle the date separately // TODO(bep) we need to "do more" in this area so this can be split up and // more easily tested without the Page, but the coupling is strong. - err := p.s.frontmatterHandler.handleDates(descriptor) + err := p.s.frontmatterHandler.HandleDates(descriptor) if err != nil { p.s.Log.ERROR.Printf("Failed to handle dates for page %q: %s", p.Path(), err) } @@ -1151,7 +1148,7 @@ func (p *Page) update(frontmatter map[string]interface{}) error { continue } - if p.s.frontmatterHandler.isDateKey(loki) { + if p.s.frontmatterHandler.IsDateKey(loki) { continue } @@ -1173,7 +1170,7 @@ func (p *Page) update(frontmatter map[string]interface{}) error { return fmt.Errorf("Only relative URLs are supported, %v provided", url) } p.URLPath.URL = cast.ToString(v) - p.URLPath.frontMatterURL = p.URLPath.URL + p.frontMatterURL = p.URLPath.URL p.params[loki] = p.URLPath.URL case "type": p.contentType = cast.ToString(v) @@ -1829,14 +1826,6 @@ func (p *Page) String() string { return fmt.Sprintf("Page(%q)", p.title) } -type URLPath struct { - URL string - frontMatterURL string - Permalink string - Slug string - Section string -} - // Scratch returns the writable context associated with this Page. func (p *Page) Scratch() *Scratch { if p.scratch == nil { diff --git a/hugolib/page_paths.go b/hugolib/page_paths.go index 5f45f7adf5a..13aebcd9120 100644 --- a/hugolib/page_paths.go +++ b/hugolib/page_paths.go @@ -88,7 +88,7 @@ func (p *Page) initTargetPathDescriptor() error { Sections: p.sections, UglyURLs: p.s.Info.uglyURLs(p), Dir: filepath.ToSlash(p.Source.Dir()), - URL: p.URLPath.frontMatterURL, + URL: p.frontMatterURL, IsMultihost: p.s.owner.IsMultihost(), } diff --git a/hugolib/site.go b/hugolib/site.go index 2f20a35d9c5..3b319454660 100644 --- a/hugolib/site.go +++ b/hugolib/site.go @@ -43,6 +43,7 @@ import ( "github.com/gohugoio/hugo/deps" "github.com/gohugoio/hugo/helpers" "github.com/gohugoio/hugo/output" + "github.com/gohugoio/hugo/pagemeta" "github.com/gohugoio/hugo/parser" "github.com/gohugoio/hugo/related" "github.com/gohugoio/hugo/source" @@ -122,7 +123,7 @@ type Site struct { mediaTypesConfig media.Types // How to handle page front matter. - frontmatterHandler frontmatterHandler + frontmatterHandler pagemeta.FrontmatterHandler // We render each site for all the relevant output formats in serial with // this rendering context pointing to the current one. @@ -252,7 +253,7 @@ func newSite(cfg deps.DepsCfg) (*Site, error) { titleFunc := helpers.GetTitleFunc(cfg.Language.GetString("titleCaseStyle")) - frontMatterHandler, err := newFrontmatterHandler(cfg.Logger, cfg.Cfg) + frontMatterHandler, err := pagemeta.NewFrontmatterHandler(cfg.Logger, cfg.Cfg) if err != nil { return nil, err } diff --git a/hugolib/page_frontmatter.go b/pagemeta/page_frontmatter.go similarity index 76% rename from hugolib/page_frontmatter.go rename to pagemeta/page_frontmatter.go index 532d33047db..c506fe8eeff 100644 --- a/hugolib/page_frontmatter.go +++ b/pagemeta/page_frontmatter.go @@ -11,7 +11,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package hugolib +package pagemeta import ( "fmt" @@ -32,37 +32,37 @@ import ( // TODO(bep) should probably make the date handling chain complete to give people the flexibility they want. -type frontmatterHandler struct { +type FrontmatterHandler struct { // Ordered chain. dateHandlers frontMatterFieldHandler logger *jww.Notepad } -type frontMatterDescriptor struct { +type FrontMatterDescriptor struct { // This the Page's front matter. - frontmatter map[string]interface{} + Frontmatter map[string]interface{} // This is the Page's base filename, e.g. page.md. - baseFilename string + BaseFilename string // The content file's mod time. - modTime time.Time + ModTime time.Time // The below are pointers to values on Page and will be updated. // This is the Page's params. - params map[string]interface{} + Params map[string]interface{} // This is the Page's dates. - dates *PageDates + Dates *PageDates // This is the Page's Slug etc. - pageURLs *URLPath + PageURLs *URLPath } -func (f frontmatterHandler) handleDate(d frontMatterDescriptor) error { +func (f FrontmatterHandler) handleDate(d FrontMatterDescriptor) error { _, err := f.dateHandlers(d) return err } @@ -88,8 +88,8 @@ func init() { allDateFrontMatterKeys["date"] = true } -func (f frontmatterHandler) handleDates(d frontMatterDescriptor) error { - if d.dates == nil { +func (f FrontmatterHandler) HandleDates(d FrontMatterDescriptor) error { + if d.Dates == nil { panic("missing dates") } @@ -97,61 +97,61 @@ func (f frontmatterHandler) handleDates(d frontMatterDescriptor) error { if err != nil { return err } - d.dates.Lastmod = f.setParamsAndReturnFirstDate(d, lastModFrontMatterKeys) - d.dates.PublishDate = f.setParamsAndReturnFirstDate(d, publishDateFrontMatterKeys) - d.dates.ExpiryDate = f.setParamsAndReturnFirstDate(d, expiryDateFrontMatterKeys) + d.Dates.Lastmod = f.setParamsAndReturnFirstDate(d, lastModFrontMatterKeys) + d.Dates.PublishDate = f.setParamsAndReturnFirstDate(d, publishDateFrontMatterKeys) + d.Dates.ExpiryDate = f.setParamsAndReturnFirstDate(d, expiryDateFrontMatterKeys) // Hugo really needs a date! - if d.dates.Date.IsZero() { - d.dates.Date = d.dates.PublishDate + if d.Dates.Date.IsZero() { + d.Dates.Date = d.Dates.PublishDate } - if d.dates.Lastmod.IsZero() { - d.dates.Lastmod = d.dates.Date + if d.Dates.Lastmod.IsZero() { + d.Dates.Lastmod = d.Dates.Date } // TODO(bep) date decide vs https://github.com/gohugoio/hugo/issues/3977 - if d.dates.PublishDate.IsZero() { + if d.Dates.PublishDate.IsZero() { //d.dates.PublishDate = d.dates.Date } - if d.dates.Date.IsZero() { - d.dates.Date = d.dates.Lastmod + if d.Dates.Date.IsZero() { + d.Dates.Date = d.Dates.Lastmod } - f.setParamIfNotZero("date", d.params, d.dates.Date) - f.setParamIfNotZero("lastmod", d.params, d.dates.Lastmod) - f.setParamIfNotZero("publishdate", d.params, d.dates.PublishDate) - f.setParamIfNotZero("expirydate", d.params, d.dates.ExpiryDate) + f.setParamIfNotZero("date", d.Params, d.Dates.Date) + f.setParamIfNotZero("lastmod", d.Params, d.Dates.Lastmod) + f.setParamIfNotZero("publishdate", d.Params, d.Dates.PublishDate) + f.setParamIfNotZero("expirydate", d.Params, d.Dates.ExpiryDate) return nil } -func (f frontmatterHandler) isDateKey(key string) bool { +func (f FrontmatterHandler) IsDateKey(key string) bool { return allDateFrontMatterKeys[key] } -func (f frontmatterHandler) setParamIfNotZero(name string, params map[string]interface{}, date time.Time) { +func (f FrontmatterHandler) setParamIfNotZero(name string, params map[string]interface{}, date time.Time) { if date.IsZero() { return } params[name] = date } -func (f frontmatterHandler) setParamsAndReturnFirstDate(d frontMatterDescriptor, keys []string) time.Time { +func (f FrontmatterHandler) setParamsAndReturnFirstDate(d FrontMatterDescriptor, keys []string) time.Time { var date time.Time for _, key := range keys { - v, found := d.frontmatter[key] + v, found := d.Frontmatter[key] if found { currentDate, err := cast.ToTimeE(v) if err == nil { - d.params[key] = currentDate + d.Params[key] = currentDate if date.IsZero() { date = currentDate } } else { - d.params[key] = v + d.Params[key] = v } } } @@ -183,10 +183,10 @@ func dateAndSlugFromBaseFilename(name string) (time.Time, string) { return d, slug } -type frontMatterFieldHandler func(d frontMatterDescriptor) (bool, error) +type frontMatterFieldHandler func(d FrontMatterDescriptor) (bool, error) -func (f frontmatterHandler) newChainedFrontMatterFieldHandler(handlers ...frontMatterFieldHandler) frontMatterFieldHandler { - return func(d frontMatterDescriptor) (bool, error) { +func (f FrontmatterHandler) newChainedFrontMatterFieldHandler(handlers ...frontMatterFieldHandler) frontMatterFieldHandler { + return func(d FrontMatterDescriptor) (bool, error) { for _, h := range handlers { // First successful handler wins. success, err := h(d) @@ -258,13 +258,13 @@ func toLowerSlice(in interface{}) []string { return out } -func newFrontmatterHandler(logger *jww.Notepad, cfg config.Provider) (frontmatterHandler, error) { +func NewFrontmatterHandler(logger *jww.Notepad, cfg config.Provider) (FrontmatterHandler, error) { if logger == nil { logger = jww.NewNotepad(jww.LevelWarn, jww.LevelWarn, os.Stdout, ioutil.Discard, "", log.Ldate|log.Ltime) } - f := frontmatterHandler{logger: logger} + f := FrontmatterHandler{logger: logger} handlers := &frontmatterFieldHandlers{logger: logger} @@ -311,8 +311,8 @@ type frontmatterFieldHandlers struct { logger *jww.Notepad } -func (f *frontmatterFieldHandlers) defaultDateHandler(d frontMatterDescriptor) (bool, error) { - v, found := d.frontmatter["date"] +func (f *frontmatterFieldHandlers) defaultDateHandler(d FrontMatterDescriptor) (bool, error) { + v, found := d.Frontmatter["date"] if !found { return false, nil } @@ -322,30 +322,30 @@ func (f *frontmatterFieldHandlers) defaultDateHandler(d frontMatterDescriptor) ( return false, err } - d.dates.Date = date + d.Dates.Date = date return true, nil } -func (f *frontmatterFieldHandlers) defaultDateFilenameHandler(d frontMatterDescriptor) (bool, error) { - date, slug := dateAndSlugFromBaseFilename(d.baseFilename) +func (f *frontmatterFieldHandlers) defaultDateFilenameHandler(d FrontMatterDescriptor) (bool, error) { + date, slug := dateAndSlugFromBaseFilename(d.BaseFilename) if date.IsZero() { return false, nil } - d.dates.Date = date + d.Dates.Date = date - if _, found := d.frontmatter["slug"]; !found { + if _, found := d.Frontmatter["slug"]; !found { // Use slug from filename - d.pageURLs.Slug = slug + d.PageURLs.Slug = slug } return true, nil } -func (f *frontmatterFieldHandlers) defaultDateModTimeHandler(d frontMatterDescriptor) (bool, error) { - if !d.modTime.IsZero() { - d.dates.Date = d.modTime +func (f *frontmatterFieldHandlers) defaultDateModTimeHandler(d FrontMatterDescriptor) (bool, error) { + if !d.ModTime.IsZero() { + d.Dates.Date = d.ModTime return true, nil } return false, nil diff --git a/hugolib/page_frontmatter_test.go b/pagemeta/page_frontmatter_test.go similarity index 87% rename from hugolib/page_frontmatter_test.go rename to pagemeta/page_frontmatter_test.go index 38f486e6c07..a5a60e378a0 100644 --- a/hugolib/page_frontmatter_test.go +++ b/pagemeta/page_frontmatter_test.go @@ -11,7 +11,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package hugolib +package pagemeta import ( "fmt" @@ -108,7 +108,7 @@ func TestFrontMatterDates(t *testing.T) { cfg := viper.New() - handler, err := newFrontmatterHandler(newWarningLogger(), cfg) + handler, err := NewFrontmatterHandler(nil, cfg) assert.NoError(err) testDate, err := time.Parse("2006-01-02", "2018-02-01") @@ -134,22 +134,22 @@ func TestFrontMatterDates(t *testing.T) { testDate = testDate.Add(24 * time.Hour) t.Log(expiryDateKey, testDate) for _, expiryDateDate := range []time.Time{testDate, sentinel} { - d := frontMatterDescriptor{ - frontmatter: make(map[string]interface{}), - params: make(map[string]interface{}), - dates: &PageDates{}, - pageURLs: &URLPath{}, + d := FrontMatterDescriptor{ + Frontmatter: make(map[string]interface{}), + Params: make(map[string]interface{}), + Dates: &PageDates{}, + PageURLs: &URLPath{}, } var expLastMod, expDate, expPubDate, expExiryDate = zero, zero, zero, zero if dateDate != sentinel { - d.frontmatter[dateKey] = dateDate + d.Frontmatter[dateKey] = dateDate expDate = dateDate } if pubDateDate != sentinel { - d.frontmatter[pubDateKey] = pubDateDate + d.Frontmatter[pubDateKey] = pubDateDate expPubDate = pubDateDate if expDate.IsZero() { expDate = expPubDate @@ -157,7 +157,7 @@ func TestFrontMatterDates(t *testing.T) { } if lastModDate != sentinel { - d.frontmatter[lastModKey] = lastModDate + d.Frontmatter[lastModKey] = lastModDate expLastMod = lastModDate if expDate.IsZero() { @@ -166,7 +166,7 @@ func TestFrontMatterDates(t *testing.T) { } if expiryDateDate != sentinel { - d.frontmatter[expiryDateKey] = expiryDateDate + d.Frontmatter[expiryDateKey] = expiryDateDate expExiryDate = expiryDateDate } @@ -174,7 +174,7 @@ func TestFrontMatterDates(t *testing.T) { expLastMod = expDate } - assert.NoError(handler.handleDates(d)) + assert.NoError(handler.HandleDates(d)) assertFrontMatterDate(assert, d, expDate, "date") assertFrontMatterDate(assert, d, expLastMod, "lastmod") @@ -190,7 +190,7 @@ func TestFrontMatterDates(t *testing.T) { } } -func assertFrontMatterDate(assert *require.Assertions, d frontMatterDescriptor, expected time.Time, dateField string) { +func assertFrontMatterDate(assert *require.Assertions, d FrontMatterDescriptor, expected time.Time, dateField string) { switch dateField { case "date": case "lastmod": @@ -200,14 +200,14 @@ func assertFrontMatterDate(assert *require.Assertions, d frontMatterDescriptor, assert.Failf("Unknown datefield %s", dateField) } - param, found := d.params[dateField] + param, found := d.Params[dateField] if found && param.(time.Time).IsZero() { assert.Fail("Zero time in params", dateField) } message := fmt.Sprintf("[%s] Found: %t Expected: %v (%t) Param: %v Params: %v Front matter: %v", - dateField, found, expected, expected.IsZero(), param, d.params, d.frontmatter) + dateField, found, expected, expected.IsZero(), param, d.Params, d.Frontmatter) assert.True(found != expected.IsZero(), message) @@ -224,8 +224,8 @@ type dateTestHelper struct { dates PageDates } -func (d dateTestHelper) descriptor() frontMatterDescriptor { - return frontMatterDescriptor{dates: &d.dates} +func (d dateTestHelper) descriptor() FrontMatterDescriptor { + return FrontMatterDescriptor{Dates: &d.dates} } func (d dateTestHelper) assert(t *testing.T) { diff --git a/pagemeta/pagemeta.go b/pagemeta/pagemeta.go new file mode 100644 index 00000000000..57cef9efab8 --- /dev/null +++ b/pagemeta/pagemeta.go @@ -0,0 +1,30 @@ +// Copyright 2018 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 pagemeta + +import "time" + +type URLPath struct { + URL string + Permalink string + Slug string + Section string +} + +type PageDates struct { + Date time.Time + Lastmod time.Time + PublishDate time.Time + ExpiryDate time.Time +}