Fix handling of top-level page bundles
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Sat, 27 Jan 2018 17:03:06 +0000 (18:03 +0100)
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Sat, 27 Jan 2018 18:13:34 +0000 (19:13 +0100)
Fixes #4332

create/content_template_handler.go
hugolib/fileInfo.go
hugolib/page.go
hugolib/page_bundler_capture_test.go
hugolib/page_bundler_test.go
source/fileInfo.go
source/fileInfo_test.go
source/filesystem.go

index 0a444abf65cd4be0bf62480519744a06433bd996..3b1f850c540fbd1be8390252bf2b7522b7189505 100644 (file)
@@ -82,7 +82,7 @@ func executeArcheTypeAsTemplate(s *hugolib.Site, kind, targetPath, archetypeFile
        )
 
        sp := source.NewSourceSpec(s.Deps.Cfg, s.Deps.Fs)
-       f := sp.NewFileInfo("", targetPath, nil)
+       f := sp.NewFileInfo("", targetPath, false, nil)
 
        data := ArchetypeFileData{
                Type: kind,
index b146aede9a763e7aeaaf3a6af84c908f7e5bfdb7..f819f6bfcb372b3bb5ed798f992790db2b817ffe 100644 (file)
@@ -57,7 +57,7 @@ func (fi *fileInfo) isContentFile() bool {
 
 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{
                bundleTp:     tp,
                ReadableFile: baseFi,
index b7afc50655ab11b80287268e5c10facdac6bc50d..fd6278bb443cc220bbb4c15225e35e17505b2983 100644 (file)
@@ -772,7 +772,7 @@ func (s *Site) newPageFromFile(fi *fileInfo) *Page {
                Keywords:    []string{}, Sitemap: Sitemap{Priority: -1},
                params:       make(map[string]interface{}),
                translations: make(Pages, 0),
-               sections:     sectionsFromDir(fi.Dir()),
+               sections:     sectionsFromFile(fi),
                Site:         &s.Info,
                s:            s,
        }
@@ -2000,12 +2000,20 @@ func (p *Page) addLangPathPrefixIfFlagSet(outfile string, should bool) string {
        return outfile
 }
 
-func sectionsFromDir(dirname string) []string {
+func sectionsFromFile(fi *fileInfo) []string {
+       dirname := fi.Dir()
        dirname = strings.Trim(dirname, helpers.FilePathSeparator)
        if dirname == "" {
                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 {
index a7a7054b40ec35054287c5c2851bd16318eaef72..3f9a57146bf8eb0246eb328061d413801b7157ce 100644 (file)
@@ -143,8 +143,9 @@ F:
 D:
 __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/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/c/index.md/resources/en/work/base/c/logo-은행.png
+__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/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:
 /work/base/assets/pic1.png
 /work/base/assets/pic2.png
index cef1e0239b8b2505c6ad11ace694084f6d8cb214..0344cf024b904bc06e0afca473f26b3591a005b4 100644 (file)
@@ -52,6 +52,7 @@ func TestPageBundlerSite(t *testing.T) {
                                        "a": ":sections/:filename",
                                        "b": ":year/:slug/",
                                        "c": ":sections/:slug",
+                                       "":  ":filename/",
                                })
 
                                cfg.Set("outputFormats", map[string]interface{}{
@@ -74,8 +75,7 @@ func TestPageBundlerSite(t *testing.T) {
 
                                th := testHelper{s.Cfg, s.Fs, t}
 
-                               // Singles (2), Below home (1), Bundle (1)
-                               assert.Len(s.RegularPages, 7)
+                               assert.Len(s.RegularPages, 8)
 
                                singlePage := s.getPage(KindPage, "a/1.md")
 
@@ -99,33 +99,47 @@ func TestPageBundlerSite(t *testing.T) {
                                // This should be just copied to destination.
                                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.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")
                                assert.NotNil(leafBundle2)
-                               unicodeBundle := s.getPage(KindPage, "c/index.md")
+                               unicodeBundle := s.getPage(KindPage, "c/bundle/index.md")
                                assert.NotNil(unicodeBundle)
 
                                pageResources := leafBundle1.Resources.ByType(pageResourceType)
                                assert.Len(pageResources, 2)
                                firstPage := pageResources[0].(*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.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(secondPage, pageResources.GetByPrefix("2"))
                                assert.Nil(pageResources.GetByPrefix("doesnotexist"))
 
                                imageResources := leafBundle1.Resources.ByType("image")
-                               assert.Len(imageResources, 3)
+                               assert.Equal(3, len(imageResources))
                                image := imageResources[0]
 
                                altFormat := leafBundle1.OutputFormats().Get("CUSTOMO")
                                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())
                                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")
@@ -161,6 +175,8 @@ func TestPageBundlerSite(t *testing.T) {
                                        assert.Equal("/2017/pageslug/", leafBundle1.RelPermalink())
                                        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/2017/pageslug/index.html"), "Single Title")
+                                       th.assertFileContent(filepath.FromSlash("/work/public/root/index.html"), "Single Title")
 
                                        assert.Equal("/a/b/", leafBundle2.RelPermalink())
 
@@ -193,8 +209,8 @@ func TestPageBundlerSiteMultilingual(t *testing.T) {
                                s := sites.Sites[0]
 
                                assert.Equal(8, len(s.RegularPages))
-                               assert.Equal(18, len(s.Pages))
-                               assert.Equal(35, len(s.AllPages))
+                               assert.Equal(16, len(s.Pages))
+                               assert.Equal(31, len(s.AllPages))
 
                                bundleWithSubPath := s.getPage(KindPage, "lb/index")
                                assert.NotNil(bundleWithSubPath)
@@ -269,9 +285,9 @@ func TestMultilingualDisableLanguage(t *testing.T) {
        s := sites.Sites[0]
 
        assert.Equal(8, len(s.RegularPages))
-       assert.Equal(18, len(s.Pages))
+       assert.Equal(16, len(s.Pages))
        // No nn pages
-       assert.Equal(18, len(s.AllPages))
+       assert.Equal(16, len(s.AllPages))
        for _, p := range s.rawAllPages {
                assert.True(p.Lang() != "nn")
        }
@@ -431,7 +447,7 @@ TheContent.
 `
 
        singleLayout := `
-Title: {{ .Title }}
+Single Title: {{ .Title }}
 Content: {{ .Content }}
 {{ $sunset := .Resources.GetByPrefix "my-sunset-1" }}
 {{ with $sunset }}
@@ -482,15 +498,15 @@ Short Thumb Width: {{ $thumb.Width }}
        writeSource(t, fs, filepath.Join(workDir, "base", "assets", "pages", "mypage.md"), pageContent)
 
        // Bundle
-       writeSource(t, fs, filepath.Join(workDir, "base", "b", "index.md"), pageWithImageShortcodeAndResourceMetadataContent)
-       writeSource(t, fs, filepath.Join(workDir, "base", "b", "1.md"), pageContent)
-       writeSource(t, fs, filepath.Join(workDir, "base", "b", "2.md"), pageContent)
-       writeSource(t, fs, filepath.Join(workDir, "base", "b", "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", "index.md"), pageWithImageShortcodeAndResourceMetadataContent)
+       writeSource(t, fs, filepath.Join(workDir, "base", "b", "my-bundle", "1.md"), pageContent)
+       writeSource(t, fs, filepath.Join(workDir, "base", "b", "my-bundle", "2.md"), pageContent)
+       writeSource(t, fs, filepath.Join(workDir, "base", "b", "my-bundle", "custom-mime.bep"), "bepsays")
+       writeSource(t, fs, filepath.Join(workDir, "base", "b", "my-bundle", "c", "logo.png"), "content")
 
        // Bundle with 은행 slug
        // 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: "은행 은행"
 slug: 은행
 date: 2017-10-09
@@ -498,16 +514,22 @@ date: 2017-10-09
 
 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.
        src, err := os.Open("testdata/sunset.jpg")
        assert.NoError(err)
 
        // 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)
-       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)
 
        _, err = io.Copy(out, src)
index a20ba27e5587c1a8e8ffcc8147def11b54f97197..eb7015aa1adbfdd85404e03d5d8a7e74eb2b9136 100644 (file)
@@ -54,6 +54,7 @@ type File interface {
        LogicalName() string
 
        // Section is first directory below the content root.
+       // For page bundles in root, the Section will be empty.
        Section() string
 
        // BaseFileName is a filename without extension.
@@ -99,6 +100,7 @@ type FileInfo struct {
        baseName            string
        translationBaseName string
        section             string
+       isLeafBundle        bool
 
        uniqueID string
 
@@ -142,16 +144,12 @@ func (fi *FileInfo) String() string { return fi.BaseFileName() }
 // in some cases that is slightly expensive to construct.
 func (fi *FileInfo) init() {
        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
-               if len(parts) == 1 {
+               if (!fi.isLeafBundle && len(parts) == 1) || len(parts) > 1 {
                        section = parts[0]
-               } else if len(parts) > 1 {
-                       if parts[0] == "" {
-                               section = parts[1]
-                       } else {
-                               section = parts[0]
-                       }
                }
 
                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)
        if !strings.HasSuffix(dir, helpers.FilePathSeparator) {
@@ -204,6 +202,7 @@ func (sp *SourceSpec) NewFileInfo(baseDir, filename string, fi os.FileInfo) *Fil
                name:                name,
                baseName:            baseName,
                translationBaseName: translationBaseName,
+               isLeafBundle:        isLeafBundle,
        }
 
        return f
index 8ce8c16efbf2241bdeb463022f6cdfa25b7f691b..1b9b130e4b15fb131510719a1e629343f5c81d0f 100644 (file)
@@ -34,10 +34,15 @@ func TestFileInfo(t *testing.T) {
                        assert.Equal(filepath.FromSlash("/a/b/page.md"), f.Filename())
                        assert.Equal(filepath.FromSlash("b/"), f.Dir())
                        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)
        }
 
index a5f2988e9062bc7a93ef80ba1aacb97cd5f18448..db004d3a12f7df9692f17185e03861e3a8e9dbbf 100644 (file)
@@ -57,7 +57,7 @@ func (f *Filesystem) add(name string, fi os.FileInfo) (err error) {
                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)
 
        return err