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