Fix union, complement, symdiff, and intersect for transient resources
Fixes #13181
This commit is contained in:
parent
48a7aee961
commit
4a5e94087b
6 changed files with 75 additions and 15 deletions
|
@ -47,6 +47,7 @@ var (
|
||||||
_ resource.Cloner = (*genericResource)(nil)
|
_ resource.Cloner = (*genericResource)(nil)
|
||||||
_ resource.ResourcesLanguageMerger = (*resource.Resources)(nil)
|
_ resource.ResourcesLanguageMerger = (*resource.Resources)(nil)
|
||||||
_ resource.Identifier = (*genericResource)(nil)
|
_ resource.Identifier = (*genericResource)(nil)
|
||||||
|
_ resource.TransientIdentifier = (*genericResource)(nil)
|
||||||
_ targetPathProvider = (*genericResource)(nil)
|
_ targetPathProvider = (*genericResource)(nil)
|
||||||
_ sourcePathProvider = (*genericResource)(nil)
|
_ sourcePathProvider = (*genericResource)(nil)
|
||||||
_ identity.IdentityGroupProvider = (*genericResource)(nil)
|
_ identity.IdentityGroupProvider = (*genericResource)(nil)
|
||||||
|
@ -359,6 +360,9 @@ func GetTestInfoForResource(r resource.Resource) GenericResourceTestInfo {
|
||||||
type genericResource struct {
|
type genericResource struct {
|
||||||
publishInit *sync.Once
|
publishInit *sync.Once
|
||||||
|
|
||||||
|
key string
|
||||||
|
keyInit *sync.Once
|
||||||
|
|
||||||
sd ResourceSourceDescriptor
|
sd ResourceSourceDescriptor
|
||||||
paths internal.ResourcePaths
|
paths internal.ResourcePaths
|
||||||
|
|
||||||
|
@ -444,19 +448,24 @@ func (l *genericResource) Data() any {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *genericResource) Key() string {
|
func (l *genericResource) Key() string {
|
||||||
basePath := l.spec.Cfg.BaseURL().BasePathNoTrailingSlash
|
l.keyInit.Do(func() {
|
||||||
var key string
|
basePath := l.spec.Cfg.BaseURL().BasePathNoTrailingSlash
|
||||||
if basePath == "" {
|
if basePath == "" {
|
||||||
key = l.RelPermalink()
|
l.key = l.RelPermalink()
|
||||||
} else {
|
} else {
|
||||||
key = strings.TrimPrefix(l.RelPermalink(), basePath)
|
l.key = strings.TrimPrefix(l.RelPermalink(), basePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
if l.spec.Cfg.IsMultihost() {
|
if l.spec.Cfg.IsMultihost() {
|
||||||
key = l.spec.Lang() + key
|
l.key = l.spec.Lang() + l.key
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
|
||||||
return key
|
return l.key
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *genericResource) TransientKey() string {
|
||||||
|
return l.Key()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *genericResource) targetPath() string {
|
func (l *genericResource) targetPath() string {
|
||||||
|
@ -623,6 +632,7 @@ func (rc *genericResource) cloneWithUpdates(u *transformationUpdate) (baseResour
|
||||||
|
|
||||||
func (l genericResource) clone() *genericResource {
|
func (l genericResource) clone() *genericResource {
|
||||||
l.publishInit = &sync.Once{}
|
l.publishInit = &sync.Once{}
|
||||||
|
l.keyInit = &sync.Once{}
|
||||||
return &l
|
return &l
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -170,11 +170,19 @@ type ResourcesLanguageMerger interface {
|
||||||
|
|
||||||
// Identifier identifies a resource.
|
// Identifier identifies a resource.
|
||||||
type Identifier interface {
|
type Identifier interface {
|
||||||
// Key is is mostly for internal use and should be considered opaque.
|
// Key is mostly for internal use and should be considered opaque.
|
||||||
// This value may change between Hugo versions.
|
// This value may change between Hugo versions.
|
||||||
Key() string
|
Key() string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TransientIdentifier identifies a transient resource.
|
||||||
|
type TransientIdentifier interface {
|
||||||
|
// TransientKey is mostly for internal use and should be considered opaque.
|
||||||
|
// This value is implemented by transient resources where pointers may be short lived and
|
||||||
|
// not suitable for use as a map keys.
|
||||||
|
TransientKey() string
|
||||||
|
}
|
||||||
|
|
||||||
// WeightProvider provides a weight.
|
// WeightProvider provides a weight.
|
||||||
type WeightProvider interface {
|
type WeightProvider interface {
|
||||||
Weight() int
|
Weight() int
|
||||||
|
|
|
@ -187,6 +187,7 @@ func (r *Spec) NewResource(rd ResourceSourceDescriptor) (resource.Resource, erro
|
||||||
Staler: &AtomicStaler{},
|
Staler: &AtomicStaler{},
|
||||||
h: &resourceHash{},
|
h: &resourceHash{},
|
||||||
publishInit: &sync.Once{},
|
publishInit: &sync.Once{},
|
||||||
|
keyInit: &sync.Once{},
|
||||||
paths: rp,
|
paths: rp,
|
||||||
spec: r,
|
spec: r,
|
||||||
sd: rd,
|
sd: rd,
|
||||||
|
|
|
@ -52,8 +52,10 @@ var (
|
||||||
_ identity.IdentityGroupProvider = (*resourceAdapterInner)(nil)
|
_ identity.IdentityGroupProvider = (*resourceAdapterInner)(nil)
|
||||||
_ resource.Source = (*resourceAdapter)(nil)
|
_ resource.Source = (*resourceAdapter)(nil)
|
||||||
_ resource.Identifier = (*resourceAdapter)(nil)
|
_ resource.Identifier = (*resourceAdapter)(nil)
|
||||||
|
_ resource.TransientIdentifier = (*resourceAdapter)(nil)
|
||||||
_ targetPathProvider = (*resourceAdapter)(nil)
|
_ targetPathProvider = (*resourceAdapter)(nil)
|
||||||
_ sourcePathProvider = (*resourceAdapter)(nil)
|
_ sourcePathProvider = (*resourceAdapter)(nil)
|
||||||
|
_ resource.Identifier = (*resourceAdapter)(nil)
|
||||||
_ resource.ResourceNameTitleProvider = (*resourceAdapter)(nil)
|
_ resource.ResourceNameTitleProvider = (*resourceAdapter)(nil)
|
||||||
_ resource.WithResourceMetaProvider = (*resourceAdapter)(nil)
|
_ resource.WithResourceMetaProvider = (*resourceAdapter)(nil)
|
||||||
_ identity.DependencyManagerProvider = (*resourceAdapter)(nil)
|
_ identity.DependencyManagerProvider = (*resourceAdapter)(nil)
|
||||||
|
@ -279,6 +281,10 @@ func (r *resourceAdapter) Key() string {
|
||||||
return r.target.(resource.Identifier).Key()
|
return r.target.(resource.Identifier).Key()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *resourceAdapter) TransientKey() string {
|
||||||
|
return r.Key()
|
||||||
|
}
|
||||||
|
|
||||||
func (r *resourceAdapter) targetPath() string {
|
func (r *resourceAdapter) targetPath() string {
|
||||||
r.init(false, false)
|
r.init(false, false)
|
||||||
return r.target.(targetPathProvider).targetPath()
|
return r.target.(targetPathProvider).targetPath()
|
||||||
|
|
|
@ -249,3 +249,32 @@ tags: ['tag-b']
|
||||||
"2: Intersect: 1|\n2: Union: 3|\n2: SymDiff: 2|\n2: Uniq: 3|",
|
"2: Intersect: 1|\n2: Union: 3|\n2: SymDiff: 2|\n2: Uniq: 3|",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Issue #13181
|
||||||
|
func TestUnionResourcesMatch(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
files := `
|
||||||
|
-- config.toml --
|
||||||
|
disableKinds = ['rss','sitemap', 'taxonomy', 'term', 'page']
|
||||||
|
-- layouts/index.html --
|
||||||
|
{{ $a := resources.Match "*a*" }}
|
||||||
|
{{ $b := resources.Match "*b*" }}
|
||||||
|
{{ $union := $a | union $b }}
|
||||||
|
{{ range $i, $e := $union }}
|
||||||
|
{{ $i }}: {{ .Name }}
|
||||||
|
{{ end }}$
|
||||||
|
-- assets/a1.html --
|
||||||
|
<div>file1</div>
|
||||||
|
-- assets/a2.html --
|
||||||
|
<div>file2</div>
|
||||||
|
-- assets/a3_b1.html --
|
||||||
|
<div>file3</div>
|
||||||
|
-- assets/b2.html --
|
||||||
|
<div>file4</div>
|
||||||
|
`
|
||||||
|
|
||||||
|
b := hugolib.Test(t, files)
|
||||||
|
|
||||||
|
b.AssertFileContentExact("public/index.html", "0: /a3_b1.html\n\n1: /b2.html\n\n2: /a1.html\n\n3: /a2.html\n$")
|
||||||
|
}
|
||||||
|
|
|
@ -20,11 +20,12 @@ import (
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/common/hashing"
|
"github.com/gohugoio/hugo/common/hashing"
|
||||||
"github.com/gohugoio/hugo/common/types"
|
"github.com/gohugoio/hugo/common/types"
|
||||||
|
"github.com/gohugoio/hugo/resources/resource"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
zero reflect.Value
|
zero reflect.Value
|
||||||
errorType = reflect.TypeOf((*error)(nil)).Elem()
|
errorType = reflect.TypeFor[error]()
|
||||||
)
|
)
|
||||||
|
|
||||||
func numberToFloat(v reflect.Value) (float64, error) {
|
func numberToFloat(v reflect.Value) (float64, error) {
|
||||||
|
@ -56,7 +57,13 @@ func normalize(v reflect.Value) any {
|
||||||
return f
|
return f
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return types.Unwrapv(v.Interface())
|
|
||||||
|
vv := types.Unwrapv(v.Interface())
|
||||||
|
if ip, ok := vv.(resource.TransientIdentifier); ok {
|
||||||
|
return ip.TransientKey()
|
||||||
|
}
|
||||||
|
|
||||||
|
return vv
|
||||||
}
|
}
|
||||||
|
|
||||||
// collects identities from the slices in seqs into a set. Numeric values are normalized,
|
// collects identities from the slices in seqs into a set. Numeric values are normalized,
|
||||||
|
@ -151,7 +158,6 @@ func convertNumber(v reflect.Value, to reflect.Kind) (reflect.Value, error) {
|
||||||
case reflect.Uint64:
|
case reflect.Uint64:
|
||||||
n = reflect.ValueOf(uint64(i))
|
n = reflect.ValueOf(uint64(i))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !n.IsValid() {
|
if !n.IsValid() {
|
||||||
|
|
Loading…
Add table
Reference in a new issue