From 0b653d6b2403e043e1ac7895296ccf16b0f6f8bb Mon Sep 17 00:00:00 2001 From: Oliver Steele Date: Tue, 25 Jul 2017 09:29:38 -0400 Subject: [PATCH] incremental pt. 1 --- README.md | 10 +++++---- commands/commands.go | 2 +- commands/flags.go | 5 ++++- config/config.go | 5 +++++ config/flags.go | 15 +++++++------ site/rebuild.go | 51 +++++++++++++++++++++++++++----------------- site/watch.go | 2 +- 7 files changed, 57 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 5e1f684..4876432 100644 --- a/README.md +++ b/README.md @@ -144,14 +144,16 @@ Muzukashii: - [x] Directory watch - [ ] Commands - [x] `build` - - [x] `--source`, `--destination`, `--drafts`, `--future`, `--unpublished`, `--watch`, `--force_polling` - - [ ] `--baseurl`, `--config`, `--incremental`, `--lsi` + - [x] `--source`, `--destination`, `--drafts`, `--future`, `--unpublished` + - [x] `--incremental`, `--watch`, `--force_polling` + - [ ] `--baseurl`, `--config`, `--lsi` - [ ] `--limit-posts`, `JEKYLL_ENV=production` – not planned - [x] `clean` - [x] `help` - [x] `serve` - - [x] `--open-uri`, `--host`, `--port`, `–watch`, `--force_polling` - - [ ] `--baseurl`, `--config`, `--incremental` + - [x] `--open-uri`, `--host`, `--port` + - [x] `--incremental`, `–watch`, `--force_polling` + - [ ] `--baseurl`, `--config` - [ ] `--detach`, `--ssl`-* – not planned - [ ] `doctor`, `import`, `new`, `new-theme` – not planned - [ ] Windows diff --git a/commands/commands.go b/commands/commands.go index 0892ebf..3fd913f 100644 --- a/commands/commands.go +++ b/commands/commands.go @@ -45,7 +45,7 @@ func buildCommand(site *site.Site) error { if err != nil { 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 { fmt.Print(event) } diff --git a/commands/flags.go b/commands/flags.go index 06a9a72..78019e2 100644 --- a/commands/flags.go +++ b/commands/flags.go @@ -48,9 +48,12 @@ func init() { 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').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) + // 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 watchText := "Watch for changes and rebuild" build.Flag("watch", watchText).Short('w').BoolVar(&options.Watch) diff --git a/config/config.go b/config/config.go index a0eab91..e836d47 100644 --- a/config/config.go +++ b/config/config.go @@ -107,6 +107,11 @@ type collectionsMap struct { 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. func (c *Config) SourceDir() string { return utils.MustAbs(c.Source) diff --git a/config/flags.go b/config/flags.go index 640c304..0d330be 100644 --- a/config/flags.go +++ b/config/flags.go @@ -7,17 +7,20 @@ import ( // Flags are applied after the configuration file is loaded. // They are pointers to represent optional types, to tell whether they have been set. 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, Verbose *bool - Port *int - // these aren't in the config file, so they can be treated more conventionally + // these are pointers so we can tell whether they've been set, and leave + // the config file alone if not + Destination, Host *string + Drafts, Future, Unpublished *bool + Incremental, Verbose *bool + Port *int + + // these aren't in the config file, so make them actual values DryRun, ForcePolling, Watch bool } // ApplyFlags overwrites the configuration with values from flags. func (c *Config) ApplyFlags(f Flags) { + // anything you can do I can do meta rs, rd := reflect.ValueOf(f), reflect.ValueOf(c).Elem() rt := rs.Type() for i, n := 0, rs.NumField(); i < n; i++ { diff --git a/site/rebuild.go b/site/rebuild.go index 387b287..1eddda3 100644 --- a/site/rebuild.go +++ b/site/rebuild.go @@ -56,10 +56,27 @@ func (s *Site) processFilesEvent(fileset FilesEvent, messages chan<- interface{} 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 { for _, path := range paths { switch { - case path == "_config.yml": + case s.config.IsConfigPath(path): + return true + case s.Exclude(path): + return false + case !s.config.Incremental: return true case strings.HasPrefix(path, s.config.DataDir): return true @@ -70,29 +87,23 @@ func (s *Site) requiresFullReload(paths []string) bool { 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 -func (s *Site) sitePaths(filenames []string) []string { +func (s *Site) affectsBuildFilter(filenames []string) []string { var ( - paths = make([]string, 0, len(filenames)) - seen = map[string]bool{} + result = make([]string, 0, len(filenames)) + seen = map[string]bool{} ) +loop: for _, path := range filenames { - if path == "_config.yml" || !s.Exclude(path) { - if !seen[path] { - seen[path] = true - paths = append(paths, path) - } + switch { + case s.config.IsConfigPath(path): + case s.Exclude(path): + continue loop + case seen[path]: + continue loop } + seen[path] = true + result = append(result, path) } - return paths + return result } diff --git a/site/watch.go b/site/watch.go index c2ef994..92fd90d 100644 --- a/site/watch.go +++ b/site/watch.go @@ -37,7 +37,7 @@ func (s *Site) WatchFiles() (<-chan FilesEvent, error) { ) go func() { for { - paths := s.sitePaths(<-debounced) + paths := s.affectsBuildFilter(<-debounced) if len(paths) > 0 { // Create a new timestamp. Except under pathological // circumstances, it will be close enough.