node to page: Handle URLs - hugo - [fork] hugo port for 9front
 (HTM) git clone git@git.drkhsh.at/hugo.git
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) Submodules
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 524eb16686bed7d110c6001c5d98b2ee0a2d80ee
 (DIR) parent c8d3124ddeb86093caf1b18dfaa328c3053e5b63
 (HTM) Author: Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
       Date:   Tue, 15 Nov 2016 10:43:49 +0100
       
       node to page: Handle URLs
       
       This includes removing the error return value from Permalink and RelPermalink.
       
       We ignore that error all over the place, so we might as well remove it.
       
       Updates #2297
       
       Diffstat:
         M hugolib/hugo_sites_build.go         |       2 +-
         M hugolib/hugo_sites_build_test.go    |      22 ++++++++++------------
         M hugolib/menu_test.go                |       3 +--
         M hugolib/node_as_page_test.go        |      44 ++++++++++++++++++++++++++++++-
         M hugolib/page.go                     |      65 +++++++++++++++++++------------
         M hugolib/page_permalink_test.go      |      10 ++--------
         M hugolib/site.go                     |      13 +++----------
         M hugolib/site_render.go              |       9 ++++-----
       
       8 files changed, 105 insertions(+), 63 deletions(-)
       ---
 (DIR) diff --git a/hugolib/hugo_sites_build.go b/hugolib/hugo_sites_build.go
       @@ -136,7 +136,7 @@ func (h *HugoSites) process(config *BuildCfg, events ...fsnotify.Event) error {
        }
        
        func (h *HugoSites) assemble(config *BuildCfg) error {
       -        // TODO(bep) np we could probably wait and do this in one go later
       +        // TODO(bep) we could probably wait and do this in one go later
                h.setupTranslations()
        
                if len(h.Sites) > 1 {
 (DIR) diff --git a/hugolib/hugo_sites_build_test.go b/hugolib/hugo_sites_build_test.go
       @@ -86,13 +86,13 @@ func doTestMultiSitesMainLangInRoot(t *testing.T, defaultInSubDir bool) {
                doc1en := enSite.RegularPages[0]
                doc1fr := frSite.RegularPages[0]
        
       -        enPerm, _ := doc1en.Permalink()
       -        enRelPerm, _ := doc1en.RelPermalink()
       +        enPerm := doc1en.Permalink()
       +        enRelPerm := doc1en.RelPermalink()
                require.Equal(t, "http://example.com/blog/en/sect/doc1-slug/", enPerm)
                require.Equal(t, "/blog/en/sect/doc1-slug/", enRelPerm)
        
       -        frPerm, _ := doc1fr.Permalink()
       -        frRelPerm, _ := doc1fr.RelPermalink()
       +        frPerm := doc1fr.Permalink()
       +        frRelPerm := doc1fr.RelPermalink()
                // Main language in root
                require.Equal(t, replaceDefaultContentLanguageValue("http://example.com/blog/fr/sect/doc1/", defaultInSubDir), frPerm)
                require.Equal(t, replaceDefaultContentLanguageValue("/blog/fr/sect/doc1/", defaultInSubDir), frRelPerm)
       @@ -223,18 +223,18 @@ func doTestMultiSitesBuild(t *testing.T, configTemplate, configSuffix string) {
                assert.Len(t, enSite.AllPages, 28, "should have 28 total pages (including translations and index types)")
        
                doc1en := enSite.RegularPages[0]
       -        permalink, err := doc1en.Permalink()
       +        permalink := doc1en.Permalink()
                assert.NoError(t, err, "permalink call failed")
                assert.Equal(t, "http://example.com/blog/en/sect/doc1-slug/", permalink, "invalid doc1.en permalink")
                assert.Len(t, doc1en.Translations(), 1, "doc1-en should have one translation, excluding itself")
        
                doc2 := enSite.RegularPages[1]
       -        permalink, err = doc2.Permalink()
       +        permalink = doc2.Permalink()
                assert.NoError(t, err, "permalink call failed")
                assert.Equal(t, "http://example.com/blog/en/sect/doc2/", permalink, "invalid doc2 permalink")
        
                doc3 := enSite.RegularPages[2]
       -        permalink, err = doc3.Permalink()
       +        permalink = doc3.Permalink()
                assert.NoError(t, err, "permalink call failed")
                // Note that /superbob is a custom URL set in frontmatter.
                // We respect that URL literally (it can be /search.json)
       @@ -246,7 +246,7 @@ func doTestMultiSitesBuild(t *testing.T, configTemplate, configSuffix string) {
                assert.Equal(t, doc2.Next, doc3, "doc3 should follow doc2, in .Next")
        
                doc1fr := doc1en.Translations()[0]
       -        permalink, err = doc1fr.Permalink()
       +        permalink = doc1fr.Permalink()
                assert.NoError(t, err, "permalink call failed")
                assert.Equal(t, "http://example.com/blog/fr/sect/doc1/", permalink, "invalid doc1fr permalink")
        
       @@ -255,16 +255,14 @@ func doTestMultiSitesBuild(t *testing.T, configTemplate, configSuffix string) {
                assert.Equal(t, "fr", doc1fr.Language().Lang)
        
                doc4 := enSite.AllPages[4]
       -        permalink, err = doc4.Permalink()
       -        assert.NoError(t, err, "permalink call failed")
       +        permalink = doc4.Permalink()
                assert.Equal(t, "http://example.com/blog/fr/sect/doc4/", permalink, "invalid doc4 permalink")
                assert.Equal(t, "/blog/fr/sect/doc4/", doc4.URL())
        
                assert.Len(t, doc4.Translations(), 0, "found translations for doc4")
        
                doc5 := enSite.AllPages[5]
       -        permalink, err = doc5.Permalink()
       -        assert.NoError(t, err, "permalink call failed")
       +        permalink = doc5.Permalink()
                assert.Equal(t, "http://example.com/blog/fr/somewhere/else/doc5", permalink, "invalid doc5 permalink")
        
                // Taxonomies and their URLs
 (DIR) diff --git a/hugolib/menu_test.go b/hugolib/menu_test.go
       @@ -560,7 +560,6 @@ func TestHomeNodeMenu(t *testing.T) {
                s := setupMenuTests(t, menuPageSources)
        
                home := s.getPage(KindHome)
       -
                homeMenuEntry := &MenuEntry{Name: home.Title, URL: home.URL()}
        
                for i, this := range []struct {
       @@ -583,7 +582,7 @@ func TestHomeNodeMenu(t *testing.T) {
                        if isMenuCurrent != this.isMenuCurrent {
                                fmt.Println("isMenuCurrent", isMenuCurrent)
                                fmt.Printf("this: %#v\n", this)
       -                        t.Errorf("[%d] Wrong result from IsMenuCurrent: %v for %q", i, isMenuCurrent, this.menu)
       +                        t.Errorf("[%d] Wrong result from IsMenuCurrent: %v for %q", i, isMenuCurrent, this.menuItem)
                        }
        
                        if hasMenuCurrent != this.hasMenuCurrent {
 (DIR) diff --git a/hugolib/node_as_page_test.go b/hugolib/node_as_page_test.go
       @@ -394,6 +394,7 @@ aliases:
        `)
        
                viper.Set("paginate", 1)
       +        viper.Set("baseURL", "http://base/")
                viper.Set("title", "Hugo Rocks!")
        
                s := newSiteDefaultLang()
       @@ -403,7 +404,7 @@ aliases:
                }
        
                assertFileContent(t, filepath.Join("public", "index.html"), true, "Home With Alias")
       -        assertFileContent(t, filepath.Join("public", "my", "new", "home.html"), true, "content=\"0; url=/")
       +        assertFileContent(t, filepath.Join("public", "my", "new", "home.html"), true, "content=\"0; url=http://base/")
        
        }
        
       @@ -431,6 +432,47 @@ My Section Content
        
        }
        
       +func TestNodesWithURLs(t *testing.T) {
       +        testCommonResetState()
       +
       +        writeLayoutsForNodeAsPageTests(t)
       +
       +        writeRegularPagesForNodeAsPageTests(t)
       +
       +        writeSource(t, filepath.Join("content", "sect", "_index.md"), `---
       +title: MySection
       +url: foo.html
       +---
       +My Section Content
       +`)
       +
       +        viper.Set("paginate", 1)
       +        viper.Set("title", "Hugo Rocks!")
       +        viper.Set("baseURL", "http://bep.is/base/")
       +
       +        s := newSiteDefaultLang()
       +
       +        if err := buildAndRenderSite(s); err != nil {
       +                t.Fatalf("Failed to build site: %s", err)
       +        }
       +
       +        assertFileContent(t, filepath.Join("public", "sect", "index.html"), true, "My Section")
       +
       +        p := s.RegularPages[0]
       +
       +        require.Equal(t, "/base/sect1/regular1/", p.URL())
       +
       +        // Section with front matter and url set (which should not be used)
       +        sect := s.getPage(KindSection, "sect")
       +        require.Equal(t, "/base/sect/", sect.URL())
       +        require.Equal(t, "http://bep.is/base/sect/", sect.Permalink())
       +        require.Equal(t, "/base/sect/", sect.RelPermalink())
       +
       +        // Home page without front matter
       +        require.Equal(t, "/base/", s.getPage(KindHome).URL())
       +
       +}
       +
        func writeRegularPagesForNodeAsPageTests(t *testing.T) {
                writeRegularPagesForNodeAsPageTestsWithLang(t, "")
        }
 (DIR) diff --git a/hugolib/page.go b/hugolib/page.go
       @@ -63,6 +63,7 @@ const (
        
                // The following are (currently) temporary nodes,
                // i.e. nodes we create just to render in isolation.
       +        kindRSS       = "RSS"
                kindSitemap   = "sitemap"
                kindRobotsTXT = "robotsTXT"
                kind404       = "404"
       @@ -698,7 +699,18 @@ func (p *Page) analyzePage() {
        }
        
        func (p *Page) permalink() (*url.URL, error) {
       +        // TODO(bep) this should probably be set once during build. Maybe.
       +        // And simplified.
                baseURL := string(p.Site.BaseURL)
       +
       +        if p.IsNode() {
       +                // No permalink config for nodes (currently)
       +                pURL := strings.TrimSpace(p.Site.pathSpec.URLize(p.URLPath.URL))
       +                pURL = p.addLangPathPrefix(pURL)
       +                url := helpers.MakePermalink(baseURL, pURL)
       +                return url, nil
       +        }
       +
                dir := strings.TrimSpace(p.Site.pathSpec.MakePath(filepath.ToSlash(strings.ToLower(p.Source.Dir()))))
                pSlug := strings.TrimSpace(p.Site.pathSpec.URLize(p.Slug))
                pURL := strings.TrimSpace(p.Site.pathSpec.URLize(p.URLPath.URL))
       @@ -802,36 +814,30 @@ func (p *Page) IsExpired() bool {
                return p.ExpiryDate.Before(time.Now())
        }
        
       -func (p *Page) Permalink() (string, error) {
       -        // TODO(bep) np permalink
       -        if p.IsNode() {
       -                return p.Site.permalink(p.URL()), nil
       -        }
       +func (p *Page) Permalink() string {
                link, err := p.permalink()
                if err != nil {
       -                return "", err
       +                return ""
                }
       -        return link.String(), nil
       +
       +        return link.String()
        }
        
        func (p *Page) URL() string {
       -        // TODO(bep np URL
       -        if p.IsNode() {
       -                return p.addLangPathPrefix(p.URLPath.URL)
       -        }
       -        if p.URLPath.URL != "" {
       +
       +        if p.IsPage() && p.URLPath.URL != "" {
                        // This is the url set in front matter
                        return p.URLPath.URL
                }
                // Fall back to the relative permalink.
       -        u, _ := p.RelPermalink()
       +        u := p.RelPermalink()
                return u
        }
        
       -func (p *Page) RelPermalink() (string, error) {
       +func (p *Page) RelPermalink() string {
                link, err := p.permalink()
                if err != nil {
       -                return "", err
       +                return ""
                }
        
                if viper.GetBool("canonifyURLs") {
       @@ -839,16 +845,27 @@ func (p *Page) RelPermalink() (string, error) {
                        // have to return the URL relative from baseURL
                        relpath, err := helpers.GetRelativePath(link.String(), string(p.Site.BaseURL))
                        if err != nil {
       -                        return "", err
       +                        return ""
       +                }
       +
       +                relpath = filepath.ToSlash(relpath)
       +
       +                if relpath[0] == '.' {
       +                        relpath = relpath[1:]
       +                }
       +
       +                if !strings.HasPrefix(relpath, "/") {
       +                        relpath = "/" + relpath
                        }
       -                return "/" + filepath.ToSlash(relpath), nil
       +
       +                return relpath
                }
        
                link.Scheme = ""
                link.Host = ""
                link.User = nil
                link.Opaque = ""
       -        return link.String(), nil
       +        return link.String()
        }
        
        var ErrHasDraftAndPublished = errors.New("both draft and published parameters were found in page's frontmatter")
       @@ -1109,7 +1126,7 @@ func (p *Page) IsMenuCurrent(menuID string, inme *MenuEntry) bool {
        
                // The following logic is kept from back when Hugo had both Page and Node types.
                // TODO(bep) consolidate / clean
       -        me := MenuEntry{Name: p.Title, URL: p.Site.createNodeMenuEntryURL(p.URL())}
       +        me := MenuEntry{Name: p.Title, URL: p.URL()}
        
                if !me.IsSameResource(inme) {
                        return false
       @@ -1154,7 +1171,7 @@ func (p *Page) Menus() PageMenus {
                        p.pageMenus = PageMenus{}
        
                        if ms, ok := p.Params["menu"]; ok {
       -                        link, _ := p.RelPermalink()
       +                        link := p.RelPermalink()
        
                                me := MenuEntry{Name: p.LinkTitle(), Weight: p.Weight, URL: link}
        
       @@ -1719,13 +1736,13 @@ func (p *Page) setNodeTypeVars(s *Site) {
                // Set Node URL
                switch p.Kind {
                case KindHome:
       -                p.URLPath.URL = ""
       +                p.URLPath.URL = "/"
                case KindSection:
       -                p.URLPath.URL = p.sections[0]
       +                p.URLPath.URL = "/" + p.sections[0] + "/"
                case KindTaxonomy:
       -                p.URLPath.URL = path.Join(p.sections...)
       +                p.URLPath.URL = "/" + path.Join(p.sections...) + "/"
                case KindTaxonomyTerm:
       -                p.URLPath.URL = path.Join(p.sections...)
       +                p.URLPath.URL = "/" + path.Join(p.sections...) + "/"
                }
        
                p.site = s
 (DIR) diff --git a/hugolib/page_permalink_test.go b/hugolib/page_permalink_test.go
       @@ -81,20 +81,14 @@ func TestPermalink(t *testing.T) {
                                })
                        }
        
       -                u, err := p.Permalink()
       -                if err != nil {
       -                        t.Errorf("Test %d: Unable to process permalink: %s", i, err)
       -                }
       +                u := p.Permalink()
        
                        expected := test.expectedAbs
                        if u != expected {
                                t.Errorf("Test %d: Expected abs url: %s, got: %s", i, expected, u)
                        }
        
       -                u, err = p.RelPermalink()
       -                if err != nil {
       -                        t.Errorf("Test %d: Unable to process permalink: %s", i, err)
       -                }
       +                u = p.RelPermalink()
        
                        expected = test.expectedRel
                        if u != expected {
 (DIR) diff --git a/hugolib/site.go b/hugolib/site.go
       @@ -299,13 +299,9 @@ func (s *SiteInfo) refLink(ref string, page *Page, relative bool) (string, error
                        }
        
                        if relative {
       -                        link, err = target.RelPermalink()
       +                        link = target.RelPermalink()
                        } else {
       -                        link, err = target.Permalink()
       -                }
       -
       -                if err != nil {
       -                        return "", err
       +                        link = target.Permalink()
                        }
                }
        
       @@ -389,11 +385,8 @@ func (s *SiteInfo) SourceRelativeLink(ref string, currentPage *Page) (string, er
                                return "", fmt.Errorf("No page found for \"%s\" on page \"%s\".\n", ref, currentPage.Source.Path())
                        }
        
       -                link, err = target.RelPermalink()
       +                link = target.RelPermalink()
        
       -                if err != nil {
       -                        return "", err
       -                }
                }
        
                if refURL.Fragment != "" {
 (DIR) diff --git a/hugolib/site_render.go b/hugolib/site_render.go
       @@ -99,7 +99,7 @@ func (s *Site) renderPaginator(p *Page) error {
        
                        aliasPath := p.addLangPathPrefix(helpers.PaginateAliasPath(path.Join(p.sections...), 1))
                        //TODO(bep) np node.permalink
       -                link, _ := p.Permalink()
       +                link := p.Permalink()
                        s.writeDestAlias(aliasPath, link, nil)
        
                        pagers := p.paginator.Pagers()
       @@ -144,6 +144,7 @@ func (s *Site) renderRSS(p *Page) error {
                // TODO(bep) np check RSS titles
                // TODO(bep) np check RSS page limit, 50?
                rssNode := p.copy()
       +        rssNode.Kind = kindRSS
        
                // TODO(bep) np todelido URL
                rssURI := s.Language.GetString("rssURI")
       @@ -248,10 +249,8 @@ func (s *Site) renderAliases() error {
                                continue
                        }
        
       -                plink, err := p.Permalink()
       -                if err != nil {
       -                        return err
       -                }
       +                plink := p.Permalink()
       +
                        for _, a := range p.Aliases {
                                if err := s.writeDestAlias(a, plink, p); err != nil {
                                        return err