Fix filename dimension identifiers (_role_X_, _version_X_) to replace mount config

Filename identifiers for roles and versions were parsed but never applied
to the SitesMatrix. Now they replace the mount's configuration for that
dimension, matching how language identifiers already worked.

Fixes #14756

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Bjørn Erik Pedersen
2026-04-15 19:11:10 +02:00
parent ce2a156a4e
commit 8d6145f3c3
4 changed files with 129 additions and 10 deletions
+3 -1
View File
@@ -214,7 +214,9 @@ type VectorProvider interface {
type VectorStore interface {
VectorProvider
Complement(...VectorProvider) VectorStore
WithLanguageIndices(i int) VectorStore
WithLanguageIndices(i ...int) VectorStore
WithVersionIndices(i ...int) VectorStore
WithRoleIndices(i ...int) VectorStore
HasLanguage(lang int) bool
HasVersion(version int) bool
HasRole(role int) bool
@@ -1901,3 +1901,55 @@ title: p1 de
</ul>
`)
}
// Issue 14756.
func TestFilenameIdentifierShouldReplaceMountDimension(t *testing.T) {
t.Parallel()
files := `
-- hugo.toml --
baseURL = "https://example.org/"
disableKinds = ["taxonomy", "term", "rss", "sitemap"]
defaultContentLanguage = "en"
defaultContentRole = "guest"
defaultContentRoleInSubdir = true
[roles]
[roles.guest]
weight = 100
[roles.member]
weight = 200
[module]
[[module.mounts]]
source = 'content/member'
target = 'content'
[module.mounts.sites.matrix]
roles = "member"
[[module.mounts]]
source = 'content/guest'
target = 'content'
[module.mounts.sites.matrix]
roles = "*"
-- content/member/bundle/index.md --
---
title: "Bundle"
---
-- content/guest/bundle/index.md --
---
title: "Bundle"
---
-- content/guest/bundle/img._role_member_.txt --
memberimg
-- content/guest/bundle/guestimg.txt --
guestimg
-- layouts/page.html --
Role: {{ .Site.Role.Name }}|{{ range .Resources }}{{ .Name }}|{{ end }}$
-- layouts/list.html --
List.
`
b := hugolib.Test(t, files)
// The guest role should only see guestimg.txt (not img._role_member_.txt).
b.AssertFileContent("public/guest/bundle/index.html", "Role: guest|guestimg.txt|$")
// The member role should see both.
b.AssertFileContent("public/member/bundle/index.html", "Role: member|guestimg.txt|img._role_member_.txt|$")
}
+49 -6
View File
@@ -209,17 +209,46 @@ func (s *vectorStoreMap) Vectors() []Vector {
return vectors
}
func (s *vectorStoreMap) WithLanguageIndices(i int) VectorStore {
func (s *vectorStoreMap) WithLanguageIndices(i ...int) VectorStore {
c := s.clone()
for v := range c.sets {
v[Language] = i
c.sets[v] = struct{}{}
for _, i := range i {
nv := v
nv[Language] = i
c.sets[nv] = struct{}{}
}
}
return c
}
func (s *vectorStoreMap) WithVersionIndices(indices ...int) VectorStore {
old := s.clone()
c := newVectorStoreMap(len(old.sets) * len(indices))
for v := range old.sets {
for _, i := range indices {
nv := v
nv[Version] = i
c.sets[nv] = struct{}{}
}
}
return c
}
func (s *vectorStoreMap) WithRoleIndices(indices ...int) VectorStore {
old := s.clone()
c := newVectorStoreMap(len(old.sets) * len(indices))
for v := range old.sets {
for _, i := range indices {
nv := v
nv[Role] = i
c.sets[nv] = struct{}{}
}
}
return c
}
func (s *vectorStoreMap) HasLanguage(i int) bool {
for v := range s.sets {
if v.Language() == i {
@@ -589,10 +618,24 @@ func (s IntSets) shallowClone() *IntSets {
return &s
}
// WithLanguageIndices replaces the current language set with a single language index.
func (s *IntSets) WithLanguageIndices(i int) VectorStore {
// WithLanguageIndices replaces the current language set with the given language indices.
func (s *IntSets) WithLanguageIndices(indices ...int) VectorStore {
c := s.shallowClone()
c.languages = hmaps.NewOrderedIntSet(i)
c.languages = hmaps.NewOrderedIntSet(indices...)
return c.init()
}
// WithVersionIndices replaces the current version set with the given version indices.
func (s *IntSets) WithVersionIndices(indices ...int) VectorStore {
c := s.shallowClone()
c.versions = hmaps.NewOrderedIntSet(indices...)
return c.init()
}
// WithRoleIndices replaces the current role set with the given role indices.
func (s *IntSets) WithRoleIndices(indices ...int) VectorStore {
c := s.shallowClone()
c.roles = hmaps.NewOrderedIntSet(indices...)
return c.init()
}