aboutsummaryrefslogtreecommitdiffhomepage
path: root/hugolib
diff options
context:
space:
mode:
authorBjørn Erik Pedersen <[email protected]>2024-03-15 10:57:51 +0100
committerBjørn Erik Pedersen <[email protected]>2024-03-15 15:42:56 +0100
commit07b2e535be469f0a95619edb2b0bd5ea569bca3e (patch)
tree20b82be66be26398b9a67fec4d3ce5ee867482b3 /hugolib
parentf038a51b3e448286287b56bed6dd76e9b00138d5 (diff)
downloadhugo-07b2e535be469f0a95619edb2b0bd5ea569bca3e.tar.gz
hugo-07b2e535be469f0a95619edb2b0bd5ea569bca3e.zip
Fix server rebuilds when adding sub sections especially on Windows
This commit also optimizes for the case where change events for both file (e.g. `_index.md`) and the container directory comes in the same event batch. While testing this on Windows 11 (ARM64), I notice that Windows behaves a little oddly when dumping a folder of files into the content tree; it works (at least after this commit), but it seems like the event batching behaves differently compared to other OSes (even older Win versions). A related tip would be to try starting the server with polling, to see if that improves the situation, e.g.: ``` hugo server --poll 700ms ``` Fixes #12230
Diffstat (limited to 'hugolib')
-rw-r--r--hugolib/hugo_sites_build.go36
-rw-r--r--hugolib/pages_capture.go2
-rw-r--r--hugolib/site.go68
3 files changed, 76 insertions, 30 deletions
diff --git a/hugolib/hugo_sites_build.go b/hugolib/hugo_sites_build.go
index ddc712a2d..7b8a6ef23 100644
--- a/hugolib/hugo_sites_build.go
+++ b/hugolib/hugo_sites_build.go
@@ -595,8 +595,10 @@ func (h *HugoSites) processPartial(ctx context.Context, l logg.LevelLogger, conf
return sb.String()
}))
+ // For a list of events for the different OSes, see the test output in https://github.com/bep/fsnotifyeventlister/.
events = h.fileEventsFilter(events)
events = h.fileEventsTranslate(events)
+ eventInfos := h.fileEventsApplyInfo(events)
logger := h.Log
@@ -631,36 +633,12 @@ func (h *HugoSites) processPartial(ctx context.Context, l logg.LevelLogger, conf
addedContentPaths []*paths.Path
)
- for _, ev := range events {
- removed := false
- added := false
-
- if ev.Op&fsnotify.Remove == fsnotify.Remove {
- removed = true
- }
-
- fi, statErr := h.Fs.Source.Stat(ev.Name)
-
- // Some editors (Vim) sometimes issue only a Rename operation when writing an existing file
- // Sometimes a rename operation means that file has been renamed other times it means
- // it's been updated.
- if ev.Op.Has(fsnotify.Rename) {
- // If the file is still on disk, it's only been updated, if it's not, it's been moved
- if statErr != nil {
- removed = true
- }
- }
- if ev.Op.Has(fsnotify.Create) {
- added = true
- }
-
- isChangedDir := statErr == nil && fi.IsDir()
-
+ for _, ev := range eventInfos {
cpss := h.BaseFs.ResolvePaths(ev.Name)
pss := make([]*paths.Path, len(cpss))
for i, cps := range cpss {
p := cps.Path
- if removed && !paths.HasExt(p) {
+ if ev.removed && !paths.HasExt(p) {
// Assume this is a renamed/removed directory.
// For deletes, we walk up the tree to find the container (e.g. branch bundle),
// so we will catch this even if it is a file without extension.
@@ -671,7 +649,7 @@ func (h *HugoSites) processPartial(ctx context.Context, l logg.LevelLogger, conf
}
pss[i] = h.Configs.ContentPathParser.Parse(cps.Component, p)
- if added && !isChangedDir && cps.Component == files.ComponentFolderContent {
+ if ev.added && !ev.isChangedDir && cps.Component == files.ComponentFolderContent {
addedContentPaths = append(addedContentPaths, pss[i])
}
@@ -683,9 +661,9 @@ func (h *HugoSites) processPartial(ctx context.Context, l logg.LevelLogger, conf
}
}
- if removed {
+ if ev.removed {
changedPaths.deleted = append(changedPaths.deleted, pss...)
- } else if isChangedDir {
+ } else if ev.isChangedDir {
changedPaths.changedDirs = append(changedPaths.changedDirs, pss...)
} else {
changedPaths.changedFiles = append(changedPaths.changedFiles, pss...)
diff --git a/hugolib/pages_capture.go b/hugolib/pages_capture.go
index 4328978db..231c2efad 100644
--- a/hugolib/pages_capture.go
+++ b/hugolib/pages_capture.go
@@ -161,7 +161,7 @@ func (c *pagesCollector) Collect() (collectErr error) {
// We always start from a directory.
collectErr = c.collectDir(id.p, id.isDir, func(fim hugofs.FileMetaInfo) bool {
if id.delete || id.isDir {
- if id.isDir {
+ if id.isDir && fim.Meta().PathInfo.IsLeafBundle() {
return strings.HasPrefix(fim.Meta().PathInfo.Path(), paths.AddTrailingSlash(id.p.Path()))
}
diff --git a/hugolib/site.go b/hugolib/site.go
index 117e10144..e7d170d09 100644
--- a/hugolib/site.go
+++ b/hugolib/site.go
@@ -19,6 +19,7 @@ import (
"io"
"mime"
"net/url"
+ "os"
"path/filepath"
"runtime"
"sort"
@@ -426,6 +427,73 @@ func (h *HugoSites) fileEventsFilter(events []fsnotify.Event) []fsnotify.Event {
return events[:n]
}
+type fileEventInfo struct {
+ fsnotify.Event
+ fi os.FileInfo
+ added bool
+ removed bool
+ isChangedDir bool
+}
+
+func (h *HugoSites) fileEventsApplyInfo(events []fsnotify.Event) []fileEventInfo {
+ var infos []fileEventInfo
+ for _, ev := range events {
+ removed := false
+ added := false
+
+ if ev.Op&fsnotify.Remove == fsnotify.Remove {
+ removed = true
+ }
+
+ fi, statErr := h.Fs.Source.Stat(ev.Name)
+
+ // Some editors (Vim) sometimes issue only a Rename operation when writing an existing file
+ // Sometimes a rename operation means that file has been renamed other times it means
+ // it's been updated.
+ if ev.Op.Has(fsnotify.Rename) {
+ // If the file is still on disk, it's only been updated, if it's not, it's been moved
+ if statErr != nil {
+ removed = true
+ }
+ }
+ if ev.Op.Has(fsnotify.Create) {
+ added = true
+ }
+
+ isChangedDir := statErr == nil && fi.IsDir()
+
+ infos = append(infos, fileEventInfo{
+ Event: ev,
+ fi: fi,
+ added: added,
+ removed: removed,
+ isChangedDir: isChangedDir,
+ })
+ }
+
+ n := 0
+
+ for _, ev := range infos {
+ // Remove any directories that's also represented by a file.
+ keep := true
+ if ev.isChangedDir {
+ for _, ev2 := range infos {
+ if ev2.fi != nil && !ev2.fi.IsDir() && filepath.Dir(ev2.Name) == ev.Name {
+ keep = false
+ break
+ }
+ }
+ }
+ if keep {
+ infos[n] = ev
+ n++
+ }
+ }
+ infos = infos[:n]
+
+ return infos
+}
+
func (h *HugoSites) fileEventsTranslate(events []fsnotify.Event) []fsnotify.Event {
eventMap := make(map[string][]fsnotify.Event)