mirror of
https://github.com/danog/gojekyll.git
synced 2024-11-26 22:24:39 +01:00
Implement --force_polling
This commit is contained in:
parent
b563633b62
commit
49a8520b76
@ -146,13 +146,13 @@ Muzukashii:
|
||||
- [x] Directory watch
|
||||
- [ ] Commands
|
||||
- [x] `build`
|
||||
- [x] `--source`, `--destination`, `--drafts`, `--future`, `--unpublished`, `--watch`
|
||||
- [x] `--source`, `--destination`, `--drafts`, `--future`, `--unpublished`, `--watch`, `--force_polling`
|
||||
- [ ] `--baseurl`, `--config`, `--incremental`, `--lsi`
|
||||
- [ ] `--force_polling`, `--limit-posts`, `JEKYLL_ENV=production` – not planned
|
||||
- [ ] `--limit-posts`, `JEKYLL_ENV=production` – not planned
|
||||
- [x] `clean`
|
||||
- [x] `help`
|
||||
- [x] `serve`
|
||||
- [x] `--open-uri`, `--host`, `--port`, `–watch` (enabled by default)
|
||||
- [x] `--open-uri`, `--host`, `--port`, `–watch`, `--force_polling`
|
||||
- [ ] `--baseurl`, `--config`, `--incremental`
|
||||
- [ ] `--detach`, `--ssl`-* – not planned
|
||||
- [ ] `doctor`, `import`, `new`, `new-theme` – not planned
|
||||
|
@ -47,7 +47,8 @@ func init() {
|
||||
app.HelpFlag.Short('h')
|
||||
app.Flag("profile", "Create a Go pprof CPU profile").BoolVar(&profile)
|
||||
app.Flag("quiet", "Silence (some) output.").Short('q').BoolVar(&quiet)
|
||||
app.Flag("verbose", "Print verbose output.").Short('V').BoolVar(&options.Verbose)
|
||||
_ = app.Flag("verbose", "Print verbose output.").Short('V').Action(boolVar("verbose", &options.Verbose)).Bool()
|
||||
app.Flag("force_polling", "Force watch to use polling").BoolVar(&options.ForcePolling)
|
||||
build.Flag("dry-run", "Dry run").Short('n').BoolVar(&options.DryRun)
|
||||
|
||||
// --watch has different defaults for build and serve
|
||||
|
@ -23,7 +23,8 @@ func ParseAndRun(args []string) error {
|
||||
options.Destination = &dest
|
||||
}
|
||||
if options.DryRun {
|
||||
options.Verbose = true
|
||||
verbose := true
|
||||
options.Verbose = &verbose
|
||||
}
|
||||
return run(cmd)
|
||||
}
|
||||
|
@ -36,6 +36,9 @@ type Config struct {
|
||||
// Plugins
|
||||
ExcerptSeparator string `yaml:"excerpt_separator"`
|
||||
|
||||
// Conversion
|
||||
Incremental bool
|
||||
|
||||
// Serving
|
||||
Host string
|
||||
Port int
|
||||
@ -44,12 +47,14 @@ type Config struct {
|
||||
|
||||
// Outputting
|
||||
Permalink string
|
||||
Timezone string
|
||||
Timezone string
|
||||
|
||||
Verbose bool
|
||||
|
||||
// CLI-only
|
||||
DryRun bool `yaml:"-"`
|
||||
Verbose bool `yaml:"-"`
|
||||
Watch bool `yaml:"-"`
|
||||
DryRun bool `yaml:"-"`
|
||||
ForcePolling bool `yaml:"-"`
|
||||
Watch bool `yaml:"-"`
|
||||
|
||||
Defaults []struct {
|
||||
Scope struct {
|
||||
|
@ -46,6 +46,7 @@ plugins: []
|
||||
|
||||
# Conversion
|
||||
excerpt_separator: "\n\n"
|
||||
incremental: false
|
||||
|
||||
# Serving
|
||||
detach: false
|
||||
@ -57,4 +58,6 @@ baseurl: "" # does not include hostname
|
||||
permalink: date
|
||||
paginate_path: /page:num
|
||||
timezone: null
|
||||
|
||||
verbose: false
|
||||
`
|
||||
|
@ -9,11 +9,11 @@ import (
|
||||
type Flags struct {
|
||||
// these are pointers so we can tell whether they've been set, and override
|
||||
// the config file only if
|
||||
Destination, Host *string
|
||||
Drafts, Future, Unpublished *bool
|
||||
Port *int
|
||||
Destination, Host *string
|
||||
Drafts, Future, Unpublished, Verbose *bool
|
||||
Port *int
|
||||
// these aren't in the config file, so they can be treated more conventionally
|
||||
DryRun, Verbose, Watch bool
|
||||
DryRun, ForcePolling, Watch bool
|
||||
}
|
||||
|
||||
// ApplyFlags overwrites the configuration with values from flags.
|
||||
|
@ -1,7 +1,6 @@
|
||||
package site
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@ -54,7 +53,6 @@ func (s *Site) Read() error {
|
||||
// Reloaded returns a new site read the same source directory, configuration file, and load flags.
|
||||
func (s *Site) Reloaded(paths []string) (*Site, error) {
|
||||
if s.requiresFullReload(paths) {
|
||||
fmt.Println("reload everything")
|
||||
copy, err := FromDirectory(s.SourceDir(), s.flags)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
100
site/watch.go
100
site/watch.go
@ -2,12 +2,15 @@ package site
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/fsnotify/fsnotify"
|
||||
"github.com/osteele/gojekyll/utils"
|
||||
"github.com/radovskyb/watcher"
|
||||
)
|
||||
|
||||
// FilesEvent is a list of changed or added site source files, with a single
|
||||
@ -23,31 +26,9 @@ func (e FilesEvent) String() string {
|
||||
return fmt.Sprintf("%d file%s changed at %s", count, inflect, e.Time.Format("3:04:05PM"))
|
||||
}
|
||||
|
||||
func (s *Site) makeEventWatcher() (<-chan string, error) {
|
||||
var (
|
||||
sourceDir = s.SourceDir()
|
||||
filenames = make(chan string, 100)
|
||||
w, err = fsnotify.NewWatcher()
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case event := <-w.Events:
|
||||
filenames <- utils.MustRel(sourceDir, event.Name)
|
||||
case err := <-w.Errors:
|
||||
fmt.Fprintln(os.Stderr, "error:", err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
return filenames, w.Add(sourceDir)
|
||||
}
|
||||
|
||||
// WatchFiles sends FilesEvent on changes within the site directory.
|
||||
func (s *Site) WatchFiles() (<-chan FilesEvent, error) {
|
||||
filenames, err := s.makeEventWatcher()
|
||||
filenames, err := s.makeFileWatcher()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -59,7 +40,7 @@ func (s *Site) WatchFiles() (<-chan FilesEvent, error) {
|
||||
for {
|
||||
paths := s.sitePaths(<-debounced)
|
||||
if len(paths) > 0 {
|
||||
// Make up a new timestamp. Except under pathological
|
||||
// Create a new timestamp. Except under pathological
|
||||
// circumstances, it will be close enough.
|
||||
filesets <- FilesEvent{time.Now(), paths}
|
||||
}
|
||||
@ -105,6 +86,72 @@ func (s *Site) WatchRebuild() (<-chan interface{}, error) {
|
||||
return events, nil
|
||||
}
|
||||
|
||||
func (s *Site) makePollingWatcher() (<-chan string, error) {
|
||||
var (
|
||||
sourceDir = utils.MustAbs(s.SourceDir())
|
||||
filenames = make(chan string, 100)
|
||||
w = watcher.New()
|
||||
)
|
||||
if err := w.AddRecursive(sourceDir); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, path := range s.config.Exclude {
|
||||
if err := w.Ignore(filepath.Join(sourceDir, path)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if err := w.Ignore(s.DestDir()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case event := <-w.Event:
|
||||
filenames <- utils.MustRel(sourceDir, event.Path)
|
||||
case err := <-w.Error:
|
||||
fmt.Fprintln(os.Stderr, "error:", err)
|
||||
case <-w.Closed:
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
go func() {
|
||||
if err := w.Start(time.Millisecond * 250); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}()
|
||||
return filenames, nil
|
||||
}
|
||||
|
||||
func (s *Site) makeEventWatcher() (<-chan string, error) {
|
||||
var (
|
||||
sourceDir = s.SourceDir()
|
||||
filenames = make(chan string, 100)
|
||||
w, err = fsnotify.NewWatcher()
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case event := <-w.Events:
|
||||
filenames <- utils.MustRel(sourceDir, event.Name)
|
||||
case err := <-w.Errors:
|
||||
fmt.Fprintln(os.Stderr, "error:", err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
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)
|
||||
@ -136,15 +183,18 @@ func (s *Site) sitePaths(filenames []string) []string {
|
||||
// faster than interval
|
||||
// TODO consider https://github.com/ReactiveX/RxGo
|
||||
func debounce(interval time.Duration, input <-chan string) <-chan []string {
|
||||
output := make(chan []string)
|
||||
var (
|
||||
pending = []string{}
|
||||
output = make(chan []string)
|
||||
ticker <-chan time.Time
|
||||
)
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case value := <-input:
|
||||
if value == "." {
|
||||
continue
|
||||
}
|
||||
pending = append(pending, value)
|
||||
ticker = time.After(interval) // replaces the previous ticker
|
||||
case <-ticker:
|
||||
|
Loading…
Reference in New Issue
Block a user