Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/gohugoio/hugo.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEgon Elbre <egonelbre@gmail.com>2013-12-15 19:19:22 +0400
committerspf13 <steve.francia@gmail.com>2013-12-28 22:46:52 +0400
commit8d80f9b39e42dd5b61af052979a7c04dc8edf851 (patch)
tree89c1474782e3a3bca03a76c88081d21c5e6f3ce6
parent1979f7d9c7d047340c9205f0d3e6d8393d498f9c (diff)
Added batching behavior for page building.
Quite often file watcher gets many changes and each change triggered a build. One build per second should be sufficient. Also added tracking for new folders.
-rw-r--r--commands/hugo.go78
-rw-r--r--watcher/batcher.go56
2 files changed, 103 insertions, 31 deletions
diff --git a/commands/hugo.go b/commands/hugo.go
index 8cfbc734f..ee1d6f27a 100644
--- a/commands/hugo.go
+++ b/commands/hugo.go
@@ -15,11 +15,11 @@ package commands
import (
"fmt"
- "github.com/howeyc/fsnotify"
"github.com/mostafah/fsync"
"github.com/spf13/cobra"
"github.com/spf13/hugo/hugolib"
"github.com/spf13/hugo/utils"
+ "github.com/spf13/hugo/watcher"
"github.com/spf13/nitro"
"os"
"path/filepath"
@@ -155,7 +155,7 @@ func buildSite(watching ...bool) (err error) {
}
func NewWatcher(port int) error {
- watcher, err := fsnotify.NewWatcher()
+ watcher, err := watcher.New(1 * time.Second)
var wg sync.WaitGroup
if err != nil {
@@ -166,15 +166,56 @@ func NewWatcher(port int) error {
defer watcher.Close()
wg.Add(1)
+
+ for _, d := range getDirList() {
+ if d != "" {
+ _ = watcher.Watch(d)
+ }
+ }
+
go func() {
for {
select {
- case ev := <-watcher.Event:
+ case evs := <-watcher.Event:
if Verbose {
- fmt.Println(ev)
+ fmt.Println(evs)
+ }
+
+ static_changed := false
+ dynamic_changed := false
+
+ for _, ev := range evs {
+ ext := filepath.Ext(ev.Name)
+ istemp := strings.HasSuffix(ext, "~") || (ext == ".swp") || (ext == ".tmp")
+ if istemp {
+ continue
+ }
+ // renames are always followed with Create/Modify
+ if ev.IsRename() {
+ continue
+ }
+
+ isstatic := strings.HasPrefix(ev.Name, Config.GetAbsPath(Config.StaticDir))
+ static_changed = static_changed || isstatic
+ dynamic_changed = dynamic_changed || !isstatic
+
+ // add new directory to watch list
+ if s, err := os.Stat(ev.Name); err == nil && s.Mode().IsDir() {
+ if ev.IsCreate() {
+ watcher.Watch(ev.Name)
+ }
+ }
+ }
+
+ if static_changed {
+ fmt.Println("Static file changed, syncing\n")
+ utils.CheckErr(copyStatic(), fmt.Sprintf("Error copying static files to %s", Config.GetAbsPath(Config.PublishDir)))
+ }
+
+ if dynamic_changed {
+ fmt.Println("Change detected, rebuilding site\n")
+ utils.StopOnErr(buildSite(true))
}
- watchChange(ev)
- // TODO add newly created directories to the watch list
case err := <-watcher.Error:
if err != nil {
fmt.Println("error:", err)
@@ -183,12 +224,6 @@ func NewWatcher(port int) error {
}
}()
- for _, d := range getDirList() {
- if d != "" {
- _ = watcher.Watch(d)
- }
- }
-
if port > 0 {
go serve(port)
}
@@ -196,22 +231,3 @@ func NewWatcher(port int) error {
wg.Wait()
return nil
}
-
-func watchChange(ev *fsnotify.FileEvent) {
- ext := filepath.Ext(ev.Name)
- // ignore temp files
- istemp := strings.HasSuffix(ext, "~") || (ext == ".swp") || (ext == ".tmp")
- if istemp {
- return
- }
-
- if strings.HasPrefix(ev.Name, Config.GetAbsPath(Config.StaticDir)) {
- fmt.Println("Static file changed, syncing\n")
- utils.CheckErr(copyStatic(), fmt.Sprintf("Error copying static files to %s", Config.GetAbsPath(Config.PublishDir)))
- } else {
- if !ev.IsRename() { // Rename is always accompanied by a create or modify
- fmt.Println("Change detected, rebuilding site\n")
- utils.StopOnErr(buildSite(true))
- }
- }
-}
diff --git a/watcher/batcher.go b/watcher/batcher.go
new file mode 100644
index 000000000..a22ad8b41
--- /dev/null
+++ b/watcher/batcher.go
@@ -0,0 +1,56 @@
+package watcher
+
+import (
+ "github.com/howeyc/fsnotify"
+ "time"
+)
+
+type Batcher struct {
+ *fsnotify.Watcher
+ interval time.Duration
+ done chan struct{}
+
+ Event chan []*fsnotify.FileEvent // Events are returned on this channel
+}
+
+func New(interval time.Duration) (*Batcher, error) {
+ watcher, err := fsnotify.NewWatcher()
+
+ batcher := &Batcher{}
+ batcher.Watcher = watcher
+ batcher.interval = interval
+ batcher.done = make(chan struct{}, 1)
+ batcher.Event = make(chan []*fsnotify.FileEvent, 1)
+
+ if err == nil {
+ go batcher.run()
+ }
+
+ return batcher, err
+}
+
+func (b *Batcher) run() {
+ tick := time.Tick(b.interval)
+ evs := make([]*fsnotify.FileEvent, 0)
+OuterLoop:
+ for {
+ select {
+ case ev := <-b.Watcher.Event:
+ evs = append(evs, ev)
+ case <-tick:
+ if len(evs) == 0 {
+ continue
+ }
+ b.Event <- evs
+ evs = make([]*fsnotify.FileEvent, 0)
+ case <-b.done:
+ break OuterLoop
+ }
+ }
+ close(b.done)
+}
+
+func (b *Batcher) Close() {
+ b.done <- struct{}{}
+ b.Watcher.Close()
+}