_ resource.Cloner = (*genericResource)(nil)
_ resource.ResourcesLanguageMerger = (*resource.Resources)(nil)
_ resource.Identifier = (*genericResource)(nil)
+ _ resource.TransientIdentifier = (*genericResource)(nil)
_ targetPathProvider = (*genericResource)(nil)
_ sourcePathProvider = (*genericResource)(nil)
_ identity.IdentityGroupProvider = (*genericResource)(nil)
type genericResource struct {
publishInit *sync.Once
+ key string
+ keyInit *sync.Once
+
sd ResourceSourceDescriptor
paths internal.ResourcePaths
}
func (l *genericResource) Key() string {
- basePath := l.spec.Cfg.BaseURL().BasePathNoTrailingSlash
- var key string
- if basePath == "" {
- key = l.RelPermalink()
- } else {
- key = strings.TrimPrefix(l.RelPermalink(), basePath)
- }
+ l.keyInit.Do(func() {
+ basePath := l.spec.Cfg.BaseURL().BasePathNoTrailingSlash
+ if basePath == "" {
+ l.key = l.RelPermalink()
+ } else {
+ l.key = strings.TrimPrefix(l.RelPermalink(), basePath)
+ }
- if l.spec.Cfg.IsMultihost() {
- key = l.spec.Lang() + key
- }
+ if l.spec.Cfg.IsMultihost() {
+ l.key = l.spec.Lang() + l.key
+ }
+ })
+
+ return l.key
+}
- return key
+func (l *genericResource) TransientKey() string {
+ return l.Key()
}
func (l *genericResource) targetPath() string {
func (l genericResource) clone() *genericResource {
l.publishInit = &sync.Once{}
+ l.keyInit = &sync.Once{}
return &l
}
// Identifier identifies a resource.
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.
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.
type WeightProvider interface {
Weight() int
Staler: &AtomicStaler{},
h: &resourceHash{},
publishInit: &sync.Once{},
+ keyInit: &sync.Once{},
paths: rp,
spec: r,
sd: rd,
_ identity.IdentityGroupProvider = (*resourceAdapterInner)(nil)
_ resource.Source = (*resourceAdapter)(nil)
_ resource.Identifier = (*resourceAdapter)(nil)
+ _ resource.TransientIdentifier = (*resourceAdapter)(nil)
_ targetPathProvider = (*resourceAdapter)(nil)
_ sourcePathProvider = (*resourceAdapter)(nil)
+ _ resource.Identifier = (*resourceAdapter)(nil)
_ resource.ResourceNameTitleProvider = (*resourceAdapter)(nil)
_ resource.WithResourceMetaProvider = (*resourceAdapter)(nil)
_ identity.DependencyManagerProvider = (*resourceAdapter)(nil)
return r.target.(resource.Identifier).Key()
}
+func (r *resourceAdapter) TransientKey() string {
+ return r.Key()
+}
+
func (r *resourceAdapter) targetPath() string {
r.init(false, false)
return r.target.(targetPathProvider).targetPath()
"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$")
+}
"github.com/gohugoio/hugo/common/hashing"
"github.com/gohugoio/hugo/common/types"
+ "github.com/gohugoio/hugo/resources/resource"
)
var (
zero reflect.Value
- errorType = reflect.TypeOf((*error)(nil)).Elem()
+ errorType = reflect.TypeFor[error]()
)
func numberToFloat(v reflect.Value) (float64, error) {
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,
case reflect.Uint64:
n = reflect.ValueOf(uint64(i))
}
-
}
if !n.IsValid() {