hugolib: Remove siteWriter

This commit is contained in:
Bjørn Erik Pedersen 2017-03-16 10:04:30 +01:00
parent d76e5f36b4
commit a49bf8707b
8 changed files with 67 additions and 323 deletions

View file

@ -41,14 +41,13 @@ func init() {
}
type aliasHandler struct {
Templates *template.Template
log *jww.Notepad
allowRoot bool
publishDir string
Templates *template.Template
log *jww.Notepad
allowRoot bool
}
func newAliasHandler(t *template.Template, l *jww.Notepad, allowRoot bool, publishDir string) aliasHandler {
return aliasHandler{t, l, allowRoot, publishDir}
func newAliasHandler(t *template.Template, l *jww.Notepad, allowRoot bool) aliasHandler {
return aliasHandler{t, l, allowRoot}
}
func (a aliasHandler) renderAlias(isXHTML bool, permalink string, page *Page) (io.Reader, error) {
@ -85,7 +84,7 @@ func (s *Site) writeDestAlias(path, permalink string, p *Page) (err error) {
func (s *Site) publishDestAlias(allowRoot bool, path, permalink string, p *Page) (err error) {
handler := newAliasHandler(s.Tmpl.Lookup("alias.html"), s.Log, allowRoot, s.absPublishDir())
handler := newAliasHandler(s.Tmpl.Lookup("alias.html"), s.Log, allowRoot)
isXHTML := strings.HasSuffix(path, ".xhtml")
@ -183,5 +182,5 @@ func (a aliasHandler) targetPathAlias(src string) (string, error) {
a.log.INFO.Printf("Alias \"%s\" translated to \"%s\"\n", originalAlias, alias)
}
return filepath.Join(a.publishDir, alias), nil
return alias, nil
}

View file

@ -15,6 +15,7 @@ package hugolib
import (
"path/filepath"
"runtime"
"testing"
"github.com/spf13/hugo/deps"
@ -73,3 +74,45 @@ func TestAliasTemplate(t *testing.T) {
// the alias redirector
th.assertFileContent(filepath.Join("public", "foo", "bar", "index.html"), "ALIASTEMPLATE")
}
func TestTargetPathHTMLRedirectAlias(t *testing.T) {
h := newAliasHandler(nil, newErrorLogger(), false)
errIsNilForThisOS := runtime.GOOS != "windows"
tests := []struct {
value string
expected string
errIsNil bool
}{
{"", "", false},
{"s", filepath.FromSlash("s/index.html"), true},
{"/", "", false},
{"alias 1", filepath.FromSlash("alias 1/index.html"), true},
{"alias 2/", filepath.FromSlash("alias 2/index.html"), true},
{"alias 3.html", "alias 3.html", true},
{"alias4.html", "alias4.html", true},
{"/alias 5.html", "alias 5.html", true},
{"/трям.html", "трям.html", true},
{"../../../../tmp/passwd", "", false},
{"/foo/../../../../tmp/passwd", filepath.FromSlash("tmp/passwd/index.html"), true},
{"foo/../../../../tmp/passwd", "", false},
{"C:\\Windows", filepath.FromSlash("C:\\Windows/index.html"), errIsNilForThisOS},
{"/trailing-space /", filepath.FromSlash("trailing-space /index.html"), errIsNilForThisOS},
{"/trailing-period./", filepath.FromSlash("trailing-period./index.html"), errIsNilForThisOS},
{"/tab\tseparated/", filepath.FromSlash("tab\tseparated/index.html"), errIsNilForThisOS},
{"/chrome/?p=help&ctx=keyboard#topic=3227046", filepath.FromSlash("chrome/?p=help&ctx=keyboard#topic=3227046/index.html"), errIsNilForThisOS},
{"/LPT1/Printer/", filepath.FromSlash("LPT1/Printer/index.html"), errIsNilForThisOS},
}
for _, test := range tests {
path, err := h.targetPathAlias(test.value)
if (err == nil) != test.errIsNil {
t.Errorf("Expected err == nil => %t, got: %t. err: %s", test.errIsNil, err == nil, err)
continue
}
if err == nil && path != test.expected {
t.Errorf("Expected: \"%s\", got: \"%s\"", test.expected, path)
}
}
}

View file

@ -39,7 +39,10 @@ type defaultHandler struct{ basicFileHandler }
func (h defaultHandler) Extensions() []string { return []string{"*"} }
func (h defaultHandler) FileConvert(f *source.File, s *Site) HandledResult {
s.w.writeDestFile(f.Path(), f.Contents)
err := s.publish(f.Path(), f.Contents)
if err != nil {
return HandledResult{err: err}
}
return HandledResult{file: f}
}
@ -48,6 +51,9 @@ type cssHandler struct{ basicFileHandler }
func (h cssHandler) Extensions() []string { return []string{"css"} }
func (h cssHandler) FileConvert(f *source.File, s *Site) HandledResult {
x := cssmin.Minify(f.Bytes())
s.w.writeDestFile(f.Path(), bytes.NewReader(x))
err := s.publish(f.Path(), bytes.NewReader(x))
if err != nil {
return HandledResult{err: err}
}
return HandledResult{file: f}
}

View file

@ -200,8 +200,6 @@ func (h *HugoSites) assemble(config *BuildCfg) error {
func (h *HugoSites) render(config *BuildCfg) error {
if !config.SkipRender {
for _, s := range h.Sites {
s.initSiteWriter()
if err := s.render(); err != nil {
return err
}

View file

@ -98,9 +98,6 @@ type Site struct {
Menus Menus
timer *nitro.B
// This is not a pointer by design.
w siteWriter
layoutHandler *output.LayoutHandler
draftCount int
@ -1215,8 +1212,6 @@ func (s *Site) convertSource() chan error {
numWorkers := getGoMaxProcs() * 4
wg := &sync.WaitGroup{}
s.initSiteWriter()
for i := 0; i < numWorkers; i++ {
wg.Add(2)
go fileConverter(s, fileConvChan, results, wg)
@ -1802,11 +1797,11 @@ func (s *Site) renderAndWriteXML(name string, dest string, d interface{}, layout
transformer := transform.NewChain(transform.AbsURLInXML)
transformer.Apply(outBuffer, renderBuffer, path)
return s.w.writeDestFile(dest, outBuffer)
return s.publish(dest, outBuffer)
}
func (s *Site) renderAndWritePage(f output.Format, name string, dest string, d interface{}, layouts ...string) error {
func (s *Site) renderAndWritePage(name string, dest string, d interface{}, layouts ...string) error {
renderBuffer := bp.GetBuffer()
defer bp.PutBuffer(renderBuffer)
@ -1819,9 +1814,6 @@ func (s *Site) renderAndWritePage(f output.Format, name string, dest string, d i
outBuffer := bp.GetBuffer()
defer bp.PutBuffer(outBuffer)
// Note: this is not a pointer, as we may mutate the state below.
w := s.w
transformLinks := transform.NewEmptyTransforms()
if s.Info.relativeURLs || s.Info.canonifyURLs {
@ -1878,7 +1870,7 @@ Your rendered home page is blank: /index.html is zero-length
}
if err = w.writeDestPage(f, dest, outBuffer); err != nil {
if err = s.publish(dest, outBuffer); err != nil {
return err
}
@ -1928,6 +1920,7 @@ func (s *Site) renderThing(d interface{}, layout string, w io.Writer) error {
}
func (s *Site) publish(path string, r io.Reader) (err error) {
path = filepath.Join(s.absPublishDir(), path)
return helpers.WriteToDisk(path, r, s.Fs.Destination)
}
@ -1938,20 +1931,6 @@ func (s *Site) langDir() string {
return ""
}
func (s *Site) initSiteWriter() {
if s.Fs == nil {
panic("Must have Fs")
}
s.w = siteWriter{
langDir: s.langDir(),
publishDir: s.absPublishDir(),
uglyURLs: s.Cfg.GetBool("uglyURLs"),
relativeURLs: s.Info.relativeURLs,
fs: s.Fs,
log: s.Log,
}
}
func (s *Site) draftStats() string {
var msg string

View file

@ -19,8 +19,6 @@ import (
"sync"
"time"
"github.com/spf13/hugo/output"
bp "github.com/spf13/hugo/bufferpool"
)
@ -100,7 +98,7 @@ func pageRenderer(s *Site, pages <-chan *Page, results chan<- error, wg *sync.Wa
s.Log.DEBUG.Printf("Render %s to %q with layouts %q", pageOutput.Kind, targetPath, layouts)
if err := s.renderAndWritePage(outFormat, "page "+pageOutput.FullFilePath(), targetPath, pageOutput, layouts...); err != nil {
if err := s.renderAndWritePage("page "+pageOutput.FullFilePath(), targetPath, pageOutput, layouts...); err != nil {
results <- err
}
@ -149,7 +147,8 @@ func (s *Site) renderPaginator(p *PageOutput) error {
addend := fmt.Sprintf("/%s/%d", paginatePath, pageNumber)
targetPath, _ := p.targetPath(addend)
if err := s.renderAndWritePage(p.outputFormat, pagerNode.Title,
if err := s.renderAndWritePage(
pagerNode.Title,
targetPath, pagerNode, p.layouts()...); err != nil {
return err
}
@ -219,7 +218,7 @@ func (s *Site) render404() error {
nfLayouts := []string{"404.html"}
return s.renderAndWritePage(output.HTMLType, "404 page", "404.html", p, s.appendThemeTemplates(nfLayouts)...)
return s.renderAndWritePage("404 page", "404.html", p, s.appendThemeTemplates(nfLayouts)...)
}
@ -289,7 +288,7 @@ func (s *Site) renderRobotsTXT() error {
err := s.renderForLayouts("robots", n, outBuffer, s.appendThemeTemplates(rLayouts)...)
if err == nil {
err = s.w.writeDestFile("robots.txt", outBuffer)
err = s.publish("robots.txt", outBuffer)
}
return err

View file

@ -1,129 +0,0 @@
// Copyright 2017 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.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package hugolib
import (
"io"
"path/filepath"
"github.com/spf13/hugo/helpers"
"github.com/spf13/hugo/hugofs"
"github.com/spf13/hugo/output"
jww "github.com/spf13/jwalterweatherman"
)
// We may find some abstractions/interface(s) here once we star with
// "Multiple Output Formats".
type siteWriter struct {
langDir string
publishDir string
relativeURLs bool
uglyURLs bool
allowRoot bool // For aliases
fs *hugofs.Fs
log *jww.Notepad
}
func (w siteWriter) targetPathPage(f output.Format, src string) (string, error) {
dir, err := w.baseTargetPathPage(f, src)
if err != nil {
return "", err
}
if w.publishDir != "" {
dir = filepath.Join(w.publishDir, dir)
}
return dir, nil
}
func (w siteWriter) baseTargetPathPage(f output.Format, src string) (string, error) {
if src == helpers.FilePathSeparator {
return "index.html", nil
}
// The anatomy of a target path:
// langDir
// BaseName
// Suffix
// ROOT?
// dir
// name
dir, file := filepath.Split(src)
isRoot := dir == ""
ext := extension(filepath.Ext(file))
name := filename(file)
if w.langDir != "" && dir == helpers.FilePathSeparator && name == w.langDir {
return filepath.Join(dir, name, "index"+ext), nil
}
if w.uglyURLs || file == "index.html" || (isRoot && file == "404.html") {
return filepath.Join(dir, name+ext), nil
}
dir = filepath.Join(dir, name, "index"+ext)
return dir, nil
}
func (w siteWriter) targetPathFile(src string) (string, error) {
return filepath.Join(w.publishDir, filepath.FromSlash(src)), nil
}
func extension(ext string) string {
switch ext {
case ".md", ".rst":
return ".html"
}
if ext != "" {
return ext
}
return ".html"
}
func filename(f string) string {
ext := filepath.Ext(f)
if ext == "" {
return f
}
return f[:len(f)-len(ext)]
}
func (w siteWriter) writeDestPage(f output.Format, path string, reader io.Reader) error {
w.log.DEBUG.Println("creating page:", path)
path, _ = w.targetPathFile(path)
// TODO(bep) output remove this file ... targetPath, err := w.targetPathPage(tp, path)
return w.publish(path, reader)
}
func (w siteWriter) writeDestFile(path string, r io.Reader) (err error) {
w.log.DEBUG.Println("creating file:", path)
targetPath, err := w.targetPathFile(path)
if err != nil {
return err
}
return w.publish(targetPath, r)
}
func (w siteWriter) publish(path string, r io.Reader) (err error) {
return helpers.WriteToDisk(path, r, w.fs.Destination)
}

View file

@ -1,151 +0,0 @@
// Copyright 2017 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.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package hugolib
import (
"path/filepath"
"runtime"
"testing"
"github.com/spf13/hugo/output"
)
func TestTargetPathHTMLRedirectAlias(t *testing.T) {
h := newAliasHandler(nil, newErrorLogger(), false, "")
errIsNilForThisOS := runtime.GOOS != "windows"
tests := []struct {
value string
expected string
errIsNil bool
}{
{"", "", false},
{"s", filepath.FromSlash("s/index.html"), true},
{"/", "", false},
{"alias 1", filepath.FromSlash("alias 1/index.html"), true},
{"alias 2/", filepath.FromSlash("alias 2/index.html"), true},
{"alias 3.html", "alias 3.html", true},
{"alias4.html", "alias4.html", true},
{"/alias 5.html", "alias 5.html", true},
{"/трям.html", "трям.html", true},
{"../../../../tmp/passwd", "", false},
{"/foo/../../../../tmp/passwd", filepath.FromSlash("tmp/passwd/index.html"), true},
{"foo/../../../../tmp/passwd", "", false},
{"C:\\Windows", filepath.FromSlash("C:\\Windows/index.html"), errIsNilForThisOS},
{"/trailing-space /", filepath.FromSlash("trailing-space /index.html"), errIsNilForThisOS},
{"/trailing-period./", filepath.FromSlash("trailing-period./index.html"), errIsNilForThisOS},
{"/tab\tseparated/", filepath.FromSlash("tab\tseparated/index.html"), errIsNilForThisOS},
{"/chrome/?p=help&ctx=keyboard#topic=3227046", filepath.FromSlash("chrome/?p=help&ctx=keyboard#topic=3227046/index.html"), errIsNilForThisOS},
{"/LPT1/Printer/", filepath.FromSlash("LPT1/Printer/index.html"), errIsNilForThisOS},
}
for _, test := range tests {
path, err := h.targetPathAlias(test.value)
if (err == nil) != test.errIsNil {
t.Errorf("Expected err == nil => %t, got: %t. err: %s", test.errIsNil, err == nil, err)
continue
}
if err == nil && path != test.expected {
t.Errorf("Expected: \"%s\", got: \"%s\"", test.expected, path)
}
}
}
func TestTargetPathPage(t *testing.T) {
w := siteWriter{log: newErrorLogger()}
tests := []struct {
content string
expected string
}{
{"/", "index.html"},
{"index.html", "index.html"},
{"bar/index.html", "bar/index.html"},
{"foo", "foo/index.html"},
{"foo.html", "foo/index.html"},
{"foo.xhtml", "foo/index.xhtml"},
{"section", "section/index.html"},
{"section/", "section/index.html"},
{"section/foo", "section/foo/index.html"},
{"section/foo.html", "section/foo/index.html"},
{"section/foo.rss", "section/foo/index.rss"},
}
for _, test := range tests {
dest, err := w.targetPathPage(output.HTMLType, filepath.FromSlash(test.content))
expected := filepath.FromSlash(test.expected)
if err != nil {
t.Fatalf("Translate returned and unexpected err: %s", err)
}
if dest != expected {
t.Errorf("Translate expected return: %s, got: %s", expected, dest)
}
}
}
func TestTargetPathPageBase(t *testing.T) {
w := siteWriter{log: newErrorLogger()}
tests := []struct {
content string
expected string
}{
{"/", "a/base/index.html"},
}
for _, test := range tests {
for _, pd := range []string{"a/base", "a/base/"} {
w.publishDir = pd
dest, err := w.targetPathPage(output.HTMLType, test.content)
if err != nil {
t.Fatalf("Translated returned and err: %s", err)
}
if dest != filepath.FromSlash(test.expected) {
t.Errorf("Translate expected: %s, got: %s", test.expected, dest)
}
}
}
}
// TODO(bep) output
func _TestTargetPathUglyURLs(t *testing.T) {
w := siteWriter{log: newErrorLogger(), uglyURLs: true}
tests := []struct {
outFormat output.Format
content string
expected string
}{
{output.HTMLType, "foo.html", "foo.html"},
{output.HTMLType, "/", "index.html"},
{output.HTMLType, "section", "section.html"},
{output.HTMLType, "index.html", "index.html"},
{output.JSONType, "section", "section.json"},
}
for i, test := range tests {
dest, err := w.targetPathPage(test.outFormat, filepath.FromSlash(test.content))
if err != nil {
t.Fatalf(" [%d] targetPathPage returned an unexpected err: %s", i, err)
}
if dest != test.expected {
t.Errorf("[%d] targetPathPage expected return: %s, got: %s", i, test.expected, dest)
}
}
}