summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2024-04-20 11:05:35 +0200
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2024-04-20 15:09:12 +0200
commit004b6943906471cff0d0232040d24cff6cb89e6b (patch)
tree75d2492a0553a283c16a26cb5df9a178c5baa5ec
parentda6112fc65346d0f4e12b52d0580258cf02716c9 (diff)
Fix partial rebuilds for SCSS fetched with GetMatch and similar
Fixes #12395
-rw-r--r--cache/dynacache/dynacache.go16
-rw-r--r--cache/dynacache/dynacache_test.go2
-rw-r--r--commands/commandeer.go50
-rw-r--r--hugolib/content_map_page.go2
-rw-r--r--hugolib/hugo_sites_build.go46
-rw-r--r--resources/resource_transformers/tocss/scss/scss_integration_test.go31
6 files changed, 114 insertions, 33 deletions
diff --git a/cache/dynacache/dynacache.go b/cache/dynacache/dynacache.go
index eab251e5d..e79de5a5b 100644
--- a/cache/dynacache/dynacache.go
+++ b/cache/dynacache/dynacache.go
@@ -140,16 +140,25 @@ func (c *Cache) DrainEvictedIdentities() []identity.Identity {
}
// ClearMatching clears all partition for which the predicate returns true.
-func (c *Cache) ClearMatching(predicate func(k, v any) bool) {
+func (c *Cache) ClearMatching(predicatePartition func(k string, p PartitionManager) bool, predicateValue func(k, v any) bool) {
+ if predicatePartition == nil {
+ predicatePartition = func(k string, p PartitionManager) bool { return true }
+ }
+ if predicateValue == nil {
+ panic("nil predicateValue")
+ }
g := rungroup.Run[PartitionManager](context.Background(), rungroup.Config[PartitionManager]{
NumWorkers: len(c.partitions),
Handle: func(ctx context.Context, partition PartitionManager) error {
- partition.clearMatching(predicate)
+ partition.clearMatching(predicateValue)
return nil
},
})
- for _, p := range c.partitions {
+ for k, p := range c.partitions {
+ if !predicatePartition(k, p) {
+ continue
+ }
g.Enqueue(p)
}
@@ -356,6 +365,7 @@ func GetOrCreatePartition[K comparable, V any](c *Cache, name string, opts Optio
trace: c.opts.Log.Logger().WithLevel(logg.LevelTrace).WithField("partition", name),
opts: opts,
}
+
c.partitions[name] = partition
return partition
diff --git a/cache/dynacache/dynacache_test.go b/cache/dynacache/dynacache_test.go
index 53de2385e..275e63f0b 100644
--- a/cache/dynacache/dynacache_test.go
+++ b/cache/dynacache/dynacache_test.go
@@ -156,7 +156,7 @@ func TestClear(t *testing.T) {
cache = newTestCache(t)
- cache.ClearMatching(func(k, v any) bool {
+ cache.ClearMatching(nil, func(k, v any) bool {
return k.(string) == "clearOnRebuild"
})
diff --git a/commands/commandeer.go b/commands/commandeer.go
index f18c3f813..616a3c867 100644
--- a/commands/commandeer.go
+++ b/commands/commandeer.go
@@ -128,6 +128,7 @@ type rootCommand struct {
verbose bool
debug bool
quiet bool
+ devMode bool // Hidden flag.
renderToMemory bool
@@ -423,29 +424,33 @@ func (r *rootCommand) PreRun(cd, runner *simplecobra.Commandeer) error {
func (r *rootCommand) createLogger(running bool) (loggers.Logger, error) {
level := logg.LevelWarn
- if r.logLevel != "" {
- switch strings.ToLower(r.logLevel) {
- case "debug":
- level = logg.LevelDebug
- case "info":
- level = logg.LevelInfo
- case "warn", "warning":
- level = logg.LevelWarn
- case "error":
- level = logg.LevelError
- default:
- return nil, fmt.Errorf("invalid log level: %q, must be one of debug, warn, info or error", r.logLevel)
- }
+ if r.devMode {
+ level = logg.LevelTrace
} else {
- if r.verbose {
- hugo.Deprecate("--verbose", "use --logLevel info", "v0.114.0")
- hugo.Deprecate("--verbose", "use --logLevel info", "v0.114.0")
- level = logg.LevelInfo
- }
+ if r.logLevel != "" {
+ switch strings.ToLower(r.logLevel) {
+ case "debug":
+ level = logg.LevelDebug
+ case "info":
+ level = logg.LevelInfo
+ case "warn", "warning":
+ level = logg.LevelWarn
+ case "error":
+ level = logg.LevelError
+ default:
+ return nil, fmt.Errorf("invalid log level: %q, must be one of debug, warn, info or error", r.logLevel)
+ }
+ } else {
+ if r.verbose {
+ hugo.Deprecate("--verbose", "use --logLevel info", "v0.114.0")
+ hugo.Deprecate("--verbose", "use --logLevel info", "v0.114.0")
+ level = logg.LevelInfo
+ }
- if r.debug {
- hugo.Deprecate("--debug", "use --logLevel debug", "v0.114.0")
- level = logg.LevelDebug
+ if r.debug {
+ hugo.Deprecate("--debug", "use --logLevel debug", "v0.114.0")
+ level = logg.LevelDebug
+ }
}
}
@@ -505,10 +510,13 @@ Complete documentation is available at https://gohugo.io/.`
cmd.PersistentFlags().BoolVarP(&r.verbose, "verbose", "v", false, "verbose output")
cmd.PersistentFlags().BoolVarP(&r.debug, "debug", "", false, "debug output")
+ cmd.PersistentFlags().BoolVarP(&r.devMode, "devMode", "", false, "only used for internal testing, flag hidden.")
cmd.PersistentFlags().StringVar(&r.logLevel, "logLevel", "", "log level (debug|info|warn|error)")
_ = cmd.RegisterFlagCompletionFunc("logLevel", cobra.FixedCompletions([]string{"debug", "info", "warn", "error"}, cobra.ShellCompDirectiveNoFileComp))
cmd.Flags().BoolVarP(&r.buildWatch, "watch", "w", false, "watch filesystem for changes and recreate as needed")
+ cmd.PersistentFlags().MarkHidden("devMode")
+
// Configure local flags
applyLocalFlagsBuild(cmd, r)
diff --git a/hugolib/content_map_page.go b/hugolib/content_map_page.go
index aa32b5320..50e1bc35d 100644
--- a/hugolib/content_map_page.go
+++ b/hugolib/content_map_page.go
@@ -1084,7 +1084,7 @@ func (h *HugoSites) resolveAndClearStateForIdentities(
return b
}
- h.MemCache.ClearMatching(shouldDelete)
+ h.MemCache.ClearMatching(nil, shouldDelete)
return ll, nil
}); err != nil {
diff --git a/hugolib/hugo_sites_build.go b/hugolib/hugo_sites_build.go
index 411f90734..3beb072e3 100644
--- a/hugolib/hugo_sites_build.go
+++ b/hugolib/hugo_sites_build.go
@@ -23,6 +23,7 @@ import (
"path"
"path/filepath"
"strings"
+ "sync"
"time"
"github.com/bep/logg"
@@ -46,6 +47,7 @@ import (
"github.com/gohugoio/hugo/resources/page"
"github.com/gohugoio/hugo/resources/page/siteidentities"
"github.com/gohugoio/hugo/resources/postpub"
+ "github.com/gohugoio/hugo/resources/resource"
"github.com/spf13/afero"
@@ -758,15 +760,45 @@ func (h *HugoSites) processPartial(ctx context.Context, l logg.LevelLogger, conf
}
}
case files.ComponentFolderAssets:
- logger.Println("Asset changed", pathInfo.Path())
+ p := pathInfo.Path()
+ logger.Println("Asset changed", p)
+
+ var matches []any
+ var mu sync.Mutex
+
+ h.MemCache.ClearMatching(
+ func(k string, pm dynacache.PartitionManager) bool {
+ // Avoid going through everything.
+ return strings.HasPrefix(k, "/res")
+ },
+ func(k, v any) bool {
+ if strings.Contains(k.(string), p) {
+ mu.Lock()
+ defer mu.Unlock()
+ switch vv := v.(type) {
+ case resource.Resources:
+ // GetMatch/Match.
+ for _, r := range vv {
+ matches = append(matches, r)
+ }
+ return true
+ default:
+ matches = append(matches, vv)
+ return true
+
+ }
+ }
+ return false
+ })
var hasID bool
- r, _ := h.ResourceSpec.ResourceCache.Get(context.Background(), dynacache.CleanKey(pathInfo.Base()))
- identity.WalkIdentitiesShallow(r, func(level int, rid identity.Identity) bool {
- hasID = true
- changes = append(changes, rid)
- return false
- })
+ for _, r := range matches {
+ identity.WalkIdentitiesShallow(r, func(level int, rid identity.Identity) bool {
+ hasID = true
+ changes = append(changes, rid)
+ return false
+ })
+ }
if !hasID {
changes = append(changes, pathInfo)
}
diff --git a/resources/resource_transformers/tocss/scss/scss_integration_test.go b/resources/resource_transformers/tocss/scss/scss_integration_test.go
index c193ca8af..02e2b9200 100644
--- a/resources/resource_transformers/tocss/scss/scss_integration_test.go
+++ b/resources/resource_transformers/tocss/scss/scss_integration_test.go
@@ -327,3 +327,34 @@ Styles: {{ $r.RelPermalink }}
b.AssertFileContent("public/index.html", "Styles: /scss/main.css")
}
+
+func TestRebuildAssetGetMatch(t *testing.T) {
+ t.Parallel()
+ if !scss.Supports() {
+ t.Skip()
+ }
+
+ files := `
+-- assets/scss/main.scss --
+b {
+ color: red;
+}
+-- layouts/index.html --
+{{ $r := resources.GetMatch "scss/main.scss" | toCSS }}
+T1: {{ $r.Content }}
+ `
+
+ b := hugolib.NewIntegrationTestBuilder(
+ hugolib.IntegrationTestConfig{
+ T: t,
+ TxtarString: files,
+ NeedsOsFS: true,
+ Running: true,
+ }).Build()
+
+ b.AssertFileContent("public/index.html", `color: red`)
+
+ b.EditFiles("assets/scss/main.scss", `b { color: blue; }`).Build()
+
+ b.AssertFileContent("public/index.html", `color: blue`)
+}