mirror of
https://github.com/gohugoio/hugo.git
synced 2024-11-21 20:46:30 -05:00
hugolib: Remove siteWriter
This commit is contained in:
parent
d76e5f36b4
commit
a49bf8707b
8 changed files with 67 additions and 323 deletions
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue