Fix various Windows-issues

File handling was broken on Windows. This commit contains a revision of the path handling with separation of file paths and urls where needed.

There may be remaining issues and there may be better ways to do this, but it is easier to start that refactoring job with a set of passing tests.

Fixes #687
Fixes #660
This commit is contained in:
bep 2014-12-07 19:48:00 +01:00 committed by spf13
parent 3a8c12418a
commit 9f77f93071
19 changed files with 205 additions and 137 deletions

View file

@ -20,9 +20,12 @@ import (
"fmt"
"io"
"net"
"path/filepath"
"strings"
)
const FilePathSeparator = string(filepath.Separator)
func FindAvailablePort() (*net.TCPAddr, error) {
l, err := net.Listen("tcp", ":0")
if err == nil {

View file

@ -16,15 +16,14 @@ package helpers
import (
"errors"
"fmt"
"github.com/spf13/afero"
"github.com/spf13/viper"
"io"
"os"
"path/filepath"
"regexp"
"strings"
"unicode"
"github.com/spf13/afero"
"github.com/spf13/viper"
)
var sanitizeRegexp = regexp.MustCompile("[^a-zA-Z0-9./_-]")
@ -173,13 +172,18 @@ func FileAndExt(in string) (name string, ext string) {
ext = filepath.Ext(in)
base := filepath.Base(in) // path.Base strips any trailing slash!
return FileAndExtSep(in, ext, base, FilePathSeparator), ext
}
func FileAndExtSep(in, ext, base, pathSeparator string) (name string) {
// No file name cases. These are defined as:
// 1. any "in" path that ends in a os.PathSeparator i.e. "/" on linux
// 2. any "base" consisting of just an os.PathSeparator
// 1. any "in" path that ends in a pathSeparator
// 2. any "base" consisting of just an pathSeparator
// 3. any "base" consisting of just an empty string
// 4. any "base" consisting of just the current directory i.e. "."
// 5. any "base" consisting of just the parent directory i.e. ".."
if (strings.LastIndex(in, string(os.PathSeparator)) == len(in)-1) || base == "" || base == "." || base == ".." || base == string(os.PathListSeparator) {
if (strings.LastIndex(in, pathSeparator) == len(in)-1) || base == "" || base == "." || base == ".." || base == pathSeparator {
name = "" // there is NO filename
} else if ext != "" { // there was an Extension
// return the filename minus the extension (and the ".")
@ -190,6 +194,7 @@ func FileAndExt(in string) (name string, ext string) {
name = base
}
return
}
func GetRelativePath(path, base string) (final string, err error) {
@ -203,14 +208,13 @@ func GetRelativePath(path, base string) (final string, err error) {
if err != nil {
return "", err
}
name = filepath.ToSlash(name)
return name, nil
}
// Given a source path, determine the section
// A section is the part between the root slash and the second slash or before the first slash
func GuessSection(in string) string {
parts := strings.Split(in, "/")
parts := strings.Split(in, FilePathSeparator)
// This will include an empty entry before and after paths with leading and trailing slashes
// eg... /sect/one/ -> ["", "sect", "one", ""]
@ -256,7 +260,7 @@ func PrettifyPath(in string) string {
if filepath.Ext(in) == "" {
// /section/name/ -> /section/name/index.html
if len(in) < 2 {
return "/"
return FilePathSeparator
}
return filepath.Join(filepath.Clean(in), "index.html")
} else {

View file

@ -4,7 +4,7 @@ import (
"fmt"
"io/ioutil"
"os"
"path"
"path/filepath"
"strconv"
"strings"
"testing"
@ -119,7 +119,7 @@ func TestReplaceExtension(t *testing.T) {
}
for i, d := range data {
output := ReplaceExtension(d.input, d.newext)
output := ReplaceExtension(filepath.FromSlash(d.input), d.newext)
if d.expected != output {
t.Errorf("Test %d failed. Expected %q got %q", i, d.expected, output)
}
@ -139,8 +139,8 @@ func TestDirExists(t *testing.T) {
{"../", true},
{"./..", true},
{"./../", true},
{"/tmp", true},
{"/tmp/", true},
{os.TempDir(), true},
{os.TempDir() + FilePathSeparator, true},
{"/", true},
{"/some-really-random-directory-name", false},
{"/some/really/random/directory/name", false},
@ -149,7 +149,7 @@ func TestDirExists(t *testing.T) {
}
for i, d := range data {
exists, _ := DirExists(d.input, new(afero.OsFs))
exists, _ := DirExists(filepath.FromSlash(d.input), new(afero.OsFs))
if d.expected != exists {
t.Errorf("Test %d failed. Expected %t got %t", i, d.expected, exists)
}
@ -366,8 +366,8 @@ func TestAbsPathify(t *testing.T) {
input, expected string
}
data := []test{
{os.TempDir(), path.Clean(os.TempDir())}, // TempDir has trailing slash
{"/banana/../dir/", "/dir"},
{os.TempDir(), filepath.Clean(os.TempDir())}, // TempDir has trailing slash
{filepath.FromSlash("/banana/../dir/"), filepath.FromSlash("/dir")},
}
for i, d := range data {
@ -400,7 +400,7 @@ func TestFilename(t *testing.T) {
}
for i, d := range data {
output := Filename(d.input)
output := Filename(filepath.FromSlash(d.input))
if d.expected != output {
t.Errorf("Test %d failed. Expected %q got %q", i, d.expected, output)
}
@ -429,7 +429,7 @@ func TestFileAndExt(t *testing.T) {
}
for i, d := range data {
file, ext := FileAndExt(d.input)
file, ext := FileAndExt(filepath.FromSlash(d.input))
if d.expectedFile != file {
t.Errorf("Test %d failed. Expected filename %q got %q.", i, d.expectedFile, file)
}
@ -467,7 +467,7 @@ func TestGuessSection(t *testing.T) {
}
for i, d := range data {
expected := GuessSection(d.input)
expected := GuessSection(filepath.FromSlash(d.input))
if d.expected != expected {
t.Errorf("Test %d failed. Expected %q got %q", i, d.expected, expected)
}

View file

@ -15,11 +15,10 @@ package helpers
import (
"fmt"
"net/url"
"path/filepath"
"strings"
"github.com/PuerkitoBio/purell"
"net/url"
"path"
"strings"
)
func SanitizeUrl(in string) string {
@ -68,7 +67,7 @@ func MakePermalink(host, plink string) *url.URL {
panic(fmt.Errorf("Can't make permalink from absolute link %q", plink))
}
base.Path = filepath.Join(base.Path, p.Path)
base.Path = path.Join(base.Path, p.Path)
// path.Join will strip off the last /, so put it back if it was there.
if strings.HasSuffix(p.Path, "/") && !strings.HasSuffix(base.Path, "/") {
@ -84,7 +83,7 @@ func UrlPrep(ugly bool, in string) string {
return x
} else {
x := PrettifyUrl(SanitizeUrl(in))
if filepath.Ext(x) == ".xml" {
if path.Ext(x) == ".xml" {
return x
}
url, err := purell.NormalizeURLString(x, purell.FlagAddTrailingSlash)
@ -98,10 +97,10 @@ func UrlPrep(ugly bool, in string) string {
// Don't Return /index.html portion.
func PrettifyUrl(in string) string {
x := PrettifyPath(in)
x := PrettifyUrlPath(in)
if filepath.Base(x) == "index.html" {
return filepath.Dir(x)
if path.Base(x) == "index.html" {
return path.Dir(x)
}
if in == "" {
@ -111,21 +110,43 @@ func PrettifyUrl(in string) string {
return x
}
// /section/name.html -> /section/name/index.html
// /section/name/ -> /section/name/index.html
// /section/name/index.html -> /section/name/index.html
func PrettifyUrlPath(in string) string {
if path.Ext(in) == "" {
// /section/name/ -> /section/name/index.html
if len(in) < 2 {
return "/"
}
return path.Join(path.Clean(in), "index.html")
} else {
name, ext := ResourceAndExt(in)
if name == "index" {
// /section/name/index.html -> /section/name/index.html
return path.Clean(in)
} else {
// /section/name.html -> /section/name/index.html
return path.Join(path.Dir(in), name, "index"+ext)
}
}
}
// /section/name/index.html -> /section/name.html
// /section/name/ -> /section/name.html
// /section/name.html -> /section/name.html
func Uglify(in string) string {
if filepath.Ext(in) == "" {
if path.Ext(in) == "" {
if len(in) < 2 {
return "/"
}
// /section/name/ -> /section/name.html
return filepath.Clean(in) + ".html"
return path.Clean(in) + ".html"
} else {
name, ext := FileAndExt(in)
name, ext := ResourceAndExt(in)
if name == "index" {
// /section/name/index.html -> /section/name.html
d := filepath.Dir(in)
d := path.Dir(in)
if len(d) > 1 {
return d + ext
} else {
@ -133,7 +154,15 @@ func Uglify(in string) string {
}
} else {
// /section/name.html -> /section/name.html
return filepath.Clean(in)
return path.Clean(in)
}
}
}
// Same as FileAndExt, but for Urls
func ResourceAndExt(in string) (name string, ext string) {
ext = path.Ext(in)
base := path.Base(in)
return FileAndExtSep(in, ext, base, "/"), ext
}

View file

@ -69,14 +69,14 @@ func TestUrlPrep(t *testing.T) {
}
func TestPretty(t *testing.T) {
assert.Equal(t, PrettifyPath("/section/name.html"), "/section/name/index.html")
assert.Equal(t, PrettifyPath("/section/sub/name.html"), "/section/sub/name/index.html")
assert.Equal(t, PrettifyPath("/section/name/"), "/section/name/index.html")
assert.Equal(t, PrettifyPath("/section/name/index.html"), "/section/name/index.html")
assert.Equal(t, PrettifyPath("/index.html"), "/index.html")
assert.Equal(t, PrettifyPath("/name.xml"), "/name/index.xml")
assert.Equal(t, PrettifyPath("/"), "/")
assert.Equal(t, PrettifyPath(""), "/")
assert.Equal(t, PrettifyUrlPath("/section/name.html"), "/section/name/index.html")
assert.Equal(t, PrettifyUrlPath("/section/sub/name.html"), "/section/sub/name/index.html")
assert.Equal(t, PrettifyUrlPath("/section/name/"), "/section/name/index.html")
assert.Equal(t, PrettifyUrlPath("/section/name/index.html"), "/section/name/index.html")
assert.Equal(t, PrettifyUrlPath("/index.html"), "/index.html")
assert.Equal(t, PrettifyUrlPath("/name.xml"), "/name/index.xml")
assert.Equal(t, PrettifyUrlPath("/"), "/")
assert.Equal(t, PrettifyUrlPath(""), "/")
assert.Equal(t, PrettifyUrl("/section/name.html"), "/section/name")
assert.Equal(t, PrettifyUrl("/section/sub/name.html"), "/section/sub/name")
assert.Equal(t, PrettifyUrl("/section/name/"), "/section/name")

View file

@ -17,13 +17,6 @@ import (
"bytes"
"errors"
"fmt"
"html/template"
"io"
"net/url"
"path/filepath"
"strings"
"time"
"github.com/spf13/cast"
"github.com/spf13/hugo/helpers"
"github.com/spf13/hugo/hugofs"
@ -32,6 +25,13 @@ import (
"github.com/spf13/hugo/tpl"
jww "github.com/spf13/jwalterweatherman"
"github.com/spf13/viper"
"html/template"
"io"
"net/url"
"path"
"path/filepath"
"strings"
"time"
)
type Page struct {
@ -197,7 +197,7 @@ func layouts(types string, layout string) (layouts []string) {
// Add type/layout.html
for i := range t {
search := t[:len(t)-i]
layouts = append(layouts, fmt.Sprintf("%s/%s.html", strings.ToLower(filepath.Join(search...)), layout))
layouts = append(layouts, fmt.Sprintf("%s/%s.html", strings.ToLower(path.Join(search...)), layout))
}
// Add _default/layout.html
@ -250,7 +250,7 @@ func (p *Page) analyzePage() {
func (p *Page) permalink() (*url.URL, error) {
baseUrl := string(p.Site.BaseUrl)
dir := strings.TrimSpace(p.Source.Dir())
dir := strings.TrimSpace(filepath.ToSlash(p.Source.Dir()))
pSlug := strings.TrimSpace(p.Slug)
pUrl := strings.TrimSpace(p.Url)
var permalink string
@ -269,10 +269,10 @@ func (p *Page) permalink() (*url.URL, error) {
// fmt.Printf("have a section override for %q in section %s → %s\n", p.Title, p.Section, permalink)
} else {
if len(pSlug) > 0 {
permalink = helpers.UrlPrep(viper.GetBool("UglyUrls"), filepath.Join(dir, p.Slug+"."+p.Extension()))
permalink = helpers.UrlPrep(viper.GetBool("UglyUrls"), path.Join(dir, p.Slug+"."+p.Extension()))
} else {
_, t := filepath.Split(p.Source.LogicalName())
permalink = helpers.UrlPrep(viper.GetBool("UglyUrls"), filepath.Join(dir, helpers.ReplaceExtension(strings.TrimSpace(t), p.Extension())))
permalink = helpers.UrlPrep(viper.GetBool("UglyUrls"), path.Join(dir, helpers.ReplaceExtension(strings.TrimSpace(t), p.Extension())))
}
}
@ -674,6 +674,7 @@ func (p *Page) TargetPath() (outfile string) {
if strings.HasSuffix(outfile, "/") {
outfile = outfile + "index.html"
}
outfile = filepath.FromSlash(outfile)
return
}
@ -685,6 +686,7 @@ func (p *Page) TargetPath() (outfile string) {
if strings.HasSuffix(outfile, "/") {
outfile += "index.html"
}
outfile = filepath.FromSlash(outfile)
return
}
}

View file

@ -2,6 +2,7 @@ package hugolib
import (
"errors"
"path/filepath"
"reflect"
"testing"
@ -26,7 +27,7 @@ var pageGroupTestSources = []pageGroupTestObject{
func preparePageGroupTestPages(t *testing.T) Pages {
var pages Pages
for _, s := range pageGroupTestSources {
p, err := NewPage(s.path)
p, err := NewPage(filepath.FromSlash(s.path))
if err != nil {
t.Fatalf("failed to prepare test page %s", s.path)
}

View file

@ -2,6 +2,7 @@ package hugolib
import (
"html/template"
"path/filepath"
"testing"
"github.com/spf13/hugo/source"
@ -48,7 +49,7 @@ func TestPermalink(t *testing.T) {
BaseUrl: test.base,
},
},
Source: Source{File: *source.NewFile(test.file)},
Source: Source{File: *source.NewFile(filepath.FromSlash(test.file))},
}
if test.slug != "" {

View file

@ -510,10 +510,10 @@ func TestDegenerateInvalidFrontMatterLeadingWhitespace(t *testing.T) {
}
func TestSectionEvaluation(t *testing.T) {
page, _ := NewPage("blue/file1.md")
page, _ := NewPage(filepath.FromSlash("blue/file1.md"))
page.ReadFrom(strings.NewReader(SIMPLE_PAGE))
if page.Section() != "blue" {
t.Errorf("Section should be %s, got: %s", "blue", page.Section)
t.Errorf("Section should be %s, got: %s", "blue", page.Section())
}
}

View file

@ -1,6 +1,7 @@
package hugolib
import (
"github.com/spf13/hugo/tpl"
"testing"
)
@ -10,8 +11,8 @@ const (
)
func TestTemplatePathSeperator(t *testing.T) {
tmpl := new(GoHtmlTemplate)
if name := tmpl.generateTemplateNameFrom(win_base, win_path); name != "sub1/index.html" {
tmpl := new(tpl.GoHtmlTemplate)
if name := tmpl.GenerateTemplateNameFrom(win_base, win_path); name != "sub1/index.html" {
t.Fatalf("Template name incorrect. Expected: %s, Got: %s", "sub1/index.html", name)
}
}

View file

@ -2,26 +2,27 @@ package hugolib
import (
"bytes"
"strings"
"testing"
"github.com/spf13/hugo/helpers"
"github.com/spf13/hugo/source"
"github.com/spf13/hugo/target"
"path/filepath"
"strings"
"testing"
)
const ALIAS_DOC_1 = "---\ntitle: alias doc\naliases:\n - \"alias1/\"\n - \"alias-2/\"\n---\naliases\n"
var fakeSource = []source.ByteSource{
{
Name: "foo/bar/file.md",
Name: filepath.FromSlash("foo/bar/file.md"),
Content: []byte(SIMPLE_PAGE),
},
{
Name: "alias/test/file1.md",
Name: filepath.FromSlash("alias/test/file1.md"),
Content: []byte(ALIAS_DOC_1),
},
{
Name: "section/somecontent.html",
Name: filepath.FromSlash("section/somecontent.html"),
Content: []byte(RENDER_NO_FRONT_MATTER),
},
}
@ -36,25 +37,24 @@ func stringInSlice(a string, list []string) bool {
}
func checkShowPlanExpected(t *testing.T, s *Site, expected string) {
out := new(bytes.Buffer)
if err := s.ShowPlan(out); err != nil {
t.Fatalf("ShowPlan unexpectedly returned an error: %s", err)
}
got := out.String()
expected = filepath.FromSlash(expected)
// hackety hack: alias is an Url
expected = strings.Replace(expected, (helpers.FilePathSeparator + " =>"), "/ =>", -1)
expected = strings.Replace(expected, "n"+(helpers.FilePathSeparator+"a"), "n/a", -1)
gotList := strings.Split(got, "\n")
expectedList := strings.Split(expected, "\n")
for _, x := range gotList {
if !stringInSlice(x, expectedList) {
t.Errorf("%v %v %v %v", "\nShowPlan expected:\n", expected, "\ngot:\n", got)
}
}
diff := DiffStringSlices(gotList, expectedList)
for _, x := range expectedList {
if !stringInSlice(x, gotList) {
t.Errorf("%v %v %v %v", "\nShowPlan expected:\n", expected, "\ngot:\n", got)
}
if len(diff) > 0 {
t.Errorf("Got diff in show plan: %s", diff)
}
}
@ -126,3 +126,26 @@ func TestFileTargetPublishDir(t *testing.T) {
"section/somecontent.html (renderer: n/a)\n canonical => ../public/section/somecontent/index.html\n\n"
checkShowPlanExpected(t, s, expected)
}
// DiffStringSlices returns the difference between two string slices.
// See:
// http://stackoverflow.com/questions/19374219/how-to-find-the-difference-between-two-slices-of-strings-in-golang
func DiffStringSlices(slice1 []string, slice2 []string) []string {
diffStr := []string{}
m := map[string]int{}
for _, s1Val := range slice1 {
m[s1Val] = 1
}
for _, s2Val := range slice2 {
m[s2Val] = m[s2Val] + 1
}
for mKey, mVal := range m {
if mVal == 1 {
diffStr = append(diffStr, mKey)
}
}
return diffStr
}

View file

@ -5,6 +5,7 @@ import (
"fmt"
"html/template"
"io"
"path/filepath"
"strings"
"testing"
@ -191,7 +192,7 @@ func TestRenderThingOrDefault(t *testing.T) {
t.Errorf("Unable to write html: %s", err)
}
file, err := hugofs.DestinationFS.Open("out/index.html")
file, err := hugofs.DestinationFS.Open(filepath.FromSlash("out/index.html"))
if err != nil {
t.Errorf("Unable to open html: %s", err)
}
@ -221,9 +222,9 @@ func TestTargetPath(t *testing.T) {
}
for _, test := range tests {
p := pageMust(NewPageFrom(strings.NewReader(test.content), helpers.AbsPathify(test.doc)))
p := pageMust(NewPageFrom(strings.NewReader(test.content), helpers.AbsPathify(filepath.FromSlash(test.doc))))
expected := test.expectedOutFile
expected := filepath.FromSlash(test.expectedOutFile)
if p.TargetPath() != expected {
t.Errorf("%s => OutFile expected: '%s', got: '%s'", test.doc, expected, p.TargetPath())
@ -238,10 +239,10 @@ func TestTargetPath(t *testing.T) {
func TestDraftAndFutureRender(t *testing.T) {
hugofs.DestinationFS = new(afero.MemMapFs)
sources := []source.ByteSource{
{"sect/doc1.md", []byte("---\ntitle: doc1\ndraft: true\npublishdate: \"2414-05-29\"\n---\n# doc1\n*some content*")},
{"sect/doc2.md", []byte("---\ntitle: doc2\ndraft: true\npublishdate: \"2012-05-29\"\n---\n# doc2\n*some content*")},
{"sect/doc3.md", []byte("---\ntitle: doc3\ndraft: false\npublishdate: \"2414-05-29\"\n---\n# doc3\n*some content*")},
{"sect/doc4.md", []byte("---\ntitle: doc4\ndraft: false\npublishdate: \"2012-05-29\"\n---\n# doc4\n*some content*")},
{filepath.FromSlash("sect/doc1.md"), []byte("---\ntitle: doc1\ndraft: true\npublishdate: \"2414-05-29\"\n---\n# doc1\n*some content*")},
{filepath.FromSlash("sect/doc2.md"), []byte("---\ntitle: doc2\ndraft: true\npublishdate: \"2012-05-29\"\n---\n# doc2\n*some content*")},
{filepath.FromSlash("sect/doc3.md"), []byte("---\ntitle: doc3\ndraft: false\npublishdate: \"2414-05-29\"\n---\n# doc3\n*some content*")},
{filepath.FromSlash("sect/doc4.md"), []byte("---\ntitle: doc4\ndraft: false\npublishdate: \"2012-05-29\"\n---\n# doc4\n*some content*")},
}
siteSetup := func() *Site {
@ -296,14 +297,14 @@ func TestDraftAndFutureRender(t *testing.T) {
func TestSkipRender(t *testing.T) {
hugofs.DestinationFS = new(afero.MemMapFs)
sources := []source.ByteSource{
{"sect/doc1.html", []byte("---\nmarkup: markdown\n---\n# title\nsome *content*")},
{"sect/doc2.html", []byte("<!doctype html><html><body>more content</body></html>")},
{"sect/doc3.md", []byte("# doc3\n*some* content")},
{"sect/doc4.md", []byte("---\ntitle: doc4\n---\n# doc4\n*some content*")},
{"sect/doc5.html", []byte("<!doctype html><html>{{ template \"head\" }}<body>body5</body></html>")},
{"sect/doc6.html", []byte("<!doctype html><html>{{ template \"head_abs\" }}<body>body5</body></html>")},
{"doc7.html", []byte("<html><body>doc7 content</body></html>")},
{"sect/doc8.html", []byte("---\nmarkup: md\n---\n# title\nsome *content*")},
{filepath.FromSlash("sect/doc1.html"), []byte("---\nmarkup: markdown\n---\n# title\nsome *content*")},
{filepath.FromSlash("sect/doc2.html"), []byte("<!doctype html><html><body>more content</body></html>")},
{filepath.FromSlash("sect/doc3.md"), []byte("# doc3\n*some* content")},
{filepath.FromSlash("sect/doc4.md"), []byte("---\ntitle: doc4\n---\n# doc4\n*some content*")},
{filepath.FromSlash("sect/doc5.html"), []byte("<!doctype html><html>{{ template \"head\" }}<body>body5</body></html>")},
{filepath.FromSlash("sect/doc6.html"), []byte("<!doctype html><html>{{ template \"head_abs\" }}<body>body5</body></html>")},
{filepath.FromSlash("doc7.html"), []byte("<html><body>doc7 content</body></html>")},
{filepath.FromSlash("sect/doc8.html"), []byte("---\nmarkup: md\n---\n# title\nsome *content*")},
}
viper.Set("verbose", true)
@ -337,14 +338,14 @@ func TestSkipRender(t *testing.T) {
doc string
expected string
}{
{"sect/doc1.html", "\n\n<h1 id=\"title:5d74edbb89ef198cd37882b687940cda\">title</h1>\n\n<p>some <em>content</em></p>\n"},
{"sect/doc2.html", "<!doctype html><html><body>more content</body></html>"},
{"sect/doc3.html", "\n\n<h1 id=\"doc3:28c75a9e2162b8eccda73a1ab9ce80b4\">doc3</h1>\n\n<p><em>some</em> content</p>\n"},
{"sect/doc4.html", "\n\n<h1 id=\"doc4:f8e6806123f341b8975509637645a4d3\">doc4</h1>\n\n<p><em>some content</em></p>\n"},
{"sect/doc5.html", "<!doctype html><html><head><script src=\"script.js\"></script></head><body>body5</body></html>"},
{"sect/doc6.html", "<!doctype html><html><head><script src=\"http://auth/bub/script.js\"></script></head><body>body5</body></html>"},
{"doc7.html", "<html><body>doc7 content</body></html>"},
{"sect/doc8.html", "\n\n<h1 id=\"title:0ae308ad73e2f37bd09874105281b5d8\">title</h1>\n\n<p>some <em>content</em></p>\n"},
{filepath.FromSlash("sect/doc1.html"), "\n\n<h1 id=\"title:5d74edbb89ef198cd37882b687940cda\">title</h1>\n\n<p>some <em>content</em></p>\n"},
{filepath.FromSlash("sect/doc2.html"), "<!doctype html><html><body>more content</body></html>"},
{filepath.FromSlash("sect/doc3.html"), "\n\n<h1 id=\"doc3:28c75a9e2162b8eccda73a1ab9ce80b4\">doc3</h1>\n\n<p><em>some</em> content</p>\n"},
{filepath.FromSlash("sect/doc4.html"), "\n\n<h1 id=\"doc4:f8e6806123f341b8975509637645a4d3\">doc4</h1>\n\n<p><em>some content</em></p>\n"},
{filepath.FromSlash("sect/doc5.html"), "<!doctype html><html><head><script src=\"script.js\"></script></head><body>body5</body></html>"},
{filepath.FromSlash("sect/doc6.html"), "<!doctype html><html><head><script src=\"http://auth/bub/script.js\"></script></head><body>body5</body></html>"},
{filepath.FromSlash("doc7.html"), "<html><body>doc7 content</body></html>"},
{filepath.FromSlash("sect/doc8.html"), "\n\n<h1 id=\"title:0ae308ad73e2f37bd09874105281b5d8\">title</h1>\n\n<p>some <em>content</em></p>\n"},
}
for _, test := range tests {
@ -363,8 +364,8 @@ func TestSkipRender(t *testing.T) {
func TestAbsUrlify(t *testing.T) {
hugofs.DestinationFS = new(afero.MemMapFs)
sources := []source.ByteSource{
{"sect/doc1.html", []byte("<!doctype html><html><head></head><body><a href=\"#frag1\">link</a></body></html>")},
{"content/blue/doc2.html", []byte("---\nf: t\n---\n<!doctype html><html><body>more content</body></html>")},
{filepath.FromSlash("sect/doc1.html"), []byte("<!doctype html><html><head></head><body><a href=\"#frag1\">link</a></body></html>")},
{filepath.FromSlash("content/blue/doc2.html"), []byte("---\nf: t\n---\n<!doctype html><html><body>more content</body></html>")},
}
for _, canonify := range []bool{true, false} {
viper.Set("CanonifyUrls", canonify)
@ -399,7 +400,7 @@ func TestAbsUrlify(t *testing.T) {
for _, test := range tests {
file, err := hugofs.DestinationFS.Open(test.file)
file, err := hugofs.DestinationFS.Open(filepath.FromSlash(test.file))
if err != nil {
t.Fatalf("Unable to locate rendered content: %s", test.file)
}
@ -454,10 +455,10 @@ my_date = 2010-05-27T07:32:00Z
Front Matter with Ordered Pages 4. This is longer content`)
var WEIGHTED_SOURCES = []source.ByteSource{
{"sect/doc1.md", WEIGHTED_PAGE_1},
{"sect/doc2.md", WEIGHTED_PAGE_2},
{"sect/doc3.md", WEIGHTED_PAGE_3},
{"sect/doc4.md", WEIGHTED_PAGE_4},
{filepath.FromSlash("sect/doc1.md"), WEIGHTED_PAGE_1},
{filepath.FromSlash("sect/doc2.md"), WEIGHTED_PAGE_2},
{filepath.FromSlash("sect/doc3.md"), WEIGHTED_PAGE_3},
{filepath.FromSlash("sect/doc4.md"), WEIGHTED_PAGE_4},
}
func TestOrderedPages(t *testing.T) {
@ -519,10 +520,10 @@ func TestOrderedPages(t *testing.T) {
}
var GROUPED_SOURCES = []source.ByteSource{
{"sect1/doc1.md", WEIGHTED_PAGE_1},
{"sect1/doc2.md", WEIGHTED_PAGE_2},
{"sect2/doc3.md", WEIGHTED_PAGE_3},
{"sect3/doc4.md", WEIGHTED_PAGE_4},
{filepath.FromSlash("sect1/doc1.md"), WEIGHTED_PAGE_1},
{filepath.FromSlash("sect1/doc2.md"), WEIGHTED_PAGE_2},
{filepath.FromSlash("sect2/doc3.md"), WEIGHTED_PAGE_3},
{filepath.FromSlash("sect3/doc4.md"), WEIGHTED_PAGE_4},
}
func TestGroupedPages(t *testing.T) {
@ -711,9 +712,9 @@ Front Matter with weighted tags and categories`)
func TestWeightedTaxonomies(t *testing.T) {
hugofs.DestinationFS = new(afero.MemMapFs)
sources := []source.ByteSource{
{"sect/doc1.md", PAGE_WITH_WEIGHTED_TAXONOMIES_1},
{"sect/doc2.md", PAGE_WITH_WEIGHTED_TAXONOMIES_2},
{"sect/doc3.md", PAGE_WITH_WEIGHTED_TAXONOMIES_3},
{filepath.FromSlash("sect/doc1.md"), PAGE_WITH_WEIGHTED_TAXONOMIES_1},
{filepath.FromSlash("sect/doc2.md"), PAGE_WITH_WEIGHTED_TAXONOMIES_2},
{filepath.FromSlash("sect/doc3.md"), PAGE_WITH_WEIGHTED_TAXONOMIES_3},
}
taxonomies := make(map[string]string)

View file

@ -2,6 +2,7 @@ package hugolib
import (
"html/template"
"path/filepath"
"testing"
"github.com/spf13/afero"
@ -47,8 +48,8 @@ func (t *InMemoryAliasTarget) Publish(label string, permalink template.HTML) (er
}
var urlFakeSource = []source.ByteSource{
{"content/blue/doc1.md", []byte(SLUG_DOC_1)},
{"content/blue/doc2.md", []byte(SLUG_DOC_2)},
{filepath.FromSlash("content/blue/doc1.md"), []byte(SLUG_DOC_1)},
{filepath.FromSlash("content/blue/doc2.md"), []byte(SLUG_DOC_2)},
}
func TestPageCount(t *testing.T) {
@ -93,7 +94,7 @@ func TestPageCount(t *testing.T) {
"sd3/index.html",
"sd4.html",
} {
if _, err := hugofs.DestinationFS.Open(s); err != nil {
if _, err := hugofs.DestinationFS.Open(filepath.FromSlash(s)); err != nil {
t.Errorf("No alias rendered: %s", s)
}
}

View file

@ -14,12 +14,10 @@
package source
import (
"github.com/spf13/hugo/helpers"
"io"
"path"
"path/filepath"
"strings"
"github.com/spf13/hugo/helpers"
)
type File struct {
@ -65,7 +63,7 @@ func (f *File) LogicalName() string {
if f.logicalName != "" {
return f.logicalName
} else {
_, f.logicalName = path.Split(f.relpath)
_, f.logicalName = filepath.Split(f.relpath)
return f.logicalName
}
}
@ -78,7 +76,7 @@ func (f *File) Dir() string {
if f.dir != "" {
return f.dir
} else {
f.dir, _ = path.Split(f.relpath)
f.dir, _ = filepath.Split(f.relpath)
return f.dir
}
}

View file

@ -8,8 +8,8 @@ package source
var platformBase = "C:\\foo\\"
var platformPaths = []TestPath{
{"foobar", "foobar", "aaa", "", ""},
{"b\\1file", "1file", "aaa", "b", "b/"},
{"c\\d\\2file", "2file", "aaa", "c", "c/d/"},
{"C:\\foo\\e\\f\\3file", "3file", "aaa", "e", "e/f/"}, // note volume case is equal to platformBase
{"section\\foo.rss", "foo.rss", "aaa", "section", "section/"},
{"b\\1file", "1file", "aaa", "b", "b\\"},
{"c\\d\\2file", "2file", "aaa", "c", "c\\d\\"},
{"C:\\foo\\e\\f\\3file", "3file", "aaa", "e", "e\\f\\"}, // note volume case is equal to platformBase
{"section\\foo.rss", "foo.rss", "aaa", "section", "section\\"},
}

View file

@ -1,6 +1,7 @@
package target
import (
"path/filepath"
"testing"
)
@ -13,14 +14,14 @@ func TestHTMLRedirectAlias(t *testing.T) {
expected string
}{
{"", ""},
{"s", "s/index.html"},
{"/", "/index.html"},
{"alias 1", "alias-1/index.html"},
{"alias 2/", "alias-2/index.html"},
{"s", filepath.FromSlash("s/index.html")},
{"/", filepath.FromSlash("/index.html")},
{"alias 1", filepath.FromSlash("alias-1/index.html")},
{"alias 2/", filepath.FromSlash("alias-2/index.html")},
{"alias 3.html", "alias-3.html"},
{"alias4.html", "alias4.html"},
{"/alias 5.html", "/alias-5.html"},
{"/трям.html", "/трям.html"},
{"/alias 5.html", filepath.FromSlash("/alias-5.html")},
{"/трям.html", filepath.FromSlash("/трям.html")},
}
for _, test := range tests {

View file

@ -32,7 +32,7 @@ func (pp *PagePub) Publish(path string, r io.Reader) (err error) {
}
func (pp *PagePub) Translate(src string) (dest string, err error) {
if src == "/" {
if src == helpers.FilePathSeparator {
if pp.PublishDir != "" {
return filepath.Join(pp.PublishDir, "index.html"), nil
}

View file

@ -1,6 +1,7 @@
package target
import (
"path/filepath"
"testing"
)
@ -24,13 +25,14 @@ func TestPageTranslator(t *testing.T) {
for _, test := range tests {
f := new(PagePub)
dest, err := f.Translate(test.content)
dest, err := f.Translate(filepath.FromSlash(test.content))
expected := filepath.FromSlash(test.expected)
if err != nil {
t.Fatalf("Translate returned and unexpected err: %s", err)
}
if dest != test.expected {
t.Errorf("Tranlate expected return: %s, got: %s", test.expected, dest)
if dest != expected {
t.Errorf("Translate expected return: %s, got: %s", expected, dest)
}
}
}
@ -53,7 +55,7 @@ func TestPageTranslatorBase(t *testing.T) {
t.Fatalf("Translated returned and err: %s", err)
}
if dest != test.expected {
if dest != filepath.FromSlash(test.expected) {
t.Errorf("Translate expected: %s, got: %s", test.expected, dest)
}
}
@ -73,7 +75,7 @@ func TestTranslateUglyUrls(t *testing.T) {
for _, test := range tests {
f := &PagePub{UglyUrls: true}
dest, err := f.Translate(test.content)
dest, err := f.Translate(filepath.FromSlash(test.content))
if err != nil {
t.Fatalf("Translate returned an unexpected err: %s", err)
}
@ -87,7 +89,7 @@ func TestTranslateUglyUrls(t *testing.T) {
func TestTranslateDefaultExtension(t *testing.T) {
f := &PagePub{DefaultExtension: ".foobar"}
dest, _ := f.Translate("baz")
if dest != "baz/index.foobar" {
if dest != filepath.FromSlash("baz/index.foobar") {
t.Errorf("Translate expected return: %s, got %s", "baz/index.foobar", dest)
}
}

View file

@ -603,6 +603,7 @@ func ExecuteTemplate(context interface{}, layouts ...string) *bytes.Buffer {
buffer := new(bytes.Buffer)
worked := false
for _, layout := range layouts {
name := layout
if localTemplates.Lookup(name) == nil {
@ -701,7 +702,7 @@ func (t *GoHtmlTemplate) AddTemplateFile(name, path string) error {
}
func (t *GoHtmlTemplate) generateTemplateNameFrom(base, path string) string {
func (t *GoHtmlTemplate) GenerateTemplateNameFrom(base, path string) string {
return filepath.ToSlash(path[len(base)+1:])
}
@ -720,7 +721,7 @@ func (t *GoHtmlTemplate) loadTemplates(absPath string, prefix string) {
return nil
}
tplName := t.generateTemplateNameFrom(absPath, path)
tplName := t.GenerateTemplateNameFrom(absPath, path)
if prefix != "" {
tplName = strings.Trim(prefix, "/") + "/" + tplName