mirror of
https://github.com/gohugoio/hugo.git
synced 2025-03-22 13:33:50 +00:00
hugolib: Read default output formats from site config
This commit is contained in:
parent
4aaed87dd9
commit
dbb83f925a
10 changed files with 101 additions and 65 deletions
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
||||||
|
|
||||||
|
|
|
@ -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())
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue