1
0
mirror of https://github.com/danog/gojekyll.git synced 2024-11-27 02:44:39 +01:00
This commit is contained in:
Oliver Steele 2017-07-25 08:57:32 -04:00
parent 20a6e9c906
commit 8074f69215
2 changed files with 75 additions and 70 deletions

70
site/rebuild.go Normal file
View File

@ -0,0 +1,70 @@
package site
import (
"fmt"
"os"
"time"
)
// WatchRebuild watches the site directory. Each time a file changes, it
// rebuilds the site. It sends status messages (strings) and errors to its output
// channel.
//
// TODO use a logger instead of a message channel?
func (s *Site) WatchRebuild() (<-chan interface{}, error) {
var (
messages = make(chan interface{})
filesets, err = s.WatchFiles()
)
if err != nil {
return nil, err
}
go func() {
for fileset := range filesets {
s = s.processFilesEvent(fileset, messages)
}
}()
return messages, nil
}
func (s *Site) processFilesEvent(fileset FilesEvent, messages chan<- interface{}) *Site {
// similar code to server.reload
messages <- fmt.Sprintf("Regenerating: %s...", fileset)
start := time.Now()
r, count, err := s.rebuild(fileset.Paths)
if err != nil {
fmt.Println()
fmt.Fprintln(os.Stderr, err)
return s
}
elapsed := time.Since(start)
messages <- fmt.Sprintf("wrote %d files in %.2fs.\n", count, elapsed.Seconds())
return r
}
// reloads and rebuilds the site; returns a copy and count
func (s *Site) rebuild(paths []string) (r *Site, n int, err error) {
r, err = s.Reloaded(paths)
if err != nil {
return
}
n, err = r.Build()
return
}
// relativize and de-dup filenames, and filter to those that affect the build
func (s *Site) sitePaths(filenames []string) []string {
var (
paths = make([]string, 0, len(filenames))
seen = map[string]bool{}
)
for _, path := range filenames {
if path == "_config.yml" || !s.Exclude(path) {
if !seen[path] {
seen[path] = true
paths = append(paths, path)
}
}
}
return paths
}

View File

@ -5,7 +5,6 @@ import (
"log" "log"
"os" "os"
"path/filepath" "path/filepath"
"sync"
"time" "time"
"github.com/fsnotify/fsnotify" "github.com/fsnotify/fsnotify"
@ -26,7 +25,7 @@ func (e FilesEvent) String() string {
return fmt.Sprintf("%d file%s changed at %s", count, inflect, e.Time.Format("3:04:05PM")) return fmt.Sprintf("%d file%s changed at %s", count, inflect, e.Time.Format("3:04:05PM"))
} }
// WatchFiles sends FilesEvent on changes within the site directory. // WatchFiles returns a channel that receives FilesEvent on changes within the site directory.
func (s *Site) WatchFiles() (<-chan FilesEvent, error) { func (s *Site) WatchFiles() (<-chan FilesEvent, error) {
filenames, err := s.makeFileWatcher() filenames, err := s.makeFileWatcher()
if err != nil { if err != nil {
@ -49,41 +48,11 @@ func (s *Site) WatchFiles() (<-chan FilesEvent, error) {
return filesets, nil return filesets, nil
} }
// WatchRebuild watches the directory. Each time a file changes, it func (s *Site) makeFileWatcher() (<-chan string, error) {
// rebuilds the site. It sends status messages and error to its output if s.config.ForcePolling {
// channel. return s.makePollingWatcher()
func (s *Site) WatchRebuild() (<-chan interface{}, error) {
var (
mu sync.Mutex
events = make(chan interface{})
changes, err = s.WatchFiles()
)
if err != nil {
return nil, err
} }
go func(rebuild func(FilesEvent)) { return s.makeEventWatcher()
for change := range changes {
rebuild(change)
}
}(func(change FilesEvent) {
mu.Lock()
defer mu.Unlock()
// similar code to server.reload
events <- fmt.Sprintf("Regenerating: %s...", change)
start := time.Now()
r, count, err := s.rebuild(change.Paths)
if err != nil {
fmt.Println()
fmt.Fprintln(os.Stderr, err)
return
}
// use the new site value the next time
s = r
elapsed := time.Since(start)
events <- fmt.Sprintf("wrote %d files in %.2fs.\n", count, elapsed.Seconds())
})
return events, nil
} }
func (s *Site) makePollingWatcher() (<-chan string, error) { func (s *Site) makePollingWatcher() (<-chan string, error) {
@ -145,40 +114,6 @@ func (s *Site) makeEventWatcher() (<-chan string, error) {
return filenames, w.Add(sourceDir) return filenames, w.Add(sourceDir)
} }
func (s *Site) makeFileWatcher() (<-chan string, error) {
if s.config.ForcePolling {
return s.makePollingWatcher()
}
return s.makeEventWatcher()
}
// reloads and rebuilds the site; returns a copy and count
func (s *Site) rebuild(paths []string) (r *Site, n int, err error) {
r, err = s.Reloaded(paths)
if err != nil {
return
}
n, err = r.Build()
return
}
// relativize and de-dup filenames, and filter to those that affect the build
func (s *Site) sitePaths(filenames []string) []string {
var (
paths = make([]string, 0, len(filenames))
seen = map[string]bool{}
)
for _, path := range filenames {
if path == "_config.yml" || !s.Exclude(path) {
if !seen[path] {
seen[path] = true
paths = append(paths, path)
}
}
}
return paths
}
// debounce relays values from input to output, merging successive values so long as they keep changing // debounce relays values from input to output, merging successive values so long as they keep changing
// faster than interval // faster than interval
// TODO consider https://github.com/ReactiveX/RxGo // TODO consider https://github.com/ReactiveX/RxGo