mirror of
https://github.com/gohugoio/hugo.git
synced 2024-11-07 20:30:36 -05:00
Fix partial rebuilds for SCSS fetched with GetMatch and similar
Fixes #12395
This commit is contained in:
parent
da6112fc65
commit
004b694390
6 changed files with 114 additions and 33 deletions
16
cache/dynacache/dynacache.go
vendored
16
cache/dynacache/dynacache.go
vendored
|
@ -140,16 +140,25 @@ func (c *Cache) DrainEvictedIdentities() []identity.Identity {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClearMatching clears all partition for which the predicate returns true.
|
// 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]{
|
g := rungroup.Run[PartitionManager](context.Background(), rungroup.Config[PartitionManager]{
|
||||||
NumWorkers: len(c.partitions),
|
NumWorkers: len(c.partitions),
|
||||||
Handle: func(ctx context.Context, partition PartitionManager) error {
|
Handle: func(ctx context.Context, partition PartitionManager) error {
|
||||||
partition.clearMatching(predicate)
|
partition.clearMatching(predicateValue)
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
for _, p := range c.partitions {
|
for k, p := range c.partitions {
|
||||||
|
if !predicatePartition(k, p) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
g.Enqueue(p)
|
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),
|
trace: c.opts.Log.Logger().WithLevel(logg.LevelTrace).WithField("partition", name),
|
||||||
opts: opts,
|
opts: opts,
|
||||||
}
|
}
|
||||||
|
|
||||||
c.partitions[name] = partition
|
c.partitions[name] = partition
|
||||||
|
|
||||||
return partition
|
return partition
|
||||||
|
|
2
cache/dynacache/dynacache_test.go
vendored
2
cache/dynacache/dynacache_test.go
vendored
|
@ -156,7 +156,7 @@ func TestClear(t *testing.T) {
|
||||||
|
|
||||||
cache = newTestCache(t)
|
cache = newTestCache(t)
|
||||||
|
|
||||||
cache.ClearMatching(func(k, v any) bool {
|
cache.ClearMatching(nil, func(k, v any) bool {
|
||||||
return k.(string) == "clearOnRebuild"
|
return k.(string) == "clearOnRebuild"
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -128,6 +128,7 @@ type rootCommand struct {
|
||||||
verbose bool
|
verbose bool
|
||||||
debug bool
|
debug bool
|
||||||
quiet bool
|
quiet bool
|
||||||
|
devMode bool // Hidden flag.
|
||||||
|
|
||||||
renderToMemory bool
|
renderToMemory bool
|
||||||
|
|
||||||
|
@ -423,29 +424,33 @@ func (r *rootCommand) PreRun(cd, runner *simplecobra.Commandeer) error {
|
||||||
func (r *rootCommand) createLogger(running bool) (loggers.Logger, error) {
|
func (r *rootCommand) createLogger(running bool) (loggers.Logger, error) {
|
||||||
level := logg.LevelWarn
|
level := logg.LevelWarn
|
||||||
|
|
||||||
if r.logLevel != "" {
|
if r.devMode {
|
||||||
switch strings.ToLower(r.logLevel) {
|
level = logg.LevelTrace
|
||||||
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 {
|
} else {
|
||||||
if r.verbose {
|
if r.logLevel != "" {
|
||||||
hugo.Deprecate("--verbose", "use --logLevel info", "v0.114.0")
|
switch strings.ToLower(r.logLevel) {
|
||||||
hugo.Deprecate("--verbose", "use --logLevel info", "v0.114.0")
|
case "debug":
|
||||||
level = logg.LevelInfo
|
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 {
|
if r.debug {
|
||||||
hugo.Deprecate("--debug", "use --logLevel debug", "v0.114.0")
|
hugo.Deprecate("--debug", "use --logLevel debug", "v0.114.0")
|
||||||
level = logg.LevelDebug
|
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.verbose, "verbose", "v", false, "verbose output")
|
||||||
cmd.PersistentFlags().BoolVarP(&r.debug, "debug", "", false, "debug 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.PersistentFlags().StringVar(&r.logLevel, "logLevel", "", "log level (debug|info|warn|error)")
|
||||||
_ = cmd.RegisterFlagCompletionFunc("logLevel", cobra.FixedCompletions([]string{"debug", "info", "warn", "error"}, cobra.ShellCompDirectiveNoFileComp))
|
_ = 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.Flags().BoolVarP(&r.buildWatch, "watch", "w", false, "watch filesystem for changes and recreate as needed")
|
||||||
|
|
||||||
|
cmd.PersistentFlags().MarkHidden("devMode")
|
||||||
|
|
||||||
// Configure local flags
|
// Configure local flags
|
||||||
applyLocalFlagsBuild(cmd, r)
|
applyLocalFlagsBuild(cmd, r)
|
||||||
|
|
||||||
|
|
|
@ -1084,7 +1084,7 @@ func (h *HugoSites) resolveAndClearStateForIdentities(
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
h.MemCache.ClearMatching(shouldDelete)
|
h.MemCache.ClearMatching(nil, shouldDelete)
|
||||||
|
|
||||||
return ll, nil
|
return ll, nil
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
|
|
@ -23,6 +23,7 @@ import (
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/bep/logg"
|
"github.com/bep/logg"
|
||||||
|
@ -46,6 +47,7 @@ import (
|
||||||
"github.com/gohugoio/hugo/resources/page"
|
"github.com/gohugoio/hugo/resources/page"
|
||||||
"github.com/gohugoio/hugo/resources/page/siteidentities"
|
"github.com/gohugoio/hugo/resources/page/siteidentities"
|
||||||
"github.com/gohugoio/hugo/resources/postpub"
|
"github.com/gohugoio/hugo/resources/postpub"
|
||||||
|
"github.com/gohugoio/hugo/resources/resource"
|
||||||
|
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
|
|
||||||
|
@ -758,15 +760,45 @@ func (h *HugoSites) processPartial(ctx context.Context, l logg.LevelLogger, conf
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case files.ComponentFolderAssets:
|
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
|
var hasID bool
|
||||||
r, _ := h.ResourceSpec.ResourceCache.Get(context.Background(), dynacache.CleanKey(pathInfo.Base()))
|
for _, r := range matches {
|
||||||
identity.WalkIdentitiesShallow(r, func(level int, rid identity.Identity) bool {
|
identity.WalkIdentitiesShallow(r, func(level int, rid identity.Identity) bool {
|
||||||
hasID = true
|
hasID = true
|
||||||
changes = append(changes, rid)
|
changes = append(changes, rid)
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
|
}
|
||||||
if !hasID {
|
if !hasID {
|
||||||
changes = append(changes, pathInfo)
|
changes = append(changes, pathInfo)
|
||||||
}
|
}
|
||||||
|
|
|
@ -327,3 +327,34 @@ Styles: {{ $r.RelPermalink }}
|
||||||
|
|
||||||
b.AssertFileContent("public/index.html", "Styles: /scss/main.css")
|
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`)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue