hugolib: Refactor/-work the permalink/target path logic

This is a pretty fundamental change in Hugo, but absolutely needed if we should have any hope of getting "multiple outputs" done.

This commit's goal is to say:

* Every file target path is created by `createTargetPath`, i.e. one function for all.
* That function takes every page and site parameter into account, to avoid fragile string parsing to uglify etc. later on.
* The path creation logic has full test coverage.
* All permalinks, paginator URLs etc. are then built on top of that same logic.

Fixes #1252
Fixes #2110
Closes #2374
Fixes #1885
Fixes #3102
Fixes #3179
Fixes #1641
Fixes #1989
This commit is contained in:
Bjørn Erik Pedersen
2017-03-09 19:19:29 +01:00
parent c8fff9501d
commit 6bf010fed4
26 changed files with 912 additions and 400 deletions

View File

@@ -16,7 +16,6 @@ package hugolib
import (
"fmt"
"path"
"path/filepath"
"sync"
"time"
@@ -63,9 +62,19 @@ func (s *Site) renderPages() error {
func pageRenderer(s *Site, pages <-chan *Page, results chan<- error, wg *sync.WaitGroup) {
defer wg.Done()
var mainPageOutput *PageOutput
for page := range pages {
for i, outputType := range page.outputTypes {
pageOutput := newPageOutput(page, i > 0, outputType)
pageOutput, err := newPageOutput(page, i > 0, outputType)
if err != nil {
s.Log.ERROR.Printf("Failed to create output page for type %q for page %q: %s", outputType.Name, page, err)
continue
}
if i == 0 {
mainPageOutput = pageOutput
}
page.mainPageOutput = mainPageOutput
var layouts []string
@@ -76,14 +85,18 @@ func pageRenderer(s *Site, pages <-chan *Page, results chan<- error, wg *sync.Wa
layouts = s.layouts(pageOutput)
}
switch pageOutput.outputType {
switch pageOutput.outputType.Name {
case output.RSSType:
case "RSS":
if err := s.renderRSS(pageOutput); err != nil {
results <- err
}
default:
targetPath := pageOutput.TargetPath()
targetPath, err := pageOutput.targetPath()
if err != nil {
s.Log.ERROR.Printf("Failed to create target path for output %q for page %q: %s", outputType.Name, page, err)
continue
}
s.Log.DEBUG.Printf("Render %s to %q with layouts %q", pageOutput.Kind, targetPath, layouts)
@@ -133,11 +146,11 @@ func (s *Site) renderPaginator(p *PageOutput) error {
}
pageNumber := i + 1
htmlBase := path.Join(append(p.sections, fmt.Sprintf("/%s/%d", paginatePath, pageNumber))...)
htmlBase = p.addLangPathPrefix(htmlBase)
addend := fmt.Sprintf("/%s/%d", paginatePath, pageNumber)
targetPath, _ := p.targetPath(addend)
if err := s.renderAndWritePage(p.outputType, pagerNode.Title,
filepath.FromSlash(htmlBase), pagerNode, p.layouts()...); err != nil {
targetPath, pagerNode, p.layouts()...); err != nil {
return err
}
@@ -178,13 +191,15 @@ func (s *Site) renderRSS(p *PageOutput) error {
p.Pages = p.Pages[:limit]
p.Data["Pages"] = p.Pages
}
rssURI := s.Language.GetString("rssURI")
rssPath := path.Join(append(p.sections, rssURI)...)
s.setPageURLs(p.Page, rssPath)
// TODO(bep) output deprecate/handle rssURI
targetPath, err := p.targetPath()
if err != nil {
return err
}
return s.renderAndWriteXML(p.Title,
p.addLangFilepathPrefix(rssPath), p, s.appendThemeTemplates(layouts)...)
targetPath, p, s.appendThemeTemplates(layouts)...)
}
func (s *Site) render404() error {