Skip to content

Commit

Permalink
Add a Page interface
Browse files Browse the repository at this point in the history
The main motivation of this commit is to add a `page.Page` interface to replace the old very file-oriented `hugolib.Page` struct to prepare for gohugoio#5074, "pages from other data sources".

But this also fixes a set of annoying limiations, especially related to custom output formats, and shortcodes. And it's faster.

See gohugoio#5074
Fixes gohugoio#5090
Fixes gohugoio#5204
Fixes gohugoio#4695
Fixes gohugoio#5607
Fixes gohugoio#5704
Fixes gohugoio#5707
Fixes gohugoio#5719
  • Loading branch information
bep committed Mar 7, 2019
1 parent 7e4b18c commit dcbf4dd
Show file tree
Hide file tree
Showing 168 changed files with 10,941 additions and 8,033 deletions.
2 changes: 2 additions & 0 deletions benchbep.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
gobench -package=./hugolib -bench="BenchmarkSiteBuilding/TOML,num_langs=3,num_pages=5000,tags_per_page=5,shortcodes,render" -count=3 > 1.bench
benchcmp -best 0.bench 1.bench
2 changes: 1 addition & 1 deletion commands/commands_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func TestExecute(t *testing.T) {
assert.NoError(resp.Err)
result := resp.Result
assert.True(len(result.Sites) == 1)
assert.True(len(result.Sites[0].RegularPages) == 1)
assert.True(len(result.Sites[0].RegularPages()) == 1)
}

func TestCommandsPersistentFlags(t *testing.T) {
Expand Down
20 changes: 11 additions & 9 deletions commands/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import (
"strings"
"time"

"github.com/gohugoio/hugo/resources/page"

"github.com/gohugoio/hugo/hugofs"

"github.com/gohugoio/hugo/helpers"
Expand Down Expand Up @@ -124,33 +126,33 @@ func (cc *convertCmd) convertContents(format metadecoders.Format) error {

site := h.Sites[0]

site.Log.FEEDBACK.Println("processing", len(site.AllPages), "content files")
for _, p := range site.AllPages {
site.Log.FEEDBACK.Println("processing", len(site.AllPages()), "content files")
for _, p := range site.AllPages() {
if err := cc.convertAndSavePage(p, site, format); err != nil {
return err
}
}
return nil
}

func (cc *convertCmd) convertAndSavePage(p *hugolib.Page, site *hugolib.Site, targetFormat metadecoders.Format) error {
func (cc *convertCmd) convertAndSavePage(p page.Page, site *hugolib.Site, targetFormat metadecoders.Format) error {
// The resources are not in .Site.AllPages.
for _, r := range p.Resources.ByType("page") {
if err := cc.convertAndSavePage(r.(*hugolib.Page), site, targetFormat); err != nil {
for _, r := range p.Resources().ByType("page") {
if err := cc.convertAndSavePage(r.(page.Page), site, targetFormat); err != nil {
return err
}
}

if p.Filename() == "" {
if p.File() == nil {
// No content file.
return nil
}

errMsg := fmt.Errorf("Error processing file %q", p.Path())

site.Log.INFO.Println("Attempting to convert", p.LogicalName())
site.Log.INFO.Println("Attempting to convert", p.File().Filename())

f, _ := p.File.(src.ReadableFile)
f, _ := p.File().(src.ReadableFile)
file, err := f.Open()
if err != nil {
site.Log.ERROR.Println(errMsg)
Expand Down Expand Up @@ -186,7 +188,7 @@ func (cc *convertCmd) convertAndSavePage(p *hugolib.Page, site *hugolib.Site, ta

newContent.Write(pf.content)

newFilename := p.Filename()
newFilename := p.File().Filename()

if cc.outputDir != "" {
contentDir := strings.TrimSuffix(newFilename, p.Path())
Expand Down
10 changes: 6 additions & 4 deletions commands/hugo.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@ package commands
import (
"fmt"
"io/ioutil"

"os/signal"
"sort"
"sync/atomic"

"github.com/gohugoio/hugo/resources/page"

"github.com/gohugoio/hugo/common/hugo"
"github.com/pkg/errors"

Expand Down Expand Up @@ -326,7 +327,7 @@ func (c *commandeer) fullBuild() error {
}

for _, s := range c.hugo.Sites {
s.ProcessingStats.Static = langCount[s.Language.Lang]
s.ProcessingStats.Static = langCount[s.Language().Lang]
}

if c.h.gc {
Expand Down Expand Up @@ -973,7 +974,7 @@ func (c *commandeer) handleEvents(watcher *watcher.Batcher,
navigate := c.Cfg.GetBool("navigateToChanged")
// We have fetched the same page above, but it may have
// changed.
var p *hugolib.Page
var p page.Page

if navigate {
if onePageName != "" {
Expand All @@ -982,7 +983,8 @@ func (c *commandeer) handleEvents(watcher *watcher.Batcher,
}

if p != nil {
livereload.NavigateToPathForPort(p.RelPermalink(), p.Site.ServerPort())
// TODO(bep) page
livereload.NavigateToPathForPort(p.RelPermalink(), 1313) // p.Site.ServerPort())
} else {
livereload.ForceRefresh()
}
Expand Down
11 changes: 6 additions & 5 deletions commands/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"path/filepath"

"github.com/gohugoio/hugo/hugolib"
"github.com/gohugoio/hugo/resources/resource"
"github.com/spf13/cobra"
jww "github.com/spf13/jwalterweatherman"
)
Expand Down Expand Up @@ -67,7 +68,7 @@ List requires a subcommand, e.g. ` + "`hugo list drafts`.",

for _, p := range sites.Pages() {
if p.IsDraft() {
jww.FEEDBACK.Println(filepath.Join(p.File.Dir(), p.File.LogicalName()))
jww.FEEDBACK.Println(filepath.Join(p.File().Dir(), p.File().LogicalName()))
}

}
Expand Down Expand Up @@ -102,8 +103,8 @@ posted in the future.`,
}

for _, p := range sites.Pages() {
if p.IsFuture() {
jww.FEEDBACK.Println(filepath.Join(p.File.Dir(), p.File.LogicalName()))
if resource.IsFuture(p) {
jww.FEEDBACK.Println(filepath.Join(p.File().Dir(), p.File().LogicalName()))
}

}
Expand Down Expand Up @@ -138,8 +139,8 @@ expired.`,
}

for _, p := range sites.Pages() {
if p.IsExpired() {
jww.FEEDBACK.Println(filepath.Join(p.File.Dir(), p.File.LogicalName()))
if resource.IsExpired(p) {
jww.FEEDBACK.Println(filepath.Join(p.File().Dir(), p.File().LogicalName()))
}

}
Expand Down
2 changes: 1 addition & 1 deletion commands/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -403,7 +403,7 @@ func (c *commandeer) serve(s *serverCmd) error {
if isMultiHost {
for _, s := range c.hugo.Sites {
baseURLs = append(baseURLs, s.BaseURL.String())
roots = append(roots, s.Language.Lang)
roots = append(roots, s.Language().Lang)
}
} else {
s := c.hugo.Sites[0]
Expand Down
1 change: 1 addition & 0 deletions common/hugio/readers.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ type ReadSeekCloser interface {
}

// ReadSeekerNoOpCloser implements ReadSeekCloser by doing nothing in Close.
// TODO(bep) rename this and simila to ReadSeekerNopCloser, naming used in stdlib, which kind of makes sense.
type ReadSeekerNoOpCloser struct {
ReadSeeker
}
Expand Down
18 changes: 18 additions & 0 deletions common/maps/scratch.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,24 @@ type Scratch struct {
mu sync.RWMutex
}

// Scratcher provides a scratching service.
type Scratcher interface {
Scratch() *Scratch
}

type scratcher struct {
s *Scratch
}

func (s scratcher) Scratch() *Scratch {
return s.s
}

// NewScratcher creates a new Scratcher.
func NewScratcher() Scratcher {
return scratcher{s: NewScratch()}
}

// Add will, for single values, add (using the + operator) the addend to the existing addend (if found).
// Supports numeric values and strings.
//
Expand Down
12 changes: 12 additions & 0 deletions config/configProvider.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,15 @@ func GetStringSlicePreserveString(cfg Provider, key string) []string {
}
return cast.ToStringSlice(sd)
}

// SetBaseTestDefaults provides some common config defaults used in tests.
func SetBaseTestDefaults(cfg Provider) {
cfg.Set("resourceDir", "resources")
cfg.Set("contentDir", "content")
cfg.Set("dataDir", "data")
cfg.Set("i18nDir", "i18n")
cfg.Set("layoutDir", "layouts")
cfg.Set("assetDir", "assets")
cfg.Set("archetypeDir", "archetypes")
cfg.Set("publishDir", "public")
}
12 changes: 12 additions & 0 deletions config/services/servicesConfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const (

disqusShortnameKey = "disqusshortname"
googleAnalyticsKey = "googleanalytics"
rssLimitKey = "rssLimit"
)

// Config is a privacy configuration for all the relevant services in Hugo.
Expand All @@ -31,6 +32,7 @@ type Config struct {
GoogleAnalytics GoogleAnalytics
Instagram Instagram
Twitter Twitter
RSS RSS
}

// Disqus holds the functional configuration settings related to the Disqus template.
Expand Down Expand Up @@ -61,6 +63,12 @@ type Twitter struct {
DisableInlineCSS bool
}

// RSS holds the functional configuration settings related to the RSS feeds.
type RSS struct {
// Limit the number of pages.
Limit int
}

// DecodeConfig creates a services Config from a given Hugo configuration.
func DecodeConfig(cfg config.Provider) (c Config, err error) {
m := cfg.GetStringMap(servicesConfigKey)
Expand All @@ -76,5 +84,9 @@ func DecodeConfig(cfg config.Provider) (c Config, err error) {
c.Disqus.Shortname = cfg.GetString(disqusShortnameKey)
}

if c.RSS.Limit == 0 {
c.RSS.Limit = cfg.GetInt(rssLimitKey)
}

return
}
15 changes: 7 additions & 8 deletions hugolib/sitemap.go → config/sitemap.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2015 The Hugo Authors. All rights reserved.
// Copyright 2019 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.
Expand All @@ -11,7 +11,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

package hugolib
package config

import (
"github.com/spf13/cast"
Expand All @@ -25,21 +25,20 @@ type Sitemap struct {
Filename string
}

func parseSitemap(input map[string]interface{}) Sitemap {
sitemap := Sitemap{Priority: -1, Filename: "sitemap.xml"}
func DecodeSitemap(prototype Sitemap, input map[string]interface{}) Sitemap {

for key, value := range input {
switch key {
case "changefreq":
sitemap.ChangeFreq = cast.ToString(value)
prototype.ChangeFreq = cast.ToString(value)
case "priority":
sitemap.Priority = cast.ToFloat64(value)
prototype.Priority = cast.ToFloat64(value)
case "filename":
sitemap.Filename = cast.ToString(value)
prototype.Filename = cast.ToString(value)
default:
jww.WARN.Printf("Unknown Sitemap field: %s\n", key)
}
}

return sitemap
return prototype
}
6 changes: 3 additions & 3 deletions create/content.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ func NewContent(

if isDir {

langFs := hugofs.NewLanguageFs(s.Language.Lang, sites.LanguageSet(), archetypeFs)
langFs := hugofs.NewLanguageFs(s.Language().Lang, sites.LanguageSet(), archetypeFs)

cm, err := mapArcheTypeDir(ps, langFs, archetypeFilename)
if err != nil {
Expand Down Expand Up @@ -113,7 +113,7 @@ func NewContent(

func targetSite(sites *hugolib.HugoSites, fi *hugofs.LanguageFileInfo) *hugolib.Site {
for _, s := range sites.Sites {
if fi.Lang() == s.Language.Lang {
if fi.Lang() == s.Language().Lang {
return s
}
}
Expand Down Expand Up @@ -245,7 +245,7 @@ func resolveContentPath(sites *hugolib.HugoSites, fs afero.Fs, targetPath string

// Try the filename: my-post.en.md
for _, ss := range sites.Sites {
if strings.Contains(targetPath, "."+ss.Language.Lang+".") {
if strings.Contains(targetPath, "."+ss.Language().Lang+".") {
s = ss
break
}
Expand Down
7 changes: 4 additions & 3 deletions deps/deps.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@ import (
"github.com/pkg/errors"

"github.com/gohugoio/hugo/cache/filecache"
"github.com/gohugoio/hugo/common/hugo"
"github.com/gohugoio/hugo/common/loggers"
"github.com/gohugoio/hugo/config"
"github.com/gohugoio/hugo/helpers"
"github.com/gohugoio/hugo/hugofs"
"github.com/gohugoio/hugo/langs"
"github.com/gohugoio/hugo/media"
"github.com/gohugoio/hugo/resources/page"

"github.com/gohugoio/hugo/metrics"
"github.com/gohugoio/hugo/output"
"github.com/gohugoio/hugo/resources"
Expand Down Expand Up @@ -67,7 +68,7 @@ type Deps struct {
Language *langs.Language

// The site building.
Site hugo.Site
Site page.Site

// All the output formats available for the current site.
OutputFormatsConfig output.Formats
Expand Down Expand Up @@ -325,7 +326,7 @@ type DepsCfg struct {
Language *langs.Language

// The Site in use
Site hugo.Site
Site page.Site

// The configuration to use.
Cfg config.Provider
Expand Down
15 changes: 4 additions & 11 deletions docs/content/en/variables/page.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,7 @@ See [`.Scratch`](/functions/scratch/) for page-scoped, writable variables.
: the page's *kind*. Possible return values are `page`, `home`, `section`, `taxonomy`, or `taxonomyTerm`. Note that there are also `RSS`, `sitemap`, `robotsTXT`, and `404` kinds, but these are only available during the rendering of each of these respective page's kind and therefore *not* available in any of the `Pages` collections.

.Language
: a language object that points to the language's definition in the site
`config`.
: a language object that points to the language's definition in the site `config`. `.Language.Lang` gives you the language code.

.Lastmod
: the date the content was last modified. `.Lastmod` pulls from the `lastmod` field in a content's front matter.
Expand All @@ -93,10 +92,7 @@ See also `.ExpiryDate`, `.Date`, `.PublishDate`, and [`.GitInfo`][gitinfo].
.LinkTitle
: access when creating links to the content. If set, Hugo will use the `linktitle` from the front matter before `title`.

.Next (deprecated)
: In older Hugo versions this pointer went the wrong direction. Please use `.PrevPage` instead.

.NextPage
.Next
: Pointer to the next [regular page](/variables/site/#site-pages) (sorted by Hugo's [default sort](/templates/lists#default-weight-date-linktitle-filepath)). Example: `{{if .NextPage}}{{.NextPage.Permalink}}{{end}}`.

.NextInSection
Expand All @@ -119,9 +115,6 @@ See also `.ExpiryDate`, `.Date`, `.PublishDate`, and [`.GitInfo`][gitinfo].
: the Page content stripped of HTML as a `[]string` using Go's [`strings.Fields`](https://golang.org/pkg/strings/#Fields) to split `.Plain` into a slice.

.Prev (deprecated)
: In older Hugo versions this pointer went the wrong direction. Please use `.NextPage` instead.

.PrevPage
: Pointer to the previous [regular page](/variables/site/#site-pages) (sorted by Hugo's [default sort](/templates/lists#default-weight-date-linktitle-filepath)). Example: `{{if .PrevPage}}{{.PrevPage.Permalink}}{{end}}`.

.PrevInSection
Expand All @@ -130,8 +123,8 @@ See also `.ExpiryDate`, `.Date`, `.PublishDate`, and [`.GitInfo`][gitinfo].
.PublishDate
: the date on which the content was or will be published; `.Publishdate` pulls from the `publishdate` field in a content's front matter. See also `.ExpiryDate`, `.Date`, and `.Lastmod`.

.RSSLink
: link to the taxonomies' RSS link.
.RSSLink (deprecated)
: link to the page's RSS feed. This is deprecated. You should instead do something like this: `{{ with .OutputFormats.Get "RSS" }}{{ . RelPermalink }}{{ end }}`.

.RawContent
: raw markdown content without the front matter. Useful with [remarkjs.com](
Expand Down
Loading

0 comments on commit dcbf4dd

Please sign in to comment.