1
0
mirror of https://github.com/danog/gojekyll.git synced 2024-11-30 08:48:59 +01:00

incremental pt. 1

This commit is contained in:
Oliver Steele 2017-07-25 09:29:38 -04:00
parent de57141230
commit 0b653d6b24
7 changed files with 57 additions and 33 deletions

View File

@ -144,14 +144,16 @@ Muzukashii:
- [x] Directory watch - [x] Directory watch
- [ ] Commands - [ ] Commands
- [x] `build` - [x] `build`
- [x] `--source`, `--destination`, `--drafts`, `--future`, `--unpublished`, `--watch`, `--force_polling` - [x] `--source`, `--destination`, `--drafts`, `--future`, `--unpublished`
- [ ] `--baseurl`, `--config`, `--incremental`, `--lsi` - [x] `--incremental`, `--watch`, `--force_polling`
- [ ] `--baseurl`, `--config`, `--lsi`
- [ ] `--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`, `--force_polling` - [x] `--open-uri`, `--host`, `--port`
- [ ] `--baseurl`, `--config`, `--incremental` - [x] `--incremental`, `watch`, `--force_polling`
- [ ] `--baseurl`, `--config`
- [ ] `--detach`, `--ssl`-* not planned - [ ] `--detach`, `--ssl`-* not planned
- [ ] `doctor`, `import`, `new`, `new-theme` not planned - [ ] `doctor`, `import`, `new`, `new-theme` not planned
- [ ] Windows - [ ] Windows

View File

@ -45,7 +45,7 @@ func buildCommand(site *site.Site) error {
if err != nil { if err != nil {
return err return err
} }
logger.label("Auto-regeneration:", "enabled for %q\n", site.SourceDir()) logger.label("Auto-regeneration:", "enabled for %q", site.SourceDir())
for event := range events { for event := range events {
fmt.Print(event) fmt.Print(event)
} }

View File

@ -48,9 +48,12 @@ func init() {
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').Action(boolVar("verbose", &options.Verbose)).Bool() _ = 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)
// these flags are just present on build and serve, but I don't see a DRY way to say this
app.Flag("incremental", "Enable incremental rebuild.").Short('I').Action(boolVar("incremental", &options.Incremental)).Bool()
app.Flag("force_polling", "Force watch to use polling").BoolVar(&options.ForcePolling)
// --watch has different defaults for build and serve // --watch has different defaults for build and serve
watchText := "Watch for changes and rebuild" watchText := "Watch for changes and rebuild"
build.Flag("watch", watchText).Short('w').BoolVar(&options.Watch) build.Flag("watch", watchText).Short('w').BoolVar(&options.Watch)

View File

@ -107,6 +107,11 @@ type collectionsMap struct {
Collections map[string]map[string]interface{} Collections map[string]map[string]interface{}
} }
// IsConfigPath returns true if its arguments is a site configuration file.
func (c *Config) IsConfigPath(rel string) bool {
return rel == "_config.yml"
}
// SourceDir returns the source directory as an absolute path. // SourceDir returns the source directory as an absolute path.
func (c *Config) SourceDir() string { func (c *Config) SourceDir() string {
return utils.MustAbs(c.Source) return utils.MustAbs(c.Source)

View File

@ -7,17 +7,20 @@ import (
// Flags are applied after the configuration file is loaded. // Flags are applied after the configuration file is loaded.
// They are pointers to represent optional types, to tell whether they have been set. // They are pointers to represent optional types, to tell whether they have been set.
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 leave
// the config file only if // the config file alone if not
Destination, Host *string Destination, Host *string
Drafts, Future, Unpublished, Verbose *bool Drafts, Future, Unpublished *bool
Incremental, 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 make them actual values
DryRun, ForcePolling, Watch bool DryRun, ForcePolling, Watch bool
} }
// ApplyFlags overwrites the configuration with values from flags. // ApplyFlags overwrites the configuration with values from flags.
func (c *Config) ApplyFlags(f Flags) { func (c *Config) ApplyFlags(f Flags) {
// anything you can do I can do meta
rs, rd := reflect.ValueOf(f), reflect.ValueOf(c).Elem() rs, rd := reflect.ValueOf(f), reflect.ValueOf(c).Elem()
rt := rs.Type() rt := rs.Type()
for i, n := 0, rs.NumField(); i < n; i++ { for i, n := 0, rs.NumField(); i < n; i++ {

View File

@ -56,10 +56,27 @@ func (s *Site) processFilesEvent(fileset FilesEvent, messages chan<- interface{}
return r return r
} }
// reloads and rebuilds the site; returns a copy and count
func (s *Site) rebuild(paths []string) (*Site, int, error) {
if s.requiresFullReload(paths) {
r, err := s.Reloaded(paths)
if err != nil {
return nil, 0, err
}
n, err := r.Build()
return r, n, err
}
return s, 0, nil
}
func (s *Site) requiresFullReload(paths []string) bool { func (s *Site) requiresFullReload(paths []string) bool {
for _, path := range paths { for _, path := range paths {
switch { switch {
case path == "_config.yml": case s.config.IsConfigPath(path):
return true
case s.Exclude(path):
return false
case !s.config.Incremental:
return true return true
case strings.HasPrefix(path, s.config.DataDir): case strings.HasPrefix(path, s.config.DataDir):
return true return true
@ -70,29 +87,23 @@ func (s *Site) requiresFullReload(paths []string) bool {
return false return false
} }
// 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 // relativize and de-dup filenames, and filter to those that affect the build
func (s *Site) sitePaths(filenames []string) []string { func (s *Site) affectsBuildFilter(filenames []string) []string {
var ( var (
paths = make([]string, 0, len(filenames)) result = make([]string, 0, len(filenames))
seen = map[string]bool{} seen = map[string]bool{}
) )
loop:
for _, path := range filenames { for _, path := range filenames {
if path == "_config.yml" || !s.Exclude(path) { switch {
if !seen[path] { case s.config.IsConfigPath(path):
case s.Exclude(path):
continue loop
case seen[path]:
continue loop
}
seen[path] = true seen[path] = true
paths = append(paths, path) result = append(result, path)
} }
} return result
}
return paths
} }

View File

@ -37,7 +37,7 @@ func (s *Site) WatchFiles() (<-chan FilesEvent, error) {
) )
go func() { go func() {
for { for {
paths := s.sitePaths(<-debounced) paths := s.affectsBuildFilter(<-debounced)
if len(paths) > 0 { if len(paths) > 0 {
// Create 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.