hugolib: Read default output formats from site config

This commit is contained in:
Bjørn Erik Pedersen 2017-03-22 11:34:17 +01:00
parent 4aaed87dd9
commit dbb83f925a
10 changed files with 101 additions and 65 deletions

View file

@ -177,7 +177,7 @@ func (h *HugoSites) assemble(config *BuildCfg) error {
for _, p := range s.Pages {
// May have been set in front matter
if len(p.outputFormats) == 0 {
p.outputFormats = s.defaultOutputDefinitions.ForKind(p.Kind)
p.outputFormats = s.outputFormats[p.Kind]
}
if err := p.initTargetPathDescriptor(); err != nil {
return err

View file

@ -859,7 +859,7 @@ func (p *Page) RelPermalink() string {
func (p *Page) initURLs() error {
// TODO(bep) output
if len(p.outputFormats) == 0 {
p.outputFormats = p.s.defaultOutputDefinitions.ForKind(p.Kind)
p.outputFormats = p.s.outputFormats[p.Kind]
}
rel := p.createRelativePermalink()
p.permalink = p.s.permalink(rel)

View file

@ -45,7 +45,6 @@ func (p *PageOutput) targetPath(addends ...string) (string, error) {
return "", err
}
return tp, nil
}
func newPageOutput(p *Page, createCopy bool, f output.Format) (*PageOutput, error) {

View file

@ -108,7 +108,10 @@ type Site struct {
disabledKinds map[string]bool
defaultOutputDefinitions siteOutputDefinitions
// Output formats defined in site config per Page Kind, or some defaults
// if not set.
// Output formats defined in Page front matter will override these.
outputFormats map[string]output.Formats
// Logger etc.
*deps.Deps `json:"-"`
@ -124,12 +127,12 @@ func (s *Site) isEnabled(kind string) bool {
// reset returns a new Site prepared for rebuild.
func (s *Site) reset() *Site {
return &Site{Deps: s.Deps,
layoutHandler: output.NewLayoutHandler(s.PathSpec.ThemeSet()),
disabledKinds: s.disabledKinds,
defaultOutputDefinitions: s.defaultOutputDefinitions,
Language: s.Language,
owner: s.owner,
PageCollections: newPageCollections()}
layoutHandler: output.NewLayoutHandler(s.PathSpec.ThemeSet()),
disabledKinds: s.disabledKinds,
outputFormats: s.outputFormats,
Language: s.Language,
owner: s.owner,
PageCollections: newPageCollections()}
}
// newSite creates a new site with the given configuration.
@ -145,14 +148,18 @@ func newSite(cfg deps.DepsCfg) (*Site, error) {
disabledKinds[disabled] = true
}
outputDefs := createSiteOutputDefinitions(cfg.Cfg)
outputFormats, err := createSiteOutputFormats(cfg.Language)
if err != nil {
return nil, err
}
s := &Site{
PageCollections: c,
layoutHandler: output.NewLayoutHandler(cfg.Cfg.GetString("themesDir") != ""),
Language: cfg.Language,
disabledKinds: disabledKinds,
defaultOutputDefinitions: outputDefs,
PageCollections: c,
layoutHandler: output.NewLayoutHandler(cfg.Cfg.GetString("themesDir") != ""),
Language: cfg.Language,
disabledKinds: disabledKinds,
outputFormats: outputFormats,
}
s.Info = newSiteInfo(siteBuilderCfg{s: s, pageCollections: c, language: s.Language})
@ -2007,7 +2014,7 @@ func (s *Site) newNodePage(typ string, sections ...string) *Page {
sections: sections,
s: s}
p.outputFormats = p.s.defaultOutputDefinitions.ForKind(typ)
p.outputFormats = p.s.outputFormats[p.Kind]
return p

View file

@ -14,56 +14,81 @@
package hugolib
import (
"fmt"
"path"
"strings"
"github.com/spf13/cast"
"github.com/spf13/hugo/config"
"github.com/spf13/hugo/output"
)
type siteOutputDefinitions []siteOutputDefinition
func createSiteOutputFormats(cfg config.Provider) (map[string]output.Formats, error) {
if !cfg.IsSet("outputs") {
return createDefaultOutputFormats(cfg)
}
type siteOutputDefinition struct {
// What Kinds of pages are excluded in this definition.
// A blank strings means NONE.
// Comma separated list (for now).
ExcludedKinds string
outFormats := make(map[string]output.Formats)
Outputs []output.Format
}
outputs := cfg.GetStringMap("outputs")
func (defs siteOutputDefinitions) ForKind(kind string) []output.Format {
var result []output.Format
if outputs == nil || len(outputs) == 0 {
// TODO(bep) outputs log a warning?
return outFormats, nil
}
for _, def := range defs {
if def.ExcludedKinds == "" || !strings.Contains(def.ExcludedKinds, kind) {
result = append(result, def.Outputs...)
for k, v := range outputs {
var formats output.Formats
vals := cast.ToStringSlice(v)
for _, format := range vals {
f, found := output.GetFormat(format)
if !found {
return nil, fmt.Errorf("Failed to resolve output format %q from site config", format)
}
formats = append(formats, f)
}
if len(formats) > 0 {
outFormats[k] = formats
}
}
return result
}
func createSiteOutputDefinitions(cfg config.Provider) siteOutputDefinitions {
var defs siteOutputDefinitions
// All have HTML
defs = append(defs, siteOutputDefinition{ExcludedKinds: "", Outputs: []output.Format{output.HTMLType}})
// TODO(bep) output deprecate rssURI
rssBase := cfg.GetString("rssURI")
if rssBase == "" {
rssBase = "index"
// Make sure every kind has at least one output format
for _, kind := range allKinds {
if _, found := outFormats[kind]; !found {
outFormats[kind] = output.Formats{output.HTMLType}
}
}
// RSS has now a well defined media type, so strip any suffix provided
rssBase = strings.TrimSuffix(rssBase, path.Ext(rssBase))
rssType := output.RSSType
rssType.BaseName = rssBase
return outFormats, nil
// Some have RSS
defs = append(defs, siteOutputDefinition{ExcludedKinds: "page", Outputs: []output.Format{rssType}})
return defs
}
func createDefaultOutputFormats(cfg config.Provider) (map[string]output.Formats, error) {
outFormats := make(map[string]output.Formats)
for _, kind := range allKinds {
var formats output.Formats
// All have HTML
formats = append(formats, output.HTMLType)
// All but page have RSS
if kind != KindPage {
// TODO(bep) output deprecate rssURI
rssBase := cfg.GetString("rssURI")
if rssBase == "" {
rssBase = "index"
}
// RSS has now a well defined media type, so strip any suffix provided
rssBase = strings.TrimSuffix(rssBase, path.Ext(rssBase))
rssType := output.RSSType
rssType.BaseName = rssBase
formats = append(formats, rssType)
}
outFormats[kind] = formats
}
return outFormats, nil
}

View file

@ -27,23 +27,25 @@ import (
"github.com/spf13/viper"
)
func TestDefaultOutputDefinitions(t *testing.T) {
func TestDefaultOutputFormats(t *testing.T) {
t.Parallel()
defs := createSiteOutputDefinitions(viper.New())
defs, err := createDefaultOutputFormats(viper.New())
require.NoError(t, err)
tests := []struct {
name string
kind string
want []output.Format
want output.Formats
}{
{"RSS not for regular pages", KindPage, []output.Format{output.HTMLType}},
{"Home Sweet Home", KindHome, []output.Format{output.HTMLType, output.RSSType}},
{"RSS not for regular pages", KindPage, output.Formats{output.HTMLType}},
{"Home Sweet Home", KindHome, output.Formats{output.HTMLType, output.RSSType}},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := defs.ForKind(tt.kind); !reflect.DeepEqual(got, tt.want) {
t.Errorf("siteOutputDefinitions.ForKind(%v) = %v, want %v", tt.kind, got, tt.want)
if got := defs[tt.kind]; !reflect.DeepEqual(got, tt.want) {
t.Errorf("createDefaultOutputFormats(%v) = %v, want %v", tt.kind, got, tt.want)
}
})
}
@ -57,6 +59,7 @@ func TestSiteWithPageOutputs(t *testing.T) {
}
}
// TODO(bep) output add test for site outputs config
func doTestSiteWithPageOutputs(t *testing.T, outputs []string) {
t.Parallel()

View file

@ -24,14 +24,14 @@ func TestDefaultTypes(t *testing.T) {
require.Equal(t, "html", HTMLType.SubType)
require.Equal(t, "html", HTMLType.Suffix)
require.Equal(t, "text/html", HTMLType.MainType())
require.Equal(t, "text/html", HTMLType.Type())
require.Equal(t, "text/html+html", HTMLType.String())
require.Equal(t, "application", RSSType.MainType)
require.Equal(t, "rss", RSSType.SubType)
require.Equal(t, "xml", RSSType.Suffix)
require.Equal(t, "application/rss", RSSType.MainType())
require.Equal(t, "application/rss", RSSType.Type())
require.Equal(t, "application/rss+xml", RSSType.String())
}

View file

@ -56,11 +56,11 @@ type TemplateLookupDescriptor struct {
ContainsAny func(filename string, subslices [][]byte) (bool, error)
}
func CreateTemplateID(d TemplateLookupDescriptor) (TemplateNames, error) {
func CreateTemplateNames(d TemplateLookupDescriptor) (TemplateNames, error) {
var id TemplateNames
name := filepath.FromSlash(d.RelPath)
name := filepath.ToSlash(d.RelPath)
if d.Prefix != "" {
name = strings.Trim(d.Prefix, "/") + "/" + name

View file

@ -124,6 +124,8 @@ func TestLayoutBase(t *testing.T) {
} {
t.Run(this.name, func(t *testing.T) {
this.basePathMatchStrings = filepath.FromSlash(this.basePathMatchStrings)
fileExists := func(filename string) (bool, error) {
stringsToMatch := strings.Split(this.basePathMatchStrings, "|")
for _, s := range stringsToMatch {
@ -148,7 +150,7 @@ func TestLayoutBase(t *testing.T) {
this.expect.MasterFilename = filepath.FromSlash(this.expect.MasterFilename)
this.expect.OverlayFilename = filepath.FromSlash(this.expect.OverlayFilename)
id, err := CreateTemplateID(this.d)
id, err := CreateTemplateNames(this.d)
require.NoError(t, err)
require.Equal(t, this.expect, id, this.name)

View file

@ -508,7 +508,7 @@ func (t *GoHTMLTemplate) loadTemplates(absPath string, prefix string) {
},
}
tplID, err := output.CreateTemplateID(descriptor)
tplID, err := output.CreateTemplateNames(descriptor)
if err != nil {
t.Log.ERROR.Printf("Failed to resolve template in path %q: %s", path, err)
return nil