mirror of
https://github.com/gohugoio/hugo.git
synced 2024-11-21 20:46:30 -05:00
parent
3477d9fcec
commit
a7df536a52
7 changed files with 108 additions and 13 deletions
|
@ -33,6 +33,7 @@ import (
|
||||||
"github.com/gohugoio/hugo/common/hcontext"
|
"github.com/gohugoio/hugo/common/hcontext"
|
||||||
"github.com/gohugoio/hugo/common/hexec"
|
"github.com/gohugoio/hugo/common/hexec"
|
||||||
"github.com/gohugoio/hugo/common/loggers"
|
"github.com/gohugoio/hugo/common/loggers"
|
||||||
|
"github.com/gohugoio/hugo/common/maps"
|
||||||
"github.com/gohugoio/hugo/hugofs/files"
|
"github.com/gohugoio/hugo/hugofs/files"
|
||||||
|
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
|
@ -55,6 +56,8 @@ var (
|
||||||
vendorInfo string
|
vendorInfo string
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var _ maps.StoreProvider = (*HugoInfo)(nil)
|
||||||
|
|
||||||
// HugoInfo contains information about the current Hugo environment
|
// HugoInfo contains information about the current Hugo environment
|
||||||
type HugoInfo struct {
|
type HugoInfo struct {
|
||||||
CommitHash string
|
CommitHash string
|
||||||
|
@ -72,6 +75,8 @@ type HugoInfo struct {
|
||||||
conf ConfigProvider
|
conf ConfigProvider
|
||||||
deps []*Dependency
|
deps []*Dependency
|
||||||
|
|
||||||
|
store *maps.Scratch
|
||||||
|
|
||||||
// Context gives access to some of the context scoped variables.
|
// Context gives access to some of the context scoped variables.
|
||||||
Context Context
|
Context Context
|
||||||
}
|
}
|
||||||
|
@ -116,6 +121,10 @@ func (i HugoInfo) Deps() []*Dependency {
|
||||||
return i.deps
|
return i.deps
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (i HugoInfo) Store() *maps.Scratch {
|
||||||
|
return i.store
|
||||||
|
}
|
||||||
|
|
||||||
// Deprecated: Use hugo.IsMultihost instead.
|
// Deprecated: Use hugo.IsMultihost instead.
|
||||||
func (i HugoInfo) IsMultiHost() bool {
|
func (i HugoInfo) IsMultiHost() bool {
|
||||||
Deprecate("hugo.IsMultiHost", "Use hugo.IsMultihost instead.", "v0.124.0")
|
Deprecate("hugo.IsMultiHost", "Use hugo.IsMultihost instead.", "v0.124.0")
|
||||||
|
@ -185,6 +194,7 @@ func NewInfo(conf ConfigProvider, deps []*Dependency) HugoInfo {
|
||||||
Environment: conf.Environment(),
|
Environment: conf.Environment(),
|
||||||
conf: conf,
|
conf: conf,
|
||||||
deps: deps,
|
deps: deps,
|
||||||
|
store: maps.NewScratch(),
|
||||||
GoVersion: goVersion,
|
GoVersion: goVersion,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,13 @@ import (
|
||||||
"github.com/gohugoio/hugo/common/math"
|
"github.com/gohugoio/hugo/common/math"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Scratch is a writable context used for stateful operations in Page/Node rendering.
|
type StoreProvider interface {
|
||||||
|
// Store returns a Scratch that can be used to store temporary state.
|
||||||
|
// Store is not reset on server rebuilds.
|
||||||
|
Store() *Scratch
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scratch is a writable context used for stateful build operations
|
||||||
type Scratch struct {
|
type Scratch struct {
|
||||||
values map[string]any
|
values map[string]any
|
||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
|
|
|
@ -1893,3 +1893,52 @@ func TestRenderWithoutArgument(t *testing.T) {
|
||||||
|
|
||||||
b.Assert(err, qt.IsNotNil)
|
b.Assert(err, qt.IsNotNil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Issue #13021
|
||||||
|
func TestAllStores(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
files := `
|
||||||
|
-- hugo.toml --
|
||||||
|
disableKinds = ["taxonomy", "term", "page", "section"]
|
||||||
|
disableLiveReload = true
|
||||||
|
-- content/_index.md --
|
||||||
|
---
|
||||||
|
title: "Home"
|
||||||
|
---
|
||||||
|
{{< s >}}
|
||||||
|
-- layouts/shortcodes/s.html --
|
||||||
|
{{ if not (.Store.Get "Shortcode") }}{{ .Store.Set "Shortcode" (printf "sh-%s" $.Page.Title) }}{{ end }}
|
||||||
|
Shortcode: {{ .Store.Get "Shortcode" }}|
|
||||||
|
-- layouts/index.html --
|
||||||
|
{{ .Content }}
|
||||||
|
{{ if not (.Store.Get "Page") }}{{ .Store.Set "Page" (printf "p-%s" $.Title) }}{{ end }}
|
||||||
|
{{ if not (hugo.Store.Get "Hugo") }}{{ hugo.Store.Set "Hugo" (printf "h-%s" $.Title) }}{{ end }}
|
||||||
|
{{ if not (site.Store.Get "Site") }}{{ site.Store.Set "Site" (printf "s-%s" $.Title) }}{{ end }}
|
||||||
|
Page: {{ .Store.Get "Page" }}|
|
||||||
|
Hugo: {{ hugo.Store.Get "Hugo" }}|
|
||||||
|
Site: {{ site.Store.Get "Site" }}|
|
||||||
|
`
|
||||||
|
|
||||||
|
b := TestRunning(t, files)
|
||||||
|
|
||||||
|
b.AssertFileContent("public/index.html",
|
||||||
|
`
|
||||||
|
Shortcode: sh-Home|
|
||||||
|
Page: p-Home|
|
||||||
|
Site: s-Home|
|
||||||
|
Hugo: h-Home|
|
||||||
|
`,
|
||||||
|
)
|
||||||
|
|
||||||
|
b.EditFileReplaceAll("content/_index.md", "Home", "Homer").Build()
|
||||||
|
|
||||||
|
b.AssertFileContent("public/index.html",
|
||||||
|
`
|
||||||
|
Shortcode: sh-Homer|
|
||||||
|
Page: p-Homer|
|
||||||
|
Site: s-Home|
|
||||||
|
Hugo: h-Home|
|
||||||
|
`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
|
@ -43,9 +43,10 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
_ urls.RefLinker = (*ShortcodeWithPage)(nil)
|
_ urls.RefLinker = (*ShortcodeWithPage)(nil)
|
||||||
_ types.Unwrapper = (*ShortcodeWithPage)(nil)
|
_ types.Unwrapper = (*ShortcodeWithPage)(nil)
|
||||||
_ text.Positioner = (*ShortcodeWithPage)(nil)
|
_ text.Positioner = (*ShortcodeWithPage)(nil)
|
||||||
|
_ maps.StoreProvider = (*ShortcodeWithPage)(nil)
|
||||||
)
|
)
|
||||||
|
|
||||||
// ShortcodeWithPage is the "." context in a shortcode template.
|
// ShortcodeWithPage is the "." context in a shortcode template.
|
||||||
|
@ -72,7 +73,7 @@ type ShortcodeWithPage struct {
|
||||||
posOffset int
|
posOffset int
|
||||||
pos text.Position
|
pos text.Position
|
||||||
|
|
||||||
scratch *maps.Scratch
|
store *maps.Scratch
|
||||||
}
|
}
|
||||||
|
|
||||||
// InnerDeindent returns the (potentially de-indented) inner content of the shortcode.
|
// InnerDeindent returns the (potentially de-indented) inner content of the shortcode.
|
||||||
|
@ -124,13 +125,19 @@ func (scp *ShortcodeWithPage) RelRef(args map[string]any) (string, error) {
|
||||||
return scp.Page.RelRefFrom(args, scp)
|
return scp.Page.RelRefFrom(args, scp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Store returns this shortcode's Store.
|
||||||
|
func (scp *ShortcodeWithPage) Store() *maps.Scratch {
|
||||||
|
if scp.store == nil {
|
||||||
|
scp.store = maps.NewScratch()
|
||||||
|
}
|
||||||
|
return scp.store
|
||||||
|
}
|
||||||
|
|
||||||
// Scratch returns a scratch-pad scoped for this shortcode. This can be used
|
// Scratch returns a scratch-pad scoped for this shortcode. This can be used
|
||||||
// as a temporary storage for variables, counters etc.
|
// as a temporary storage for variables, counters etc.
|
||||||
|
// Deprecated: Use Store instead. Note that from the templates this should be considered a "soft deprecation".
|
||||||
func (scp *ShortcodeWithPage) Scratch() *maps.Scratch {
|
func (scp *ShortcodeWithPage) Scratch() *maps.Scratch {
|
||||||
if scp.scratch == nil {
|
return scp.Store()
|
||||||
scp.scratch = maps.NewScratch()
|
|
||||||
}
|
|
||||||
return scp.scratch
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get is a convenience method to look up shortcode parameters by its key.
|
// Get is a convenience method to look up shortcode parameters by its key.
|
||||||
|
@ -399,7 +406,16 @@ func doRenderShortcode(
|
||||||
hasVariants = hasVariants || more
|
hasVariants = hasVariants || more
|
||||||
}
|
}
|
||||||
|
|
||||||
data := &ShortcodeWithPage{Ordinal: sc.ordinal, posOffset: sc.pos, indentation: sc.indentation, Params: sc.params, Page: newPageForShortcode(p), Parent: parent, Name: sc.name}
|
data := &ShortcodeWithPage{
|
||||||
|
Ordinal: sc.ordinal,
|
||||||
|
posOffset: sc.pos,
|
||||||
|
indentation: sc.indentation,
|
||||||
|
Params: sc.params,
|
||||||
|
Page: newPageForShortcode(p),
|
||||||
|
Parent: parent,
|
||||||
|
Name: sc.name,
|
||||||
|
}
|
||||||
|
|
||||||
if sc.params != nil {
|
if sc.params != nil {
|
||||||
data.IsNamedParams = reflect.TypeOf(sc.params).Kind() == reflect.Map
|
data.IsNamedParams = reflect.TypeOf(sc.params).Kind() == reflect.Map
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,6 +95,7 @@ type Site struct {
|
||||||
language *langs.Language
|
language *langs.Language
|
||||||
languagei int
|
languagei int
|
||||||
pageMap *pageMap
|
pageMap *pageMap
|
||||||
|
store *maps.Scratch
|
||||||
|
|
||||||
// The owning container.
|
// The owning container.
|
||||||
h *HugoSites
|
h *HugoSites
|
||||||
|
@ -248,6 +249,7 @@ func NewHugoSites(cfg deps.DepsCfg) (*HugoSites, error) {
|
||||||
language: language,
|
language: language,
|
||||||
languagei: i,
|
languagei: i,
|
||||||
frontmatterHandler: frontmatterHandler,
|
frontmatterHandler: frontmatterHandler,
|
||||||
|
store: maps.NewScratch(),
|
||||||
}
|
}
|
||||||
|
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
|
@ -614,6 +616,10 @@ func (s *Site) AllRegularPages() page.Pages {
|
||||||
return s.h.RegularPages()
|
return s.h.RegularPages()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Site) Store() *maps.Scratch {
|
||||||
|
return s.store
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Site) CheckReady() {
|
func (s *Site) CheckReady() {
|
||||||
if s.state != siteStateReady {
|
if s.state != siteStateReady {
|
||||||
panic("this method cannot be called before the site is fully initialized")
|
panic("this method cannot be called before the site is fully initialized")
|
||||||
|
|
|
@ -331,9 +331,7 @@ type PageWithoutContent interface {
|
||||||
// Deprecated: From Hugo v0.138.0 this is just an alias for Store.
|
// Deprecated: From Hugo v0.138.0 this is just an alias for Store.
|
||||||
Scratch() *maps.Scratch
|
Scratch() *maps.Scratch
|
||||||
|
|
||||||
// Store returns a Scratch that can be used to store temporary state.
|
maps.StoreProvider
|
||||||
// In contrast to Scratch(), this Scratch is not reset on server rebuilds.
|
|
||||||
Store() *maps.Scratch
|
|
||||||
|
|
||||||
RelatedKeywordsProvider
|
RelatedKeywordsProvider
|
||||||
|
|
||||||
|
|
|
@ -135,6 +135,8 @@ type Site interface {
|
||||||
// Deprecated: Use .Site.Home.OutputFormats.Get "rss" instead.
|
// Deprecated: Use .Site.Home.OutputFormats.Get "rss" instead.
|
||||||
RSSLink() template.URL
|
RSSLink() template.URL
|
||||||
|
|
||||||
|
maps.StoreProvider
|
||||||
|
|
||||||
// For internal use only.
|
// For internal use only.
|
||||||
// This will panic if the site is not fully initialized.
|
// This will panic if the site is not fully initialized.
|
||||||
// This is typically used to inform the user in the content adapter templates,
|
// This is typically used to inform the user in the content adapter templates,
|
||||||
|
@ -327,6 +329,10 @@ func (s *siteWrapper) RSSLink() template.URL {
|
||||||
return s.s.RSSLink()
|
return s.s.RSSLink()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *siteWrapper) Store() *maps.Scratch {
|
||||||
|
return s.s.Store()
|
||||||
|
}
|
||||||
|
|
||||||
// For internal use only.
|
// For internal use only.
|
||||||
func (s *siteWrapper) ForEeachIdentityByName(name string, f func(identity.Identity) bool) {
|
func (s *siteWrapper) ForEeachIdentityByName(name string, f func(identity.Identity) bool) {
|
||||||
s.s.(identity.ForEeachIdentityByNameProvider).ForEeachIdentityByName(name, f)
|
s.s.(identity.ForEeachIdentityByNameProvider).ForEeachIdentityByName(name, f)
|
||||||
|
@ -491,6 +497,10 @@ func (s testSite) RSSLink() template.URL {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s testSite) Store() *maps.Scratch {
|
||||||
|
return maps.NewScratch()
|
||||||
|
}
|
||||||
|
|
||||||
func (s testSite) CheckReady() {
|
func (s testSite) CheckReady() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue