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 }