From 571c193a79ca8d4b9bea6991db50c977631f99fa Mon Sep 17 00:00:00 2001 From: bep Date: Sun, 7 Dec 2014 19:48:00 +0100 Subject: [PATCH] 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 --- helpers/general.go | 3 + helpers/path.go | 22 +++++--- helpers/path_test.go | 20 +++---- helpers/url.go | 55 +++++++++++++----- helpers/url_test.go | 16 +++--- hugolib/page.go | 24 ++++---- hugolib/pageGroup_test.go | 3 +- hugolib/page_permalink_test.go | 3 +- hugolib/page_test.go | 4 +- hugolib/path_seperators_windows_test.go | 5 +- hugolib/site_show_plan_test.go | 53 ++++++++++++----- hugolib/site_test.go | 75 +++++++++++++------------ hugolib/site_url_test.go | 7 ++- source/file.go | 8 +-- source/filesystem_windows_test.go | 8 +-- target/alias_test.go | 13 +++-- target/page.go | 2 +- target/page_test.go | 14 +++-- tpl/template.go | 5 +- 19 files changed, 204 insertions(+), 136 deletions(-) diff --git a/helpers/general.go b/helpers/general.go index bfac5beae90..cf3c0ac5424 100644 --- a/helpers/general.go +++ b/helpers/general.go @@ -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 { diff --git a/helpers/path.go b/helpers/path.go index e5f07450d95..b65533d8a80 100644 --- a/helpers/path.go +++ b/helpers/path.go @@ -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 { diff --git a/helpers/path_test.go b/helpers/path_test.go index a7cca35bb1e..603723c27c5 100644 --- a/helpers/path_test.go +++ b/helpers/path_test.go @@ -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) } diff --git a/helpers/url.go b/helpers/url.go index dd8d7508b68..a2dc0ac69f9 100644 --- a/helpers/url.go +++ b/helpers/url.go @@ -15,11 +15,10 @@ package helpers import ( "fmt" + "github.com/PuerkitoBio/purell" "net/url" - "path/filepath" + "path" "strings" - - "github.com/PuerkitoBio/purell" ) 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 +} diff --git a/helpers/url_test.go b/helpers/url_test.go index 4014ee3437e..1d5c770ead8 100644 --- a/helpers/url_test.go +++ b/helpers/url_test.go @@ -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") diff --git a/hugolib/page.go b/hugolib/page.go index add8fdbaaeb..67a6842c1ad 100644 --- a/hugolib/page.go +++ b/hugolib/page.go @@ -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 } } diff --git a/hugolib/pageGroup_test.go b/hugolib/pageGroup_test.go index ff85fba8e02..c8d89fb0308 100644 --- a/hugolib/pageGroup_test.go +++ b/hugolib/pageGroup_test.go @@ -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) } diff --git a/hugolib/page_permalink_test.go b/hugolib/page_permalink_test.go index f420b19c629..97b3d24c6ed 100644 --- a/hugolib/page_permalink_test.go +++ b/hugolib/page_permalink_test.go @@ -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 != "" { diff --git a/hugolib/page_test.go b/hugolib/page_test.go index 178c72d0ee9..f6ff83aaa28 100644 --- a/hugolib/page_test.go +++ b/hugolib/page_test.go @@ -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()) } } diff --git a/hugolib/path_seperators_windows_test.go b/hugolib/path_seperators_windows_test.go index 5cdd7c5f685..7f549b54e3a 100644 --- a/hugolib/path_seperators_windows_test.go +++ b/hugolib/path_seperators_windows_test.go @@ -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) } } diff --git a/hugolib/site_show_plan_test.go b/hugolib/site_show_plan_test.go index 7d18a7e5bc3..f05304f23f4 100644 --- a/hugolib/site_show_plan_test.go +++ b/hugolib/site_show_plan_test.go @@ -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 +} diff --git a/hugolib/site_test.go b/hugolib/site_test.go index 94f7373432a..ea21205b1a5 100644 --- a/hugolib/site_test.go +++ b/hugolib/site_test.go @@ -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("more content")}, - {"sect/doc3.md", []byte("# doc3\n*some* content")}, - {"sect/doc4.md", []byte("---\ntitle: doc4\n---\n# doc4\n*some content*")}, - {"sect/doc5.html", []byte("{{ template \"head\" }}body5")}, - {"sect/doc6.html", []byte("{{ template \"head_abs\" }}body5")}, - {"doc7.html", []byte("doc7 content")}, - {"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("more content")}, + {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("{{ template \"head\" }}body5")}, + {filepath.FromSlash("sect/doc6.html"), []byte("{{ template \"head_abs\" }}body5")}, + {filepath.FromSlash("doc7.html"), []byte("doc7 content")}, + {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

title

\n\n

some content

\n"}, - {"sect/doc2.html", "more content"}, - {"sect/doc3.html", "\n\n

doc3

\n\n

some content

\n"}, - {"sect/doc4.html", "\n\n

doc4

\n\n

some content

\n"}, - {"sect/doc5.html", "body5"}, - {"sect/doc6.html", "body5"}, - {"doc7.html", "doc7 content"}, - {"sect/doc8.html", "\n\n

title

\n\n

some content

\n"}, + {filepath.FromSlash("sect/doc1.html"), "\n\n

title

\n\n

some content

\n"}, + {filepath.FromSlash("sect/doc2.html"), "more content"}, + {filepath.FromSlash("sect/doc3.html"), "\n\n

doc3

\n\n

some content

\n"}, + {filepath.FromSlash("sect/doc4.html"), "\n\n

doc4

\n\n

some content

\n"}, + {filepath.FromSlash("sect/doc5.html"), "body5"}, + {filepath.FromSlash("sect/doc6.html"), "body5"}, + {filepath.FromSlash("doc7.html"), "doc7 content"}, + {filepath.FromSlash("sect/doc8.html"), "\n\n

title

\n\n

some content

\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("link")}, - {"content/blue/doc2.html", []byte("---\nf: t\n---\nmore content")}, + {filepath.FromSlash("sect/doc1.html"), []byte("link")}, + {filepath.FromSlash("content/blue/doc2.html"), []byte("---\nf: t\n---\nmore content")}, } 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) { @@ -712,9 +713,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) diff --git a/hugolib/site_url_test.go b/hugolib/site_url_test.go index c0825e56b16..331cbc49f3a 100644 --- a/hugolib/site_url_test.go +++ b/hugolib/site_url_test.go @@ -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) } } diff --git a/source/file.go b/source/file.go index 4c6196a9fb4..a4a5b27c3df 100644 --- a/source/file.go +++ b/source/file.go @@ -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 } } diff --git a/source/filesystem_windows_test.go b/source/filesystem_windows_test.go index e9cbdd4a101..ee618537481 100644 --- a/source/filesystem_windows_test.go +++ b/source/filesystem_windows_test.go @@ -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\\"}, } diff --git a/target/alias_test.go b/target/alias_test.go index d19349f230f..ec686af5402 100644 --- a/target/alias_test.go +++ b/target/alias_test.go @@ -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 { diff --git a/target/page.go b/target/page.go index 924037402ff..b02e139258c 100644 --- a/target/page.go +++ b/target/page.go @@ -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 } diff --git a/target/page_test.go b/target/page_test.go index 69ad1cfa21c..ab3b0f1ca6d 100644 --- a/target/page_test.go +++ b/target/page_test.go @@ -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) } } diff --git a/tpl/template.go b/tpl/template.go index f61376552c5..5010af9ae56 100644 --- a/tpl/template.go +++ b/tpl/template.go @@ -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