Fix handling of top-level page bundles

Fixes #4332
This commit is contained in:
Bjørn Erik Pedersen 2018-01-27 18:03:06 +01:00
parent 83c761b71a
commit 4eb2fec67c
8 changed files with 75 additions and 40 deletions

View file

@ -82,7 +82,7 @@ func executeArcheTypeAsTemplate(s *hugolib.Site, kind, targetPath, archetypeFile
) )
sp := source.NewSourceSpec(s.Deps.Cfg, s.Deps.Fs) sp := source.NewSourceSpec(s.Deps.Cfg, s.Deps.Fs)
f := sp.NewFileInfo("", targetPath, nil) f := sp.NewFileInfo("", targetPath, false, nil)
data := ArchetypeFileData{ data := ArchetypeFileData{
Type: kind, Type: kind,

View file

@ -57,7 +57,7 @@ func (fi *fileInfo) isContentFile() bool {
func newFileInfo(sp *source.SourceSpec, baseDir, filename string, fi os.FileInfo, tp bundleDirType) *fileInfo { func newFileInfo(sp *source.SourceSpec, baseDir, filename string, fi os.FileInfo, tp bundleDirType) *fileInfo {
baseFi := sp.NewFileInfo(baseDir, filename, fi) baseFi := sp.NewFileInfo(baseDir, filename, tp == bundleLeaf, fi)
f := &fileInfo{ f := &fileInfo{
bundleTp: tp, bundleTp: tp,
ReadableFile: baseFi, ReadableFile: baseFi,

View file

@ -772,7 +772,7 @@ func (s *Site) newPageFromFile(fi *fileInfo) *Page {
Keywords: []string{}, Sitemap: Sitemap{Priority: -1}, Keywords: []string{}, Sitemap: Sitemap{Priority: -1},
params: make(map[string]interface{}), params: make(map[string]interface{}),
translations: make(Pages, 0), translations: make(Pages, 0),
sections: sectionsFromDir(fi.Dir()), sections: sectionsFromFile(fi),
Site: &s.Info, Site: &s.Info,
s: s, s: s,
} }
@ -2000,12 +2000,20 @@ func (p *Page) addLangPathPrefixIfFlagSet(outfile string, should bool) string {
return outfile return outfile
} }
func sectionsFromDir(dirname string) []string { func sectionsFromFile(fi *fileInfo) []string {
dirname := fi.Dir()
dirname = strings.Trim(dirname, helpers.FilePathSeparator) dirname = strings.Trim(dirname, helpers.FilePathSeparator)
if dirname == "" { if dirname == "" {
return nil return nil
} }
return strings.Split(dirname, helpers.FilePathSeparator) parts := strings.Split(dirname, helpers.FilePathSeparator)
if fi.bundleTp == bundleLeaf && len(parts) > 0 {
// my-section/mybundle/index.md => my-section
return parts[:len(parts)-1]
}
return parts
} }
func kindFromFileInfo(fi *fileInfo) string { func kindFromFileInfo(fi *fileInfo) string {

View file

@ -143,8 +143,9 @@ F:
D: D:
__bundle/en/work/base/_index.md/resources/en/work/base/_1.png __bundle/en/work/base/_index.md/resources/en/work/base/_1.png
__bundle/en/work/base/a/b/index.md/resources/en/work/base/a/b/ab1.md __bundle/en/work/base/a/b/index.md/resources/en/work/base/a/b/ab1.md
__bundle/en/work/base/b/index.md/resources/en/work/base/b/1.md|en/work/base/b/2.md|en/work/base/b/c/logo.png|en/work/base/b/custom-mime.bep|en/work/base/b/sunset1.jpg|en/work/base/b/sunset2.jpg __bundle/en/work/base/b/my-bundle/index.md/resources/en/work/base/b/my-bundle/1.md|en/work/base/b/my-bundle/2.md|en/work/base/b/my-bundle/c/logo.png|en/work/base/b/my-bundle/custom-mime.bep|en/work/base/b/my-bundle/sunset1.jpg|en/work/base/b/my-bundle/sunset2.jpg
__bundle/en/work/base/c/index.md/resources/en/work/base/c/logo-은행.png __bundle/en/work/base/c/bundle/index.md/resources/en/work/base/c/bundle/logo-은행.png
__bundle/en/work/base/root/index.md/resources/en/work/base/root/1.md|en/work/base/root/c/logo.png
C: C:
/work/base/assets/pic1.png /work/base/assets/pic1.png
/work/base/assets/pic2.png /work/base/assets/pic2.png

View file

@ -52,6 +52,7 @@ func TestPageBundlerSite(t *testing.T) {
"a": ":sections/:filename", "a": ":sections/:filename",
"b": ":year/:slug/", "b": ":year/:slug/",
"c": ":sections/:slug", "c": ":sections/:slug",
"": ":filename/",
}) })
cfg.Set("outputFormats", map[string]interface{}{ cfg.Set("outputFormats", map[string]interface{}{
@ -74,8 +75,7 @@ func TestPageBundlerSite(t *testing.T) {
th := testHelper{s.Cfg, s.Fs, t} th := testHelper{s.Cfg, s.Fs, t}
// Singles (2), Below home (1), Bundle (1) assert.Len(s.RegularPages, 8)
assert.Len(s.RegularPages, 7)
singlePage := s.getPage(KindPage, "a/1.md") singlePage := s.getPage(KindPage, "a/1.md")
@ -99,33 +99,47 @@ func TestPageBundlerSite(t *testing.T) {
// This should be just copied to destination. // This should be just copied to destination.
th.assertFileContent(filepath.FromSlash("/work/public/assets/pic1.png"), "content") th.assertFileContent(filepath.FromSlash("/work/public/assets/pic1.png"), "content")
leafBundle1 := s.getPage(KindPage, "b/index.md") leafBundle1 := s.getPage(KindPage, "b/my-bundle/index.md")
assert.NotNil(leafBundle1) assert.NotNil(leafBundle1)
assert.Equal("b", leafBundle1.Section())
assert.NotNil(s.getPage(KindSection, "b"))
// This is a root bundle and should live in the "home section"
// See https://github.com/gohugoio/hugo/issues/4332
rootBundle := s.getPage(KindPage, "root")
assert.NotNil(rootBundle)
assert.True(rootBundle.Parent().IsHome())
if ugly {
assert.Equal("/root.html", rootBundle.RelPermalink())
} else {
assert.Equal("/root/", rootBundle.RelPermalink())
}
leafBundle2 := s.getPage(KindPage, "a/b/index.md") leafBundle2 := s.getPage(KindPage, "a/b/index.md")
assert.NotNil(leafBundle2) assert.NotNil(leafBundle2)
unicodeBundle := s.getPage(KindPage, "c/index.md") unicodeBundle := s.getPage(KindPage, "c/bundle/index.md")
assert.NotNil(unicodeBundle) assert.NotNil(unicodeBundle)
pageResources := leafBundle1.Resources.ByType(pageResourceType) pageResources := leafBundle1.Resources.ByType(pageResourceType)
assert.Len(pageResources, 2) assert.Len(pageResources, 2)
firstPage := pageResources[0].(*Page) firstPage := pageResources[0].(*Page)
secondPage := pageResources[1].(*Page) secondPage := pageResources[1].(*Page)
assert.Equal(filepath.FromSlash("b/1.md"), firstPage.pathOrTitle(), secondPage.pathOrTitle()) assert.Equal(filepath.FromSlash("b/my-bundle/1.md"), firstPage.pathOrTitle(), secondPage.pathOrTitle())
assert.Contains(firstPage.Content, "TheContent") assert.Contains(firstPage.Content, "TheContent")
assert.Len(leafBundle1.Resources, 6) // 2 pages 3 images 1 custom mime type assert.Equal(6, len(leafBundle1.Resources))
assert.Equal(firstPage, pageResources.GetByPrefix("1")) assert.Equal(firstPage, pageResources.GetByPrefix("1"))
assert.Equal(secondPage, pageResources.GetByPrefix("2")) assert.Equal(secondPage, pageResources.GetByPrefix("2"))
assert.Nil(pageResources.GetByPrefix("doesnotexist")) assert.Nil(pageResources.GetByPrefix("doesnotexist"))
imageResources := leafBundle1.Resources.ByType("image") imageResources := leafBundle1.Resources.ByType("image")
assert.Len(imageResources, 3) assert.Equal(3, len(imageResources))
image := imageResources[0] image := imageResources[0]
altFormat := leafBundle1.OutputFormats().Get("CUSTOMO") altFormat := leafBundle1.OutputFormats().Get("CUSTOMO")
assert.NotNil(altFormat) assert.NotNil(altFormat)
assert.Equal(filepath.FromSlash("/work/base/b/c/logo.png"), image.(resource.Source).AbsSourceFilename()) assert.Equal(filepath.FromSlash("/work/base/b/my-bundle/c/logo.png"), image.(resource.Source).AbsSourceFilename())
assert.Equal("https://example.com/2017/pageslug/c/logo.png", image.Permalink()) assert.Equal("https://example.com/2017/pageslug/c/logo.png", image.Permalink())
th.assertFileContent(filepath.FromSlash("/work/public/2017/pageslug/c/logo.png"), "content") th.assertFileContent(filepath.FromSlash("/work/public/2017/pageslug/c/logo.png"), "content")
th.assertFileContent(filepath.FromSlash("/work/public/cpath/2017/pageslug/c/logo.png"), "content") th.assertFileContent(filepath.FromSlash("/work/public/cpath/2017/pageslug/c/logo.png"), "content")
@ -161,6 +175,8 @@ func TestPageBundlerSite(t *testing.T) {
assert.Equal("/2017/pageslug/", leafBundle1.RelPermalink()) assert.Equal("/2017/pageslug/", leafBundle1.RelPermalink())
th.assertFileContent(filepath.FromSlash("/work/public/2017/pageslug/index.html"), "TheContent") th.assertFileContent(filepath.FromSlash("/work/public/2017/pageslug/index.html"), "TheContent")
th.assertFileContent(filepath.FromSlash("/work/public/cpath/2017/pageslug/cindex.html"), "TheContent") th.assertFileContent(filepath.FromSlash("/work/public/cpath/2017/pageslug/cindex.html"), "TheContent")
th.assertFileContent(filepath.FromSlash("/work/public/2017/pageslug/index.html"), "Single Title")
th.assertFileContent(filepath.FromSlash("/work/public/root/index.html"), "Single Title")
assert.Equal("/a/b/", leafBundle2.RelPermalink()) assert.Equal("/a/b/", leafBundle2.RelPermalink())
@ -193,8 +209,8 @@ func TestPageBundlerSiteMultilingual(t *testing.T) {
s := sites.Sites[0] s := sites.Sites[0]
assert.Equal(8, len(s.RegularPages)) assert.Equal(8, len(s.RegularPages))
assert.Equal(18, len(s.Pages)) assert.Equal(16, len(s.Pages))
assert.Equal(35, len(s.AllPages)) assert.Equal(31, len(s.AllPages))
bundleWithSubPath := s.getPage(KindPage, "lb/index") bundleWithSubPath := s.getPage(KindPage, "lb/index")
assert.NotNil(bundleWithSubPath) assert.NotNil(bundleWithSubPath)
@ -269,9 +285,9 @@ func TestMultilingualDisableLanguage(t *testing.T) {
s := sites.Sites[0] s := sites.Sites[0]
assert.Equal(8, len(s.RegularPages)) assert.Equal(8, len(s.RegularPages))
assert.Equal(18, len(s.Pages)) assert.Equal(16, len(s.Pages))
// No nn pages // No nn pages
assert.Equal(18, len(s.AllPages)) assert.Equal(16, len(s.AllPages))
for _, p := range s.rawAllPages { for _, p := range s.rawAllPages {
assert.True(p.Lang() != "nn") assert.True(p.Lang() != "nn")
} }
@ -431,7 +447,7 @@ TheContent.
` `
singleLayout := ` singleLayout := `
Title: {{ .Title }} Single Title: {{ .Title }}
Content: {{ .Content }} Content: {{ .Content }}
{{ $sunset := .Resources.GetByPrefix "my-sunset-1" }} {{ $sunset := .Resources.GetByPrefix "my-sunset-1" }}
{{ with $sunset }} {{ with $sunset }}
@ -482,15 +498,15 @@ Short Thumb Width: {{ $thumb.Width }}
writeSource(t, fs, filepath.Join(workDir, "base", "assets", "pages", "mypage.md"), pageContent) writeSource(t, fs, filepath.Join(workDir, "base", "assets", "pages", "mypage.md"), pageContent)
// Bundle // Bundle
writeSource(t, fs, filepath.Join(workDir, "base", "b", "index.md"), pageWithImageShortcodeAndResourceMetadataContent) writeSource(t, fs, filepath.Join(workDir, "base", "b", "my-bundle", "index.md"), pageWithImageShortcodeAndResourceMetadataContent)
writeSource(t, fs, filepath.Join(workDir, "base", "b", "1.md"), pageContent) writeSource(t, fs, filepath.Join(workDir, "base", "b", "my-bundle", "1.md"), pageContent)
writeSource(t, fs, filepath.Join(workDir, "base", "b", "2.md"), pageContent) writeSource(t, fs, filepath.Join(workDir, "base", "b", "my-bundle", "2.md"), pageContent)
writeSource(t, fs, filepath.Join(workDir, "base", "b", "custom-mime.bep"), "bepsays") writeSource(t, fs, filepath.Join(workDir, "base", "b", "my-bundle", "custom-mime.bep"), "bepsays")
writeSource(t, fs, filepath.Join(workDir, "base", "b", "c", "logo.png"), "content") writeSource(t, fs, filepath.Join(workDir, "base", "b", "my-bundle", "c", "logo.png"), "content")
// Bundle with 은행 slug // Bundle with 은행 slug
// See https://github.com/gohugoio/hugo/issues/4241 // See https://github.com/gohugoio/hugo/issues/4241
writeSource(t, fs, filepath.Join(workDir, "base", "c", "index.md"), `--- writeSource(t, fs, filepath.Join(workDir, "base", "c", "bundle", "index.md"), `---
title: "은행 은행" title: "은행 은행"
slug: 은행 slug: 은행
date: 2017-10-09 date: 2017-10-09
@ -498,16 +514,22 @@ date: 2017-10-09
Content for 은행. Content for 은행.
`) `)
writeSource(t, fs, filepath.Join(workDir, "base", "c", "logo-은행.png"), "은행 PNG")
// Bundle in root
writeSource(t, fs, filepath.Join(workDir, "base", "root", "index.md"), pageWithImageShortcodeAndResourceMetadataContent)
writeSource(t, fs, filepath.Join(workDir, "base", "root", "1.md"), pageContent)
writeSource(t, fs, filepath.Join(workDir, "base", "root", "c", "logo.png"), "content")
writeSource(t, fs, filepath.Join(workDir, "base", "c", "bundle", "logo-은행.png"), "은행 PNG")
// Write a real image into one of the bundle above. // Write a real image into one of the bundle above.
src, err := os.Open("testdata/sunset.jpg") src, err := os.Open("testdata/sunset.jpg")
assert.NoError(err) assert.NoError(err)
// We need 2 to test https://github.com/gohugoio/hugo/issues/4202 // We need 2 to test https://github.com/gohugoio/hugo/issues/4202
out, err := fs.Source.Create(filepath.Join(workDir, "base", "b", "sunset1.jpg")) out, err := fs.Source.Create(filepath.Join(workDir, "base", "b", "my-bundle", "sunset1.jpg"))
assert.NoError(err) assert.NoError(err)
out2, err := fs.Source.Create(filepath.Join(workDir, "base", "b", "sunset2.jpg")) out2, err := fs.Source.Create(filepath.Join(workDir, "base", "b", "my-bundle", "sunset2.jpg"))
assert.NoError(err) assert.NoError(err)
_, err = io.Copy(out, src) _, err = io.Copy(out, src)

View file

@ -54,6 +54,7 @@ type File interface {
LogicalName() string LogicalName() string
// Section is first directory below the content root. // Section is first directory below the content root.
// For page bundles in root, the Section will be empty.
Section() string Section() string
// BaseFileName is a filename without extension. // BaseFileName is a filename without extension.
@ -99,6 +100,7 @@ type FileInfo struct {
baseName string baseName string
translationBaseName string translationBaseName string
section string section string
isLeafBundle bool
uniqueID string uniqueID string
@ -142,16 +144,12 @@ func (fi *FileInfo) String() string { return fi.BaseFileName() }
// in some cases that is slightly expensive to construct. // in some cases that is slightly expensive to construct.
func (fi *FileInfo) init() { func (fi *FileInfo) init() {
fi.lazyInit.Do(func() { fi.lazyInit.Do(func() {
parts := strings.Split(fi.relDir, helpers.FilePathSeparator) relDir := strings.Trim(fi.relDir, helpers.FilePathSeparator)
parts := strings.Split(relDir, helpers.FilePathSeparator)
var section string var section string
if len(parts) == 1 { if (!fi.isLeafBundle && len(parts) == 1) || len(parts) > 1 {
section = parts[0] section = parts[0]
} else if len(parts) > 1 {
if parts[0] == "" {
section = parts[1]
} else {
section = parts[0]
}
} }
fi.section = section fi.section = section
@ -161,7 +159,7 @@ func (fi *FileInfo) init() {
}) })
} }
func (sp *SourceSpec) NewFileInfo(baseDir, filename string, fi os.FileInfo) *FileInfo { func (sp *SourceSpec) NewFileInfo(baseDir, filename string, isLeafBundle bool, fi os.FileInfo) *FileInfo {
dir, name := filepath.Split(filename) dir, name := filepath.Split(filename)
if !strings.HasSuffix(dir, helpers.FilePathSeparator) { if !strings.HasSuffix(dir, helpers.FilePathSeparator) {
@ -204,6 +202,7 @@ func (sp *SourceSpec) NewFileInfo(baseDir, filename string, fi os.FileInfo) *Fil
name: name, name: name,
baseName: baseName, baseName: baseName,
translationBaseName: translationBaseName, translationBaseName: translationBaseName,
isLeafBundle: isLeafBundle,
} }
return f return f

View file

@ -34,10 +34,15 @@ func TestFileInfo(t *testing.T) {
assert.Equal(filepath.FromSlash("/a/b/page.md"), f.Filename()) assert.Equal(filepath.FromSlash("/a/b/page.md"), f.Filename())
assert.Equal(filepath.FromSlash("b/"), f.Dir()) assert.Equal(filepath.FromSlash("b/"), f.Dir())
assert.Equal(filepath.FromSlash("b/page.md"), f.Path()) assert.Equal(filepath.FromSlash("b/page.md"), f.Path())
assert.Equal("b", f.Section())
}},
{filepath.FromSlash("/a/"), filepath.FromSlash("/a/b/c/d/page.md"), func(f *FileInfo) {
assert.Equal("b", f.Section())
}}, }},
} { } {
f := s.NewFileInfo(this.base, this.filename, nil) f := s.NewFileInfo(this.base, this.filename, false, nil)
this.assert(f) this.assert(f)
} }

View file

@ -57,7 +57,7 @@ func (f *Filesystem) add(name string, fi os.FileInfo) (err error) {
name = norm.NFC.String(name) name = norm.NFC.String(name)
} }
file = f.SourceSpec.NewFileInfo(f.Base, name, fi) file = f.SourceSpec.NewFileInfo(f.Base, name, false, fi)
f.files = append(f.files, file) f.files = append(f.files, file)
return err return err