ref: 88972b0d5b62861128f101256027a52ab48eae86
parent: 640b8bed21eabfd6e256814eab4b3ab3ad2e3354
author: Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
date: Thu Nov 10 15:55:52 EST 2016
node to page: Refactor the build process To make it easier to follow and understand. Both building and rebuilding now follow a four step flow: 1. Init 2. Process 3. Assemble 4. Render And now there are only one Build method, used for both builds and rebuilds. Updates #2297
--- a/commands/hugo.go
+++ b/commands/hugo.go
@@ -670,7 +670,7 @@
if err := initSites(); err != nil {return err
}
- return Hugo.Rebuild(hugolib.BuildCfg{PrintStats: !quiet, Watching: true}, events...)+ return Hugo.Build(hugolib.BuildCfg{PrintStats: !quiet, Watching: true}, events...)}
// NewWatcher creates a new watcher to watch filesystem events.
--- a/hugolib/hugo_sites.go
+++ b/hugolib/hugo_sites.go
@@ -14,7 +14,6 @@
package hugolib
import (
- "errors"
"fmt"
"html/template"
"os"
@@ -21,7 +20,6 @@
"path"
"strings"
"sync"
- "time"
"github.com/spf13/hugo/helpers"
@@ -28,7 +26,6 @@
"github.com/spf13/viper"
"github.com/bep/inflect"
- "github.com/fsnotify/fsnotify"
"github.com/spf13/hugo/source"
"github.com/spf13/hugo/tpl"
jww "github.com/spf13/jwalterweatherman"
@@ -109,7 +106,7 @@
tpl.ResetCaches()
}
-func (h *HugoSites) reCreateFromConfig() error {+func (h *HugoSites) createSitesFromConfig() error {sites, err := createSitesFromConfig()
@@ -158,191 +155,10 @@
// Use this to add templates to use for rendering.
// Useful for testing.
withTemplate func(templ tpl.Template) error
+ // Use this to indicate what changed (for rebuilds).
+ whatChanged *whatChanged
}
-// Build builds all sites.
-func (h *HugoSites) Build(config BuildCfg) error {-
- t0 := time.Now()
-
- // TODO(bep) np init page collections
- for _, s := range h.Sites {- if s.PageCollections == nil {- s.PageCollections = newPageCollections()
- }
- }
-
- if config.ResetState {- h.reset()
- }
-
- if config.CreateSitesFromConfig {- if err := h.reCreateFromConfig(); err != nil {- return err
- }
- }
-
- h.runMode.Watching = config.Watching
-
- // We should probably refactor the Site and pull up most of the logic from there to here,
- // but that seems like a daunting task.
- // So for now, if there are more than one site (language),
- // we pre-process the first one, then configure all the sites based on that.
- firstSite := h.Sites[0]
-
- if err := firstSite.preProcess(config); err != nil {- return err
- }
-
- h.setupTranslations()
-
- if len(h.Sites) > 1 {- // Initialize the rest
- for _, site := range h.Sites[1:] {- site.initializeSiteInfo()
- }
- }
-
- // TODO(bep) make a more logical grouping of these.
- h.assembleGitInfo()
-
- for _, s := range h.Sites {- if err := s.postProcess(); err != nil {- return err
- }
- }
-
- // TODO(bep) np createMissingNodes needs taxonomies and sections
- if err := h.createMissingNodes(); err != nil {- return err
- }
-
- for _, s := range h.Sites {- // TODO(bep) np Needed by all who use .Pages, .AllPages, .indexPages
- s.refreshPageCaches()
- s.setupPrevNext()
- }
-
- if err := h.assignMissingTranslations(); err != nil {- return err
- }
-
- if err := h.preRender(config, whatChanged{source: true, other: true}); err != nil {- return err
- }
-
- if !config.SkipRender {- for _, s := range h.Sites {-
- if err := s.render(); err != nil {- return err
- }
-
- if config.PrintStats {- s.Stats()
- }
- }
-
- if err := h.render(); err != nil {- return err
- }
- }
-
- if config.PrintStats {- jww.FEEDBACK.Printf("total in %v ms\n", int(1000*time.Since(t0).Seconds()))- }
-
- return nil
-
-}
-
-// Rebuild rebuilds all sites.
-func (h *HugoSites) Rebuild(config BuildCfg, events ...fsnotify.Event) error {- t0 := time.Now()
-
- if config.CreateSitesFromConfig {- return errors.New("Rebuild does not support 'CreateSitesFromConfig'. Use Build.")- }
-
- if config.ResetState {- return errors.New("Rebuild does not support 'ResetState'. Use Build.")- }
-
- if !config.Watching {- return errors.New("Rebuild called when not in watch mode")- }
-
- h.runMode.Watching = config.Watching
-
- firstSite := h.Sites[0]
-
- for _, s := range h.Sites {- s.resetBuildState()
- }
-
- helpers.InitLoggers()
-
- changed, err := firstSite.reBuild(events)
-
- if err != nil {- return err
- }
-
- // Assign pages to sites per translation.
- h.setupTranslations()
-
- if changed.source {- h.assembleGitInfo()
- for _, s := range h.Sites {- if err := s.postProcess(); err != nil {- return err
- }
- }
-
- }
-
- // TODO(bep) np consolidate the build lifecycle methods
- // See also the regular Build() method, and check vs. the changed.source
- if err := h.createMissingNodes(); err != nil {- return err
- }
-
- for _, s := range h.Sites {- s.refreshPageCaches()
- s.setupPrevNext()
- }
-
- if err := h.assignMissingTranslations(); err != nil {- return err
- }
-
- if err := h.preRender(config, changed); err != nil {- return err
- }
-
- if !config.SkipRender {- for _, s := range h.Sites {- if err := s.render(); err != nil {- return err
- }
- if config.PrintStats {- s.Stats()
- }
- }
-
- if err := h.render(); err != nil {- return err
- }
- }
-
- if config.PrintStats {- jww.FEEDBACK.Printf("total in %v ms\n", int(1000*time.Since(t0).Seconds()))- }
-
- return nil
-
-}
-
// Analyze prints a build report to Stdout.
// Useful for debugging.
func (h *HugoSites) Analyze() error {@@ -353,8 +169,7 @@
return s.ShowPlan(os.Stdout)
}
-// Render the cross-site artifacts.
-func (h *HugoSites) render() error {+func (h *HugoSites) renderCrossSitesArtifacts() error { if !h.multilingual.enabled() {return nil
@@ -494,6 +309,7 @@
return nil
}
+// TODO(bep) np move
// Move the new* methods after cleanup in site.go
func (s *Site) newNodePage(typ NodeType) *Page { return &Page{--- /dev/null
+++ b/hugolib/hugo_sites_build.go
@@ -1,0 +1,197 @@
+// Copyright 2016-present 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 (
+ "time"
+
+ "errors"
+
+ "github.com/fsnotify/fsnotify"
+ "github.com/spf13/hugo/helpers"
+ jww "github.com/spf13/jwalterweatherman"
+)
+
+// Build builds all sites. If filesystem events are provided,
+// this is considered to be a potential partial rebuild.
+func (h *HugoSites) Build(config BuildCfg, events ...fsnotify.Event) error {+ t0 := time.Now()
+
+ // Need a pointer as this may be modified.
+ conf := &config
+
+ if conf.whatChanged == nil {+ // Assume everything has changed
+ conf.whatChanged = &whatChanged{source: true, other: true}+ }
+
+ if len(events) > 0 {+ // Rebuild
+ if err := h.initRebuild(conf); err != nil {+ return err
+ }
+ } else {+ if err := h.init(conf); err != nil {+ return err
+ }
+ }
+
+ if err := h.process(conf, events...); err != nil {+ return err
+ }
+
+ if err := h.assemble(conf); err != nil {+ return err
+ }
+
+ if err := h.render(conf); err != nil {+ return err
+ }
+
+ if config.PrintStats {+ jww.FEEDBACK.Printf("total in %v ms\n", int(1000*time.Since(t0).Seconds()))+ }
+
+ return nil
+
+}
+
+// Build lifecycle methods below.
+// The order listed matches the order of execution.
+
+func (h *HugoSites) init(config *BuildCfg) error {+
+ for _, s := range h.Sites {+ if s.PageCollections == nil {+ s.PageCollections = newPageCollections()
+ }
+ }
+
+ if config.ResetState {+ h.reset()
+ }
+
+ if config.CreateSitesFromConfig {+ if err := h.createSitesFromConfig(); err != nil {+ return err
+ }
+ }
+
+ h.runMode.Watching = config.Watching
+
+ return nil
+}
+
+func (h *HugoSites) initRebuild(config *BuildCfg) error {+ if config.CreateSitesFromConfig {+ return errors.New("Rebuild does not support 'CreateSitesFromConfig'.")+ }
+
+ if config.ResetState {+ return errors.New("Rebuild does not support 'ResetState'.")+ }
+
+ if !config.Watching {+ return errors.New("Rebuild called when not in watch mode")+ }
+
+ h.runMode.Watching = config.Watching
+
+ for _, s := range h.Sites {+ s.resetBuildState()
+ }
+
+ helpers.InitLoggers()
+
+ return nil
+}
+
+func (h *HugoSites) process(config *BuildCfg, events ...fsnotify.Event) error {+ // We should probably refactor the Site and pull up most of the logic from there to here,
+ // but that seems like a daunting task.
+ // So for now, if there are more than one site (language),
+ // we pre-process the first one, then configure all the sites based on that.
+ firstSite := h.Sites[0]
+
+ if len(events) > 0 {+ // This is a rebuild
+ changed, err := firstSite.reProcess(events)
+ config.whatChanged = &changed
+ return err
+ }
+
+ return firstSite.process(*config)
+
+}
+
+func (h *HugoSites) assemble(config *BuildCfg) error {+ // TODO(bep) np we could probably wait and do this in one go later
+ h.setupTranslations()
+
+ if len(h.Sites) > 1 {+ // The first is initialized during process; initialize the rest
+ for _, site := range h.Sites[1:] {+ site.initializeSiteInfo()
+ }
+ }
+
+ if config.whatChanged.source {+ h.assembleGitInfo()
+
+ for _, s := range h.Sites {+ if err := s.buildSiteMeta(); err != nil {+ return err
+ }
+ }
+ }
+
+ if err := h.createMissingNodes(); err != nil {+ return err
+ }
+
+ for _, s := range h.Sites {+ s.refreshPageCaches()
+ s.setupPrevNext()
+ }
+
+ if err := h.assignMissingTranslations(); err != nil {+ return err
+ }
+
+ if err := h.preRender(*config, whatChanged{source: true, other: true}); err != nil {+ return err
+ }
+
+ return nil
+}
+
+func (h *HugoSites) render(config *BuildCfg) error {+ if !config.SkipRender {+ for _, s := range h.Sites {+ if err := s.render(); err != nil {+ return err
+ }
+
+ if config.PrintStats {+ s.Stats()
+ }
+ }
+
+ if err := h.renderCrossSitesArtifacts(); err != nil {+ return err
+ }
+ }
+
+ return nil
+}
--- a/hugolib/hugo_sites_test.go
+++ b/hugolib/hugo_sites_test.go
@@ -543,7 +543,8 @@
if this.preFunc != nil {this.preFunc(t)
}
- err = sites.Rebuild(cfg, this.events...)
+
+ err = sites.Build(cfg, this.events...)
if err != nil { t.Fatalf("[%d] Failed to rebuild sites: %s", i, err)--- a/hugolib/site.go
+++ b/hugolib/site.go
@@ -482,7 +482,7 @@
// reBuild partially rebuilds a site given the filesystem events.
// It returns whetever the content source was changed.
-func (s *Site) reBuild(events []fsnotify.Event) (whatChanged, error) {+func (s *Site) reProcess(events []fsnotify.Event) (whatChanged, error) { jww.DEBUG.Printf("Rebuild for events %q", events)@@ -763,7 +763,7 @@
return err
}
-func (s *Site) preProcess(config BuildCfg) (err error) {+func (s *Site) process(config BuildCfg) (err error) { s.timerStep("Go initialization") if err = s.initialize(); err != nil {return
@@ -785,16 +785,6 @@
}
-func (s *Site) postProcess() (err error) {-
- if err = s.buildSiteMeta(); err != nil {- return
- }
-
- s.timerStep("build taxonomies")- return
-}
-
func (s *Site) setupPrevNext() { for i, page := range s.Pages { if i < len(s.Pages)-1 {@@ -1333,6 +1323,7 @@
}
func (s *Site) buildSiteMeta() (err error) {+ defer s.timerStep("build Site meta")s.assembleMenus()
--
⑨