Optimize walkdir for pages
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
@@ -44,20 +44,21 @@ func (h *handler) handleMove(w http.ResponseWriter, r *http.Request, srcURL, src
|
||||
return
|
||||
}
|
||||
|
||||
// Phase 1: walk the tree and rewrite every index.md whose content changes.
|
||||
// Keep the pre-rewrite bytes in memory so we can revert on failure.
|
||||
// Phase 1: walk the tree and rewrite every index.md that references the
|
||||
// moved path. Keep the pre-rewrite bytes in memory so we can revert on
|
||||
// failure. The walker only reads directory listings and files literally
|
||||
// named index.md; hidden directories are pruned. A cheap substring check
|
||||
// skips parsing files that cannot contain a relevant link.
|
||||
rewritten := map[string][]byte{}
|
||||
walkErr := filepath.WalkDir(h.root, func(fsPath string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if d.IsDir() || d.Name() != "index.md" {
|
||||
return nil
|
||||
}
|
||||
needle := []byte("[[" + oldPath)
|
||||
walkErr := walkIndexFiles(h.root, func(fsPath string) error {
|
||||
orig, err := os.ReadFile(fsPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !bytes.Contains(orig, needle) {
|
||||
return nil
|
||||
}
|
||||
updated, changed := rewriteWikiLinks(orig, oldPath, newPath)
|
||||
if !changed {
|
||||
return nil
|
||||
@@ -186,6 +187,36 @@ func rollbackRewrites(rewritten map[string][]byte) {
|
||||
}
|
||||
}
|
||||
|
||||
// walkIndexFiles visits every `index.md` under root, skipping hidden
|
||||
// directories (names beginning with `.`). Unlike filepath.WalkDir this does
|
||||
// not stat each regular file — on spinning disks that saves the bulk of the
|
||||
// traversal cost when folders contain many non-page files (photos, archives).
|
||||
func walkIndexFiles(root string, visit func(fsPath string) error) error {
|
||||
entries, err := os.ReadDir(root)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, e := range entries {
|
||||
name := e.Name()
|
||||
if strings.HasPrefix(name, ".") {
|
||||
continue
|
||||
}
|
||||
full := filepath.Join(root, name)
|
||||
if e.IsDir() {
|
||||
if err := walkIndexFiles(full, visit); err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
if name == "index.md" {
|
||||
if err := visit(full); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// writeFileAtomic writes data to a temp file in the same directory as path
|
||||
// and renames it into place so readers never observe a partial file.
|
||||
func writeFileAtomic(path string, data []byte, perm os.FileMode) error {
|
||||
|
||||
Reference in New Issue
Block a user