github.com/kovansky/hugo@v0.92.3-0.20220224232819-63076e4ff19f/deploy/deployConfig.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 //go:build !nodeploy 15 // +build !nodeploy 16 17 package deploy 18 19 import ( 20 "fmt" 21 "regexp" 22 23 "github.com/gobwas/glob" 24 "github.com/gohugoio/hugo/config" 25 hglob "github.com/gohugoio/hugo/hugofs/glob" 26 "github.com/gohugoio/hugo/media" 27 "github.com/mitchellh/mapstructure" 28 "github.com/pkg/errors" 29 ) 30 31 const deploymentConfigKey = "deployment" 32 33 // deployConfig is the complete configuration for deployment. 34 type deployConfig struct { 35 Targets []*target 36 Matchers []*matcher 37 Order []string 38 39 ordering []*regexp.Regexp // compiled Order 40 mediaTypes media.Types 41 } 42 43 type target struct { 44 Name string 45 URL string 46 47 CloudFrontDistributionID string 48 49 // GoogleCloudCDNOrigin specifies the Google Cloud project and CDN origin to 50 // invalidate when deploying this target. It is specified as <project>/<origin>. 51 GoogleCloudCDNOrigin string 52 53 // Optional patterns of files to include/exclude for this target. 54 // Parsed using github.com/gobwas/glob. 55 Include string 56 Exclude string 57 58 // Parsed versions of Include/Exclude. 59 includeGlob glob.Glob 60 excludeGlob glob.Glob 61 } 62 63 func (tgt *target) parseIncludeExclude() error { 64 var err error 65 if tgt.Include != "" { 66 tgt.includeGlob, err = hglob.GetGlob(tgt.Include) 67 if err != nil { 68 return fmt.Errorf("invalid deployment.target.include %q: %v", tgt.Include, err) 69 } 70 } 71 if tgt.Exclude != "" { 72 tgt.excludeGlob, err = hglob.GetGlob(tgt.Exclude) 73 if err != nil { 74 return fmt.Errorf("invalid deployment.target.exclude %q: %v", tgt.Exclude, err) 75 } 76 } 77 return nil 78 } 79 80 // matcher represents configuration to be applied to files whose paths match 81 // a specified pattern. 82 type matcher struct { 83 // Pattern is the string pattern to match against paths. 84 // Matching is done against paths converted to use / as the path separator. 85 Pattern string 86 87 // CacheControl specifies caching attributes to use when serving the blob. 88 // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control 89 CacheControl string 90 91 // ContentEncoding specifies the encoding used for the blob's content, if any. 92 // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding 93 ContentEncoding string 94 95 // ContentType specifies the MIME type of the blob being written. 96 // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type 97 ContentType string 98 99 // Gzip determines whether the file should be gzipped before upload. 100 // If so, the ContentEncoding field will automatically be set to "gzip". 101 Gzip bool 102 103 // Force indicates that matching files should be re-uploaded. Useful when 104 // other route-determined metadata (e.g., ContentType) has changed. 105 Force bool 106 107 // re is Pattern compiled. 108 re *regexp.Regexp 109 } 110 111 func (m *matcher) Matches(path string) bool { 112 return m.re.MatchString(path) 113 } 114 115 // decode creates a config from a given Hugo configuration. 116 func decodeConfig(cfg config.Provider) (deployConfig, error) { 117 var ( 118 mediaTypesConfig []map[string]interface{} 119 dcfg deployConfig 120 ) 121 122 if !cfg.IsSet(deploymentConfigKey) { 123 return dcfg, nil 124 } 125 if err := mapstructure.WeakDecode(cfg.GetStringMap(deploymentConfigKey), &dcfg); err != nil { 126 return dcfg, err 127 } 128 for _, tgt := range dcfg.Targets { 129 if tgt == nil { 130 return dcfg, errors.New("empty deployment target") 131 } 132 if err := tgt.parseIncludeExclude(); err != nil { 133 return dcfg, err 134 } 135 } 136 var err error 137 for _, m := range dcfg.Matchers { 138 if m == nil { 139 return dcfg, errors.New("empty deployment matcher") 140 } 141 m.re, err = regexp.Compile(m.Pattern) 142 if err != nil { 143 return dcfg, fmt.Errorf("invalid deployment.matchers.pattern: %v", err) 144 } 145 } 146 for _, o := range dcfg.Order { 147 re, err := regexp.Compile(o) 148 if err != nil { 149 return dcfg, fmt.Errorf("invalid deployment.orderings.pattern: %v", err) 150 } 151 dcfg.ordering = append(dcfg.ordering, re) 152 } 153 154 if cfg.IsSet("mediaTypes") { 155 mediaTypesConfig = append(mediaTypesConfig, cfg.GetStringMap("mediaTypes")) 156 } 157 158 dcfg.mediaTypes, err = media.DecodeTypes(mediaTypesConfig...) 159 if err != nil { 160 return dcfg, err 161 } 162 return dcfg, nil 163 }