shithub: hugo

Download patch

ref: 6d2281c8ead70ac07122027c989807c0aa1a7722
parent: e096917f8738404696627a279277820dbe3a8f94
author: Bjørn Erik Pedersen <[email protected]>
date: Sat Feb 18 05:02:12 EST 2017

hugolib: Add disableKinds option

Fixes #2534

--- a/commands/hugo.go
+++ b/commands/hugo.go
@@ -153,6 +153,7 @@
 	themesDir       string
 	source          string
 	logI18nWarnings bool
+	disableKinds    []string
 )
 
 // Execute adds all child commands to the root command HugoCmd and sets flags appropriately.
@@ -239,6 +240,8 @@
 	cmd.Flags().BoolP("noChmod", "", false, "Don't sync permission mode of files")
 	cmd.Flags().BoolVarP(&logI18nWarnings, "i18n-warnings", "", false, "Print missing translations")
 
+	cmd.Flags().StringSliceVar(&disableKinds, "disableKinds", []string{}, "Disable different kind of pages (home, RSS etc.)")
+
 	// Set bash-completion.
 	// Each flag must first be defined before using the SetAnnotation() call.
 	cmd.Flags().SetAnnotation("source", cobra.BashCompSubdirsInDir, []string{})
@@ -290,6 +293,10 @@
 		c.initializeFlags(cmdV)
 	}
 
+	if len(disableKinds) > 0 {
+		c.Set("disableKinds", disableKinds)
+	}
+
 	logger, err := createLogger(cfg.Cfg)
 	if err != nil {
 		return cfg, err
@@ -450,6 +457,7 @@
 	for _, key := range flagKeys {
 		c.setValueFromFlag(cmd.Flags(), key)
 	}
+
 }
 
 func (c *commandeer) setValueFromFlag(flags *flag.FlagSet, key string) {
--- /dev/null
+++ b/hugolib/disableKinds_test.go
@@ -1,0 +1,216 @@
+// Copyright 2016 The Hugo Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package hugolib
+
+import (
+	"strings"
+	"testing"
+
+	"fmt"
+
+	"github.com/spf13/afero"
+	"github.com/spf13/hugo/deps"
+
+	"github.com/spf13/hugo/helpers"
+	"github.com/spf13/hugo/hugofs"
+	"github.com/stretchr/testify/require"
+)
+
+func TestDisableKindsNoneDisabled(t *testing.T) {
+	t.Parallel()
+	doTestDisableKinds(t)
+}
+
+func TestDisableKindsSomeDisabled(t *testing.T) {
+	t.Parallel()
+	doTestDisableKinds(t, KindSection, kind404)
+}
+
+func TestDisableKindsOneDisabled(t *testing.T) {
+	t.Parallel()
+	for _, kind := range allKinds {
+		doTestDisableKinds(t, kind)
+	}
+}
+
+func TestDisableKindsAllDisabled(t *testing.T) {
+	t.Parallel()
+	doTestDisableKinds(t, allKinds...)
+}
+
+func doTestDisableKinds(t *testing.T, disabled ...string) {
+
+	siteConfigTemplate := `
+baseURL = "http://example.com/blog"
+enableRobotsTXT = true
+disableKinds = %s
+
+paginate = 1
+defaultContentLanguage = "en"
+
+[Taxonomies]
+tag = "tags"
+category = "categories"
+`
+
+	pageTemplate := `---
+title: "%s"
+tags:
+%s
+categories:
+- Hugo
+---
+# Doc
+`
+
+	mf := afero.NewMemMapFs()
+
+	disabledStr := "[]"
+
+	if len(disabled) > 0 {
+		disabledStr = strings.Replace(fmt.Sprintf("%#v", disabled), "[]string{", "[", -1)
+		disabledStr = strings.Replace(disabledStr, "}", "]", -1)
+	}
+
+	siteConfig := fmt.Sprintf(siteConfigTemplate, disabledStr)
+	writeToFs(t, mf, "config.toml", siteConfig)
+
+	cfg, err := LoadConfig(mf, "", "config.toml")
+	require.NoError(t, err)
+
+	fs := hugofs.NewFrom(mf, cfg)
+	th := testHelper{cfg, fs, t}
+
+	writeSource(t, fs, "layouts/index.html", "Home|{{ .Title }}|{{ .Content }}")
+	writeSource(t, fs, "layouts/_default/single.html", "Single|{{ .Title }}|{{ .Content }}")
+	writeSource(t, fs, "layouts/_default/list.html", "List|{{ .Title }}|{{ .Content }}")
+	writeSource(t, fs, "layouts/_default/terms.html", "Terms List|{{ .Title }}|{{ .Content }}")
+	writeSource(t, fs, "layouts/404.html", "Page Not Found")
+
+	writeSource(t, fs, "content/sect/p1.md", fmt.Sprintf(pageTemplate, "P1", "- tag1"))
+
+	writeNewContentFile(t, fs, "Category Terms", "2017-01-01", "content/categories/_index.md", 10)
+	writeNewContentFile(t, fs, "Tag1 List", "2017-01-01", "content/tags/tag1/_index.md", 10)
+
+	h, err := NewHugoSites(deps.DepsCfg{Fs: fs, Cfg: cfg})
+
+	require.NoError(t, err)
+	require.Len(t, h.Sites, 1)
+
+	err = h.Build(BuildCfg{})
+
+	require.NoError(t, err)
+
+	assertDisabledKinds(th, h.Sites[0], disabled...)
+
+}
+
+func assertDisabledKinds(th testHelper, s *Site, disabled ...string) {
+	assertDisabledKind(th,
+		func(isDisabled bool) bool {
+			if isDisabled {
+				return len(s.RegularPages) == 0
+			}
+			return len(s.RegularPages) > 0
+		}, disabled, KindPage, "public/sect/p1/index.html", "Single|P1")
+	assertDisabledKind(th,
+		func(isDisabled bool) bool {
+			p := s.getPage(KindHome)
+			if isDisabled {
+				return p == nil
+			}
+			return p != nil
+		}, disabled, KindHome, "public/index.html", "Home")
+	assertDisabledKind(th,
+		func(isDisabled bool) bool {
+			p := s.getPage(KindSection, "sect")
+			if isDisabled {
+				return p == nil
+			}
+			return p != nil
+		}, disabled, KindSection, "public/sect/index.html", "Sects")
+	assertDisabledKind(th,
+		func(isDisabled bool) bool {
+			p := s.getPage(KindTaxonomy, "tags", "tag1")
+
+			if isDisabled {
+				return p == nil
+			}
+			return p != nil
+
+		}, disabled, KindTaxonomy, "public/tags/tag1/index.html", "Tag1")
+	assertDisabledKind(th,
+		func(isDisabled bool) bool {
+			p := s.getPage(KindTaxonomyTerm, "tags")
+			if isDisabled {
+				return p == nil
+			}
+			return p != nil
+
+		}, disabled, KindTaxonomyTerm, "public/tags/index.html", "Tags")
+	assertDisabledKind(th,
+		func(isDisabled bool) bool {
+			p := s.getPage(KindTaxonomyTerm, "categories")
+
+			if isDisabled {
+				return p == nil
+			}
+			return p != nil
+
+		}, disabled, KindTaxonomyTerm, "public/categories/index.html", "Category Terms")
+	assertDisabledKind(th,
+		func(isDisabled bool) bool {
+			p := s.getPage(KindTaxonomy, "categories", "hugo")
+			if isDisabled {
+				return p == nil
+			}
+			return p != nil
+
+		}, disabled, KindTaxonomy, "public/categories/hugo/index.html", "Hugo")
+	// The below have no page in any collection.
+	assertDisabledKind(th, func(isDisabled bool) bool { return true }, disabled, kindRSS, "public/index.xml", "<link>")
+	assertDisabledKind(th, func(isDisabled bool) bool { return true }, disabled, kindSitemap, "public/sitemap.xml", "sitemap")
+	assertDisabledKind(th, func(isDisabled bool) bool { return true }, disabled, kindRobotsTXT, "public/robots.txt", "User-agent")
+	assertDisabledKind(th, func(isDisabled bool) bool { return true }, disabled, kind404, "public/404.html", "Page Not Found")
+}
+
+func assertDisabledKind(th testHelper, kindAssert func(bool) bool, disabled []string, kind, path, matcher string) {
+	isDisabled := stringSliceContains(kind, disabled...)
+	require.True(th.T, kindAssert(isDisabled), fmt.Sprintf("%s: %t", kind, isDisabled))
+
+	if kind == kindRSS && !isDisabled {
+		// If the home page is also disabled, there is not RSS to look for.
+		if stringSliceContains(KindHome, disabled...) {
+			isDisabled = true
+		}
+	}
+
+	if isDisabled {
+		// Path should not exist
+		fileExists, err := helpers.Exists(path, th.Fs.Destination)
+		require.False(th.T, fileExists)
+		require.NoError(th.T, err)
+
+	} else {
+		th.assertFileContent(path, matcher)
+	}
+}
+
+func stringSliceContains(k string, values ...string) bool {
+	for _, v := range values {
+		if k == v {
+			return true
+		}
+	}
+	return false
+}
--- a/hugolib/hugo_sites.go
+++ b/hugolib/hugo_sites.go
@@ -303,16 +303,18 @@
 
 	for _, s := range h.Sites {
 
-		// home pages
-		home := s.findPagesByKind(KindHome)
-		if len(home) > 1 {
-			panic("Too many homes")
+		if s.isEnabled(KindHome) {
+			// home pages
+			home := s.findPagesByKind(KindHome)
+			if len(home) > 1 {
+				panic("Too many homes")
+			}
+			if len(home) == 0 {
+				n := s.newHomePage()
+				s.Pages = append(s.Pages, n)
+				newPages = append(newPages, n)
+			}
 		}
-		if len(home) == 0 {
-			n := s.newHomePage()
-			s.Pages = append(s.Pages, n)
-			newPages = append(newPages, n)
-		}
 
 		// taxonomy list and terms pages
 		taxonomies := s.Language.GetStringMapString("taxonomies")
@@ -339,44 +341,51 @@
 							break
 						}
 					}
-					if !foundTaxonomyPage {
-						n := s.newTaxonomyPage(plural, key)
-						s.Pages = append(s.Pages, n)
-						newPages = append(newPages, n)
+
+					if s.isEnabled(KindTaxonomy) {
+						if !foundTaxonomyPage {
+							n := s.newTaxonomyPage(plural, key)
+							s.Pages = append(s.Pages, n)
+							newPages = append(newPages, n)
+						}
 					}
 
-					if !foundTaxonomyTermsPage {
-						foundTaxonomyTermsPage = true
-						n := s.newTaxonomyTermsPage(plural)
-						s.Pages = append(s.Pages, n)
-						newPages = append(newPages, n)
+					if s.isEnabled(KindTaxonomyTerm) {
+						if !foundTaxonomyTermsPage {
+							foundTaxonomyTermsPage = true
+							n := s.newTaxonomyTermsPage(plural)
+							s.Pages = append(s.Pages, n)
+							newPages = append(newPages, n)
+						}
 					}
 				}
 			}
 		}
 
-		sectionPages := s.findPagesByKind(KindSection)
-		if len(sectionPages) < len(s.Sections) {
-			for name, section := range s.Sections {
-				// A section may be created for the root content folder if a
-				// content file is placed there.
-				// We cannot create a section node for that, because
-				// that would overwrite the home page.
-				if name == "" {
-					continue
-				}
-				foundSection := false
-				for _, sectionPage := range sectionPages {
-					if sectionPage.sections[0] == name {
-						foundSection = true
-						break
+		if s.isEnabled(KindSection) {
+			sectionPages := s.findPagesByKind(KindSection)
+			if len(sectionPages) < len(s.Sections) {
+				for name, section := range s.Sections {
+					// A section may be created for the root content folder if a
+					// content file is placed there.
+					// We cannot create a section node for that, because
+					// that would overwrite the home page.
+					if name == "" {
+						continue
 					}
+					foundSection := false
+					for _, sectionPage := range sectionPages {
+						if sectionPage.sections[0] == name {
+							foundSection = true
+							break
+						}
+					}
+					if !foundSection {
+						n := s.newSectionPage(name, section)
+						s.Pages = append(s.Pages, n)
+						newPages = append(newPages, n)
+					}
 				}
-				if !foundSection {
-					n := s.newSectionPage(name, section)
-					s.Pages = append(s.Pages, n)
-					newPages = append(newPages, n)
-				}
 			}
 		}
 	}
@@ -427,6 +436,14 @@
 	for _, p := range master.rawAllPages {
 		if p.Lang() == "" {
 			panic("Page language missing: " + p.Title)
+		}
+
+		if p.Kind == kindUnknown {
+			p.Kind = p.s.kindFromSections(p.sections)
+		}
+
+		if !p.s.isEnabled(p.Kind) {
+			continue
 		}
 
 		shouldBuild := p.shouldBuild()
--- a/hugolib/hugo_sites_build.go
+++ b/hugolib/hugo_sites_build.go
@@ -136,6 +136,12 @@
 }
 
 func (h *HugoSites) assemble(config *BuildCfg) error {
+	if config.whatChanged.source {
+		for _, s := range h.Sites {
+			s.createTaxonomiesEntries()
+		}
+	}
+
 	// TODO(bep) we could probably wait and do this in one go later
 	h.setupTranslations()
 
--- a/hugolib/hugo_sites_build_test.go
+++ b/hugolib/hugo_sites_build_test.go
@@ -218,6 +218,7 @@
 	// Check site config
 	for _, s := range sites.Sites {
 		require.True(t, s.Info.defaultContentLanguageInSubdir, s.Info.Title)
+		require.NotNil(t, s.disabledKinds)
 	}
 
 	enSite := sites.Sites[0]
--- a/hugolib/page.go
+++ b/hugolib/page.go
@@ -42,7 +42,8 @@
 )
 
 var (
-	cjk = regexp.MustCompile(`\p{Han}|\p{Hangul}|\p{Hiragana}|\p{Katakana}`)
+	cjk      = regexp.MustCompile(`\p{Han}|\p{Hangul}|\p{Hiragana}|\p{Katakana}`)
+	allKinds = []string{KindHome, KindSection, KindTaxonomy, KindTaxonomyTerm, kindRSS, kindSitemap, kindRobotsTXT, kind404}
 )
 
 const (
--- a/hugolib/site.go
+++ b/hugolib/site.go
@@ -105,13 +105,22 @@
 	Data           map[string]interface{}
 	Language       *helpers.Language
 
+	disabledKinds map[string]bool
+
 	// Logger etc.
 	*deps.Deps `json:"-"`
 }
 
+func (s *Site) isEnabled(kind string) bool {
+	if kind == kindUnknown {
+		panic("Unknown kind")
+	}
+	return !s.disabledKinds[kind]
+}
+
 // reset returns a new Site prepared for rebuild.
 func (s *Site) reset() *Site {
-	return &Site{Deps: s.Deps, Language: s.Language, owner: s.owner, PageCollections: newPageCollections()}
+	return &Site{Deps: s.Deps, disabledKinds: s.disabledKinds, Language: s.Language, owner: s.owner, PageCollections: newPageCollections()}
 }
 
 // newSite creates a new site with the given configuration.
@@ -122,8 +131,13 @@
 		cfg.Language = helpers.NewDefaultLanguage(cfg.Cfg)
 	}
 
-	s := &Site{PageCollections: c, Language: cfg.Language}
+	disabledKinds := make(map[string]bool)
+	for _, disabled := range cast.ToStringSlice(cfg.Language.Get("disableKinds")) {
+		disabledKinds[disabled] = true
+	}
 
+	s := &Site{PageCollections: c, Language: cfg.Language, disabledKinds: disabledKinds}
+
 	s.Info = newSiteInfo(siteBuilderCfg{s: s, pageCollections: c, language: s.Language})
 	return s, nil
 
@@ -820,6 +834,7 @@
 }
 
 func (s *Site) render() (err error) {
+
 	if err = s.preparePages(); err != nil {
 		return
 	}
@@ -1493,8 +1508,18 @@
 	}
 	return s.PathSpec.MakePathSanitized(key)
 }
-func (s *Site) assembleTaxonomies() {
+
+// We need to create the top level taxonomy early in the build process
+// to be able to determine the page Kind correctly.
+func (s *Site) createTaxonomiesEntries() {
 	s.Taxonomies = make(TaxonomyList)
+	taxonomies := s.Language.GetStringMapString("taxonomies")
+	for _, plural := range taxonomies {
+		s.Taxonomies[plural] = make(Taxonomy)
+	}
+}
+
+func (s *Site) assembleTaxonomies() {
 	s.taxonomiesPluralSingular = make(map[string]string)
 	s.taxonomiesOrigKey = make(map[string]string)
 
@@ -1503,7 +1528,6 @@
 	s.Log.INFO.Printf("found taxonomies: %#v\n", taxonomies)
 
 	for singular, plural := range taxonomies {
-		s.Taxonomies[plural] = make(Taxonomy)
 		s.taxonomiesPluralSingular[plural] = singular
 
 		for _, p := range s.Pages {
--- a/hugolib/site_render.go
+++ b/hugolib/site_render.go
@@ -130,6 +130,10 @@
 
 func (s *Site) renderRSS(p *Page) error {
 
+	if !s.isEnabled(kindRSS) {
+		return nil
+	}
+
 	if s.Cfg.GetBool("disableRSS") {
 		return nil
 	}
@@ -167,6 +171,10 @@
 }
 
 func (s *Site) render404() error {
+	if !s.isEnabled(kind404) {
+		return nil
+	}
+
 	if s.Cfg.GetBool("disable404") {
 		return nil
 	}
@@ -184,6 +192,10 @@
 }
 
 func (s *Site) renderSitemap() error {
+	if !s.isEnabled(kindSitemap) {
+		return nil
+	}
+
 	if s.Cfg.GetBool("disableSitemap") {
 		return nil
 	}
@@ -227,6 +239,10 @@
 }
 
 func (s *Site) renderRobotsTXT() error {
+	if !s.isEnabled(kindRobotsTXT) {
+		return nil
+	}
+
 	if !s.Cfg.GetBool("enableRobotsTXT") {
 		return nil
 	}