resources.go (6165B)
1 // Copyright 2019 The Hugo Authors. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13
14 package resource
15
16 import (
17 "fmt"
18 "strings"
19
20 "github.com/gohugoio/hugo/hugofs/glob"
21 "github.com/spf13/cast"
22 )
23
24 var _ ResourceFinder = (*Resources)(nil)
25
26 // Resources represents a slice of resources, which can be a mix of different types.
27 // I.e. both pages and images etc.
28 type Resources []Resource
29
30 // var _ resource.ResourceFinder = (*Namespace)(nil)
31 // ResourcesConverter converts a given slice of Resource objects to Resources.
32 type ResourcesConverter interface {
33 // For internal use.
34 ToResources() Resources
35 }
36
37 // ByType returns resources of a given resource type (e.g. "image").
38 func (r Resources) ByType(typ any) Resources {
39 tpstr, err := cast.ToStringE(typ)
40 if err != nil {
41 panic(err)
42 }
43 var filtered Resources
44
45 for _, resource := range r {
46 if resource.ResourceType() == tpstr {
47 filtered = append(filtered, resource)
48 }
49 }
50 return filtered
51 }
52
53 // Get locates the name given in Resources.
54 // The search is case insensitive.
55 func (r Resources) Get(name any) Resource {
56 namestr, err := cast.ToStringE(name)
57 if err != nil {
58 panic(err)
59 }
60 namestr = strings.ToLower(namestr)
61 for _, resource := range r {
62 if strings.EqualFold(namestr, resource.Name()) {
63 return resource
64 }
65 }
66 return nil
67 }
68
69 // GetMatch finds the first Resource matching the given pattern, or nil if none found.
70 // See Match for a more complete explanation about the rules used.
71 func (r Resources) GetMatch(pattern any) Resource {
72 patternstr, err := cast.ToStringE(pattern)
73 if err != nil {
74 panic(err)
75 }
76
77 g, err := glob.GetGlob(patternstr)
78 if err != nil {
79 panic(err)
80 }
81
82 for _, resource := range r {
83 if g.Match(strings.ToLower(resource.Name())) {
84 return resource
85 }
86 }
87
88 return nil
89 }
90
91 // Match gets all resources matching the given base filename prefix, e.g
92 // "*.png" will match all png files. The "*" does not match path delimiters (/),
93 // so if you organize your resources in sub-folders, you need to be explicit about it, e.g.:
94 // "images/*.png". To match any PNG image anywhere in the bundle you can do "**.png", and
95 // to match all PNG images below the images folder, use "images/**.jpg".
96 // The matching is case insensitive.
97 // Match matches by using the value of Resource.Name, which, by default, is a filename with
98 // path relative to the bundle root with Unix style slashes (/) and no leading slash, e.g. "images/logo.png".
99 // See https://github.com/gobwas/glob for the full rules set.
100 func (r Resources) Match(pattern any) Resources {
101 patternstr, err := cast.ToStringE(pattern)
102 if err != nil {
103 panic(err)
104 }
105
106 g, err := glob.GetGlob(patternstr)
107 if err != nil {
108 panic(err)
109 }
110
111 var matches Resources
112 for _, resource := range r {
113 if g.Match(strings.ToLower(resource.Name())) {
114 matches = append(matches, resource)
115 }
116 }
117 return matches
118 }
119
120 type translatedResource interface {
121 TranslationKey() string
122 }
123
124 // MergeByLanguage adds missing translations in r1 from r2.
125 func (r Resources) MergeByLanguage(r2 Resources) Resources {
126 result := append(Resources(nil), r...)
127 m := make(map[string]bool)
128 for _, rr := range r {
129 if translated, ok := rr.(translatedResource); ok {
130 m[translated.TranslationKey()] = true
131 }
132 }
133
134 for _, rr := range r2 {
135 if translated, ok := rr.(translatedResource); ok {
136 if _, found := m[translated.TranslationKey()]; !found {
137 result = append(result, rr)
138 }
139 }
140 }
141 return result
142 }
143
144 // MergeByLanguageInterface is the generic version of MergeByLanguage. It
145 // is here just so it can be called from the tpl package.
146 func (r Resources) MergeByLanguageInterface(in any) (any, error) {
147 r2, ok := in.(Resources)
148 if !ok {
149 return nil, fmt.Errorf("%T cannot be merged by language", in)
150 }
151 return r.MergeByLanguage(r2), nil
152 }
153
154 // Source is an internal template and not meant for use in the templates. It
155 // may change without notice.
156 type Source interface {
157 Publish() error
158 }
159
160 // ResourceFinder provides methods to find Resources.
161 // Note that GetRemote (as found in resources.GetRemote) is
162 // not covered by this interface, as this is only available as a global template function.
163 type ResourceFinder interface {
164
165 // Get locates the Resource with the given name in the current context (e.g. in .Page.Resources).
166 //
167 // It returns nil if no Resource could found, panics if name is invalid.
168 Get(name any) Resource
169
170 // GetMatch finds the first Resource matching the given pattern, or nil if none found.
171 //
172 // See Match for a more complete explanation about the rules used.
173 //
174 // It returns nil if no Resource could found, panics if pattern is invalid.
175 GetMatch(pattern any) Resource
176
177 // Match gets all resources matching the given base path prefix, e.g
178 // "*.png" will match all png files. The "*" does not match path delimiters (/),
179 // so if you organize your resources in sub-folders, you need to be explicit about it, e.g.:
180 // "images/*.png". To match any PNG image anywhere in the bundle you can do "**.png", and
181 // to match all PNG images below the images folder, use "images/**.jpg".
182 //
183 // The matching is case insensitive.
184 //
185 // Match matches by using a relative pathwith Unix style slashes (/) and no
186 // leading slash, e.g. "images/logo.png".
187 //
188 // See https://github.com/gobwas/glob for the full rules set.
189 //
190 // See Match for a more complete explanation about the rules used.
191 //
192 // It returns nil if no Resources could found, panics if pattern is invalid.
193 Match(pattern any) Resources
194
195 // ByType returns resources of a given resource type (e.g. "image").
196 // It returns nil if no Resources could found, panics if typ is invalid.
197 ByType(typ any) Resources
198 }