Skip to content

Commit e914f3f

Browse files
committed
Delegees
1 parent 7c681b5 commit e914f3f

File tree

10 files changed

+173
-76
lines changed

10 files changed

+173
-76
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ require (
2222
github.com/bep/overlayfs v0.10.0
2323
github.com/bep/simplecobra v0.6.0
2424
github.com/bep/tmc v0.5.1
25+
github.com/bits-and-blooms/bitset v1.22.0
2526
github.com/cespare/xxhash/v2 v2.3.0
2627
github.com/clbanning/mxj/v2 v2.7.0
2728
github.com/disintegration/gift v1.2.1
@@ -118,7 +119,6 @@ require (
118119
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4 // indirect
119120
github.com/aws/aws-sdk-go-v2/service/sts v1.30.3 // indirect
120121
github.com/aws/smithy-go v1.22.2 // indirect
121-
github.com/bits-and-blooms/bitset v1.22.0 // indirect
122122
github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect
123123
github.com/dlclark/regexp2 v1.11.5 // indirect
124124
github.com/felixge/httpsnoop v1.0.4 // indirect

hugolib/content_map.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,10 @@ func (r *resourceSource) GetIdentity() identity.Identity {
9797
return r.path
9898
}
9999

100+
func (p *resourceSource) matchDirectOrInDelegees(doctree.Dimensions) contentNodeI {
101+
panic("not implemented")
102+
}
103+
100104
func (r *resourceSource) ForEeachIdentity(f func(identity.Identity) bool) bool {
101105
return f(r.GetIdentity())
102106
}
@@ -137,6 +141,10 @@ func (n resourceSources) resetBuildState() {
137141
}
138142
}
139143

144+
func (n resourceSources) matchDirectOrInDelegees(doctree.Dimensions) contentNodeI {
145+
panic("not implemented")
146+
}
147+
140148
func (n resourceSources) GetIdentity() identity.Identity {
141149
for _, r := range n {
142150
if r != nil {

hugolib/content_map_page.go

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
"context"
1818
"fmt"
1919
"io"
20+
"iter"
2021
"path"
2122
"sort"
2223
"strconv"
@@ -367,8 +368,9 @@ func (m *pageMap) getPagesInSection(q pageMapQueryPagesInSection) page.Pages {
367368
}
368369

369370
w := &doctree.NodeShiftTreeWalker[contentNodeI]{
370-
Tree: m.treePages,
371-
Prefix: prefix,
371+
Tree: m.treePages,
372+
Prefix: prefix,
373+
DelegeeFallback: true,
372374
}
373375

374376
w.Handle = func(key string, n contentNodeI, match doctree.DimensionFlag) (bool, error) {
@@ -649,6 +651,7 @@ type contentNodeI interface {
649651
identity.ForEeachIdentityProvider
650652
Path() string
651653
isContentNodeBranch() bool
654+
matchDirectOrInDelegees(doctree.Dimensions) contentNodeI
652655
buildStateReseter
653656
resource.StaleMarker
654657
}
@@ -672,6 +675,10 @@ func (n contentNodeIs) isContentNodeBranch() bool {
672675
return n.one().isContentNodeBranch()
673676
}
674677

678+
func (p contentNodeIs) matchDirectOrInDelegees(doctree.Dimensions) contentNodeI {
679+
panic("not implemented")
680+
}
681+
675682
func (n contentNodeIs) GetIdentity() identity.Identity {
676683
return n.one().GetIdentity()
677684
}
@@ -750,8 +757,18 @@ func (s *contentNodeShifter) Delete(n contentNodeI, dimension doctree.Dimensions
750757
}
751758
}
752759

753-
func (s *contentNodeShifter) Shift(n contentNodeI, dims doctree.Dimensions, exact bool) (contentNodeI, bool, doctree.DimensionFlag) {
754-
// How accurate is the match.
760+
func (s *contentNodeShifter) findDelegee(q doctree.Dimensions, candidates iter.Seq[contentNodeI]) contentNodeI {
761+
for n := range candidates {
762+
if nn := n.matchDirectOrInDelegees(q); nn != nil {
763+
return nn
764+
}
765+
}
766+
return nil
767+
}
768+
769+
func (s *contentNodeShifter) Shift(n contentNodeI, dims doctree.Dimensions, exact, delegeeFallback bool) (contentNodeI, bool, doctree.DimensionFlag) {
770+
// dims: language, version and role
771+
// How accurate is the match. TODO1 revise this.
755772
accuracy := doctree.DimensionLanguage
756773
switch v := n.(type) {
757774
case contentNodeIs:
@@ -762,6 +779,20 @@ func (s *contentNodeShifter) Shift(n contentNodeI, dims doctree.Dimensions, exac
762779
if vv != nil {
763780
return vv, true, accuracy
764781
}
782+
if !delegeeFallback {
783+
return nil, false, 0
784+
}
785+
iter := func(yield func(n contentNodeI) bool) {
786+
for _, nn := range v {
787+
if !yield(nn) {
788+
return
789+
}
790+
}
791+
}
792+
if vv = s.findDelegee(dims, iter); vv != nil {
793+
fmt.Println(n.Path(), "found delegee", dims, vv) // TODO1
794+
return vv, true, accuracy
795+
}
765796
return nil, false, 0
766797
case resourceSources:
767798
vv := v[dims]
@@ -1050,7 +1081,7 @@ func (m *pageMap) debugPrint(prefix string, maxLevel int, w io.Writer) {
10501081

10511082
resourceWalker.Handle = func(ss string, n contentNodeI, match doctree.DimensionFlag) (bool, error) {
10521083
if isBranch {
1053-
ownerKey, _ := pageWalker.Tree.LongestPrefix(ss, true, nil)
1084+
ownerKey, _ := pageWalker.Tree.LongestPrefix(ss, true, false, nil)
10541085
if ownerKey != keyPage {
10551086
// Stop walking downwards, someone else owns this resource.
10561087
pageWalker.SkipPrefix(ownerKey + "/")
@@ -1500,7 +1531,7 @@ func (sa *sitePagesAssembler) applyAggregates() error {
15001531

15011532
rw.Handle = func(resourceKey string, n contentNodeI, match doctree.DimensionFlag) (bool, error) {
15021533
if isBranch {
1503-
ownerKey, _ := pw.Tree.LongestPrefix(resourceKey, true, nil)
1534+
ownerKey, _ := pw.Tree.LongestPrefix(resourceKey, true, false, nil)
15041535
if ownerKey != keyPage {
15051536
// Stop walking downwards, someone else owns this resource.
15061537
rw.SkipPrefix(ownerKey + "/")

hugolib/doctree/nodeshifttree.go

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ type (
5454
// Shift shifts T into the given dimension
5555
// and returns the shifted T and a bool indicating if the shift was successful and
5656
// how accurate a match T is according to its dimensions.
57-
Shift(v T, dimension Dimensions, exact bool) (T, bool, DimensionFlag)
57+
Shift(v T, dimension Dimensions, exact, delegeeFallback bool) (T, bool, DimensionFlag)
5858
}
5959
)
6060

@@ -226,12 +226,12 @@ func (t *NodeShiftTree[T]) Lock(writable bool) (commit func()) {
226226

227227
// LongestPrefix finds the longest prefix of s that exists in the tree that also matches the predicate (if set).
228228
// Set exact to true to only match exact in the current dimension (e.g. language).
229-
func (r *NodeShiftTree[T]) LongestPrefix(s string, exact bool, predicate func(v T) bool) (string, T) {
229+
func (r *NodeShiftTree[T]) LongestPrefix(s string, exact, delegeeFallback bool, predicate func(v T) bool) (string, T) {
230230
for {
231231
longestPrefix, v, found := r.tree.LongestPrefix(s)
232232

233233
if found {
234-
if t, ok, _ := r.shift(v.(T), exact); ok && (predicate == nil || predicate(t)) {
234+
if t, ok, _ := r.shift(v.(T), exact, delegeeFallback); ok && (predicate == nil || predicate(t)) {
235235
return longestPrefix, t
236236
}
237237
}
@@ -317,6 +317,9 @@ type NodeShiftTreeWalker[T any] struct {
317317
// Don't fall back to alternative dimensions (e.g. language).
318318
Exact bool
319319

320+
// TODO1 document this and check vs exact.
321+
DelegeeFallback bool
322+
320323
// Used in development only.
321324
Debug bool
322325

@@ -408,7 +411,7 @@ func (r *NodeShiftTreeWalker[T]) toT(tree *NodeShiftTree[T], v any) (t T, ok boo
408411
t = v.(T)
409412
ok = true
410413
} else {
411-
t, ok, exact = tree.shift(v.(T), r.Exact)
414+
t, ok, exact = tree.shift(v.(T), r.Exact, r.DelegeeFallback)
412415
}
413416
return
414417
}
@@ -422,10 +425,10 @@ func (t NodeShiftTree[T]) clone() *NodeShiftTree[T] {
422425
return &t
423426
}
424427

425-
func (r *NodeShiftTree[T]) shift(t T, exact bool) (T, bool, DimensionFlag) {
428+
func (r *NodeShiftTree[T]) shift(t T, exact, delegeeFallback bool) (T, bool, DimensionFlag) {
426429
// TODO1 exact.
427430
exact = true
428-
return r.shifter.Shift(t, r.dims, exact)
431+
return r.shifter.Shift(t, r.dims, exact, delegeeFallback)
429432
}
430433

431434
func (r *NodeShiftTree[T]) get(s string) (T, bool) {
@@ -435,7 +438,7 @@ func (r *NodeShiftTree[T]) get(s string) (T, bool) {
435438
var t T
436439
return t, false
437440
}
438-
t, ok, _ := r.shift(v.(T), true)
441+
t, ok, _ := r.shift(v.(T), true, false) // TODO1
439442
return t, ok
440443
}
441444

hugolib/page.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ import (
4444
"github.com/gohugoio/hugo/common/text"
4545
"github.com/gohugoio/hugo/resources/kinds"
4646
"github.com/gohugoio/hugo/resources/page"
47+
"github.com/gohugoio/hugo/resources/page/pagemeta"
4748
"github.com/gohugoio/hugo/resources/resource"
4849
)
4950

@@ -218,6 +219,21 @@ func (p *pageState) isContentNodeBranch() bool {
218219
return p.IsNode()
219220
}
220221

222+
func (p *pageState) matchDirectOrInDelegees(dims doctree.Dimensions) contentNodeI {
223+
pc := p.m.pageConfig
224+
if !pagemeta.MatchLanguageOrLanguageDelegee(pc, dims) {
225+
return nil
226+
}
227+
if !pagemeta.MatchVersionOrVersionDelegee(pc, dims) {
228+
return nil
229+
}
230+
if !pagemeta.MatchRoleOrRoleDelegee(pc, dims) {
231+
return nil
232+
}
233+
fmt.Println(p.Path(), p.s.dims, "====>", dims, pc.LanguagesCompiledSet, pc.VersionsCompiledSet, pc.RolesCompiledSet)
234+
return p
235+
}
236+
221237
// Eq returns whether the current page equals the given page.
222238
// This is what's invoked when doing `{{ if eq $page $otherPage }}`
223239
func (p *pageState) Eq(other any) bool {

hugolib/page__meta.go

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -268,13 +268,11 @@ func (p *pageMeta) setMetaPre(pi *contentParseInfo, logger loggers.Logger, conf
268268
// Look for path, lang, roles and kind, all of which values we need early on.
269269
if v, found := frontmatter["path"]; found {
270270
pcfg.Path = paths.ToSlashPreserveLeading(cast.ToString(v))
271-
pcfg.Params["path"] = pcfg.Path
272271
}
273272
if v, found := frontmatter["lang"]; found {
274273
lang := strings.ToLower(cast.ToString(v))
275274
if _, ok := conf.PathParser().LanguageIndex[lang]; ok {
276275
pcfg.Lang = lang
277-
pcfg.Params["lang"] = pcfg.Lang
278276
}
279277
}
280278
if v, found := frontmatter["kind"]; found {
@@ -284,20 +282,25 @@ func (p *pageMeta) setMetaPre(pi *contentParseInfo, logger loggers.Logger, conf
284282
if pcfg.Kind == "" {
285283
return fmt.Errorf("unknown kind %q in front matter", s)
286284
}
287-
pcfg.Params["kind"] = pcfg.Kind
288285
}
289286
}
290287
if v, found := frontmatter["roles"]; found {
291288
pcfg.Roles = cast.ToStringSlice(v)
292-
pcfg.Params["roles"] = pcfg.Roles
293289
}
294290
if v, found := frontmatter["versions"]; found {
295291
pcfg.Versions = cast.ToStringSlice(v)
296-
pcfg.Params["versions"] = pcfg.Versions
297292
}
298293
if v, found := frontmatter["languages"]; found {
299294
pcfg.Languages = cast.ToStringSlice(v)
300-
pcfg.Params["languages"] = pcfg.Languages
295+
}
296+
if v, found := frontmatter["languagedelegees"]; found {
297+
pcfg.LanguageDelegees = cast.ToStringSlice(v)
298+
}
299+
if v, found := frontmatter["versiondelegees"]; found {
300+
pcfg.VersionDelegees = cast.ToStringSlice(v)
301+
}
302+
if v, found := frontmatter["roledelegees"]; found {
303+
pcfg.RoleDelegees = cast.ToStringSlice(v)
301304
}
302305

303306
} else if p.pageMetaParams.pageConfig.Params == nil {

hugolib/page__tree.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ func (pt pageTree) CurrentSection() page.Page {
6666
return pt.p.s.home
6767
}
6868

69-
_, n := pt.p.s.pageMap.treePages.LongestPrefix(dir, true, func(n contentNodeI) bool { return n.isContentNodeBranch() })
69+
_, n := pt.p.s.pageMap.treePages.LongestPrefix(dir, true, false, func(n contentNodeI) bool { return n.isContentNodeBranch() })
7070
if n != nil {
7171
return n.(page.Page)
7272
}
@@ -81,7 +81,7 @@ func (pt pageTree) FirstSection() page.Page {
8181
}
8282

8383
for {
84-
k, n := pt.p.s.pageMap.treePages.LongestPrefix(s, true, func(n contentNodeI) bool { return n.isContentNodeBranch() })
84+
k, n := pt.p.s.pageMap.treePages.LongestPrefix(s, true, false, func(n contentNodeI) bool { return n.isContentNodeBranch() })
8585
if n == nil {
8686
return nil
8787
}
@@ -125,7 +125,7 @@ func (pt pageTree) Parent() page.Page {
125125
}
126126

127127
for {
128-
_, n := pt.p.s.pageMap.treePages.LongestPrefix(dir, true, nil)
128+
_, n := pt.p.s.pageMap.treePages.LongestPrefix(dir, true, false, nil)
129129
if n == nil {
130130
return pt.p.s.home
131131
}

hugolib/roles/roles_integration_test.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,12 @@ title: "Public v3"
7272
versions: ["v3.*"]
7373
---
7474
Users with guest role will see this.
75-
-- layouts/home.html --
75+
-- layouts/all.html --
7676
Role: {{ .Site.Role.Name }}|Version: {{ .Site.Version.Name }}|Lang: {{ .Site.Language.Lang }}|
7777
Roles: {{ range .Site.Roles }}Name: {{ .Name }} Site.Version: {{.Site.Version.Name }} Site.Language.Lang: {{ .Site.Language.Lang}}|{{ end }}$
7878
Versions: {{ range site.Versions }}Name: {{ .Name }} Site.Role: {{ .Site.Role.Name }} Site.Language.Lang: {{ .Site.Language.Lang }}|{{ end }}$
79-
-- layouts/page.html --
80-
{{ .Title }}|{{ .Content }}|{{ .Site.Version.Name }}|{{ .Site.Role.Name }}|
79+
RegularPages: {{ range .RegularPages }}{{ .RelPermalink }} r: {{ .Site.Language.Name }} v: {{ .Site.Version.Name }} l: {{ .Site.Role.Name }}|{{ end }}$
80+
8181
`
8282

8383
b := hugolib.Test(t, files)
@@ -96,4 +96,6 @@ Versions: {{ range site.Versions }}Name: {{ .Name }} Site.Role: {{ .Site.Role.Na
9696
"Role: guest|Version: v2.0.0|",
9797
"Roles: Name: member Site.Version: v2.0.0 Site.Language.Lang: en|Name: guest Site.Version: v2.0.0 Site.Language.Lang: en|$",
9898
"Versions: Name: v3.0.0 Site.Role: guest Site.Language.Lang: en|Name: v2.1.0 Site.Role: guest Site.Language.Lang: en|Name: v2.0.0 Site.Role: guest Site.Language.Lang: en|Name: v1.2.3 Site.Role: guest Site.Language.Lang: en|$")
99+
100+
// b.AssertFileContent("public/guest/v3.0.0/en/index.html", "asdf")
99101
}

langs/language.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ import (
3232

3333
type Language struct {
3434
// The language code, e.g. "en" or "no".
35-
// This is currently only settable as the key in the language map in the config.
35+
// This is the key used in the languages map in the configuration,
36+
// and currently only settable as the key in the language map in the config.
3637
Lang string
3738

3839
// Fields from the language config.
@@ -55,6 +56,11 @@ type Language struct {
5556
params maps.Params
5657
}
5758

59+
// Name is an alias for Lang.
60+
func (l *Language) Name() string {
61+
return l.Lang
62+
}
63+
5864
// TODO1 add Site.
5965

6066
// NewLanguage creates a new language.

0 commit comments

Comments
 (0)