github.com/graemephi/kahugo@v0.62.3-0.20211121071557-d78c0423784d/resources/resource_metadata.go (about) 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 resources 15 16 import ( 17 "fmt" 18 "strconv" 19 "strings" 20 21 "github.com/gohugoio/hugo/hugofs/glob" 22 "github.com/gohugoio/hugo/media" 23 "github.com/gohugoio/hugo/resources/resource" 24 25 "github.com/pkg/errors" 26 "github.com/spf13/cast" 27 28 "github.com/gohugoio/hugo/common/maps" 29 ) 30 31 var ( 32 _ metaAssigner = (*genericResource)(nil) 33 _ metaAssigner = (*imageResource)(nil) 34 _ metaAssignerProvider = (*resourceAdapter)(nil) 35 ) 36 37 type metaAssignerProvider interface { 38 getMetaAssigner() metaAssigner 39 } 40 41 // metaAssigner allows updating metadata in resources that supports it. 42 type metaAssigner interface { 43 setTitle(title string) 44 setName(name string) 45 setMediaType(mediaType media.Type) 46 updateParams(params map[string]interface{}) 47 } 48 49 const counterPlaceHolder = ":counter" 50 51 // AssignMetadata assigns the given metadata to those resources that supports updates 52 // and matching by wildcard given in `src` using `filepath.Match` with lower cased values. 53 // This assignment is additive, but the most specific match needs to be first. 54 // The `name` and `title` metadata field support shell-matched collection it got a match in. 55 // See https://golang.org/pkg/path/#Match 56 func AssignMetadata(metadata []map[string]interface{}, resources ...resource.Resource) error { 57 counters := make(map[string]int) 58 59 for _, r := range resources { 60 var ma metaAssigner 61 mp, ok := r.(metaAssignerProvider) 62 if ok { 63 ma = mp.getMetaAssigner() 64 } else { 65 ma, ok = r.(metaAssigner) 66 if !ok { 67 continue 68 } 69 } 70 71 var ( 72 nameSet, titleSet bool 73 nameCounter, titleCounter = 0, 0 74 nameCounterFound, titleCounterFound bool 75 resourceSrcKey = strings.ToLower(r.Name()) 76 ) 77 78 for _, meta := range metadata { 79 src, found := meta["src"] 80 if !found { 81 return fmt.Errorf("missing 'src' in metadata for resource") 82 } 83 84 srcKey := strings.ToLower(cast.ToString(src)) 85 86 glob, err := glob.GetGlob(srcKey) 87 if err != nil { 88 return errors.Wrap(err, "failed to match resource with metadata") 89 } 90 91 match := glob.Match(resourceSrcKey) 92 93 if match { 94 if !nameSet { 95 name, found := meta["name"] 96 if found { 97 name := cast.ToString(name) 98 if !nameCounterFound { 99 nameCounterFound = strings.Contains(name, counterPlaceHolder) 100 } 101 if nameCounterFound && nameCounter == 0 { 102 counterKey := "name_" + srcKey 103 nameCounter = counters[counterKey] + 1 104 counters[counterKey] = nameCounter 105 } 106 107 ma.setName(replaceResourcePlaceholders(name, nameCounter)) 108 nameSet = true 109 } 110 } 111 112 if !titleSet { 113 title, found := meta["title"] 114 if found { 115 title := cast.ToString(title) 116 if !titleCounterFound { 117 titleCounterFound = strings.Contains(title, counterPlaceHolder) 118 } 119 if titleCounterFound && titleCounter == 0 { 120 counterKey := "title_" + srcKey 121 titleCounter = counters[counterKey] + 1 122 counters[counterKey] = titleCounter 123 } 124 ma.setTitle((replaceResourcePlaceholders(title, titleCounter))) 125 titleSet = true 126 } 127 } 128 129 params, found := meta["params"] 130 if found { 131 m := maps.ToStringMap(params) 132 // Needed for case insensitive fetching of params values 133 maps.PrepareParams(m) 134 ma.updateParams(m) 135 } 136 } 137 } 138 } 139 140 return nil 141 } 142 143 func replaceResourcePlaceholders(in string, counter int) string { 144 return strings.Replace(in, counterPlaceHolder, strconv.Itoa(counter), -1) 145 }