]> git.maquefel.me Git - brevno-suite/hugo/commitdiff
Fix server rebuilds when adding sub sections especially on Windows
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Fri, 15 Mar 2024 09:57:51 +0000 (10:57 +0100)
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Fri, 15 Mar 2024 14:42:56 +0000 (15:42 +0100)
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

hugolib/hugo_sites_build.go
hugolib/pages_capture.go
hugolib/site.go

index ddc712a2d67668c383e5086d9158dc5a6c7b3507..7b8a6ef232679352a2e480e6d83109a16003d600 100644 (file)
@@ -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...)
index 4328978db1cf15f4d1a95378b48e03b00dbac5cf..231c2efad1545142739aea4d0891bafa11ec4132 100644 (file)
@@ -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()))
                                                }
 
index 117e101442109364129c1323199253f9e9159319..e7d170d093722d9e77bac3a025b428f85e41fa81 100644 (file)
@@ -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)