diff --git a/hugolib/hugo_sites_build.go b/hugolib/hugo_sites_build.go index 4f9ad4e04..596323e2b 100644 --- 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 { diff --git a/hugolib/hugo_sites_build_test.go b/hugolib/hugo_sites_build_test.go index 3498de67f..10b5baad3 100644 --- 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 diff --git a/hugolib/menu_test.go b/hugolib/menu_test.go index 460440fa8..2fd2e43ab 100644 --- 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 { diff --git a/hugolib/node_as_page_test.go b/hugolib/node_as_page_test.go index 1c091821f..daebee092 100644 --- 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, "") } diff --git a/hugolib/page.go b/hugolib/page.go index cc2b9110d..bf403f7a1 100644 --- 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 "" } - return "/" + filepath.ToSlash(relpath), nil + + relpath = filepath.ToSlash(relpath) + + if relpath[0] == '.' { + relpath = relpath[1:] + } + + if !strings.HasPrefix(relpath, "/") { + relpath = "/" + relpath + } + + 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 diff --git a/hugolib/page_permalink_test.go b/hugolib/page_permalink_test.go index 13a9311f3..341639529 100644 --- 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 { diff --git a/hugolib/site.go b/hugolib/site.go index 771256b17..ce1f9b8cd 100644 --- 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 != "" { diff --git a/hugolib/site_render.go b/hugolib/site_render.go index d9f718a7a..f57a24a60 100644 --- 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