mirror of
https://github.com/gohugoio/hugo.git
synced 2025-08-22 21:42:50 +02:00
@@ -126,7 +126,7 @@ func (ns *Namespace) include(ctx context.Context, name string, dataList ...any)
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return includeResult{err: err}
|
return includeResult{err: err}
|
||||||
}
|
}
|
||||||
return ns.doInclude(ctx, v, dataList...)
|
return ns.doInclude(ctx, "", v, dataList...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ns *Namespace) lookup(name string) (*tplimpl.TemplInfo, error) {
|
func (ns *Namespace) lookup(name string) (*tplimpl.TemplInfo, error) {
|
||||||
@@ -144,7 +144,7 @@ func (ns *Namespace) lookup(name string) (*tplimpl.TemplInfo, error) {
|
|||||||
|
|
||||||
// include is a helper function that lookups and executes the named partial.
|
// include is a helper function that lookups and executes the named partial.
|
||||||
// Returns the final template name and the rendered output.
|
// Returns the final template name and the rendered output.
|
||||||
func (ns *Namespace) doInclude(ctx context.Context, templ *tplimpl.TemplInfo, dataList ...any) includeResult {
|
func (ns *Namespace) doInclude(ctx context.Context, key string, templ *tplimpl.TemplInfo, dataList ...any) includeResult {
|
||||||
var data any
|
var data any
|
||||||
if len(dataList) > 0 {
|
if len(dataList) > 0 {
|
||||||
data = dataList[0]
|
data = dataList[0]
|
||||||
@@ -170,7 +170,7 @@ func (ns *Namespace) doInclude(ctx context.Context, templ *tplimpl.TemplInfo, da
|
|||||||
w = b
|
w = b
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := ns.deps.GetTemplateStore().ExecuteWithContext(ctx, templ, w, data); err != nil {
|
if err := ns.deps.GetTemplateStore().ExecuteWithContextAndKey(ctx, key, templ, w, data); err != nil {
|
||||||
return includeResult{err: err}
|
return includeResult{err: err}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,6 +198,8 @@ func (ns *Namespace) IncludeCached(ctx context.Context, name string, context any
|
|||||||
Name: name,
|
Name: name,
|
||||||
Variants: variants,
|
Variants: variants,
|
||||||
}
|
}
|
||||||
|
keyString := key.Key()
|
||||||
|
|
||||||
depsManagerIn := tpl.Context.GetDependencyManagerInCurrentScope(ctx)
|
depsManagerIn := tpl.Context.GetDependencyManagerInCurrentScope(ctx)
|
||||||
ti, err := ns.lookup(name)
|
ti, err := ns.lookup(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -206,7 +208,7 @@ func (ns *Namespace) IncludeCached(ctx context.Context, name string, context any
|
|||||||
|
|
||||||
if parent := tpl.Context.CurrentTemplate.Get(ctx); parent != nil {
|
if parent := tpl.Context.CurrentTemplate.Get(ctx); parent != nil {
|
||||||
for parent != nil {
|
for parent != nil {
|
||||||
if parent.CurrentTemplateInfoOps == ti {
|
if parent.CurrentTemplateInfoOps == ti && parent.Key == keyString {
|
||||||
// This will deadlock if we continue.
|
// This will deadlock if we continue.
|
||||||
return nil, fmt.Errorf("circular call stack detected in partial %q", ti.Filename())
|
return nil, fmt.Errorf("circular call stack detected in partial %q", ti.Filename())
|
||||||
}
|
}
|
||||||
@@ -214,7 +216,7 @@ func (ns *Namespace) IncludeCached(ctx context.Context, name string, context any
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
r, found, err := ns.cachedPartials.cache.GetOrCreate(key.Key(), func(string) (includeResult, error) {
|
r, found, err := ns.cachedPartials.cache.GetOrCreate(keyString, func(string) (includeResult, error) {
|
||||||
var depsManagerShared identity.Manager
|
var depsManagerShared identity.Manager
|
||||||
if ns.deps.Conf.Watching() {
|
if ns.deps.Conf.Watching() {
|
||||||
// We need to create a shared dependency manager to pass downwards
|
// We need to create a shared dependency manager to pass downwards
|
||||||
@@ -222,7 +224,7 @@ func (ns *Namespace) IncludeCached(ctx context.Context, name string, context any
|
|||||||
depsManagerShared = identity.NewManager("partials")
|
depsManagerShared = identity.NewManager("partials")
|
||||||
ctx = tpl.Context.DependencyManagerScopedProvider.Set(ctx, depsManagerShared.(identity.DependencyManagerScopedProvider))
|
ctx = tpl.Context.DependencyManagerScopedProvider.Set(ctx, depsManagerShared.(identity.DependencyManagerScopedProvider))
|
||||||
}
|
}
|
||||||
r := ns.doInclude(ctx, ti, context)
|
r := ns.doInclude(ctx, keyString, ti, context)
|
||||||
if ns.deps.Conf.Watching() {
|
if ns.deps.Conf.Watching() {
|
||||||
r.mangager = depsManagerShared
|
r.mangager = depsManagerShared
|
||||||
}
|
}
|
||||||
|
@@ -299,6 +299,32 @@ timeout = '200ms'
|
|||||||
b.Assert(err.Error(), qt.Contains, `error calling partialCached: circular call stack detected in partial`)
|
b.Assert(err.Error(), qt.Contains, `error calling partialCached: circular call stack detected in partial`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// See Issue #13889
|
||||||
|
func TestIncludeCachedDifferentKey(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
files := `
|
||||||
|
-- config.toml --
|
||||||
|
baseURL = 'http://example.com/'
|
||||||
|
timeout = '200ms'
|
||||||
|
-- layouts/index.html --
|
||||||
|
{{ partialCached "foo.html" "a" "a" }}
|
||||||
|
-- layouts/partials/foo.html --
|
||||||
|
{{ if eq . "a" }}
|
||||||
|
{{ partialCached "bar.html" . }}
|
||||||
|
{{ else }}
|
||||||
|
DONE
|
||||||
|
{{ end }}
|
||||||
|
-- layouts/partials/bar.html --
|
||||||
|
{{ partialCached "foo.html" "b" "b" }}
|
||||||
|
`
|
||||||
|
b := hugolib.Test(t, files)
|
||||||
|
|
||||||
|
b.AssertFileContent("public/index.html", `
|
||||||
|
DONE
|
||||||
|
`)
|
||||||
|
}
|
||||||
|
|
||||||
// See Issue #10789
|
// See Issue #10789
|
||||||
func TestReturnExecuteFromTemplateInPartial(t *testing.T) {
|
func TestReturnExecuteFromTemplateInPartial(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
@@ -161,6 +161,7 @@ type CurrentTemplateInfoCommonOps interface {
|
|||||||
type CurrentTemplateInfo struct {
|
type CurrentTemplateInfo struct {
|
||||||
Parent *CurrentTemplateInfo
|
Parent *CurrentTemplateInfo
|
||||||
Level int
|
Level int
|
||||||
|
Key string
|
||||||
CurrentTemplateInfoOps
|
CurrentTemplateInfoOps
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -485,6 +485,10 @@ func (s *TemplateStore) FindAllBaseTemplateCandidates(overlayKey string, desc Te
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *TemplateStore) ExecuteWithContext(ctx context.Context, ti *TemplInfo, wr io.Writer, data any) error {
|
func (t *TemplateStore) ExecuteWithContext(ctx context.Context, ti *TemplInfo, wr io.Writer, data any) error {
|
||||||
|
return t.ExecuteWithContextAndKey(ctx, "", ti, wr, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TemplateStore) ExecuteWithContextAndKey(ctx context.Context, key string, ti *TemplInfo, wr io.Writer, data any) error {
|
||||||
defer func() {
|
defer func() {
|
||||||
ti.executionCounter.Add(1)
|
ti.executionCounter.Add(1)
|
||||||
if ti.base != nil {
|
if ti.base != nil {
|
||||||
@@ -502,6 +506,7 @@ func (t *TemplateStore) ExecuteWithContext(ctx context.Context, ti *TemplInfo, w
|
|||||||
currentTi := &tpl.CurrentTemplateInfo{
|
currentTi := &tpl.CurrentTemplateInfo{
|
||||||
Parent: parent,
|
Parent: parent,
|
||||||
Level: level,
|
Level: level,
|
||||||
|
Key: key,
|
||||||
CurrentTemplateInfoOps: ti,
|
CurrentTemplateInfoOps: ti,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user