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 { for _, p := range s.Pages {
// May have been set in front matter // May have been set in front matter
if len(p.outputFormats) == 0 { if len(p.outputFormats) == 0 {
p.outputFormats = s.defaultOutputDefinitions.ForKind(p.Kind) p.outputFormats = s.outputFormats[p.Kind]
} }
if err := p.initTargetPathDescriptor(); err != nil { if err := p.initTargetPathDescriptor(); err != nil {
return err return err

View file

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

View file

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

View file

@ -108,7 +108,10 @@ type Site struct {
disabledKinds map[string]bool 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. // Logger etc.
*deps.Deps `json:"-"` *deps.Deps `json:"-"`
@ -124,12 +127,12 @@ func (s *Site) isEnabled(kind string) bool {
// reset returns a new Site prepared for rebuild. // reset returns a new Site prepared for rebuild.
func (s *Site) reset() *Site { func (s *Site) reset() *Site {
return &Site{Deps: s.Deps, return &Site{Deps: s.Deps,
layoutHandler: output.NewLayoutHandler(s.PathSpec.ThemeSet()), layoutHandler: output.NewLayoutHandler(s.PathSpec.ThemeSet()),
disabledKinds: s.disabledKinds, disabledKinds: s.disabledKinds,
defaultOutputDefinitions: s.defaultOutputDefinitions, outputFormats: s.outputFormats,
Language: s.Language, Language: s.Language,
owner: s.owner, owner: s.owner,
PageCollections: newPageCollections()} PageCollections: newPageCollections()}
} }
// newSite creates a new site with the given configuration. // newSite creates a new site with the given configuration.
@ -145,14 +148,18 @@ func newSite(cfg deps.DepsCfg) (*Site, error) {
disabledKinds[disabled] = true disabledKinds[disabled] = true
} }
outputDefs := createSiteOutputDefinitions(cfg.Cfg) outputFormats, err := createSiteOutputFormats(cfg.Language)
if err != nil {
return nil, err
}
s := &Site{ s := &Site{
PageCollections: c, PageCollections: c,
layoutHandler: output.NewLayoutHandler(cfg.Cfg.GetString("themesDir") != ""), layoutHandler: output.NewLayoutHandler(cfg.Cfg.GetString("themesDir") != ""),
Language: cfg.Language, Language: cfg.Language,
disabledKinds: disabledKinds, disabledKinds: disabledKinds,
defaultOutputDefinitions: outputDefs, outputFormats: outputFormats,
} }
s.Info = newSiteInfo(siteBuilderCfg{s: s, pageCollections: c, language: s.Language}) 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, sections: sections,
s: s} s: s}
p.outputFormats = p.s.defaultOutputDefinitions.ForKind(typ) p.outputFormats = p.s.outputFormats[p.Kind]
return p return p

View file

@ -14,56 +14,81 @@
package hugolib package hugolib
import ( import (
"fmt"
"path" "path"
"strings" "strings"
"github.com/spf13/cast"
"github.com/spf13/hugo/config" "github.com/spf13/hugo/config"
"github.com/spf13/hugo/output" "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 { outFormats := make(map[string]output.Formats)
// What Kinds of pages are excluded in this definition.
// A blank strings means NONE.
// Comma separated list (for now).
ExcludedKinds string
Outputs []output.Format outputs := cfg.GetStringMap("outputs")
}
func (defs siteOutputDefinitions) ForKind(kind string) []output.Format { if outputs == nil || len(outputs) == 0 {
var result []output.Format // TODO(bep) outputs log a warning?
return outFormats, nil
}
for _, def := range defs { for k, v := range outputs {
if def.ExcludedKinds == "" || !strings.Contains(def.ExcludedKinds, kind) { var formats output.Formats
result = append(result, def.Outputs...) 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 // Make sure every kind has at least one output format
} for _, kind := range allKinds {
if _, found := outFormats[kind]; !found {
func createSiteOutputDefinitions(cfg config.Provider) siteOutputDefinitions { outFormats[kind] = output.Formats{output.HTMLType}
}
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"
} }
// RSS has now a well defined media type, so strip any suffix provided return outFormats, nil
rssBase = strings.TrimSuffix(rssBase, path.Ext(rssBase))
rssType := output.RSSType
rssType.BaseName = rssBase
// Some have RSS }
defs = append(defs, siteOutputDefinition{ExcludedKinds: "page", Outputs: []output.Format{rssType}})
func createDefaultOutputFormats(cfg config.Provider) (map[string]output.Formats, error) {
return defs 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" "github.com/spf13/viper"
) )
func TestDefaultOutputDefinitions(t *testing.T) { func TestDefaultOutputFormats(t *testing.T) {
t.Parallel() t.Parallel()
defs := createSiteOutputDefinitions(viper.New()) defs, err := createDefaultOutputFormats(viper.New())
require.NoError(t, err)
tests := []struct { tests := []struct {
name string name string
kind string kind string
want []output.Format want output.Formats
}{ }{
{"RSS not for regular pages", KindPage, []output.Format{output.HTMLType}}, {"RSS not for regular pages", KindPage, output.Formats{output.HTMLType}},
{"Home Sweet Home", KindHome, []output.Format{output.HTMLType, output.RSSType}}, {"Home Sweet Home", KindHome, output.Formats{output.HTMLType, output.RSSType}},
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
if got := defs.ForKind(tt.kind); !reflect.DeepEqual(got, tt.want) { if got := defs[tt.kind]; !reflect.DeepEqual(got, tt.want) {
t.Errorf("siteOutputDefinitions.ForKind(%v) = %v, want %v", tt.kind, 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) { func doTestSiteWithPageOutputs(t *testing.T, outputs []string) {
t.Parallel() t.Parallel()

View file

@ -24,14 +24,14 @@ func TestDefaultTypes(t *testing.T) {
require.Equal(t, "html", HTMLType.SubType) require.Equal(t, "html", HTMLType.SubType)
require.Equal(t, "html", HTMLType.Suffix) 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, "text/html+html", HTMLType.String())
require.Equal(t, "application", RSSType.MainType) require.Equal(t, "application", RSSType.MainType)
require.Equal(t, "rss", RSSType.SubType) require.Equal(t, "rss", RSSType.SubType)
require.Equal(t, "xml", RSSType.Suffix) 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()) 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) ContainsAny func(filename string, subslices [][]byte) (bool, error)
} }
func CreateTemplateID(d TemplateLookupDescriptor) (TemplateNames, error) { func CreateTemplateNames(d TemplateLookupDescriptor) (TemplateNames, error) {
var id TemplateNames var id TemplateNames
name := filepath.FromSlash(d.RelPath) name := filepath.ToSlash(d.RelPath)
if d.Prefix != "" { if d.Prefix != "" {
name = strings.Trim(d.Prefix, "/") + "/" + name 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) { t.Run(this.name, func(t *testing.T) {
this.basePathMatchStrings = filepath.FromSlash(this.basePathMatchStrings)
fileExists := func(filename string) (bool, error) { fileExists := func(filename string) (bool, error) {
stringsToMatch := strings.Split(this.basePathMatchStrings, "|") stringsToMatch := strings.Split(this.basePathMatchStrings, "|")
for _, s := range stringsToMatch { for _, s := range stringsToMatch {
@ -148,7 +150,7 @@ func TestLayoutBase(t *testing.T) {
this.expect.MasterFilename = filepath.FromSlash(this.expect.MasterFilename) this.expect.MasterFilename = filepath.FromSlash(this.expect.MasterFilename)
this.expect.OverlayFilename = filepath.FromSlash(this.expect.OverlayFilename) this.expect.OverlayFilename = filepath.FromSlash(this.expect.OverlayFilename)
id, err := CreateTemplateID(this.d) id, err := CreateTemplateNames(this.d)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, this.expect, id, this.name) 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 { if err != nil {
t.Log.ERROR.Printf("Failed to resolve template in path %q: %s", path, err) t.Log.ERROR.Printf("Failed to resolve template in path %q: %s", path, err)
return nil return nil