shithub: hugo

Download patch

ref: 75dd596e6c38466fcb97a8b9dc9eb20fc2fb7fd6
parent: 618948e4a83665f8355b01d8a3f7a7186e6bd3eb
author: Bjørn Erik Pedersen <[email protected]>
date: Tue Jul 26 06:24:27 EDT 2016

Introduce HugoSites type

And a Hugo global variable which contains the site under build.

This is really needed to get some level of control of the "multiple languages" in play.

There are still work related to this scattered around, but that will come.

With this commit, the multilingual feature is starting to work.

--- a/commands/benchmark.go
+++ b/commands/benchmark.go
@@ -57,8 +57,8 @@
 			return err
 		}
 		for i := 0; i < benchmarkTimes; i++ {
-			Sites = nil
-			_ = buildSite()
+			_ = buildSites()
+			Hugo.Reset()
 		}
 		pprof.WriteHeapProfile(f)
 		f.Close()
@@ -76,8 +76,8 @@
 		pprof.StartCPUProfile(f)
 		defer pprof.StopCPUProfile()
 		for i := 0; i < benchmarkTimes; i++ {
-			Sites = nil
-			_ = buildSite()
+			_ = buildSites()
+			Hugo.Reset()
 		}
 	}
 
--- a/commands/hugo.go
+++ b/commands/hugo.go
@@ -46,10 +46,20 @@
 	"github.com/spf13/viper"
 )
 
-// Sites represents the Hugo sites to build. This variable is exported as it
+type HugoSites []*hugolib.Site
+
+// Reset resets the sites, making it ready for a full rebuild.
+// TODO(bep) multilingo
+func (h HugoSites) Reset() {
+	for i, s := range h {
+		h[i] = s.Reset()
+	}
+}
+
+// Hugo represents the Hugo sites to build. This variable is exported as it
 // is used by at least one external library (the Hugo caddy plugin). We should
 // provide a cleaner external API, but until then, this is it.
-var Sites map[string]*hugolib.Site
+var Hugo HugoSites
 
 // Reset resets Hugo ready for a new full build. This is mainly only useful
 // for benchmark testing etc. via the CLI commands.
@@ -493,8 +503,16 @@
 			helpers.HugoReleaseVersion(), minVersion)
 	}
 
-	return readMultilingualConfiguration()
+	h, err := readMultilingualConfiguration()
 
+	if err != nil {
+		return err
+	}
+	//TODO(bep) refactor ...
+	Hugo = h
+
+	return nil
+
 }
 
 func flagChanged(flags *flag.FlagSet, key string) bool {
@@ -510,8 +528,8 @@
 	viper.OnConfigChange(func(e fsnotify.Event) {
 		fmt.Println("Config file changed:", e.Name)
 		// Force a full rebuild
-		Sites = nil
-		utils.CheckErr(buildSite(true))
+		Hugo.Reset()
+		utils.CheckErr(buildSites(true))
 		if !viper.GetBool("DisableLiveReload") {
 			// Will block forever trying to write to a channel that nobody is reading if livereload isn't initialized
 			livereload.ForceRefresh()
@@ -537,7 +555,7 @@
 	if len(watches) > 0 && watches[0] {
 		watch = true
 	}
-	if err := buildSite(buildWatch || watch); err != nil {
+	if err := buildSites(buildWatch || watch); err != nil {
 		return fmt.Errorf("Error building site: %s", err)
 	}
 
@@ -704,32 +722,21 @@
 	return a
 }
 
-func buildSite(watching ...bool) (err error) {
+func buildSites(watching ...bool) (err error) {
 	fmt.Println("Started building site")
 	t0 := time.Now()
 
-	if Sites == nil {
-		Sites = make(map[string]*hugolib.Site)
-	}
-
-	for _, lang := range langConfigsList {
+	for _, site := range Hugo {
 		t1 := time.Now()
-		mainSite, present := Sites[lang.Lang]
-		if !present {
-			mainSite = new(hugolib.Site)
-			Sites[lang.Lang] = mainSite
-			mainSite.SetMultilingualConfig(lang, langConfigsList)
-		}
-
 		if len(watching) > 0 && watching[0] {
-			mainSite.RunMode.Watching = true
+			site.RunMode.Watching = true
 		}
 
-		if err := mainSite.Build(); err != nil {
+		if err := site.Build(); err != nil {
 			return err
 		}
 
-		mainSite.Stats(lang.Lang, t1)
+		site.Stats(t1)
 	}
 
 	jww.FEEDBACK.Printf("total in %v ms\n", int(1000*time.Since(t0).Seconds()))
@@ -737,18 +744,17 @@
 	return nil
 }
 
-func rebuildSite(events []fsnotify.Event) error {
+func rebuildSites(events []fsnotify.Event) error {
 	t0 := time.Now()
 
-	for _, lang := range langConfigsList {
+	for _, site := range Hugo {
 		t1 := time.Now()
-		site := Sites[lang.Lang]
 
 		if err := site.ReBuild(events); err != nil {
 			return err
 		}
 
-		site.Stats(lang.Lang, t1)
+		site.Stats(t1)
 	}
 
 	jww.FEEDBACK.Printf("total in %v ms\n", int(1000*time.Since(t0).Seconds()))
@@ -969,7 +975,7 @@
 					const layout = "2006-01-02 15:04 -0700"
 					fmt.Println(time.Now().Format(layout))
 
-					rebuildSite(dynamicEvents)
+					rebuildSites(dynamicEvents)
 
 					if !buildWatch && !viper.GetBool("DisableLiveReload") {
 						// Will block forever trying to write to a channel that nobody is reading if livereload isn't initialized
--- a/commands/multilingual.go
+++ b/commands/multilingual.go
@@ -11,24 +11,30 @@
 	"github.com/spf13/viper"
 )
 
-var langConfigsList hugolib.Languages
-
-func readMultilingualConfiguration() error {
+func readMultilingualConfiguration() (HugoSites, error) {
+	h := make(HugoSites, 0)
 	multilingual := viper.GetStringMap("Multilingual")
 	if len(multilingual) == 0 {
 		// TODO(bep) multilingo langConfigsList = append(langConfigsList, hugolib.NewLanguage("en"))
-		return nil
+		h = append(h, hugolib.NewSite(hugolib.NewLanguage("en")))
+		return h, nil
 	}
 
 	var err error
 
-	langConfigsList, err = toSortedLanguages(multilingual)
+	langConfigsList, err := toSortedLanguages(multilingual)
 
 	if err != nil {
-		return fmt.Errorf("Failed to parse multilingual config: %s", err)
+		return nil, fmt.Errorf("Failed to parse multilingual config: %s", err)
 	}
 
-	return nil
+	for _, lang := range langConfigsList {
+		s := hugolib.NewSite(lang)
+		s.SetMultilingualConfig(lang, langConfigsList)
+		h = append(h, s)
+	}
+
+	return h, nil
 }
 
 func toSortedLanguages(l map[string]interface{}) (hugolib.Languages, error) {
--- a/hugolib/datafiles_test.go
+++ b/hugolib/datafiles_test.go
@@ -87,7 +87,7 @@
 	sources := []source.ByteSource{
 		{Name: filepath.FromSlash("test.roml"), Content: []byte("boo")},
 	}
-	s := &Site{}
+	s := newSiteDefaultLang()
 	err := s.loadData([]source.Input{&source.InMemorySource{ByteSource: sources}})
 	if err != nil {
 		t.Fatalf("Should not return an error")
@@ -95,7 +95,7 @@
 }
 
 func doTestDataDir(t *testing.T, expected interface{}, sources []source.Input) {
-	s := &Site{}
+	s := newSiteDefaultLang()
 	err := s.loadData(sources)
 	if err != nil {
 		t.Fatalf("Error loading data: %s", err)
--- a/hugolib/handler_test.go
+++ b/hugolib/handler_test.go
@@ -47,6 +47,7 @@
 	s := &Site{
 		Source:  &source.InMemorySource{ByteSource: sources},
 		targets: targetList{page: &target.PagePub{UglyURLs: true}},
+		Lang:    NewLanguage("en"),
 	}
 
 	s.initializeSiteInfo()
--- a/hugolib/menu_test.go
+++ b/hugolib/menu_test.go
@@ -683,6 +683,7 @@
 
 	s := &Site{
 		Source: &source.InMemorySource{ByteSource: pageSources},
+		Lang:   newDefaultLanguage(),
 	}
 	return s
 }
--- a/hugolib/multilingual.go
+++ b/hugolib/multilingual.go
@@ -22,6 +22,11 @@
 	return &Language{Lang: lang, params: make(map[string]interface{})}
 }
 
+// TODO(bep) multilingo
+func newDefaultLanguage() *Language {
+	return NewLanguage("en")
+}
+
 type Languages []*Language
 
 func NewLanguages(l ...*Language) Languages {
@@ -93,10 +98,9 @@
 	return viper.Get(key)
 }
 
+// TODO(bep) multilingo move this to a constructor.
 func (s *Site) SetMultilingualConfig(currentLang *Language, languages Languages) {
 
-	// TODO(bep) multilingo evaluate
-	viper.Set("CurrentLanguage", currentLang)
 	ml := &Multilingual{
 		Languages: languages,
 	}
@@ -108,14 +112,11 @@
 	return s.Multilingual != nil && s.Multilingual.enabled()
 }
 
-func currentLanguageString() string {
-	return currentLanguage().Lang
+// TODO(bep) multilingo remove these
+func (s *Site) currentLanguageString() string {
+	return s.currentLanguage().Lang
 }
 
-func currentLanguage() *Language {
-	l := viper.Get("CurrentLanguage")
-	if l == nil {
-		panic("CurrentLanguage not set")
-	}
-	return l.(*Language)
+func (s *Site) currentLanguage() *Language {
+	return s.Lang
 }
--- a/hugolib/pagination_test.go
+++ b/hugolib/pagination_test.go
@@ -226,7 +226,7 @@
 		viper.Set("paginate", -1)
 	}
 	pages := createTestPages(12)
-	s := &Site{}
+	s := newSiteDefaultLang()
 	n1 := s.newHomeNode()
 	n2 := s.newHomeNode()
 	n1.Data["Pages"] = pages
@@ -264,7 +264,7 @@
 	defer viper.Reset()
 
 	viper.Set("paginate", -1)
-	s := &Site{}
+	s := newSiteDefaultLang()
 	_, err := s.newHomeNode().Paginator()
 	assert.NotNil(t, err)
 }
@@ -287,7 +287,7 @@
 	}
 
 	pages := createTestPages(6)
-	s := &Site{}
+	s := newSiteDefaultLang()
 	n1 := s.newHomeNode()
 	n2 := s.newHomeNode()
 
@@ -320,7 +320,7 @@
 }
 
 func TestInvalidOptions(t *testing.T) {
-	s := &Site{}
+	s := newSiteDefaultLang()
 	n1 := s.newHomeNode()
 	_, err := n1.Paginate(createTestPages(1), 1, 2)
 	assert.NotNil(t, err)
@@ -335,7 +335,7 @@
 	defer viper.Reset()
 
 	viper.Set("paginate", -1)
-	s := &Site{}
+	s := newSiteDefaultLang()
 	_, err := s.newHomeNode().Paginate(createTestPages(2))
 	assert.NotNil(t, err)
 }
@@ -358,7 +358,7 @@
 	defer viper.Reset()
 
 	viper.Set("paginate", 10)
-	s := &Site{}
+	s := newSiteDefaultLang()
 	n1 := s.newHomeNode()
 	n2 := s.newHomeNode()
 
@@ -377,7 +377,7 @@
 	defer viper.Reset()
 
 	viper.Set("paginate", 10)
-	s := &Site{}
+	s := newSiteDefaultLang()
 	n1 := s.newHomeNode()
 	n2 := s.newHomeNode()
 
--- a/hugolib/robotstxt_test.go
+++ b/hugolib/robotstxt_test.go
@@ -40,6 +40,7 @@
 
 	s := &Site{
 		Source: &source.InMemorySource{ByteSource: weightedSources},
+		Lang:   newDefaultLanguage(),
 	}
 
 	s.initializeSiteInfo()
--- a/hugolib/rss_test.go
+++ b/hugolib/rss_test.go
@@ -55,6 +55,7 @@
 	hugofs.InitMemFs()
 	s := &Site{
 		Source: &source.InMemorySource{ByteSource: weightedSources},
+		Lang:   newDefaultLanguage(),
 	}
 	s.initializeSiteInfo()
 	s.prepTemplates("rss.xml", rssTemplate)
--- a/hugolib/shortcode_test.go
+++ b/hugolib/shortcode_test.go
@@ -499,6 +499,7 @@
 	s := &Site{
 		Source:  &source.InMemorySource{ByteSource: sources},
 		targets: targetList{page: &target.PagePub{UglyURLs: false}},
+		Lang:    newDefaultLanguage(),
 	}
 
 	s.initializeSiteInfo()
--- a/hugolib/site.go
+++ b/hugolib/site.go
@@ -92,8 +92,23 @@
 	futureCount    int
 	expiredCount   int
 	Data           map[string]interface{}
+	Lang           *Language
 }
 
+// TODO(bep) multilingo
+// Reset returns a new Site prepared for rebuild.
+func (s *Site) Reset() *Site {
+	return &Site{Lang: s.Lang, Multilingual: s.Multilingual}
+}
+
+func NewSite(lang *Language) *Site {
+	return &Site{Lang: lang}
+}
+
+func newSiteDefaultLang() *Site {
+	return NewSite(newDefaultLanguage())
+}
+
 type targetList struct {
 	page     target.Output
 	pageUgly target.Output
@@ -705,7 +720,7 @@
 		i18nSources = []source.Input{&source.Filesystem{Base: themeI18nDir}, i18nSources[0]}
 	}
 
-	if err = loadI18n(i18nSources, currentLanguageString()); err != nil {
+	if err = loadI18n(i18nSources, s.currentLanguageString()); err != nil {
 		return
 	}
 	s.timerStep("load i18n")
@@ -742,7 +757,7 @@
 		return
 	}
 
-	currentLang := currentLanguageString()
+	currentLang := s.currentLanguageString()
 
 	allTranslations := pagesToTranslationsMap(s.Multilingual, s.AllPages)
 	assignTranslationsToPages(allTranslations, s.AllPages)
@@ -819,20 +834,10 @@
 func (s *Site) initializeSiteInfo() {
 
 	var (
-		lang      *Language
+		lang      *Language = s.Lang
 		languages Languages
 	)
 
-	cl := viper.Get("CurrentLanguage")
-	if cl == nil {
-		// Set default to english
-		// TODO(bep) multilingo this looks clumsy
-		lang = NewLanguage("en")
-		viper.Set("CurrentLanguage", lang)
-	} else {
-		lang = cl.(*Language)
-	}
-
 	if s.Multilingual != nil {
 		languages = s.Multilingual.Languages
 	}
@@ -1610,7 +1615,7 @@
 func (s *Site) addMultilingualPrefix(basePath string) string {
 	hadPrefix := strings.HasPrefix(basePath, "/")
 	if s.multilingualEnabled() {
-		basePath = path.Join(currentLanguageString(), basePath)
+		basePath = path.Join(s.currentLanguageString(), basePath)
 		if hadPrefix {
 			basePath = "/" + basePath
 		}
@@ -1961,7 +1966,7 @@
 
 // Stats prints Hugo builds stats to the console.
 // This is what you see after a successful hugo build.
-func (s *Site) Stats(lang string, t0 time.Time) {
+func (s *Site) Stats(t0 time.Time) {
 	jww.FEEDBACK.Println(s.draftStats())
 	jww.FEEDBACK.Println(s.futureStats())
 	jww.FEEDBACK.Println(s.expiredStats())
@@ -1974,9 +1979,9 @@
 		jww.FEEDBACK.Printf("%d %s created\n", len(s.Taxonomies[pl]), pl)
 	}
 
-	if lang != "" {
-		jww.FEEDBACK.Printf("rendered lang %q in %v ms\n", lang, int(1000*time.Since(t0).Seconds()))
-	}
+	// TODO(bep) will always have lang. Not sure this should always be printed.
+	jww.FEEDBACK.Printf("rendered lang %q in %v ms\n", s.Lang.Lang, int(1000*time.Since(t0).Seconds()))
+
 }
 
 func (s *Site) setURLs(n *Node, in string) {
--- a/hugolib/site_test.go
+++ b/hugolib/site_test.go
@@ -215,7 +215,7 @@
 
 	for i, test := range tests {
 
-		s := &Site{}
+		s := newSiteDefaultLang()
 
 		p, err := NewPageFrom(strings.NewReader(pageSimpleTitle), "content/a/file.md")
 		if err != nil {
@@ -262,6 +262,7 @@
 	siteSetup := func() *Site {
 		s := &Site{
 			Source: &source.InMemorySource{ByteSource: sources},
+			Lang:   newDefaultLanguage(),
 		}
 
 		s.initializeSiteInfo()
@@ -320,6 +321,7 @@
 	siteSetup := func() *Site {
 		s := &Site{
 			Source: &source.InMemorySource{ByteSource: sources},
+			Lang:   newDefaultLanguage(),
 		}
 
 		s.initializeSiteInfo()
@@ -413,6 +415,7 @@
 	s := &Site{
 		Source:  &source.InMemorySource{ByteSource: sources},
 		targets: targetList{page: &target.PagePub{UglyURLs: uglyURLs}},
+		Lang:    newDefaultLanguage(),
 	}
 
 	s.initializeSiteInfo()
@@ -479,6 +482,7 @@
 	s := &Site{
 		Source:  &source.InMemorySource{ByteSource: sources},
 		targets: targetList{page: &target.PagePub{UglyURLs: uglyURLs}},
+		Lang:    newDefaultLanguage(),
 	}
 
 	s.initializeSiteInfo()
@@ -572,6 +576,7 @@
 	s := &Site{
 		Source:  &source.InMemorySource{ByteSource: sources},
 		targets: targetList{page: &target.PagePub{UglyURLs: uglify}},
+		Lang:    newDefaultLanguage(),
 	}
 
 	s.initializeSiteInfo()
@@ -636,6 +641,7 @@
 	s := &Site{
 		Source:  &source.InMemorySource{ByteSource: sources},
 		targets: targetList{page: &target.PagePub{UglyURLs: true}},
+		Lang:    newDefaultLanguage(),
 	}
 
 	s.initializeSiteInfo()
@@ -693,6 +699,7 @@
 			s := &Site{
 				Source:  &source.InMemorySource{ByteSource: sources},
 				targets: targetList{page: &target.PagePub{UglyURLs: true}},
+				Lang:    newDefaultLanguage(),
 			}
 			t.Logf("Rendering with BaseURL %q and CanonifyURLs set %v", viper.GetString("baseURL"), canonify)
 			s.initializeSiteInfo()
@@ -788,6 +795,7 @@
 	viper.Set("baseurl", "http://auth/bub")
 	s := &Site{
 		Source: &source.InMemorySource{ByteSource: weightedSources},
+		Lang:   newDefaultLanguage(),
 	}
 	s.initializeSiteInfo()
 
@@ -1040,6 +1048,7 @@
 	viper.Set("taxonomies", taxonomies)
 	s := &Site{
 		Source: &source.InMemorySource{ByteSource: sources},
+		Lang:   newDefaultLanguage(),
 	}
 	s.initializeSiteInfo()
 
@@ -1107,6 +1116,7 @@
 
 	site := &Site{
 		Source: &source.InMemorySource{ByteSource: sources},
+		Lang:   newDefaultLanguage(),
 	}
 
 	site.initializeSiteInfo()
@@ -1402,7 +1412,6 @@
 	// Multilingual settings
 	viper.Set("Multilingual", true)
 	en := NewLanguage("en")
-	viper.Set("CurrentLanguage", en)
 	viper.Set("DefaultContentLanguage", "fr")
 	viper.Set("paginate", "2")
 
@@ -1409,6 +1418,7 @@
 	languages := NewLanguages(en, NewLanguage("fr"))
 	s := &Site{
 		Source: &source.InMemorySource{ByteSource: sources},
+		Lang:   en,
 		Multilingual: &Multilingual{
 			Languages: languages,
 		},
--- a/hugolib/site_url_test.go
+++ b/hugolib/site_url_test.go
@@ -73,7 +73,7 @@
 		{"http://base.com", "http://base.com"}} {
 
 		viper.Set("BaseURL", this.in)
-		s := &Site{}
+		s := newSiteDefaultLang()
 		s.initializeSiteInfo()
 
 		if s.Info.BaseURL != template.URL(this.expected) {
@@ -93,6 +93,7 @@
 	viper.Set("paginate", 10)
 	s := &Site{
 		Source: &source.InMemorySource{ByteSource: urlFakeSource},
+		Lang:   newDefaultLanguage(),
 	}
 	s.initializeSiteInfo()
 	s.prepTemplates("indexes/blue.html", indexTemplate)
--- a/hugolib/siteinfo_test.go
+++ b/hugolib/siteinfo_test.go
@@ -27,7 +27,7 @@
 	defer viper.Reset()
 
 	viper.Set("Params", map[string]interface{}{"MyGlobalParam": "FOOBAR_PARAM"})
-	s := &Site{}
+	s := newSiteDefaultLang()
 
 	s.initialize()
 	if s.Info.Params["MyGlobalParam"] != "FOOBAR_PARAM" {
@@ -53,7 +53,7 @@
 	defer viper.Reset()
 
 	viper.Set("Permalinks", map[string]interface{}{"section": "/:title"})
-	s := &Site{}
+	s := newSiteDefaultLang()
 
 	s.initialize()
 	permalink := s.Info.Permalinks["section"]
--- a/hugolib/sitemap_test.go
+++ b/hugolib/sitemap_test.go
@@ -17,11 +17,12 @@
 	"bytes"
 	"testing"
 
+	"reflect"
+
 	"github.com/spf13/hugo/helpers"
 	"github.com/spf13/hugo/hugofs"
 	"github.com/spf13/hugo/source"
 	"github.com/spf13/viper"
-	"reflect"
 )
 
 const SITEMAP_TEMPLATE = `<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
@@ -45,6 +46,7 @@
 
 	s := &Site{
 		Source: &source.InMemorySource{ByteSource: weightedSources},
+		Lang:   newDefaultLanguage(),
 	}
 
 	s.initializeSiteInfo()