diff options
Diffstat (limited to 'deploy/deployconfig/deployConfig.go')
-rw-r--r-- | deploy/deployconfig/deployConfig.go | 174 |
1 files changed, 174 insertions, 0 deletions
diff --git a/deploy/deployconfig/deployConfig.go b/deploy/deployconfig/deployConfig.go new file mode 100644 index 000000000..b5b8973b2 --- /dev/null +++ b/deploy/deployconfig/deployConfig.go @@ -0,0 +1,174 @@ +// Copyright 2024 The Hugo Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package deployconfig + +import ( + "errors" + "fmt" + "regexp" + + "github.com/gobwas/glob" + "github.com/gohugoio/hugo/config" + hglob "github.com/gohugoio/hugo/hugofs/glob" + "github.com/mitchellh/mapstructure" +) + +const DeploymentConfigKey = "deployment" + +// DeployConfig is the complete configuration for deployment. +type DeployConfig struct { + Targets []*Target + Matchers []*Matcher + Order []string + + // Usually set via flags. + // Target deployment Name; defaults to the first one. + Target string + // Show a confirm prompt before deploying. + Confirm bool + // DryRun will try the deployment without any remote changes. + DryRun bool + // Force will re-upload all files. + Force bool + // Invalidate the CDN cache listed in the deployment target. + InvalidateCDN bool + // MaxDeletes is the maximum number of files to delete. + MaxDeletes int + // Number of concurrent workers to use when uploading files. + Workers int + + Ordering []*regexp.Regexp `json:"-"` // compiled Order +} + +type Target struct { + Name string + URL string + + CloudFrontDistributionID string + + // GoogleCloudCDNOrigin specifies the Google Cloud project and CDN origin to + // invalidate when deploying this target. It is specified as <project>/<origin>. + GoogleCloudCDNOrigin string + + // Optional patterns of files to include/exclude for this target. + // Parsed using github.com/gobwas/glob. + Include string + Exclude string + + // Parsed versions of Include/Exclude. + IncludeGlob glob.Glob `json:"-"` + ExcludeGlob glob.Glob `json:"-"` +} + +func (tgt *Target) ParseIncludeExclude() error { + var err error + if tgt.Include != "" { + tgt.IncludeGlob, err = hglob.GetGlob(tgt.Include) + if err != nil { + return fmt.Errorf("invalid deployment.target.include %q: %v", tgt.Include, err) + } + } + if tgt.Exclude != "" { + tgt.ExcludeGlob, err = hglob.GetGlob(tgt.Exclude) + if err != nil { + return fmt.Errorf("invalid deployment.target.exclude %q: %v", tgt.Exclude, err) + } + } + return nil +} + +// Matcher represents configuration to be applied to files whose paths match +// a specified pattern. +type Matcher struct { + // Pattern is the string pattern to match against paths. + // Matching is done against paths converted to use / as the path separator. + Pattern string + + // CacheControl specifies caching attributes to use when serving the blob. + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control + CacheControl string + + // ContentEncoding specifies the encoding used for the blob's content, if any. + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding + ContentEncoding string + + // ContentType specifies the MIME type of the blob being written. + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type + ContentType string + + // Gzip determines whether the file should be gzipped before upload. + // If so, the ContentEncoding field will automatically be set to "gzip". + Gzip bool + + // Force indicates that matching files should be re-uploaded. Useful when + // other route-determined metadata (e.g., ContentType) has changed. + Force bool + + // Re is Pattern compiled. + Re *regexp.Regexp `json:"-"` +} + +func (m *Matcher) Matches(path string) bool { + return m.Re.MatchString(path) +} + +var DefaultConfig = DeployConfig{ + Workers: 10, + InvalidateCDN: true, + MaxDeletes: 256, +} + +// DecodeConfig creates a config from a given Hugo configuration. +func DecodeConfig(cfg config.Provider) (DeployConfig, error) { + dcfg := DefaultConfig + + if !cfg.IsSet(DeploymentConfigKey) { + return dcfg, nil + } + if err := mapstructure.WeakDecode(cfg.GetStringMap(DeploymentConfigKey), &dcfg); err != nil { + return dcfg, err + } + + if dcfg.Workers <= 0 { + dcfg.Workers = 10 + } + + for _, tgt := range dcfg.Targets { + if *tgt == (Target{}) { + return dcfg, errors.New("empty deployment target") + } + if err := tgt.ParseIncludeExclude(); err != nil { + return dcfg, err + } + } + var err error + for _, m := range dcfg.Matchers { + if *m == (Matcher{}) { + return dcfg, errors.New("empty deployment matcher") + } + m.Re, err = regexp.Compile(m.Pattern) + if err != nil { + return dcfg, fmt.Errorf("invalid deployment.matchers.pattern: %v", err) + } + } + for _, o := range dcfg.Order { + re, err := regexp.Compile(o) + if err != nil { + return dcfg, fmt.Errorf("invalid deployment.orderings.pattern: %v", err) + } + dcfg.Ordering = append(dcfg.Ordering, re) + } + + return dcfg, nil +} |