mirror of
https://github.com/gohugoio/hugo.git
synced 2024-11-28 23:02:05 -05:00
Fix rebuild regression on non-default content language edits
Fixes #12043
This commit is contained in:
parent
43ea2cd660
commit
68f67c9aeb
4 changed files with 91 additions and 15 deletions
|
@ -125,37 +125,52 @@ type pageTrees struct {
|
||||||
resourceTrees doctree.MutableTrees
|
resourceTrees doctree.MutableTrees
|
||||||
}
|
}
|
||||||
|
|
||||||
// collectIdentities collects all identities from in all trees matching the given key.
|
// collectAndMarkStaleIdentities collects all identities from in all trees matching the given key.
|
||||||
// This will at most match in one tree, but may give identies from multiple dimensions (e.g. language).
|
// We currently re-read all page/resources for all languages that share the same path,
|
||||||
func (t *pageTrees) collectIdentities(p *paths.Path) []identity.Identity {
|
// so we mark all entries as stale (which will trigger cache invalidation), then
|
||||||
ids := t.collectIdentitiesFor(p.Base())
|
// return the first.
|
||||||
|
func (t *pageTrees) collectAndMarkStaleIdentities(p *paths.Path) []identity.Identity {
|
||||||
|
ids := t.collectAndMarkStaleIdentitiesFor(p.Base())
|
||||||
|
|
||||||
if p.Component() == files.ComponentFolderContent {
|
if p.Component() == files.ComponentFolderContent {
|
||||||
// It may also be a bundled content resource.
|
// It may also be a bundled content resource.
|
||||||
if n := t.treeResources.Get(p.ForBundleType(paths.PathTypeContentResource).Base()); n != nil {
|
key := p.ForBundleType(paths.PathTypeContentResource).Base()
|
||||||
|
tree := t.treeResources
|
||||||
|
if n := tree.Get(key); n != nil {
|
||||||
n.ForEeachIdentity(func(id identity.Identity) bool {
|
n.ForEeachIdentity(func(id identity.Identity) bool {
|
||||||
ids = append(ids, id)
|
ids = append(ids, id)
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
|
if n, ok := tree.GetRaw(key); ok {
|
||||||
|
n.MarkStale()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ids
|
return ids
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *pageTrees) collectIdentitiesFor(key string) []identity.Identity {
|
func (t *pageTrees) collectAndMarkStaleIdentitiesFor(key string) []identity.Identity {
|
||||||
var ids []identity.Identity
|
var ids []identity.Identity
|
||||||
if n := t.treePages.Get(key); n != nil {
|
tree := t.treePages
|
||||||
|
if n := tree.Get(key); n != nil {
|
||||||
n.ForEeachIdentity(func(id identity.Identity) bool {
|
n.ForEeachIdentity(func(id identity.Identity) bool {
|
||||||
ids = append(ids, id)
|
ids = append(ids, id)
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
|
if n, ok := tree.GetRaw(key); ok {
|
||||||
|
n.MarkStale()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if n := t.treeResources.Get(key); n != nil {
|
tree = t.treeResources
|
||||||
|
if n := tree.Get(key); n != nil {
|
||||||
n.ForEeachIdentity(func(id identity.Identity) bool {
|
n.ForEeachIdentity(func(id identity.Identity) bool {
|
||||||
ids = append(ids, id)
|
ids = append(ids, id)
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
|
if n, ok := tree.GetRaw(key); ok {
|
||||||
|
n.MarkStale()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ids
|
return ids
|
||||||
|
@ -626,9 +641,7 @@ func (n contentNodeIs) resetBuildState() {
|
||||||
|
|
||||||
func (n contentNodeIs) MarkStale() {
|
func (n contentNodeIs) MarkStale() {
|
||||||
for _, nn := range n {
|
for _, nn := range n {
|
||||||
if nn != nil {
|
resource.MarkStale(nn)
|
||||||
nn.MarkStale()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -799,6 +812,7 @@ func (s *contentNodeShifter) Insert(old, new contentNodeI) contentNodeI {
|
||||||
if !ok {
|
if !ok {
|
||||||
panic(fmt.Sprintf("unknown type %T", new))
|
panic(fmt.Sprintf("unknown type %T", new))
|
||||||
}
|
}
|
||||||
|
resource.MarkStale(vv[newp.s.languagei])
|
||||||
vv[newp.s.languagei] = new
|
vv[newp.s.languagei] = new
|
||||||
return vv
|
return vv
|
||||||
case *resourceSource:
|
case *resourceSource:
|
||||||
|
@ -818,6 +832,7 @@ func (s *contentNodeShifter) Insert(old, new contentNodeI) contentNodeI {
|
||||||
if !ok {
|
if !ok {
|
||||||
panic(fmt.Sprintf("unknown type %T", new))
|
panic(fmt.Sprintf("unknown type %T", new))
|
||||||
}
|
}
|
||||||
|
resource.MarkStale(vv[newp.LangIndex()])
|
||||||
vv[newp.LangIndex()] = newp
|
vv[newp.LangIndex()] = newp
|
||||||
return vv
|
return vv
|
||||||
default:
|
default:
|
||||||
|
@ -1014,8 +1029,12 @@ func (h *HugoSites) resolveAndClearStateForIdentities(
|
||||||
)
|
)
|
||||||
|
|
||||||
for _, id := range changes {
|
for _, id := range changes {
|
||||||
if staler, ok := id.(resource.Staler); ok {
|
if staler, ok := id.(resource.Staler); ok && !staler.IsStale() {
|
||||||
h.Log.Trace(logg.StringFunc(func() string { return fmt.Sprintf("Marking stale: %s (%T)\n", id, id) }))
|
var msgDetail string
|
||||||
|
if p, ok := id.(*pageState); ok && p.File() != nil {
|
||||||
|
msgDetail = fmt.Sprintf(" (%s)", p.File().Filename())
|
||||||
|
}
|
||||||
|
h.Log.Trace(logg.StringFunc(func() string { return fmt.Sprintf("Marking stale: %s (%T)%s\n", id, id, msgDetail) }))
|
||||||
staler.MarkStale()
|
staler.MarkStale()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -702,7 +702,7 @@ func (h *HugoSites) processPartial(ctx context.Context, l logg.LevelLogger, conf
|
||||||
switch pathInfo.Component() {
|
switch pathInfo.Component() {
|
||||||
case files.ComponentFolderContent:
|
case files.ComponentFolderContent:
|
||||||
logger.Println("Source changed", pathInfo.Path())
|
logger.Println("Source changed", pathInfo.Path())
|
||||||
if ids := h.pageTrees.collectIdentities(pathInfo); len(ids) > 0 {
|
if ids := h.pageTrees.collectAndMarkStaleIdentities(pathInfo); len(ids) > 0 {
|
||||||
changes = append(changes, ids...)
|
changes = append(changes, ids...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1171,6 +1171,59 @@ Hello: {{ i18n "hello" }}
|
||||||
b.AssertFileContent("public/index.html", "Hello: Hugo")
|
b.AssertFileContent("public/index.html", "Hello: Hugo")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRebuildEditContentNonDefaultLanguage(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
files := `
|
||||||
|
-- hugo.toml --
|
||||||
|
baseURL = "https://example.com"
|
||||||
|
disableLiveReload = true
|
||||||
|
defaultContentLanguage = "en"
|
||||||
|
defaultContentLanguageInSubdir = true
|
||||||
|
[languages]
|
||||||
|
[languages.en]
|
||||||
|
weight = 1
|
||||||
|
[languages.nn]
|
||||||
|
weight = 2
|
||||||
|
-- content/p1/index.en.md --
|
||||||
|
---
|
||||||
|
title: "P1 en"
|
||||||
|
---
|
||||||
|
P1 en.
|
||||||
|
-- content/p1/b.en.md --
|
||||||
|
---
|
||||||
|
title: "B en"
|
||||||
|
---
|
||||||
|
B en.
|
||||||
|
-- content/p1/f1.en.txt --
|
||||||
|
F1 en
|
||||||
|
-- content/p1/index.nn.md --
|
||||||
|
---
|
||||||
|
title: "P1 nn"
|
||||||
|
---
|
||||||
|
P1 nn.
|
||||||
|
-- content/p1/b.nn.md --
|
||||||
|
---
|
||||||
|
title: "B nn"
|
||||||
|
---
|
||||||
|
B nn.
|
||||||
|
-- content/p1/f1.nn.txt --
|
||||||
|
F1 nn
|
||||||
|
-- layouts/_default/single.html --
|
||||||
|
Single: {{ .Title }}|{{ .Content }}|Bundled File: {{ with .Resources.GetMatch "f1.*" }}{{ .Content }}{{ end }}|Bundled Page: {{ with .Resources.GetMatch "b.*" }}{{ .Content }}{{ end }}|
|
||||||
|
`
|
||||||
|
|
||||||
|
b := TestRunning(t, files)
|
||||||
|
|
||||||
|
b.AssertFileContent("public/nn/p1/index.html", "Single: P1 nn|<p>P1 nn.</p>", "F1 nn|")
|
||||||
|
b.EditFileReplaceAll("content/p1/index.nn.md", "P1 nn.", "P1 nn edit.").Build()
|
||||||
|
b.AssertFileContent("public/nn/p1/index.html", "Single: P1 nn|<p>P1 nn edit.</p>\n|")
|
||||||
|
b.EditFileReplaceAll("content/p1/f1.nn.txt", "F1 nn", "F1 nn edit.").Build()
|
||||||
|
b.AssertFileContent("public/nn/p1/index.html", "Bundled File: F1 nn edit.")
|
||||||
|
b.EditFileReplaceAll("content/p1/b.nn.md", "B nn.", "B nn edit.").Build()
|
||||||
|
b.AssertFileContent("public/nn/p1/index.html", "B nn edit.")
|
||||||
|
}
|
||||||
|
|
||||||
func TestRebuildVariationsAssetsSassImport(t *testing.T) {
|
func TestRebuildVariationsAssetsSassImport(t *testing.T) {
|
||||||
if !htesting.IsCI() {
|
if !htesting.IsCI() {
|
||||||
t.Skip("skip CI only")
|
t.Skip("skip CI only")
|
||||||
|
|
|
@ -17,6 +17,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/common/maps"
|
"github.com/gohugoio/hugo/common/maps"
|
||||||
|
"github.com/gohugoio/hugo/common/types"
|
||||||
"github.com/gohugoio/hugo/langs"
|
"github.com/gohugoio/hugo/langs"
|
||||||
"github.com/gohugoio/hugo/media"
|
"github.com/gohugoio/hugo/media"
|
||||||
|
|
||||||
|
@ -250,7 +251,10 @@ func IsStaleAny(os ...any) bool {
|
||||||
// MarkStale will mark any of the oses as stale, if possible.
|
// MarkStale will mark any of the oses as stale, if possible.
|
||||||
func MarkStale(os ...any) {
|
func MarkStale(os ...any) {
|
||||||
for _, o := range os {
|
for _, o := range os {
|
||||||
if s, ok := o.(Staler); ok {
|
if types.IsNil(o) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if s, ok := o.(StaleMarker); ok {
|
||||||
s.MarkStale()
|
s.MarkStale()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue