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