diff options
author | Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com> | 2021-10-20 11:11:48 +0300 |
---|---|---|
committer | Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com> | 2022-04-05 19:00:44 +0300 |
commit | e58a540895c28b8884823dcb1b64c272422f9923 (patch) | |
tree | 3fefb267f87e61a969a6ccf776d75fe64b50b2b1 /resources | |
parent | 20162518c450770ebfd54e0e987f34a5cccf236b (diff) |
resources: Create a common ResourceFinder interface
And make both .Resources and resources implement it.
This gets us 2 new methods/functions, so you can now also do:
* .Resources.Get
* resources.ByType
Note that GetRemote is not covered by this interface, as that is only available as a global template function.
Fixes #8653
Diffstat (limited to 'resources')
-rw-r--r-- | resources/resource/resources.go | 92 | ||||
-rw-r--r-- | resources/resource_factories/create/create.go | 25 |
2 files changed, 98 insertions, 19 deletions
diff --git a/resources/resource/resources.go b/resources/resource/resources.go index aaa747194..428decf84 100644 --- a/resources/resource/resources.go +++ b/resources/resource/resources.go @@ -18,35 +18,64 @@ import ( "strings" "github.com/gohugoio/hugo/hugofs/glob" + "github.com/spf13/cast" ) +var _ ResourceFinder = (*Resources)(nil) + // Resources represents a slice of resources, which can be a mix of different types. // I.e. both pages and images etc. type Resources []Resource +// var _ resource.ResourceFinder = (*Namespace)(nil) // ResourcesConverter converts a given slice of Resource objects to Resources. type ResourcesConverter interface { ToResources() Resources } -// ByType returns resources of a given resource type (ie. "image"). -func (r Resources) ByType(tp string) Resources { +// ByType returns resources of a given resource type (e.g. "image"). +func (r Resources) ByType(typ any) Resources { + tpstr, err := cast.ToStringE(typ) + if err != nil { + panic(err) + } var filtered Resources for _, resource := range r { - if resource.ResourceType() == tp { + if resource.ResourceType() == tpstr { filtered = append(filtered, resource) } } return filtered } +// Get locates the name given in Resources. +// The search is case insensitive. +func (r Resources) Get(name any) Resource { + namestr, err := cast.ToStringE(name) + if err != nil { + panic(err) + } + namestr = strings.ToLower(namestr) + for _, resource := range r { + if strings.EqualFold(namestr, resource.Name()) { + return resource + } + } + return nil +} + // GetMatch finds the first Resource matching the given pattern, or nil if none found. // See Match for a more complete explanation about the rules used. -func (r Resources) GetMatch(pattern string) Resource { - g, err := glob.GetGlob(pattern) +func (r Resources) GetMatch(pattern any) Resource { + patternstr, err := cast.ToStringE(pattern) + if err != nil { + panic(err) + } + + g, err := glob.GetGlob(patternstr) if err != nil { - return nil + panic(err) } for _, resource := range r { @@ -67,10 +96,15 @@ func (r Resources) GetMatch(pattern string) Resource { // Match matches by using the value of Resource.Name, which, by default, is a filename with // path relative to the bundle root with Unix style slashes (/) and no leading slash, e.g. "images/logo.png". // See https://github.com/gobwas/glob for the full rules set. -func (r Resources) Match(pattern string) Resources { - g, err := glob.GetGlob(pattern) +func (r Resources) Match(pattern any) Resources { + patternstr, err := cast.ToStringE(pattern) if err != nil { - return nil + panic(err) + } + + g, err := glob.GetGlob(patternstr) + if err != nil { + panic(err) } var matches Resources @@ -121,3 +155,43 @@ func (r Resources) MergeByLanguageInterface(in any) (any, error) { type Source interface { Publish() error } + +// ResourceFinder provides methods to find Resources. +// Note that GetRemote (as found in resources.GetRemote) is +// not covered by this interface, as this is only available as a global template function. +type ResourceFinder interface { + + // Get locates the Resource with the given name in the current context (e.g. in .Page.Resources). + // + // It returns nil if no Resource could found, panics if name is invalid. + Get(name any) Resource + + // GetMatch finds the first Resource matching the given pattern, or nil if none found. + // + // See Match for a more complete explanation about the rules used. + // + // It returns nil if no Resource could found, panics if pattern is invalid. + GetMatch(pattern any) Resource + + // Match gets all resources matching the given base path prefix, e.g + // "*.png" will match all png files. The "*" does not match path delimiters (/), + // so if you organize your resources in sub-folders, you need to be explicit about it, e.g.: + // "images/*.png". To match any PNG image anywhere in the bundle you can do "**.png", and + // to match all PNG images below the images folder, use "images/**.jpg". + // + // The matching is case insensitive. + // + // Match matches by using a relative pathwith Unix style slashes (/) and no + // leading slash, e.g. "images/logo.png". + // + // See https://github.com/gobwas/glob for the full rules set. + // + // See Match for a more complete explanation about the rules used. + // + // It returns nil if no Resources could found, panics if pattern is invalid. + Match(pattern any) Resources + + // ByType returns resources of a given resource type (e.g. "image"). + // It returns nil if no Resources could found, panics if typ is invalid. + ByType(typ any) Resources +} diff --git a/resources/resource_factories/create/create.go b/resources/resource_factories/create/create.go index f8e7e18db..3827411a9 100644 --- a/resources/resource_factories/create/create.go +++ b/resources/resource_factories/create/create.go @@ -65,26 +65,27 @@ func (c *Client) Get(filename string) (resource.Resource, error) { // Match gets the resources matching the given pattern from the assets filesystem. func (c *Client) Match(pattern string) (resource.Resources, error) { - return c.match(pattern, false) + return c.match("__match", pattern, nil, false) +} + +func (c *Client) ByType(tp string) resource.Resources { + res, err := c.match(path.Join("_byType", tp), "**", func(r resource.Resource) bool { return r.ResourceType() == tp }, false) + if err != nil { + panic(err) + } + return res } // GetMatch gets first resource matching the given pattern from the assets filesystem. func (c *Client) GetMatch(pattern string) (resource.Resource, error) { - res, err := c.match(pattern, true) + res, err := c.match("__get-match", pattern, nil, true) if err != nil || len(res) == 0 { return nil, err } return res[0], err } -func (c *Client) match(pattern string, firstOnly bool) (resource.Resources, error) { - var name string - if firstOnly { - name = "__get-match" - } else { - name = "__match" - } - +func (c *Client) match(name, pattern string, matchFunc func(r resource.Resource) bool, firstOnly bool) (resource.Resources, error) { pattern = glob.NormalizePath(pattern) partitions := glob.FilterGlobParts(strings.Split(pattern, "/")) if len(partitions) == 0 { @@ -110,6 +111,10 @@ func (c *Client) match(pattern string, firstOnly bool) (resource.Resources, erro return true, err } + if matchFunc != nil && !matchFunc(r) { + return false, nil + } + res = append(res, r) return firstOnly, nil |