ref: 7e196a82944148ed3f78f334303b452ab2bd4078
parent: e01c340915f971e86fef9a1c013a3183c50e51fc
author: Steve Francia <steve.francia@gmail.com>
date: Mon Jan 11 07:06:52 EST 2016
Handle remove & rename source operations incrementally
--- a/commands/hugo.go
+++ b/commands/hugo.go
@@ -546,9 +546,9 @@
return nil
}
-func rebuildSite(changes map[string]bool) error {+func rebuildSite(events []fsnotify.Event) error {startTime := time.Now()
- err := mainSite.ReBuild(changes)
+ err := mainSite.ReBuild(events)
if err != nil {return err
}
@@ -585,12 +585,10 @@
for { select {case evs := <-watcher.Events:
- jww.INFO.Println("File System Event:", evs)+ jww.INFO.Println("Recieved System Events:", evs)- staticChanged := false
- dynamicChanged := false
- staticFilesChanged := make(map[string]bool)
- dynamicFilesChanged := make(map[string]bool)
+ staticEvents := []fsnotify.Event{} //ev make(map[string]bool)+ dynamicEvents := []fsnotify.Event{} //make(map[string]bool) for _, ev := range evs {ext := filepath.Ext(ev.Name)
@@ -598,10 +596,6 @@
if istemp {continue
}
- // renames are always followed with Create/Modify
- if ev.Op&fsnotify.Rename == fsnotify.Rename {- continue
- }
// Write and rename operations are often followed by CHMOD.
// There may be valid use cases for rebuilding the site on CHMOD,
@@ -615,18 +609,6 @@
continue
}
- isstatic := strings.HasPrefix(ev.Name, helpers.GetStaticDirPath()) || (len(helpers.GetThemesDirPath()) > 0 && strings.HasPrefix(ev.Name, helpers.GetThemesDirPath()))
- staticChanged = staticChanged || isstatic
- dynamicChanged = dynamicChanged || !isstatic
-
- if isstatic {- if staticPath, err := helpers.MakeStaticPathRelative(ev.Name); err == nil {- staticFilesChanged[staticPath] = true
- }
- } else {- dynamicFilesChanged[ev.Name] = true
- }
-
// add new directory to watch list
if s, err := os.Stat(ev.Name); err == nil && s.Mode().IsDir() { if ev.Op&fsnotify.Create == fsnotify.Create {@@ -633,9 +615,18 @@
watcher.Add(ev.Name)
}
}
+
+ isstatic := strings.HasPrefix(ev.Name, helpers.GetStaticDirPath()) || (len(helpers.GetThemesDirPath()) > 0 && strings.HasPrefix(ev.Name, helpers.GetThemesDirPath()))
+
+ if isstatic {+ staticEvents = append(staticEvents, ev)
+// }
+ } else {+ dynamicEvents = append(dynamicEvents, ev)
+ }
}
- if staticChanged {+ if len(staticEvents) > 0 { jww.FEEDBACK.Printf("Static file changed, syncing\n") if viper.GetBool("ForceSyncStatic") { jww.FEEDBACK.Printf("Syncing all static files\n")@@ -645,7 +636,6 @@
utils.StopOnErr(err, fmt.Sprintf("Error copying static files to %s", helpers.AbsPathify(viper.GetString("PublishDir"))))}
} else {-
syncer := fsync.NewSyncer()
syncer.NoTimes = viper.GetBool("notimes")syncer.SrcFs = hugofs.SourceFs
@@ -660,25 +650,41 @@
staticDir := helpers.GetStaticDirPath()
themeStaticDir := helpers.GetThemesDirPath()
- jww.FEEDBACK.Printf("StaticDir '%s'\nThemeStaticDir '%s'\n", staticDir, themeStaticDir)+ jww.FEEDBACK.Printf("Syncing from: \n \tStaticDir: '%s'\n\tThemeStaticDir: '%s'\n", staticDir, themeStaticDir)- for path := range staticFilesChanged {+ for _, ev := range staticEvents {+ fmt.Println(ev)
+ fromPath := ev.Name
var publishPath string
- if strings.HasPrefix(path, staticDir) {- publishPath = filepath.Join(publishDir, strings.TrimPrefix(path, staticDir))
- } else if strings.HasPrefix(path, themeStaticDir) {- publishPath = filepath.Join(publishDir, strings.TrimPrefix(path, themeStaticDir))
+ // If we are here we already know the event took place in a static dir
+ relPath, err := helpers.MakeStaticPathRelative(fromPath)
+ if err != nil {+ fmt.Println(err)
+ continue
}
- jww.FEEDBACK.Printf("Syncing file '%s'", path)- if _, err := os.Stat(path); err == nil {- jww.INFO.Println("syncing from ", path, " to ", publishPath)- err := syncer.Sync(publishPath, path)
- if err != nil {- jww.FEEDBACK.Printf("Error on syncing file '%s'\n", path)- }
+ if strings.HasPrefix(fromPath, staticDir) {+ publishPath = filepath.Join(publishDir, strings.TrimPrefix(fromPath, staticDir))
+ } else if strings.HasPrefix(relPath, themeStaticDir) {+ publishPath = filepath.Join(publishDir, strings.TrimPrefix(fromPath, themeStaticDir))
}
+ jww.FEEDBACK.Println("Syncing file", relPath)+
+ // Due to our approach of layering many directories onto one we can't accurately
+ // remove file not in one of the source directories.
+ // If a file is in the local static dir and also in the theme static dir and we remove
+ // it from one of those locations we expect it to still exist in the destination
+
+ // if remove or rename ignore
+ if ev.Op&fsnotify.Rename == fsnotify.Rename || ev.Op&fsnotify.Remove == fsnotify.Remove {+ continue
+ }
+
+ jww.INFO.Println("syncing from ", fromPath, " to ", publishPath)+ if er := syncer.Sync(publishPath, fromPath); er != nil {+ jww.ERROR.Printf("Error on syncing file '%s'\n %s\n", relPath, er)+ }
}
}
@@ -686,8 +692,9 @@
// Will block forever trying to write to a channel that nobody is reading if livereload isn't initalized
// force refresh when more than one file
- if len(staticFilesChanged) == 1 {- for path := range staticFilesChanged {+ if len(staticEvents) == 1 {+ for _, ev := range staticEvents {+ path, _ := helpers.MakeStaticPathRelative(ev.Name)
livereload.RefreshPath(path)
}
@@ -697,14 +704,12 @@
}
}
- if dynamicChanged {+ if len(dynamicEvents) >0 { fmt.Print("\nChange detected, rebuilding site\n")const layout = "2006-01-02 15:04 -0700"
fmt.Println(time.Now().Format(layout))
- //TODO here
- // utils.CheckErr(buildSite(true))
- rebuildSite(dynamicFilesChanged)
+ rebuildSite(dynamicEvents)
if !BuildWatch && !viper.GetBool("DisableLiveReload") {// Will block forever trying to write to a channel that nobody is reading if livereload isn't initalized
--- a/hugolib/page.go
+++ b/hugolib/page.go
@@ -112,20 +112,20 @@
// }
//}
-//func (ps Pages) FindPageByFilePath(inPath string) *Page {-// for _, x := range ps {-// if x.Source.LogicalName() == inPath {-// return x
-// }
-// }
-// return nil
-//}
+func (ps Pages) FindPagePosByFilePath(inPath string) int {+ for i, x := range ps {+ if x.Source.Path() == inPath {+ return i
+ }
+ }
+ return -1
+}
// FindPagePos Given a page, it will find the position in Pages
// will return -1 if not found
func (ps Pages) FindPagePos(page *Page) int { for i, x := range ps {- if x.Source.LogicalName() == page.Source.LogicalName() {+ if x.Source.Path() == page.Source.Path() {return i
}
}
--- a/hugolib/site.go
+++ b/hugolib/site.go
@@ -43,6 +43,7 @@
jww "github.com/spf13/jwalterweatherman"
"github.com/spf13/nitro"
"github.com/spf13/viper"
+ "gopkg.in/fsnotify.v1"
)
var _ = transform.AbsURL
@@ -426,28 +427,29 @@
return nil
}
-func (s *Site) ReBuild(changed map[string]bool) error {+func (s *Site) ReBuild(events []fsnotify.Event) error { s.timerStep("initialize rebuild")// First we need to determine what changed
- sourceChanged := []string{}- tmplChanged := []string{}- dataChanged := []string{}+ sourceChanged := []fsnotify.Event{}+ tmplChanged := []fsnotify.Event{}+ dataChanged := []fsnotify.Event{}+
var err error
- for f := range changed {+ for _, ev := range events {// Need to re-read source
- if strings.HasPrefix(f, s.absContentDir()) {- fmt.Println("Source changed", f)- sourceChanged = append(sourceChanged, f)
+ if strings.HasPrefix(ev.Name, s.absContentDir()) {+ fmt.Println("Source changed", ev)+ sourceChanged = append(sourceChanged, ev)
}
- if strings.HasPrefix(f, s.absLayoutDir()) || strings.HasPrefix(f, s.absThemeDir()) {- fmt.Println("Template changed", f)- tmplChanged = append(tmplChanged, f)
+ if strings.HasPrefix(ev.Name, s.absLayoutDir()) || strings.HasPrefix(ev.Name, s.absThemeDir()) {+ fmt.Println("Template changed", ev)+ tmplChanged = append(tmplChanged, ev)
}
- if strings.HasPrefix(f, s.absDataDir()) {- fmt.Println("Data changed", f)- dataChanged = append(dataChanged, f)
+ if strings.HasPrefix(ev.Name, s.absDataDir()) {+ fmt.Println("Data changed", ev)+ dataChanged = append(dataChanged,ev)
}
}
@@ -497,8 +499,15 @@
go incrementalReadCollator(s, readResults, pageChan, fileConvChan, coordinator, errs)
go converterCollator(s, convertResults, errs)
- for _, x := range sourceChanged {- file, err := s.ReReadFile(x)
+ for _, ev := range sourceChanged {+ if ev.Op&fsnotify.Rename == fsnotify.Rename || ev.Op&fsnotify.Remove == fsnotify.Remove {+ //remove the file & a create will follow
+ path, _ := helpers.GetRelativePath(ev.Name, s.absContentDir())
+ s.RemovePageByPath(path)
+ continue
+ }
+
+ file, err := s.ReReadFile(ev.Name)
if err != nil {errs <- err
}
@@ -540,7 +549,6 @@
if err = s.Render(); err != nil {// Better reporting when the template is missing (commit 2bbecc7b)
jww.ERROR.Printf("Error rendering site: %s", err)-
jww.ERROR.Printf("Available templates:")var keys []string
for _, template := range s.Tmpl.Templates() {@@ -1002,6 +1010,23 @@
if page.IsFuture() {s.futureCount++
+ }
+}
+
+
+func (s *Site) RemovePageByPath(path string) {+ if i := s.Pages.FindPagePosByFilePath(path); i >= 0 {+ page := s.Pages[i]
+
+ if page.IsDraft() {+ s.draftCount--
+ }
+
+ if page.IsFuture() {+ s.futureCount--
+ }
+
+ s.Pages = append(s.Pages[:i], s.Pages[i+1:]...)
}
}
--
⑨