mirror of
https://github.com/gohugoio/hugo.git
synced 2024-11-21 20:46:30 -05:00
resources: Add key
to reources.GetRemote options map
If set, `key` will be used as the only cache key element for the resource. The default behaviour is to calculate the key based on the URL and all the options. This means that you can now do: ``` {{ $cacheKey := print $url (now.Format "2006-01-02") }} {{ $resource := resource.GetRemote $url (dict "key" $cacheKey) }} ``` Fixes #9755
This commit is contained in:
parent
f8c4e1690a
commit
2dbdf38a54
5 changed files with 70 additions and 1 deletions
|
@ -109,6 +109,20 @@ func ToSliceStringMap(in any) ([]map[string]any, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LookupEqualFold finds key in m with case insensitive equality checks.
|
||||||
|
func LookupEqualFold[T any | string](m map[string]T, key string) (T, bool) {
|
||||||
|
if v, found := m[key]; found {
|
||||||
|
return v, true
|
||||||
|
}
|
||||||
|
for k, v := range m {
|
||||||
|
if strings.EqualFold(k, key) {
|
||||||
|
return v, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var s T
|
||||||
|
return s, false
|
||||||
|
}
|
||||||
|
|
||||||
type keyRename struct {
|
type keyRename struct {
|
||||||
pattern glob.Glob
|
pattern glob.Glob
|
||||||
newKey string
|
newKey string
|
||||||
|
|
|
@ -171,3 +171,26 @@ func TestRenameKeys(t *testing.T) {
|
||||||
t.Errorf("Expected\n%#v, got\n%#v\n", expected, m)
|
t.Errorf("Expected\n%#v, got\n%#v\n", expected, m)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestLookupEqualFold(t *testing.T) {
|
||||||
|
c := qt.New(t)
|
||||||
|
|
||||||
|
m1 := map[string]any{
|
||||||
|
"a": "av",
|
||||||
|
"B": "bv",
|
||||||
|
}
|
||||||
|
|
||||||
|
v, found := LookupEqualFold(m1, "b")
|
||||||
|
c.Assert(found, qt.IsTrue)
|
||||||
|
c.Assert(v, qt.Equals, "bv")
|
||||||
|
|
||||||
|
m2 := map[string]string{
|
||||||
|
"a": "av",
|
||||||
|
"B": "bv",
|
||||||
|
}
|
||||||
|
|
||||||
|
v, found = LookupEqualFold(m2, "b")
|
||||||
|
c.Assert(found, qt.IsTrue)
|
||||||
|
c.Assert(v, qt.Equals, "bv")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -53,6 +53,19 @@ With `resources.GetRemote`, the first argument is a remote URL:
|
||||||
|
|
||||||
`resources.Get` and `resources.GetRemote` return `nil` if the resource is not found.
|
`resources.Get` and `resources.GetRemote` return `nil` if the resource is not found.
|
||||||
|
|
||||||
|
### Caching
|
||||||
|
|
||||||
|
By default, Hugo calculates a cache key based on the `URL` and the `options` (e.g. headers) given.
|
||||||
|
|
||||||
|
|
||||||
|
{{< new-in "0.97.0" >}} You can override this by setting a `key` in the options map. This can be used to get more fine grained control over how often a remote resource is fetched, e.g.:
|
||||||
|
|
||||||
|
|
||||||
|
```go-html-template
|
||||||
|
{{ $cacheKey := print $url (now.Format "2006-01-02") }}
|
||||||
|
{{ $resource := resource.GetRemote $url (dict "key" $cacheKey) }}
|
||||||
|
```
|
||||||
|
|
||||||
### Error Handling
|
### Error Handling
|
||||||
|
|
||||||
{{< new-in "0.91.0" >}}
|
{{< new-in "0.91.0" >}}
|
||||||
|
|
|
@ -27,6 +27,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/common/hugio"
|
"github.com/gohugoio/hugo/common/hugio"
|
||||||
|
"github.com/gohugoio/hugo/common/maps"
|
||||||
"github.com/gohugoio/hugo/common/types"
|
"github.com/gohugoio/hugo/common/types"
|
||||||
"github.com/gohugoio/hugo/helpers"
|
"github.com/gohugoio/hugo/helpers"
|
||||||
"github.com/gohugoio/hugo/media"
|
"github.com/gohugoio/hugo/media"
|
||||||
|
@ -79,7 +80,7 @@ func (c *Client) FromRemote(uri string, optionsm map[string]any) (resource.Resou
|
||||||
return nil, errors.Wrapf(err, "failed to parse URL for resource %s", uri)
|
return nil, errors.Wrapf(err, "failed to parse URL for resource %s", uri)
|
||||||
}
|
}
|
||||||
|
|
||||||
resourceID := helpers.HashString(uri, optionsm)
|
resourceID := calculateResourceID(uri, optionsm)
|
||||||
|
|
||||||
_, httpResponse, err := c.cacheGetResource.GetOrCreate(resourceID, func() (io.ReadCloser, error) {
|
_, httpResponse, err := c.cacheGetResource.GetOrCreate(resourceID, func() (io.ReadCloser, error) {
|
||||||
options, err := decodeRemoteOptions(optionsm)
|
options, err := decodeRemoteOptions(optionsm)
|
||||||
|
@ -199,6 +200,13 @@ func (c *Client) validateFromRemoteArgs(uri string, options fromRemoteOptions) e
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func calculateResourceID(uri string, optionsm map[string]any) string {
|
||||||
|
if key, found := maps.LookupEqualFold(optionsm, "key"); found {
|
||||||
|
return helpers.HashString(key)
|
||||||
|
}
|
||||||
|
return helpers.HashString(uri, optionsm)
|
||||||
|
}
|
||||||
|
|
||||||
func addDefaultHeaders(req *http.Request, accepts ...string) {
|
func addDefaultHeaders(req *http.Request, accepts ...string) {
|
||||||
for _, accept := range accepts {
|
for _, accept := range accepts {
|
||||||
if !hasHeaderValue(req.Header, "Accept", accept) {
|
if !hasHeaderValue(req.Header, "Accept", accept) {
|
||||||
|
|
|
@ -83,3 +83,14 @@ func TestDecodeRemoteOptions(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCalculateResourceID(t *testing.T) {
|
||||||
|
c := qt.New(t)
|
||||||
|
|
||||||
|
c.Assert(calculateResourceID("foo", nil), qt.Equals, "5917621528921068675")
|
||||||
|
c.Assert(calculateResourceID("foo", map[string]any{"bar": "baz"}), qt.Equals, "7294498335241413323")
|
||||||
|
|
||||||
|
c.Assert(calculateResourceID("foo", map[string]any{"key": "1234", "bar": "baz"}), qt.Equals, "14904296279238663669")
|
||||||
|
c.Assert(calculateResourceID("asdf", map[string]any{"key": "1234", "bar": "asdf"}), qt.Equals, "14904296279238663669")
|
||||||
|
c.Assert(calculateResourceID("asdf", map[string]any{"key": "12345", "bar": "asdf"}), qt.Equals, "12191037851845371770")
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue