From 5dbc29dc6c02d8d1e2f0deef7be6a58609b78d5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Pedersen?= Date: Mon, 19 Feb 2024 11:32:28 +0100 Subject: [PATCH] Handle rebuilds when resources passed to transform.Unmarshal etc. changes Fixes #12065 --- hugolib/rebuild_test.go | 21 ++++++++++++++++ .../texttemplate/hugo_template.go | 10 +++++++- .../texttemplate/hugo_template_test.go | 3 +++ tpl/tplimpl/template_funcs.go | 24 +++++++++++++++++++ 4 files changed, 57 insertions(+), 1 deletion(-) diff --git a/hugolib/rebuild_test.go b/hugolib/rebuild_test.go index d29215a01..cf98f55da 100644 --- a/hugolib/rebuild_test.go +++ b/hugolib/rebuild_test.go @@ -77,6 +77,27 @@ func TestRebuildEditTextFileInLeafBundle(t *testing.T) { b.AssertRenderCountContent(1) } +func TestRebuiEditUnmarshaledYamlFileInLeafBundle(t *testing.T) { + files := ` +-- hugo.toml -- +baseURL = "https://example.com" +disableLiveReload = true +disableKinds = ["taxonomy", "term", "sitemap", "robotsTXT", "404", "rss"] +-- content/mybundle/index.md -- +-- content/mybundle/mydata.yml -- +foo: bar +-- layouts/_default/single.html -- +MyData: {{ .Resources.Get "mydata.yml" | transform.Unmarshal }}| +` + b := TestRunning(t, files) + + b.AssertFileContent("public/mybundle/index.html", "MyData: map[foo:bar]") + + b.EditFileReplaceAll("content/mybundle/mydata.yml", "bar", "bar edited").Build() + + b.AssertFileContent("public/mybundle/index.html", "MyData: map[foo:bar edited]") +} + func TestRebuildEditTextFileInHomeBundle(t *testing.T) { b := TestRunning(t, rebuildFilesSimple) b.AssertFileContent("public/index.html", "Home Content.") diff --git a/tpl/internal/go_templates/texttemplate/hugo_template.go b/tpl/internal/go_templates/texttemplate/hugo_template.go index 4db40ce82..276367a7c 100644 --- a/tpl/internal/go_templates/texttemplate/hugo_template.go +++ b/tpl/internal/go_templates/texttemplate/hugo_template.go @@ -44,6 +44,7 @@ type ExecHelper interface { GetFunc(ctx context.Context, tmpl Preparer, name string) (reflect.Value, reflect.Value, bool) GetMethod(ctx context.Context, tmpl Preparer, receiver reflect.Value, name string) (method reflect.Value, firstArg reflect.Value) GetMapValue(ctx context.Context, tmpl Preparer, receiver, key reflect.Value) (reflect.Value, bool) + OnCalled(ctx context.Context, tmpl Preparer, name string, args []reflect.Value, result reflect.Value) } // Executer executes a given template. @@ -356,7 +357,14 @@ func (s *state) evalCall(dot, fun reflect.Value, isBuiltin bool, node parse.Node s.at(node) s.errorf("error calling %s: %w", name, err) } - return unwrap(v) + vv := unwrap(v) + + // Added for Hugo + if s.helper != nil { + s.helper.OnCalled(s.ctx, s.prep, name, argv, vv) + } + + return vv } func isTrue(val reflect.Value) (truth, ok bool) { diff --git a/tpl/internal/go_templates/texttemplate/hugo_template_test.go b/tpl/internal/go_templates/texttemplate/hugo_template_test.go index c68b747dd..920d96fac 100644 --- a/tpl/internal/go_templates/texttemplate/hugo_template_test.go +++ b/tpl/internal/go_templates/texttemplate/hugo_template_test.go @@ -64,6 +64,9 @@ func (e *execHelper) GetMethod(ctx context.Context, tmpl Preparer, receiver refl return m, reflect.ValueOf("v2") } +func (e *execHelper) OnCalled(ctx context.Context, tmpl Preparer, name string, args []reflect.Value, returnValue reflect.Value) { +} + func TestTemplateExecutor(t *testing.T) { c := qt.New(t) diff --git a/tpl/tplimpl/template_funcs.go b/tpl/tplimpl/template_funcs.go index 8997c83d6..9d14b9e56 100644 --- a/tpl/tplimpl/template_funcs.go +++ b/tpl/tplimpl/template_funcs.go @@ -150,6 +150,30 @@ func (t *templateExecHelper) GetMethod(ctx context.Context, tmpl texttemplate.Pr return fn, zero } +func (t *templateExecHelper) OnCalled(ctx context.Context, tmpl texttemplate.Preparer, name string, args []reflect.Value, result reflect.Value) { + if !t.running { + return + } + + // This switch is mostly for speed. + switch name { + case "Unmarshal": + default: + return + } + idm := tpl.Context.GetDependencyManagerInCurrentScope(ctx) + if idm == nil { + return + } + + for _, arg := range args { + identity.WalkIdentitiesShallow(arg.Interface(), func(level int, id identity.Identity) bool { + idm.AddIdentity(id) + return false + }) + } +} + func (t *templateExecHelper) trackDependencies(ctx context.Context, tmpl texttemplate.Preparer, name string, receiver reflect.Value) context.Context { if tmpl == nil { panic("must provide a template")