Compare commits

..

1 Commits

Author SHA1 Message Date
Bjørn Erik Pedersen 10ddc2ef92 Improve error messages for PostCSS etc.
Fixes #9730
2023-07-17 19:42:13 +02:00
649 changed files with 28262 additions and 11007 deletions
+2 -2
View File
@@ -4,7 +4,7 @@ parameters:
defaults: &defaults
resource_class: large
docker:
- image: bepsays/ci-hugoreleaser:1.22100.20001
- image: bepsays/ci-hugoreleaser:1.22000.20100
environment: &buildenv
GOMODCACHE: /root/project/gomodcache
version: 2
@@ -60,7 +60,7 @@ jobs:
environment:
<<: [*buildenv]
docker:
- image: bepsays/ci-hugoreleaser-linux-arm64:1.22100.20001
- image: bepsays/ci-hugoreleaser-linux-arm64:1.22000.20100
steps:
- *restore-cache
- &attach-workspace
+1 -6
View File
@@ -5,12 +5,7 @@ assignees: ''
about: Create a report to help us improve
---
<!--
Please do not use the issue queue for questions or troubleshooting. Unless you are certain that your issue is a software defect, use the forum:
https://discourse.gohugo.io
-->
<!-- Please answer these questions before submitting your issue. Thanks! -->
### What version of Hugo are you using (`hugo version`)?
+1 -1
View File
@@ -14,7 +14,7 @@ jobs:
test:
strategy:
matrix:
go-version: [1.21.x]
go-version: [1.20.x]
os: [ubuntu-latest]
runs-on: ${{ matrix.os }}
steps:
+5 -5
View File
@@ -16,7 +16,7 @@ jobs:
test:
strategy:
matrix:
go-version: [1.20.x,1.21.x]
go-version: [1.19.x,1.20.x]
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
@@ -34,7 +34,7 @@ jobs:
- name: Install Ruby
uses: ruby/setup-ruby@ee2113536afb7f793eed4ce60e8d3b26db912da4
with:
ruby-version: '2.7'
ruby-version: '2.7'
bundler-cache: true #
- name: Install Python
uses: actions/setup-python@3105fb18c05ddd93efea5f9e0bef7a03a6e9e7df
@@ -64,7 +64,7 @@ jobs:
run: |
Choco-Install -PackageName mingw -ArgumentList "--version","12.2.0","--allow-downgrade"
- if: matrix.os == 'ubuntu-latest'
name: Install dart-sass Linux
name: Install dart-sass-embedded Linux
run: |
echo "Install Dart Sass version ${SASS_VERSION} ..."
curl -LJO "https://github.com/sass/dart-sass/releases/download/${SASS_VERSION}/dart-sass-${SASS_VERSION}-linux-x64.tar.gz";
@@ -73,7 +73,7 @@ jobs:
echo "$GOBIN"
echo "$GITHUB_WORKSPACE/dart-sass/" >> $GITHUB_PATH
- if: matrix.os == 'macos-latest'
name: Install dart-sass MacOS
name: Install dart-sass-embedded MacOS
run: |
echo "Install Dart Sass version ${SASS_VERSION} ..."
curl -LJO "https://github.com/sass/dart-sass/releases/download/${SASS_VERSION}/dart-sass-${SASS_VERSION}-macos-x64.tar.gz";
@@ -81,7 +81,7 @@ jobs:
tar -xvf "dart-sass-${SASS_VERSION}-macos-x64.tar.gz";
echo "$GITHUB_WORKSPACE/dart-sass/" >> $GITHUB_PATH
- if: matrix.os == 'windows-latest'
name: Install dart-sass Windows
name: Install dart-sass-embedded Windows
run: |
echo "Install Dart Sass version ${env:SASS_VERSION} ..."
curl -LJO "https://github.com/sass/dart-sass/releases/download/${env:SASS_VERSION}/dart-sass-${env:SASS_VERSION}-windows-x64.zip";
+2 -2
View File
@@ -2,7 +2,7 @@
# Twitter: https://twitter.com/gohugoio
# Website: https://gohugo.io/
FROM golang:1.21-alpine AS build
FROM golang:1.19-alpine AS build
# Optionally set HUGO_BUILD_TAGS to "extended" or "nodeploy" when building like so:
# docker build --build-arg HUGO_BUILD_TAGS=extended .
@@ -26,7 +26,7 @@ RUN mage hugo && mage install
# ---
FROM alpine:3.18
FROM alpine:3.16
COPY --from=build /go/bin/hugo /usr/bin/hugo
+1 -1
View File
@@ -1,4 +1,4 @@
[bep]: https://github.com/bep
[bep]: https://github.com/spf13
[bugs]: https://github.com/gohugoio/hugo/issues?q=is%3Aopen+is%3Aissue+label%3ABug
[contributing]: CONTRIBUTING.md
[create a proposal]: https://github.com/gohugoio/hugo/issues/new?labels=Proposal%2C+NeedsTriage&template=feature_request.md
+4 -33
View File
@@ -51,9 +51,6 @@ type Cache struct {
pruneAllRootDir string
nlocker *lockTracker
initOnce sync.Once
initErr error
}
type lockTracker struct {
@@ -106,23 +103,9 @@ func (l *lockedFile) Close() error {
return l.File.Close()
}
func (c *Cache) init() error {
c.initOnce.Do(func() {
// Create the base dir if it does not exist.
if err := c.Fs.MkdirAll("", 0777); err != nil && !os.IsExist(err) {
c.initErr = err
}
})
return c.initErr
}
// WriteCloser returns a transactional writer into the cache.
// It's important that it's closed when done.
func (c *Cache) WriteCloser(id string) (ItemInfo, io.WriteCloser, error) {
if err := c.init(); err != nil {
return ItemInfo{}, nil, err
}
id = cleanID(id)
c.nlocker.Lock(id)
@@ -147,10 +130,6 @@ func (c *Cache) WriteCloser(id string) (ItemInfo, io.WriteCloser, error) {
func (c *Cache) ReadOrCreate(id string,
read func(info ItemInfo, r io.ReadSeeker) error,
create func(info ItemInfo, w io.WriteCloser) error) (info ItemInfo, err error) {
if err := c.init(); err != nil {
return ItemInfo{}, err
}
id = cleanID(id)
c.nlocker.Lock(id)
@@ -184,9 +163,6 @@ func (c *Cache) ReadOrCreate(id string,
// be invoked and the result cached.
// This method is protected by a named lock using the given id as identifier.
func (c *Cache) GetOrCreate(id string, create func() (io.ReadCloser, error)) (ItemInfo, io.ReadCloser, error) {
if err := c.init(); err != nil {
return ItemInfo{}, nil, err
}
id = cleanID(id)
c.nlocker.Lock(id)
@@ -221,9 +197,6 @@ func (c *Cache) GetOrCreate(id string, create func() (io.ReadCloser, error)) (It
// GetOrCreateBytes is the same as GetOrCreate, but produces a byte slice.
func (c *Cache) GetOrCreateBytes(id string, create func() ([]byte, error)) (ItemInfo, []byte, error) {
if err := c.init(); err != nil {
return ItemInfo{}, nil, err
}
id = cleanID(id)
c.nlocker.Lock(id)
@@ -259,9 +232,6 @@ func (c *Cache) GetOrCreateBytes(id string, create func() ([]byte, error)) (Item
// GetBytes gets the file content with the given id from the cache, nil if none found.
func (c *Cache) GetBytes(id string) (ItemInfo, []byte, error) {
if err := c.init(); err != nil {
return ItemInfo{}, nil, err
}
id = cleanID(id)
c.nlocker.Lock(id)
@@ -280,9 +250,6 @@ func (c *Cache) GetBytes(id string) (ItemInfo, []byte, error) {
// Get gets the file with the given id from the cache, nil if none found.
func (c *Cache) Get(id string) (ItemInfo, io.ReadCloser, error) {
if err := c.init(); err != nil {
return ItemInfo{}, nil, err
}
id = cleanID(id)
c.nlocker.Lock(id)
@@ -380,6 +347,10 @@ func NewCaches(p *helpers.PathSpec) (Caches, error) {
baseDir := v.DirCompiled
if err := cfs.MkdirAll(baseDir, 0777); err != nil && !os.IsExist(err) {
return nil, err
}
bfs := afero.NewBasePathFs(cfs, baseDir)
var pruneAllRootDir string
+1 -1
View File
@@ -93,7 +93,7 @@ type FileCacheConfig struct {
// Will resources/_gen will get its own composite filesystem that
// also checks any theme.
IsResourceDir bool `json:"-"`
IsResourceDir bool
}
// GetJSONCache gets the file cache for getJSON.
-6
View File
@@ -53,9 +53,6 @@ func (c *Cache) Prune(force bool) (int, error) {
if c.pruneAllRootDir != "" {
return c.pruneRootDir(force)
}
if err := c.init(); err != nil {
return 0, err
}
counter := 0
@@ -120,9 +117,6 @@ func (c *Cache) Prune(force bool) (int, error) {
}
func (c *Cache) pruneRootDir(force bool) (int, error) {
if err := c.init(); err != nil {
return 0, err
}
info, err := c.Fs.Stat(c.pruneAllRootDir)
if err != nil {
if herrors.IsNotExist(err) {
+1 -1
View File
@@ -515,7 +515,7 @@ Complete documentation is available at https://gohugo.io/.`
func applyLocalFlagsBuildConfig(cmd *cobra.Command, r *rootCommand) {
cmd.Flags().StringSliceP("theme", "t", []string{}, "themes to use (located in /themes/THEMENAME/)")
cmd.Flags().StringVarP(&r.baseURL, "baseURL", "b", "", "hostname (and path) to the root, e.g. https://spf13.com/")
cmd.Flags().StringP("cacheDir", "", "", "filesystem path to cache directory")
cmd.Flags().StringP("cacheDir", "", "", "filesystem path to cache directory. Defaults: $TMPDIR/hugo_cache_$USER/")
_ = cmd.Flags().SetAnnotation("cacheDir", cobra.BashCompSubdirsInDir, []string{})
cmd.Flags().StringP("contentDir", "c", "", "filesystem path to content directory")
_ = cmd.Flags().SetAnnotation("theme", cobra.BashCompSubdirsInDir, []string{"themes"})
-2
View File
@@ -23,7 +23,6 @@ import (
"time"
"github.com/bep/simplecobra"
"github.com/gohugoio/hugo/common/maps"
"github.com/gohugoio/hugo/config/allconfig"
"github.com/gohugoio/hugo/modules"
"github.com/gohugoio/hugo/parser"
@@ -93,7 +92,6 @@ func (c *configCommand) Run(ctx context.Context, cd *simplecobra.Commandeer, arg
if err := json.Unmarshal(buf.Bytes(), &m); err != nil {
return err
}
maps.ConvertFloat64WithNoDecimalsToInt(m)
switch format {
case "yaml":
return parser.InterfaceToConfig(m, metadecoders.YAML, os.Stdout)
+6 -28
View File
@@ -14,7 +14,6 @@
package commands
import (
"bytes"
"context"
"encoding/json"
"fmt"
@@ -31,11 +30,8 @@ import (
"github.com/gohugoio/hugo/docshelper"
"github.com/gohugoio/hugo/helpers"
"github.com/gohugoio/hugo/hugofs"
"github.com/gohugoio/hugo/hugolib"
"github.com/gohugoio/hugo/parser"
"github.com/spf13/cobra"
"github.com/spf13/cobra/doc"
"gopkg.in/yaml.v2"
)
func newGenCommand() *genCommand {
@@ -190,36 +186,18 @@ url: %s
run: func(ctx context.Context, cd *simplecobra.Commandeer, r *rootCommand, args []string) error {
r.Println("Generate docs data to", docsHelperTarget)
var buf bytes.Buffer
jsonEnc := json.NewEncoder(&buf)
configProvider := func() docshelper.DocProvider {
conf := hugolib.DefaultConfig()
conf.CacheDir = "" // The default value does not make sense in the docs.
defaultConfig := parser.LowerCaseCamelJSONMarshaller{Value: conf}
return docshelper.DocProvider{"config": defaultConfig}
}
docshelper.AddDocProviderFunc(configProvider)
if err := jsonEnc.Encode(docshelper.GetDocProvider()); err != nil {
return err
}
// Decode the JSON to a map[string]interface{} and then unmarshal it again to the correct format.
var m map[string]interface{}
if err := json.Unmarshal(buf.Bytes(), &m); err != nil {
return err
}
targetFile := filepath.Join(docsHelperTarget, "docs.yaml")
targetFile := filepath.Join(docsHelperTarget, "docs.json")
f, err := os.Create(targetFile)
if err != nil {
return err
}
defer f.Close()
yamlEnc := yaml.NewEncoder(f)
if err := yamlEnc.Encode(m); err != nil {
enc := json.NewEncoder(f)
enc.SetIndent("", " ")
if err := enc.Encode(docshelper.GetDocProvider()); err != nil {
return err
}
+18 -6
View File
@@ -14,6 +14,7 @@
package commands
import (
"bytes"
"errors"
"fmt"
"log"
@@ -23,6 +24,8 @@ import (
"github.com/bep/simplecobra"
"github.com/gohugoio/hugo/config"
"github.com/gohugoio/hugo/helpers"
"github.com/spf13/afero"
"github.com/spf13/pflag"
)
@@ -83,12 +86,13 @@ func flagsToCfgWithAdditionalConfigBase(cd *simplecobra.Commandeer, cfg config.P
// Flags that we for some reason don't want to expose in the site config.
internalKeySet := map[string]bool{
"quiet": true,
"verbose": true,
"watch": true,
"liveReloadPort": true,
"renderToMemory": true,
"clock": true,
"quiet": true,
"verbose": true,
"watch": true,
"disableLiveReload": true,
"liveReloadPort": true,
"renderToMemory": true,
"clock": true,
}
cmd := cd.CobraCommand
@@ -120,3 +124,11 @@ func mkdir(x ...string) {
log.Fatal(err)
}
}
func touchFile(fs afero.Fs, filename string) {
mkdir(filepath.Dir(filename))
err := helpers.WriteToDisk(filename, bytes.NewReader([]byte{}), fs)
if err != nil {
log.Fatal(err)
}
}
+191 -26
View File
@@ -16,14 +16,19 @@ package commands
import (
"bytes"
"context"
"errors"
"fmt"
"path/filepath"
"strings"
"github.com/bep/simplecobra"
"github.com/gohugoio/hugo/common/paths"
"github.com/gohugoio/hugo/common/htime"
"github.com/gohugoio/hugo/config"
"github.com/gohugoio/hugo/create"
"github.com/gohugoio/hugo/create/skeletons"
"github.com/gohugoio/hugo/helpers"
"github.com/gohugoio/hugo/parser"
"github.com/gohugoio/hugo/parser/metadecoders"
"github.com/spf13/afero"
"github.com/spf13/cobra"
)
@@ -94,13 +99,52 @@ Use ` + "`hugo new [contentPath]`" + ` to create new content.`,
}
sourceFs := conf.fs.Source
err = skeletons.CreateSite(createpath, sourceFs, force, format)
if err != nil {
return err
archeTypePath := filepath.Join(createpath, "archetypes")
dirs := []string{
archeTypePath,
filepath.Join(createpath, "assets"),
filepath.Join(createpath, "content"),
filepath.Join(createpath, "data"),
filepath.Join(createpath, "layouts"),
filepath.Join(createpath, "static"),
filepath.Join(createpath, "themes"),
}
r.Printf("Congratulations! Your new Hugo site was created in %s.\n\n", createpath)
r.Println(c.newSiteNextStepsText(createpath, format))
if exists, _ := helpers.Exists(createpath, sourceFs); exists {
if isDir, _ := helpers.IsDir(createpath, sourceFs); !isDir {
return errors.New(createpath + " already exists but not a directory")
}
isEmpty, _ := helpers.IsEmpty(createpath, sourceFs)
switch {
case !isEmpty && !force:
return errors.New(createpath + " already exists and is not empty. See --force.")
case !isEmpty && force:
all := append(dirs, filepath.Join(createpath, "hugo."+format))
for _, path := range all {
if exists, _ := helpers.Exists(path, sourceFs); exists {
return errors.New(path + " already exists")
}
}
}
}
for _, dir := range dirs {
if err := sourceFs.MkdirAll(dir, 0777); err != nil {
return fmt.Errorf("failed to create dir: %w", err)
}
}
c.newSiteCreateConfig(sourceFs, createpath, format)
// Create a default archetype file.
helpers.SafeWriteToDisk(filepath.Join(archeTypePath, "default.md"),
strings.NewReader(create.DefaultArchetypeTemplateTemplate), sourceFs)
r.Printf("Congratulations! Your new Hugo site is created in %s.\n\n", createpath)
r.Println(c.newSiteNextStepsText())
return nil
},
@@ -121,22 +165,91 @@ according to your needs.`,
if len(args) < 1 {
return newUserError("theme name needs to be provided")
}
cfg := config.New()
cfg.Set("publishDir", "public")
conf, err := r.ConfigFromProvider(r.configVersionID.Load(), flagsToCfg(cd, cfg))
h, err := r.Hugo(flagsToCfg(cd, nil))
if err != nil {
return err
}
sourceFs := conf.fs.Source
createpath := paths.AbsPathify(conf.configs.Base.WorkingDir, filepath.Join(conf.configs.Base.ThemesDir, args[0]))
r.Println("Creating new theme in", createpath)
ps := h.PathSpec
sourceFs := ps.Fs.Source
themesDir := h.Configs.LoadingInfo.BaseConfig.ThemesDir
createpath := ps.AbsPathify(filepath.Join(themesDir, args[0]))
r.Println("Creating theme at", createpath)
err = skeletons.CreateTheme(createpath, sourceFs)
if x, _ := helpers.Exists(createpath, sourceFs); x {
return errors.New(createpath + " already exists")
}
for _, filename := range []string{
"index.html",
"404.html",
"_default/list.html",
"_default/single.html",
"partials/head.html",
"partials/header.html",
"partials/footer.html",
} {
touchFile(sourceFs, filepath.Join(createpath, "layouts", filename))
}
baseofDefault := []byte(`<!DOCTYPE html>
<html>
{{- partial "head.html" . -}}
<body>
{{- partial "header.html" . -}}
<div id="content">
{{- block "main" . }}{{- end }}
</div>
{{- partial "footer.html" . -}}
</body>
</html>
`)
err = helpers.WriteToDisk(filepath.Join(createpath, "layouts", "_default", "baseof.html"), bytes.NewReader(baseofDefault), sourceFs)
if err != nil {
return err
}
mkdir(createpath, "archetypes")
archDefault := []byte("+++\n+++\n")
err = helpers.WriteToDisk(filepath.Join(createpath, "archetypes", "default.md"), bytes.NewReader(archDefault), sourceFs)
if err != nil {
return err
}
mkdir(createpath, "static", "js")
mkdir(createpath, "static", "css")
by := []byte(`The MIT License (MIT)
Copyright (c) ` + htime.Now().Format("2006") + ` YOUR_NAME_HERE
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
`)
err = helpers.WriteToDisk(filepath.Join(createpath, "LICENSE"), bytes.NewReader(by), sourceFs)
if err != nil {
return err
}
c.createThemeMD(ps.Fs.Source, createpath)
return nil
},
},
@@ -186,25 +299,77 @@ func (c *newCommand) PreRun(cd, runner *simplecobra.Commandeer) error {
return nil
}
func (c *newCommand) newSiteNextStepsText(path string, format string) string {
format = strings.ToLower(format)
func (c *newCommand) newSiteCreateConfig(fs afero.Fs, inpath string, kind string) (err error) {
in := map[string]string{
"baseURL": "http://example.org/",
"title": "My New Hugo Site",
"languageCode": "en-us",
}
var buf bytes.Buffer
err = parser.InterfaceToConfig(in, metadecoders.FormatFromString(kind), &buf)
if err != nil {
return err
}
return helpers.WriteToDisk(filepath.Join(inpath, "hugo."+kind), &buf, fs)
}
func (c *newCommand) newSiteNextStepsText() string {
var nextStepsText bytes.Buffer
nextStepsText.WriteString(`Just a few more steps...
nextStepsText.WriteString(`Just a few more steps and you're ready to go:
1. Change the current directory to ` + path + `.
2. Create or install a theme:
- Create a new theme with the command "hugo new theme <THEMENAME>"
- Install a theme from https://themes.gohugo.io/
3. Edit hugo.` + format + `, setting the "theme" property to the theme name.
4. Create new content with the command "hugo new content `)
1. Download a theme into the same-named folder.
Choose a theme from https://themes.gohugo.io/ or
create your own with the "hugo new theme <THEMENAME>" command.
2. Perhaps you want to add some content. You can add single files
with "hugo new `)
nextStepsText.WriteString(filepath.Join("<SECTIONNAME>", "<FILENAME>.<FORMAT>"))
nextStepsText.WriteString(`".
5. Start the embedded web server with the command "hugo server --buildDrafts".
3. Start the built-in live server via "hugo server".
See documentation at https://gohugo.io/.`)
Visit https://gohugo.io/ for quickstart guide and full documentation.`)
return nextStepsText.String()
}
func (c *newCommand) createThemeMD(fs afero.Fs, inpath string) (err error) {
by := []byte(`# theme.toml template for a Hugo theme
# See https://github.com/gohugoio/hugoThemes#themetoml for an example
name = "` + strings.Title(helpers.MakeTitle(filepath.Base(inpath))) + `"
license = "MIT"
licenselink = "https://github.com/yourname/yourtheme/blob/master/LICENSE"
description = ""
homepage = "http://example.com/"
tags = []
features = []
min_version = "0.115.0"
[author]
name = ""
homepage = ""
# If porting an existing theme
[original]
name = ""
homepage = ""
repo = ""
`)
err = helpers.WriteToDisk(filepath.Join(inpath, "theme.toml"), bytes.NewReader(by), fs)
if err != nil {
return
}
err = helpers.WriteToDisk(filepath.Join(inpath, "hugo.toml"), strings.NewReader("# Theme config.\n"), fs)
if err != nil {
return
}
return nil
}
+11 -11
View File
@@ -23,6 +23,7 @@ import (
"errors"
"fmt"
"io"
"io/ioutil"
"net"
"net/http"
"net/url"
@@ -469,6 +470,14 @@ func (c *serverCommand) Name() string {
}
func (c *serverCommand) Run(ctx context.Context, cd *simplecobra.Commandeer, args []string) error {
err := func() error {
defer c.r.timeTrack(time.Now(), "Built")
err := c.build()
return err
}()
if err != nil {
return err
}
// Watch runs its own server as part of the routine
if c.serverWatch {
@@ -492,15 +501,6 @@ func (c *serverCommand) Run(ctx context.Context, cd *simplecobra.Commandeer, arg
}
err := func() error {
defer c.r.timeTrack(time.Now(), "Built")
err := c.build()
return err
}()
if err != nil {
return err
}
return c.serve()
}
@@ -685,9 +685,9 @@ func (c *serverCommand) createCertificates(conf *commonConfig) error {
c.tlsKeyFile = filepath.Join(keyDir, fmt.Sprintf("%s-key.pem", hostname))
// Check if the certificate already exists and is valid.
certPEM, err := os.ReadFile(c.tlsCertFile)
certPEM, err := ioutil.ReadFile(c.tlsCertFile)
if err == nil {
rootPem, err := os.ReadFile(filepath.Join(mclib.GetCAROOT(), "rootCA.pem"))
rootPem, err := ioutil.ReadFile(filepath.Join(mclib.GetCAROOT(), "rootCA.pem"))
if err == nil {
if err := c.verifyCert(rootPem, certPEM, hostname); err == nil {
c.r.Println("Using existing", c.tlsCertFile, "and", c.tlsKeyFile)
-44
View File
@@ -15,9 +15,7 @@ package hstrings
import (
"fmt"
"regexp"
"strings"
"sync"
"github.com/gohugoio/hugo/compare"
)
@@ -57,45 +55,3 @@ func EqualAny(a string, b ...string) bool {
}
return false
}
// regexpCache represents a cache of regexp objects protected by a mutex.
type regexpCache struct {
mu sync.RWMutex
re map[string]*regexp.Regexp
}
func (rc *regexpCache) getOrCompileRegexp(pattern string) (re *regexp.Regexp, err error) {
var ok bool
if re, ok = rc.get(pattern); !ok {
re, err = regexp.Compile(pattern)
if err != nil {
return nil, err
}
rc.set(pattern, re)
}
return re, nil
}
func (rc *regexpCache) get(key string) (re *regexp.Regexp, ok bool) {
rc.mu.RLock()
re, ok = rc.re[key]
rc.mu.RUnlock()
return
}
func (rc *regexpCache) set(key string, re *regexp.Regexp) {
rc.mu.Lock()
rc.re[key] = re
rc.mu.Unlock()
}
var reCache = regexpCache{re: make(map[string]*regexp.Regexp)}
// GetOrCompileRegexp retrieves a regexp object from the cache based upon the pattern.
// If the pattern is not found in the cache, the pattern is compiled and added to
// the cache.
func GetOrCompileRegexp(pattern string) (re *regexp.Regexp, err error) {
return reCache.getOrCompileRegexp(pattern)
}
-22
View File
@@ -14,7 +14,6 @@
package hstrings
import (
"regexp"
"testing"
qt "github.com/frankban/quicktest"
@@ -35,24 +34,3 @@ func TestStringEqualFold(t *testing.T) {
c.Assert(StringEqualFold(s1).Eq("b"), qt.Equals, false)
}
func TestGetOrCompileRegexp(t *testing.T) {
c := qt.New(t)
re, err := GetOrCompileRegexp(`\d+`)
c.Assert(err, qt.IsNil)
c.Assert(re.MatchString("123"), qt.Equals, true)
}
func BenchmarkGetOrCompileRegexp(b *testing.B) {
for i := 0; i < b.N; i++ {
GetOrCompileRegexp(`\d+`)
}
}
func BenchmarkCompileRegexp(b *testing.B) {
for i := 0; i < b.N; i++ {
regexp.MustCompile(`\d+`)
}
}
-83
View File
@@ -1,83 +0,0 @@
// Copyright 2022 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 htime_test
import (
"testing"
"github.com/gohugoio/hugo/hugolib"
)
// Issue #11267
func TestApplyWithContext(t *testing.T) {
t.Parallel()
files := `
-- config.toml --
defaultContentLanguage = 'it'
-- layouts/index.html --
{{ $dates := slice
"2022-01-03"
"2022-02-01"
"2022-03-02"
"2022-04-07"
"2022-05-06"
"2022-06-04"
"2022-07-03"
"2022-08-01"
"2022-09-06"
"2022-10-05"
"2022-11-03"
"2022-12-02"
}}
{{ range $dates }}
{{ . | time.Format "month: _January_ weekday: _Monday_" }}
{{ . | time.Format "month: _Jan_ weekday: _Mon_" }}
{{ end }}
`
b := hugolib.NewIntegrationTestBuilder(
hugolib.IntegrationTestConfig{
T: t,
TxtarString: files,
},
).Build()
b.AssertFileContent("public/index.html", `
month: _gennaio_ weekday: _lunedì_
month: _gen_ weekday: _lun_
month: _febbraio_ weekday: _martedì_
month: _feb_ weekday: _mar_
month: _marzo_ weekday: _mercoledì_
month: _mar_ weekday: _mer_
month: _aprile_ weekday: _giovedì_
month: _apr_ weekday: _gio_
month: _maggio_ weekday: _venerdì_
month: _mag_ weekday: _ven_
month: _giugno_ weekday: _sabato_
month: _giu_ weekday: _sab_
month: _luglio_ weekday: _domenica_
month: _lug_ weekday: _dom_
month: _agosto_ weekday: _lunedì_
month: _ago_ weekday: _lun_
month: _settembre_ weekday: _martedì_
month: _set_ weekday: _mar_
month: _ottobre_ weekday: _mercoledì_
month: _ott_ weekday: _mer_
month: _novembre_ weekday: _giovedì_
month: _nov_ weekday: _gio_
month: _dicembre_ weekday: _venerdì_
month: _dic_ weekday: _ven_
`)
}
+4 -7
View File
@@ -124,15 +124,12 @@ func (f TimeFormatter) Format(t time.Time, layout string) string {
monthIdx := t.Month() - 1 // Month() starts at 1.
dayIdx := t.Weekday()
if strings.Contains(layout, "January") {
s = strings.ReplaceAll(s, longMonthNames[monthIdx], f.ltr.MonthWide(t.Month()))
} else if strings.Contains(layout, "Jan") {
s = strings.ReplaceAll(s, longMonthNames[monthIdx], f.ltr.MonthWide(t.Month()))
if !strings.Contains(s, f.ltr.MonthWide(t.Month())) {
s = strings.ReplaceAll(s, shortMonthNames[monthIdx], f.ltr.MonthAbbreviated(t.Month()))
}
if strings.Contains(layout, "Monday") {
s = strings.ReplaceAll(s, longDayNames[dayIdx], f.ltr.WeekdayWide(t.Weekday()))
} else if strings.Contains(layout, "Mon") {
s = strings.ReplaceAll(s, longDayNames[dayIdx], f.ltr.WeekdayWide(t.Weekday()))
if !strings.Contains(s, f.ltr.WeekdayWide(t.Weekday())) {
s = strings.ReplaceAll(s, shortDayNames[dayIdx], f.ltr.WeekdayAbbreviated(t.Weekday()))
}
+3 -3
View File
@@ -17,7 +17,7 @@ package hugo
// This should be the only one.
var CurrentVersion = Version{
Major: 0,
Minor: 118,
PatchLevel: 1,
Suffix: "",
Minor: 116,
PatchLevel: 0,
Suffix: "-DEV",
}
+9 -19
View File
@@ -37,13 +37,13 @@ var (
// Options defines options for the logger.
type Options struct {
Level logg.Level
Stdout io.Writer
Stderr io.Writer
Distinct bool
StoreErrors bool
HandlerPost func(e *logg.Entry) error
SuppressStatements map[string]bool
Level logg.Level
Stdout io.Writer
Stderr io.Writer
Distinct bool
StoreErrors bool
HandlerPost func(e *logg.Entry) error
SuppresssStatements map[string]bool
}
// New creates a new logger with the given options.
@@ -97,8 +97,8 @@ func New(opts Options) Logger {
logHandler = newStopHandler(logOnce, logHandler)
}
if opts.SuppressStatements != nil && len(opts.SuppressStatements) > 0 {
logHandler = newStopHandler(newSuppressStatementsHandler(opts.SuppressStatements), logHandler)
if opts.SuppresssStatements != nil && len(opts.SuppresssStatements) > 0 {
logHandler = newStopHandler(newSuppressStatementsHandler(opts.SuppresssStatements), logHandler)
}
logger := logg.New(
@@ -173,7 +173,6 @@ type Logger interface {
WarnCommand(command string) logg.LevelLogger
Warnf(format string, v ...any)
Warnln(v ...any)
Deprecatef(fail bool, format string, v ...any)
}
type logAdapter struct {
@@ -298,15 +297,6 @@ func (l *logAdapter) sprint(v ...any) string {
return strings.TrimRight(fmt.Sprintln(v...), "\n")
}
func (l *logAdapter) Deprecatef(fail bool, format string, v ...any) {
format = "DEPRECATED: " + format
if fail {
l.errorl.Logf(format, v...)
} else {
l.warnl.Logf(format, v...)
}
}
type logWriter struct {
l logg.LevelLogger
}
+1 -1
View File
@@ -110,7 +110,7 @@ func TestSuppressStatements(t *testing.T) {
opts := loggers.Options{
StoreErrors: true,
SuppressStatements: map[string]bool{
SuppresssStatements: map[string]bool{
"error-1": true,
},
}
-25
View File
@@ -210,28 +210,3 @@ func (r KeyRenamer) renamePath(parentKeyPath string, m map[string]any) {
}
}
}
// ConvertFloat64WithNoDecimalsToInt converts float64 values with no decimals to int recursively.
func ConvertFloat64WithNoDecimalsToInt(m map[string]any) {
for k, v := range m {
switch vv := v.(type) {
case float64:
if v == float64(int64(vv)) {
m[k] = int64(vv)
}
case map[string]any:
ConvertFloat64WithNoDecimalsToInt(vv)
case []any:
for i, vvv := range vv {
switch vvvv := vvv.(type) {
case float64:
if vvv == float64(int64(vvvv)) {
vv[i] = int64(vvvv)
}
case map[string]any:
ConvertFloat64WithNoDecimalsToInt(vvvv)
}
}
}
}
}
+17 -38
View File
@@ -45,7 +45,6 @@ import (
"github.com/gohugoio/hugo/output"
"github.com/gohugoio/hugo/related"
"github.com/gohugoio/hugo/resources/images"
"github.com/gohugoio/hugo/resources/kinds"
"github.com/gohugoio/hugo/resources/page"
"github.com/gohugoio/hugo/resources/page/pagemeta"
"github.com/spf13/afero"
@@ -58,11 +57,12 @@ type InternalConfig struct {
// Server mode?
Running bool
Quiet bool
Verbose bool
Clock string
Watch bool
LiveReloadPort int
Quiet bool
Verbose bool
Clock string
Watch bool
DisableLiveReload bool
LiveReloadPort int
}
// All non-params config keys for language.
@@ -240,14 +240,9 @@ func (c *Config) CompileConfig(logger loggers.Logger) error {
disabledKinds := make(map[string]bool)
for _, kind := range c.DisableKinds {
kind = strings.ToLower(kind)
if newKind := kinds.IsDeprecatedAndReplacedWith(kind); newKind != "" {
logger.Deprecatef(false, "Kind %q used in disableKinds is deprecated, use %q instead.", kind, newKind)
if kind == "taxonomyterm" {
// Legacy config.
kind = newKind
}
if kinds.GetKindAny(kind) == "" {
logger.Warnf("Unknown kind %q in disableKinds configuration.", kind)
continue
kind = "term"
}
disabledKinds[kind] = true
}
@@ -255,17 +250,9 @@ func (c *Config) CompileConfig(logger loggers.Logger) error {
isRssDisabled := disabledKinds["rss"]
outputFormats := c.OutputFormats.Config
for kind, formats := range c.Outputs {
if newKind := kinds.IsDeprecatedAndReplacedWith(kind); newKind != "" {
logger.Deprecatef(false, "Kind %q used in outputs configuration is deprecated, use %q instead.", kind, newKind)
kind = newKind
}
if disabledKinds[kind] {
continue
}
if kinds.GetKindAny(kind) == "" {
logger.Warnf("Unknown kind %q in outputs configuration.", kind)
continue
}
for _, format := range formats {
if isRssDisabled && format == "rss" {
// Legacy config.
@@ -467,9 +454,6 @@ type RootConfig struct {
// Disable the injection of the Hugo generator tag on the home page.
DisableHugoGeneratorInject bool
// Disable live reloading in server mode.
DisableLiveReload bool
// Enable replacement in Pages' Content of Emoji shortcodes with their equivalent Unicode characters.
// <docsmeta>{"identifiers": ["Content", "Unicode"] }</docsmeta>
EnableEmoji bool
@@ -743,8 +727,7 @@ func fromLoadConfigResult(fs afero.Fs, logger loggers.Logger, res config.LoadCon
cfg := res.Cfg
all := &Config{}
err := decodeConfigFromParams(fs, logger, bcfg, cfg, all, nil)
err := decodeConfigFromParams(fs, bcfg, cfg, all, nil)
if err != nil {
return nil, err
}
@@ -832,7 +815,7 @@ func fromLoadConfigResult(fs afero.Fs, logger loggers.Logger, res config.LoadCon
// Create a copy of the complete config and replace the root keys with the language specific ones.
clone := all.cloneForLang()
if err := decodeConfigFromParams(fs, logger, bcfg, mergedConfig, clone, differentRootKeys); err != nil {
if err := decodeConfigFromParams(fs, bcfg, mergedConfig, clone, differentRootKeys); err != nil {
return nil, fmt.Errorf("failed to decode config for language %q: %w", k, err)
}
if err := clone.CompileConfig(logger); err != nil {
@@ -886,10 +869,6 @@ func fromLoadConfigResult(fs afero.Fs, logger loggers.Logger, res config.LoadCon
bcfg.PublishDir = all.PublishDir
res.BaseConfig = bcfg
all.CommonDirs.CacheDir = bcfg.CacheDir
for _, l := range langConfigs {
l.CommonDirs.CacheDir = bcfg.CacheDir
}
cm := &Configs{
Base: all,
@@ -904,7 +883,7 @@ func fromLoadConfigResult(fs afero.Fs, logger loggers.Logger, res config.LoadCon
return cm, nil
}
func decodeConfigFromParams(fs afero.Fs, logger loggers.Logger, bcfg config.BaseConfig, p config.Provider, target *Config, keys []string) error {
func decodeConfigFromParams(fs afero.Fs, bcfg config.BaseConfig, p config.Provider, target *Config, keys []string) error {
var decoderSetups []decodeWeight
@@ -917,7 +896,7 @@ func decodeConfigFromParams(fs afero.Fs, logger loggers.Logger, bcfg config.Base
if v, found := allDecoderSetups[key]; found {
decoderSetups = append(decoderSetups, v)
} else {
logger.Warnf("Skip unknown config key %q", key)
return fmt.Errorf("unknown config key %q", key)
}
}
}
@@ -954,11 +933,11 @@ func createDefaultOutputFormats(allFormats output.Formats) map[string][]string {
}
m := map[string][]string{
kinds.KindPage: {htmlOut.Name},
kinds.KindHome: defaultListTypes,
kinds.KindSection: defaultListTypes,
kinds.KindTerm: defaultListTypes,
kinds.KindTaxonomy: defaultListTypes,
page.KindPage: {htmlOut.Name},
page.KindHome: defaultListTypes,
page.KindSection: defaultListTypes,
page.KindTerm: defaultListTypes,
page.KindTaxonomy: defaultListTypes,
}
// May be disabled
+5 -10
View File
@@ -49,11 +49,10 @@ type decodeConfig struct {
}
type decodeWeight struct {
key string
decode func(decodeWeight, decodeConfig) error
getCompiler func(c *Config) configCompiler
weight int
internalOrDeprecated bool // Hide it from the docs.
key string
decode func(decodeWeight, decodeConfig) error
getCompiler func(c *Config) configCompiler
weight int
}
var allDecoderSetups = map[string]decodeWeight{
@@ -240,7 +239,7 @@ var allDecoderSetups = map[string]decodeWeight{
} else {
p.c.Related = related.DefaultConfig
if _, found := p.c.Taxonomies["tag"]; found {
p.c.Related.Add(related.IndexConfig{Name: "tags", Weight: 80, Type: related.TypeBasic})
p.c.Related.Add(related.IndexConfig{Name: "tags", Weight: 80})
}
}
return nil
@@ -341,7 +340,6 @@ var allDecoderSetups = map[string]decodeWeight{
p.c.Author = maps.CleanConfigStringMap(p.p.GetStringMap(d.key))
return nil
},
internalOrDeprecated: true,
},
"social": {
key: "social",
@@ -349,7 +347,6 @@ var allDecoderSetups = map[string]decodeWeight{
p.c.Social = maps.CleanConfigStringMapString(p.p.GetStringMapString(d.key))
return nil
},
internalOrDeprecated: true,
},
"uglyurls": {
key: "uglyurls",
@@ -365,14 +362,12 @@ var allDecoderSetups = map[string]decodeWeight{
}
return nil
},
internalOrDeprecated: true,
},
"internal": {
key: "internal",
decode: func(d decodeWeight, p decodeConfig) error {
return mapstructure.WeakDecode(p.p.GetStringMap(d.key), &p.c.Internal)
},
internalOrDeprecated: true,
},
}
+1 -1
View File
@@ -140,7 +140,7 @@ func (c ConfigLanguage) GetConfigSection(s string) any {
return c.config.Permalinks
case "minify":
return c.config.Minify
case "allModules":
case "activeModules":
return c.m.Modules
case "deployment":
return c.config.Deployment
+7 -28
View File
@@ -79,12 +79,11 @@ func LoadConfig(d ConfigSourceDescriptor) (*Configs, error) {
if err := configs.transientErr(); err != nil {
return nil, fmt.Errorf("failed to create config from modules config: %w", err)
}
configs.LoadingInfo.ConfigFiles = append(configs.LoadingInfo.ConfigFiles, l.ModulesConfigFiles...)
} else if err := configs.transientErr(); err != nil {
return nil, fmt.Errorf("failed to create config: %w", err)
}
configs.Modules = moduleConfig.AllModules
configs.Modules = moduleConfig.ActiveModules
configs.ModulesClient = modulesClient
if err := configs.Init(); err != nil {
@@ -298,20 +297,14 @@ func (l configLoader) applyOsEnvOverrides(environ []string) error {
if nestedKey != "" {
owner[nestedKey] = env.Value
} else {
var val any
key := strings.ReplaceAll(env.Key, delim, ".")
_, ok := allDecoderSetups[key]
if ok {
var val any = env.Value
if _, ok := allDecoderSetups[env.Key]; ok {
// A map.
if v, err := metadecoders.Default.UnmarshalStringTo(env.Value, map[string]interface{}{}); err == nil {
val = v
}
val, err = metadecoders.Default.UnmarshalStringTo(env.Value, map[string]interface{}{})
}
if val == nil {
// A string.
val = l.envStringToVal(key, env.Value)
if err == nil {
l.cfg.Set(strings.ReplaceAll(env.Key, delim, "."), val)
}
l.cfg.Set(key, val)
}
}
}
@@ -319,20 +312,6 @@ func (l configLoader) applyOsEnvOverrides(environ []string) error {
return nil
}
func (l *configLoader) envStringToVal(k, v string) any {
switch k {
case "disablekinds", "disablelanguages":
if strings.Contains(v, ",") {
return strings.Split(v, ",")
} else {
return strings.Fields(v)
}
default:
return v
}
}
func (l *configLoader) loadConfigMain(d ConfigSourceDescriptor) (config.LoadConfigResult, modules.ModulesConfig, error) {
var res config.LoadConfigResult
@@ -471,7 +450,7 @@ func (l *configLoader) loadModules(configs *Configs) (modules.ModulesConfig, *mo
ex := hexec.New(conf.Security)
hook := func(m *modules.ModulesConfig) error {
for _, tc := range m.AllModules {
for _, tc := range m.ActiveModules {
if len(tc.ConfigFilenames()) > 0 {
if tc.Watch() {
l.ModulesConfigFiles = append(l.ModulesConfigFiles, tc.ConfigFilenames()...)
+8 -8
View File
@@ -333,11 +333,11 @@ func (c *CacheBuster) CompileConfig(logger loggers.Logger) error {
}
source := c.Source
target := c.Target
sourceRe, err := regexp.Compile(source)
if err != nil {
return fmt.Errorf("failed to compile cache buster source %q: %w", c.Source, err)
}
target := c.Target
var compileErr error
debugl := logger.Logger().WithLevel(logg.LevelDebug).WithField(loggers.FieldNameCmd, "cachebuster")
@@ -353,23 +353,23 @@ func (c *CacheBuster) CompileConfig(logger loggers.Logger) error {
return nil
}
groups := m[1:]
currentTarget := target
// Replace $1, $2 etc. in target.
for i, g := range groups {
currentTarget = strings.ReplaceAll(target, fmt.Sprintf("$%d", i+1), g)
target = strings.ReplaceAll(target, fmt.Sprintf("$%d", i+1), g)
}
targetRe, err := regexp.Compile(currentTarget)
targetRe, err := regexp.Compile(target)
if err != nil {
compileErr = fmt.Errorf("failed to compile cache buster target %q: %w", currentTarget, err)
compileErr = fmt.Errorf("failed to compile cache buster target %q: %w", target, err)
return nil
}
return func(ss string) bool {
match = targetRe.MatchString(ss)
return func(s string) bool {
match = targetRe.MatchString(s)
matchString := "no match"
if match {
matchString = "match!"
}
logger.Debugf("Matching %q with target %q: %s", ss, currentTarget, matchString)
logger.Debugf("Matching %q with target %q: %s", s, target, matchString)
return match
}
-33
View File
@@ -164,36 +164,3 @@ func TestBuildConfigCacheBusters(t *testing.T) {
c.Assert(m("json"), qt.IsTrue)
}
func TestBuildConfigCacheBusterstTailwindSetup(t *testing.T) {
c := qt.New(t)
cfg := New()
cfg.Set("build", map[string]interface{}{
"cacheBusters": []map[string]string{
{
"source": "assets/watching/hugo_stats\\.json",
"target": "css",
},
{
"source": "(postcss|tailwind)\\.config\\.js",
"target": "css",
},
{
"source": "assets/.*\\.(js|ts|jsx|tsx)",
"target": "js",
},
{
"source": "assets/.*\\.(.*)$",
"target": "$1",
},
},
})
conf := DecodeBuildConfig(cfg)
l := loggers.NewDefault()
c.Assert(conf.CompileConfig(l), qt.IsNil)
m, err := conf.MatchCacheBuster(l, "assets/watching/hugo_stats.json")
c.Assert(err, qt.IsNil)
c.Assert(m("css"), qt.IsTrue)
}
@@ -1,4 +1,4 @@
// Copyright 2023 The Hugo Authors. All rights reserved.
// Copyright 2021 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.
@@ -11,11 +11,10 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package allconfig
package config
import (
"github.com/gohugoio/hugo/common/maps"
"github.com/gohugoio/hugo/config"
"github.com/gohugoio/hugo/docshelper"
)
@@ -23,11 +22,8 @@ import (
func init() {
docsProvider := func() docshelper.DocProvider {
cfg := config.New()
for configRoot, v := range allDecoderSetups {
if v.internalOrDeprecated {
continue
}
cfg := New()
for _, configRoot := range ConfigRootKeys {
cfg.Set(configRoot, make(maps.Params))
}
lang := maps.Params{
@@ -42,7 +38,7 @@ func init() {
configHelpers := map[string]any{
"mergeStrategy": cfg.Get(""),
}
return docshelper.DocProvider{"config_helpers": configHelpers}
return docshelper.DocProvider{"config": configHelpers}
}
docshelper.AddDocProviderFunc(docsProvider)
+26
View File
@@ -0,0 +1,26 @@
// Copyright 2021 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 security
import (
"github.com/gohugoio/hugo/docshelper"
)
func init() {
docsProvider := func() docshelper.DocProvider {
return docshelper.DocProvider{"config": DefaultConfig.ToSecurityMap()}
}
docshelper.AddDocProviderFunc(docsProvider)
}
+1 -1
View File
@@ -42,7 +42,7 @@ const (
// DefaultArchetypeTemplateTemplate is the template used in 'hugo new site'
// and the template we use as a fall back.
DefaultArchetypeTemplateTemplate = `---
title: "{{ replace .File.ContentBaseName "-" " " | title }}"
title: "{{ replace .Name "-" " " | title }}"
date: {{ .Date }}
draft: true
---
@@ -1,5 +0,0 @@
+++
title = '{{ replace .File.ContentBaseName "-" " " | title }}'
date = {{ .Date }}
draft = true
+++
View File
View File
-111
View File
@@ -1,111 +0,0 @@
// Copyright 2023 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 skeletons
import (
"bytes"
"embed"
"errors"
"io/fs"
"path/filepath"
"strings"
"github.com/gohugoio/hugo/helpers"
"github.com/gohugoio/hugo/parser"
"github.com/gohugoio/hugo/parser/metadecoders"
"github.com/spf13/afero"
)
//go:embed all:site/*
var siteFs embed.FS
//go:embed all:theme/*
var themeFs embed.FS
// CreateTheme creates a theme skeleton.
func CreateTheme(createpath string, sourceFs afero.Fs) error {
if exists, _ := helpers.Exists(createpath, sourceFs); exists {
return errors.New(createpath + " already exists")
}
return copyFiles(createpath, sourceFs, themeFs)
}
// CreateSite creates a site skeleton.
func CreateSite(createpath string, sourceFs afero.Fs, force bool, format string) error {
format = strings.ToLower(format)
if exists, _ := helpers.Exists(createpath, sourceFs); exists {
if isDir, _ := helpers.IsDir(createpath, sourceFs); !isDir {
return errors.New(createpath + " already exists but not a directory")
}
isEmpty, _ := helpers.IsEmpty(createpath, sourceFs)
switch {
case !isEmpty && !force:
return errors.New(createpath + " already exists and is not empty. See --force.")
case !isEmpty && force:
var all []string
fs.WalkDir(siteFs, ".", func(path string, d fs.DirEntry, err error) error {
if d.IsDir() && path != "." {
all = append(all, path)
}
return nil
})
all = append(all, filepath.Join(createpath, "hugo."+format))
for _, path := range all {
if exists, _ := helpers.Exists(path, sourceFs); exists {
return errors.New(path + " already exists")
}
}
}
}
err := newSiteCreateConfig(sourceFs, createpath, format)
if err != nil {
return err
}
return copyFiles(createpath, sourceFs, siteFs)
}
func copyFiles(createpath string, sourceFs afero.Fs, skeleton embed.FS) error {
return fs.WalkDir(skeleton, ".", func(path string, d fs.DirEntry, err error) error {
_, slug, _ := strings.Cut(path, "/")
if d.IsDir() {
return sourceFs.MkdirAll(filepath.Join(createpath, slug), 0777)
} else {
if filepath.Base(path) != ".gitkeep" {
data, _ := fs.ReadFile(skeleton, path)
return helpers.WriteToDisk(filepath.Join(createpath, slug), bytes.NewReader(data), sourceFs)
}
return nil
}
})
}
func newSiteCreateConfig(fs afero.Fs, createpath string, format string) (err error) {
in := map[string]string{
"baseURL": "https://example.org/",
"title": "My New Hugo Site",
"languageCode": "en-us",
}
var buf bytes.Buffer
err = parser.InterfaceToConfig(in, metadecoders.FormatFromString(format), &buf)
if err != nil {
return err
}
return helpers.WriteToDisk(filepath.Join(createpath, "hugo."+format), &buf, fs)
}
-21
View File
@@ -1,21 +0,0 @@
MIT License
Copyright (c) [year] [fullname]
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
-7
View File
@@ -1,7 +0,0 @@
# Theme Name
## Features
## Installation
## Configuration
@@ -1,5 +0,0 @@
+++
title = '{{ replace .File.ContentBaseName "-" " " | title }}'
date = {{ .Date }}
draft = true
+++
@@ -1,22 +0,0 @@
body {
color: #222;
font-family: sans-serif;
line-height: 1.5;
margin: 1rem;
max-width: 768px;
}
header {
border-bottom: 1px solid #222;
margin-bottom: 1rem;
}
footer {
border-top: 1px solid #222;
margin-top: 1rem;
}
a {
color: #00e;
text-decoration: none;
}
-1
View File
@@ -1 +0,0 @@
console.log('This site was generated by Hugo.');
-9
View File
@@ -1,9 +0,0 @@
+++
title = 'Home'
date = 2023-01-01T08:00:00-07:00
draft = false
+++
Laborum voluptate pariatur ex culpa magna nostrud est incididunt fugiat
pariatur do dolor ipsum enim. Consequat tempor do dolor eu. Non id id anim anim
excepteur excepteur pariatur nostrud qui irure ullamco.
@@ -1,7 +0,0 @@
+++
title = 'Posts'
date = 2023-01-01T08:30:00-07:00
draft = false
+++
Tempor est exercitation ad qui pariatur quis adipisicing aliquip nisi ea consequat ipsum occaecat. Nostrud consequat ullamco laboris fugiat esse esse adipisicing velit laborum ipsum incididunt ut enim. Dolor pariatur nulla quis fugiat dolore excepteur. Aliquip ad quis aliqua enim do consequat.
@@ -1,10 +0,0 @@
+++
title = 'Post 1'
date = 2023-01-15T09:00:00-07:00
draft = false
tags = ['red']
+++
Tempor proident minim aliquip reprehenderit dolor et ad anim Lorem duis sint eiusmod. Labore ut ea duis dolor. Incididunt consectetur proident qui occaecat incididunt do nisi Lorem. Tempor do laborum elit laboris excepteur eiusmod do. Eiusmod nisi excepteur ut amet pariatur adipisicing Lorem.
Occaecat nulla excepteur dolore excepteur duis eiusmod ullamco officia anim in voluptate ea occaecat officia. Cillum sint esse velit ea officia minim fugiat. Elit ea esse id aliquip pariatur cupidatat id duis minim incididunt ea ea. Anim ut duis sunt nisi. Culpa cillum sit voluptate voluptate eiusmod dolor. Enim nisi Lorem ipsum irure est excepteur voluptate eu in enim nisi. Nostrud ipsum Lorem anim sint labore consequat do.
@@ -1,10 +0,0 @@
+++
title = 'Post 2'
date = 2023-02-15T10:00:00-07:00
draft = false
tags = ['red','green']
+++
Anim eiusmod irure incididunt sint cupidatat. Incididunt irure irure irure nisi ipsum do ut quis fugiat consectetur proident cupidatat incididunt cillum. Dolore voluptate occaecat qui mollit laborum ullamco et. Ipsum laboris officia anim laboris culpa eiusmod ex magna ex cupidatat anim ipsum aute. Mollit aliquip occaecat qui sunt velit ut cupidatat reprehenderit enim sunt laborum. Velit veniam in officia nulla adipisicing ut duis officia.
Exercitation voluptate irure in irure tempor mollit Lorem nostrud ad officia. Velit id fugiat occaecat do tempor. Sit officia Lorem aliquip eu deserunt consectetur. Aute proident deserunt in nulla aliquip dolore ipsum Lorem ut cupidatat consectetur sit sint laborum. Esse cupidatat sit sint sunt tempor exercitation deserunt. Labore dolor duis laborum est do nisi ut veniam dolor et nostrud nostrud.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

@@ -1,12 +0,0 @@
+++
title = 'Post 3'
date = 2023-03-15T11:00:00-07:00
draft = false
tags = ['red','green','blue']
+++
Occaecat aliqua consequat laborum ut ex aute aliqua culpa quis irure esse magna dolore quis. Proident fugiat labore eu laboris officia Lorem enim. Ipsum occaecat cillum ut tempor id sint aliqua incididunt nisi incididunt reprehenderit. Voluptate ad minim sint est aute aliquip esse occaecat tempor officia qui sunt. Aute ex ipsum id ut in est velit est laborum incididunt. Aliqua qui id do esse sunt eiusmod id deserunt eu nostrud aute sit ipsum. Deserunt esse cillum Lorem non magna adipisicing mollit amet consequat.
![Bryce Canyon National Park](bryce-canyon.jpg)
Sit excepteur do velit veniam mollit in nostrud laboris incididunt ea. Amet eu cillum ut reprehenderit culpa aliquip labore laborum amet sit sit duis. Laborum id proident nostrud dolore laborum reprehenderit quis mollit nulla amet veniam officia id id. Aliquip in deserunt qui magna duis qui pariatur officia sunt deserunt.
-23
View File
@@ -1,23 +0,0 @@
baseURL = 'https://example.org/'
languageCode = 'en-us'
title = 'My New Hugo Site'
[[menus.main]]
name = 'Home'
pageRef = '/'
weight = 10
[[menus.main]]
name = 'Posts'
pageRef = '/posts'
weight = 20
[[menus.main]]
name = 'Tags'
pageRef = '/tags'
weight = 30
[module]
[module.hugoVersion]
extended = false
min = "0.116.0"
@@ -1,17 +0,0 @@
<!DOCTYPE html>
<html lang="{{ or site.Language.LanguageCode site.Language.Lang }}" dir="{{ or site.Language.LanguageDirection `ltr` }}">
<head>
{{ partial "head.html" . }}
</head>
<body>
<header>
{{ partial "header.html" . }}
</header>
<main>
{{ block "main" . }}{{ end }}
</main>
<footer>
{{ partial "footer.html" . }}
</footer>
</body>
</html>
@@ -1,7 +0,0 @@
{{ define "main" }}
{{ .Content }}
{{ range site.RegularPages }}
<h2><a href="{{ .RelPermalink }}">{{ .LinkTitle }}</a></h2>
{{ .Summary }}
{{ end }}
{{ end }}
@@ -1,8 +0,0 @@
{{ define "main" }}
<h1>{{ .Title }}</h1>
{{ .Content }}
{{ range .Pages }}
<h2><a href="{{ .RelPermalink }}">{{ .LinkTitle }}</a></h2>
{{ .Summary }}
{{ end }}
{{ end }}
@@ -1,10 +0,0 @@
{{ define "main" }}
<h1>{{ .Title }}</h1>
{{ $dateMachine := .Date | time.Format "2006-01-02T15:04:05-07:00" }}
{{ $dateHuman := .Date | time.Format ":date_long" }}
<time datetime="{{ $dateMachine }}">{{ $dateHuman }}</time>
{{ .Content }}
{{ partial "terms.html" (dict "taxonomy" "tags" "page" .) }}
{{ end }}
@@ -1 +0,0 @@
<p>Copyright {{ now.Year }}. All rights reserved.</p>
@@ -1,5 +0,0 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0">
<title>{{ if .IsHome }}{{ site.Title }}{{ else }}{{ printf "%s | %s" .Title site.Title }}{{ end }}</title>
{{ partialCached "head/css.html" . }}
{{ partialCached "head/js.html" . }}
@@ -1,9 +0,0 @@
{{- with resources.Get "css/main.css" }}
{{- if eq hugo.Environment "development" }}
<link rel="stylesheet" href="{{ .RelPermalink }}">
{{- else }}
{{- with . | minify | fingerprint }}
<link rel="stylesheet" href="{{ .RelPermalink }}" integrity="{{ .Data.Integrity }}" crossorigin="anonymous">
{{- end }}
{{- end }}
{{- end }}
@@ -1,12 +0,0 @@
{{- with resources.Get "js/main.js" }}
{{- if eq hugo.Environment "development" }}
{{- with . | js.Build }}
<script src="{{ .RelPermalink }}"></script>
{{- end }}
{{- else }}
{{- $opts := dict "minify" true }}
{{- with . | js.Build $opts | fingerprint }}
<script src="{{ .RelPermalink }}" integrity="{{- .Data.Integrity }}" crossorigin="anonymous"></script>
{{- end }}
{{- end }}
{{- end }}
@@ -1,2 +0,0 @@
<h1>{{ site.Title }}</h1>
{{ partial "menu.html" (dict "menuID" "main" "page" .) }}
@@ -1,45 +0,0 @@
{{- /*
Renders a menu for the given menu ID.
@context {page} page The current page.
@context {string} menuID The menu ID.
@example: {{ partial "menu.html" (dict "menuID" "main" "page" .) }}
*/}}
{{- $page := .page }}
{{- $menuID := .menuID }}
{{- with index site.Menus $menuID }}
<nav>
<ul>
{{- partial "inline/menu/walk.html" (dict "page" $page "menuEntries" .) }}
</ul>
</nav>
{{- end }}
{{- define "partials/inline/menu/walk.html" }}
{{- $page := .page }}
{{- range .menuEntries }}
{{- $attrs := dict "href" .URL }}
{{- if $page.IsMenuCurrent .Menu . }}
{{- $attrs = merge $attrs (dict "class" "active" "aria-current" "page") }}
{{- else if $page.HasMenuCurrent .Menu .}}
{{- $attrs = merge $attrs (dict "class" "ancestor" "aria-current" "true") }}
{{- end }}
<li>
<a
{{- range $k, $v := $attrs }}
{{- with $v }}
{{- printf " %s=%q" $k $v | safeHTMLAttr }}
{{- end }}
{{- end -}}
>{{ or (T .Identifier) .Name | safeHTML }}</a>
{{- with .Children }}
<ul>
{{- partial "inline/menu/walk.html" (dict "page" $page "menuEntries" .) }}
</ul>
{{- end }}
</li>
{{- end }}
{{- end }}
@@ -1,23 +0,0 @@
{{- /*
For a given taxonomy, renders a list of terms assigned to the page.
@context {page} page The current page.
@context {string} taxonomy The taxonony.
@example: {{ partial "terms.html" (dict "taxonomy" "tags" "page" .) }}
*/}}
{{- $page := .page }}
{{- $taxonomy := .taxonomy }}
{{- with $page.GetTerms $taxonomy }}
{{- $label := (index . 0).Parent.LinkTitle }}
<div>
<div>{{ $label }}:</div>
<ul>
{{- range . }}
<li><a href="{{ .RelPermalink }}">{{ .LinkTitle }}</a></li>
{{- end }}
</ul>
</div>
{{- end }}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

-31
View File
@@ -1,31 +0,0 @@
name = 'Theme name'
license = 'MIT'
licenselink = 'https://github.com/owner/repo/LICENSE'
description = 'Theme description'
# The home page of the theme, where the source can be found
homepage = 'https://github.com/owner/repo'
# If you have a running demo of the theme
demosite = 'https://owner.github.io/repo'
# Taxonomy terms
tags = ['blog', 'company']
features = ['some', 'awesome', 'features']
# If the theme has multiple authors
authors = [
{name = 'Name of author', homepage = 'Website of author'},
{name = 'Name of author', homepage = 'Website of author'}
]
# If the theme has a single author
[author]
name = 'Your name'
homepage = 'Your website'
# If porting an existing theme
[original]
author = 'Name of original author'
homepage = 'Website of original author'
repo = 'https://github.com/owner/repo'
+12 -10
View File
@@ -18,27 +18,29 @@ package deploy
import (
"context"
"net/url"
"time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/cloudfront"
gcaws "gocloud.dev/aws"
)
// InvalidateCloudFront invalidates the CloudFront cache for distributionID.
// Uses AWS credentials config from the bucket URL.
func InvalidateCloudFront(ctx context.Context, target *Target) error {
u, err := url.Parse(target.URL)
if err != nil {
return err
}
sess, _, err := gcaws.NewSessionFromURLParams(u.Query())
// It uses the default AWS credentials from the environment.
func InvalidateCloudFront(ctx context.Context, distributionID string) error {
// SharedConfigEnable enables loading "shared config (~/.aws/config) and
// shared credentials (~/.aws/credentials) files".
// See https://docs.aws.amazon.com/sdk-for-go/api/aws/session/ for more
// details.
// This is the same codepath used by Go CDK when creating an s3 URL.
// TODO: Update this to a Go CDK helper once available
// (https://github.com/google/go-cloud/issues/2003).
sess, err := session.NewSessionWithOptions(session.Options{SharedConfigState: session.SharedConfigEnable})
if err != nil {
return err
}
req := &cloudfront.CreateInvalidationInput{
DistributionId: aws.String(target.CloudFrontDistributionID),
DistributionId: aws.String(distributionID),
InvalidationBatch: &cloudfront.InvalidationBatch{
CallerReference: aws.String(time.Now().Format("20060102150405")),
Paths: &cloudfront.Paths{
+1 -1
View File
@@ -271,7 +271,7 @@ func (d *Deployer) Deploy(ctx context.Context) error {
}
} else {
d.logger.Println("Invalidating CloudFront CDN...")
if err := InvalidateCloudFront(ctx, d.target); err != nil {
if err := InvalidateCloudFront(ctx, d.target.CloudFrontDistributionID); err != nil {
d.logger.Printf("Failed to invalidate CloudFront CDN: %v\n", err)
return err
}
+1 -1
View File
@@ -1,3 +1,3 @@
### Asking support questions
### Asking Support Questions
We have an active [discussion forum](https://discourse.gohugo.io) where users and developers can ask questions. Please don't use the GitHub issue tracker to ask questions.
@@ -12,18 +12,6 @@
color: white;
}
.prose-glossary h3 {
margin-top: 0;
font-size: 1.125rem;
}
.prose-glossary h3:first-of-type {
margin-top: 3em;
}
.prose-glossary h3 ~ p {
margin: 0.5em 0 2em 0;
}
body {
File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 9.3 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 13 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 13 KiB

@@ -804,8 +804,6 @@ img { max-width: 100%; }
.b--washed-red { border-color: #ffdfdf; }
.b--transparent { border-color: transparent; }
.b--inherit { border-color: inherit; }
.b--initial { border-color: currentColor; border-color: initial; }
.b--unset { border-color: unset; }
/*
BORDER RADIUS
@@ -854,9 +852,6 @@ img { max-width: 100%; }
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.br-inherit { border-radius: inherit; }
.br-initial { border-radius: 0; border-radius: initial; }
.br-unset { border-radius: unset; }
@media screen and (min-width: 30em) {
.br0-ns { border-radius: 0; }
.br1-ns { border-radius: .125rem; }
@@ -881,9 +876,6 @@ img { max-width: 100%; }
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.br-inherit-ns { border-radius: inherit; }
.br-initial-ns { border-radius: 0; border-radius: initial; }
.br-unset-ns { border-radius: unset; }
}
@media screen and (min-width: 30em) and (max-width: 60em) {
.br0-m { border-radius: 0; }
@@ -909,9 +901,6 @@ img { max-width: 100%; }
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.br-inherit-m { border-radius: inherit; }
.br-initial-m { border-radius: 0; border-radius: initial; }
.br-unset-m { border-radius: unset; }
}
@media screen and (min-width: 60em) {
.br0-l { border-radius: 0; }
@@ -937,9 +926,6 @@ img { max-width: 100%; }
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.br-inherit-l { border-radius: inherit; }
.br-initial-l { border-radius: 0; border-radius: initial; }
.br-unset-l { border-radius: unset; }
}
/*
@@ -2381,7 +2367,6 @@ img { max-width: 100%; }
.washed-yellow { color: #fffceb; }
.washed-red { color: #ffdfdf; }
.color-inherit { color: inherit; }
/* Background colors */
.bg-black-90 { background-color: rgba(0, 0, 0, .9); }
.bg-black-80 { background-color: rgba(0, 0, 0, .8); }
.bg-black-70 { background-color: rgba(0, 0, 0, .7); }
@@ -2401,6 +2386,7 @@ img { max-width: 100%; }
.bg-white-30 { background-color: rgba(255, 255, 255, .3); }
.bg-white-20 { background-color: rgba(255, 255, 255, .2); }
.bg-white-10 { background-color: rgba(255, 255, 255, .1); }
/* Background colors */
.bg-black { background-color: #000; }
.bg-near-black { background-color: #111; }
.bg-dark-gray { background-color: #333; }
@@ -4685,7 +4671,6 @@ h6:hover .header-link {
.searchbox__input::-webkit-input-placeholder{color:#aaa}
.searchbox__input:-ms-input-placeholder{color:#aaa}
.searchbox__input::-ms-input-placeholder{color:#aaa}
.searchbox__input::-moz-placeholder{color:#aaa}
.searchbox__input::placeholder{color:#aaa}
.searchbox__submit{position:absolute;top:0;margin:0;border:0;border-radius:16px 0 0 16px;background-color:rgba(69, 142, 225, 0);padding:0;width:32px;height:100%;vertical-align:middle;text-align:center;font-size:inherit;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;right:inherit;left:0}
.searchbox__submit:before{display:inline-block;margin-right:-4px;height:100%;vertical-align:middle;content:""}
@@ -4919,14 +4904,14 @@ pre {
text-decoration: none;
}
.column-count-2 {-webkit-column-count: 1;-moz-column-count: 1;column-count: 1}
.column-gap-1 {-webkit-column-gap: 0;-moz-column-gap: 0;column-gap: 0}
.break-inside-avoid {-webkit-column-break-inside: auto;page-break-inside: auto;break-inside: auto}
.column-count-2 {-webkit-column-count: 1;column-count: 1}
.column-gap-1 {-webkit-column-gap: 0;column-gap: 0}
.break-inside-avoid {-webkit-column-break-inside: auto;break-inside: auto}
@media screen and (min-width: 60em) {
.column-count-3-l {-webkit-column-count: 3;-moz-column-count: 3;column-count: 3}
.column-count-2-l {-webkit-column-count: 2;-moz-column-count: 2;column-count: 2}
.column-gap-1-l {-webkit-column-gap: 1;-moz-column-gap: 1;column-gap: 1}
.break-inside-avoid-l {-webkit-column-break-inside: avoid;page-break-inside: avoid;break-inside: avoid}
.column-count-3-l {-webkit-column-count: 3;column-count: 3}
.column-count-2-l {-webkit-column-count: 2;column-count: 2}
.column-gap-1-l {-webkit-column-gap: 1;column-gap: 1}
.break-inside-avoid-l {-webkit-column-break-inside: avoid;break-inside: avoid}
}
.prose ul, .prose ol {
margin-bottom: 2em;
@@ -4937,24 +4922,10 @@ pre {
.prose li:hover {
background-color: #eee
}
.prose ::-moz-selection {
background: #0594CB; /* WebKit/Blink Browsers */
color: white;
}
.prose ::selection {
background: #0594CB; /* WebKit/Blink Browsers */
color: white;
}
.prose-glossary h3 {
margin-top: 0;
font-size: 1.125rem;
}
.prose-glossary h3:first-of-type {
margin-top: 3em;
}
.prose-glossary h3 ~ p {
margin: 0.5em 0 2em 0;
}
body {
line-height: 1.45;
File diff suppressed because one or more lines are too long
@@ -3,20 +3,19 @@
link = "https://www.linode.com/"
logo = "images/sponsors/linode-logo.svg"
utm_campaign = "hugosponsor"
bgcolor = "#ffffff"
[[banners]]
name = "CloudCannon"
link = "https://cloudcannon.com/hugo-cms/"
logo = "/images/sponsors/cloudcannon-white.svg"
utm_campaign = "HugoSponsorship"
utm_source = "sponsor"
utm_content = "gohugo"
bgcolor = "#034AD8"
[[banners]]
name = "Your Company?"
link = "https://bep.is/en/hugo-sponsor-2023-01/"
logo = "/images/sponsors/your-company.svg"
utm_campaign = "hugosponsor"
show_on_hover = true
bgcolor = "#4e4f4f"
bgcolor = "#004887"
[[banners]]
name = "Your Company?"
link = "https://bep.is/en/hugo-sponsor-2023-01/"
logo = "/images/sponsors/your-company.svg"
utm_campaign = "hugosponsor"
show_on_hover = true
bgcolor = "#004887"
@@ -31,7 +31,7 @@
<img src="{{ . }}" alt="Featured Image for {{ $.Title }}" class="mw-100">
{{ end }}
<div class="prose prose-{{ .Type }}" id="prose">
<div class="prose" id="prose">
{{- partial "docs/functions-signature.html" . -}}
{{ .Content }}
</div>
@@ -23,7 +23,7 @@
class="{{ $classes_box }} o-100"
style="background-color: {{ .bgcolor }};">
{{ $query_params := .query_params | default "" }}
{{ $url := printf "%s?%s%s" .link $query_params (querify "utm_source" (.utm_source | default $utmSource ) "utm_medium" "banner" "utm_campaign" (.utm_campaign | default "hugosponsor") "utm_content" (.utm_content | default "gohugoio")) | safeURL }}
{{ $url := printf "%s?%s%s" .link $query_params (querify "utm_source" $utmSource "utm_medium" "banner" "utm_campaign" (.utm_campaign | default "hugosponsor")) | safeURL }}
{{ $logo := resources.Get .logo }}
{{ if hugo.IsProduction }}
{{ $gtagID := printf "Sponsor %s %s" .name $gtag | title }}
@@ -34,7 +34,7 @@
show-on-hover
{{ end }}"
style="">
{{ with $logo }}{{ .Content | safeHTML }}{{ end }}
{{ $logo.Content | safeHTML }}
</a>
{{ else }}
<a
@@ -42,7 +42,7 @@
class="w-100 grow pa3{{ if .show_on_hover }}
show-on-hover
{{ end }}">
{{ with $logo }}{{ .Content | safeHTML }}{{ end }}
{{ $logo.Content | safeHTML }}
</a>
{{ end }}
</div>
+1 -1
View File
@@ -1 +1 @@
# github.com/gohugoio/gohugoioTheme v0.0.0-20230812102551-06f8256e7ee5
# github.com/gohugoio/gohugoioTheme v0.0.0-20230527124826-78bc315d7b8a
+6 -6
View File
@@ -11,7 +11,7 @@
url = "/installation/"
[[docs]]
name = "Getting started"
name = "Getting Started"
weight = 30
identifier = "getting-started"
url = "/getting-started/"
@@ -26,7 +26,7 @@
# Core menus
[[docs]]
name = "Content management"
name = "Content Management"
weight = 50
identifier = "content-management"
post = "expanded"
@@ -53,7 +53,7 @@
[[docs]]
name = "Hugo Pipes"
weight = 90
identifier = "hugo-pipes"
identifier = "pipes"
url = "/hugo-pipes/"
[[docs]]
@@ -72,13 +72,13 @@
url = "/troubleshooting/"
[[docs]]
name = "Developer tools"
name = "Tools"
weight = 120
identifier = "developer-tools"
identifier = "tools"
url = "/tools/"
[[docs]]
name = "Hosting and deployment"
name = "Hosting & Deployment"
weight = 130
identifier = "hosting-and-deployment"
url = "/hosting-and-deployment/"
+3 -1
View File
@@ -8,6 +8,8 @@ ghrepo = "https://github.com/gohugoio/hugoDocs/"
github_repo = "https://github.com/gohugoio/hugo/issues/new"
### Edit content repo (set to automatically enter "edit" mode; this is good for "improve this page" links)
ghdocsrepo = "https://github.com/gohugoio/hugoDocs/tree/master/docs"
## Gitter URL
gitter = "https://gitter.im/spf13/hugo"
## Discuss Forum URL
forum = "https://discourse.gohugo.io/"
## Google Tag Manager
@@ -18,4 +20,4 @@ images = ["images/gohugoio-card.png"]
flex_box_interior_classes = "flex-auto w-100 w-40-l mr3 mb3 bg-white ba b--moon-gray nested-copy-line-height"
#sidebar_direction = "sidebar_left"
#sidebar_direction = "sidebar_left"
+4
View File
@@ -1,6 +1,10 @@
enableInlineShortcodes = false
[exec]
allow = ['^go$']
osEnv = ['^PATH$']
[funcs]
getenv = ['^HUGO_', '^REPOSITORY_URL$', '^BRANCH$']
+1 -1
View File
@@ -1,5 +1,5 @@
---
title: The worlds fastest framework for building websites
title: "The worlds fastest framework for building websites"
date: 2017-03-02T12:00:00-05:00
features:
- heading: Blistering Speed
+3 -4
View File
@@ -1,15 +1,14 @@
---
title: About Hugo
linkTitle: Overview
linktitle: Overview
description: Hugo's features, roadmap, license, and motivation.
categories: []
keywords: []
menu:
docs:
identifier: about-hugo-overview
parent: about
weight: 10
weight: 10
weight: 1
weight: 1
aliases: [/about-hugo/,/docs/]
---
+5 -5
View File
@@ -1,13 +1,13 @@
---
title: Benefits of static site generators
linkTitle: Static site generators
title: The Benefits of Static Site Generators
linktitle: The Benefits of Static
description: Improved performance, security and ease of use are just a few of the reasons static site generators are so appealing.
keywords: [ssg,static,performance,security]
menu:
docs:
parent: about
weight: 40
weight: 40
weight: 30
weight: 30
---
The purpose of website generators is to render content into HTML files. Most are "dynamic site generators." That means the HTTP server---i.e., the program that sends files to the browser to be viewed---runs the generator to create a new HTML file every time an end user requests a page.
@@ -18,7 +18,7 @@ Hugo takes caching a step further and all HTML files are rendered on your comput
This has many benefits. The most noticeable is performance. HTTP servers are *very* good at sending files---so good, in fact, that you can effectively serve the same number of pages with a fraction of the memory and CPU needed for a dynamic site.
## More on static site generators
## More on Static Site Generators
* ["An Introduction to Static Site Generators", David Walsh]
* ["Hugo vs. WordPress page load speed comparison: Hugo leaves WordPress in its dust", GettingThingsTech][hugovwordpress]
+4 -4
View File
@@ -1,11 +1,11 @@
---
title: Hugo features
title: Hugo Features
description: Hugo boasts blistering speed, robust content management, and a powerful templating language making it a great fit for all kinds of static websites.
menu:
docs:
parent: about
weight: 30
weight: 30
weight: 20
weight: 20
toc: true
---
@@ -40,7 +40,7 @@ toc: true
* ["Minutes to Read"][pagevars] functionality
* ["WordCount"][pagevars] functionality
## Additional features
## Additional Features
* Integrated [Disqus] comment support
* Integrated [Google Analytics] support
+11 -11
View File
@@ -1,14 +1,14 @@
---
title: Hugo and the General Data Protection Regulation
linkTitle: Hugo and the GDPR
title: Hugo and the General Data Protection Regulation (GDPR)
linktitle: Hugo and GDPR
description: About how to configure your Hugo site to meet the new regulations.
layout: single
keywords: ["GDPR", "Privacy", "Data Protection"]
menu:
docs:
parent: about
weight: 60
weight: 60
weight: 5
weight: 5
aliases: [/privacy/,/gdpr/]
toc: true
---
@@ -17,7 +17,7 @@ toc: true
**Hugo is a static site generator. By using Hugo you are already standing on very solid ground. Static HTML files on disk are much easier to reason about compared to server and database driven web sites.**
But even static websites can integrate with external services, so from version `0.41`, Hugo provides a **privacy configuration** that covers the relevant built-in templates.
But even static websites can integrate with external services, so from version `0.41`, Hugo provides a **Privacy Config** that covers the relevant built-in templates.
Note that:
@@ -25,9 +25,9 @@ toc: true
* These settings work with the [internal templates](/templates/internal/). Some theme may contain custom templates for embedding services like Google Analytics. In that case these options have no effect.
* We will continue this work and improve this further in future Hugo versions.
## All privacy settings
## All Privacy Settings
Below are all privacy settings and their default value. These settings need to be put in your site configuration (e.g. `hugo.toml`).
Below are all privacy settings and their default value. These settings need to be put in your site config (e.g. `hugo.toml`).
{{< code-toggle file="hugo" >}}
[privacy]
@@ -54,11 +54,11 @@ disable = false
privacyEnhanced = false
{{< /code-toggle >}}
## Disable all services
## Disable All Services
An example privacy configuration that disables all the relevant services in Hugo. With this configuration, the other settings will not matter.
An example Privacy Config that disables all the relevant services in Hugo. With this configuration, the other settings will not matter.
{{< code-toggle file="hugo" >}}
{{< code-toggle file="hugo" >}}
[privacy]
[privacy.disqus]
disable = true
@@ -74,7 +74,7 @@ disable = true
disable = true
{{< /code-toggle >}}
## The privacy settings explained
## The Privacy Settings Explained
### GoogleAnalytics
+4 -3
View File
@@ -1,13 +1,14 @@
---
title: License
title: Apache License
linktitle: License
description: Hugo v0.15 and later are released under the Apache 2.0 license.
categories: ["about hugo"]
keywords: ["License","apache"]
menu:
docs:
parent: about
weight: 70
weight: 70
weight: 60
weight: 60
aliases: [/meta/license]
toc: true
---
@@ -1,18 +1,18 @@
---
title: Hugo's security model
title: Hugo's Security Model
description: A summary of Hugo's security model.
layout: single
keywords: ["Security", "Privacy"]
menu:
docs:
parent: about
weight: 50
weight: 50
weight: 4
weight: 5
aliases: [/security/]
toc: true
---
## Runtime security
## Runtime Security
Hugo produces static output, so once built, the runtime is the browser (assuming the output is HTML) and any server (API) that you integrate with.
@@ -25,7 +25,7 @@ But when developing and building your site, the runtime is the `hugo` executable
* User-defined components have read-only access to the filesystem.
* We shell out to some external binaries to support [Asciidoctor](/content-management/formats/#list-of-content-formats) and similar, but those binaries and their flags are predefined and disabled by default (see [Security Policy](#security-policy)). General functions to run arbitrary external OS commands have been [discussed](https://github.com/gohugoio/hugo/issues/796), but not implemented because of security concerns.
## Security policy
## Security Policy
Hugo has a built-in security policy that restricts access to [os/exec](https://pkg.go.dev/os/exec), remote communication and similar.
@@ -33,19 +33,19 @@ The default configuration is listed below. Any build using features not in the a
{{< code-toggle config="security" />}}
Note that these and other configuration settings in Hugo can be overridden by the OS environment. If you want to block all remote HTTP fetching of data:
Note that these and other config settings in Hugo can be overridden by the OS environment. If you want to block all remote HTTP fetching of data:
```txt
HUGO_SECURITY_HTTP_URLS=none hugo
```
## Dependency security
## Dependency Security
Hugo is built as a static binary using [Go Modules](https://github.com/golang/go/wiki/Modules) to manage its dependencies. Go Modules have several safeguards, one of them being the `go.sum` file. This is a database of the expected cryptographic checksums of all of your dependencies, including transitive dependencies.
[Hugo Modules](/hugo-modules/) is a feature built on top of the functionality of Go Modules. Like Go Modules, a Hugo project using Hugo Modules will have a `go.sum` file. We recommend that you commit this file to your version control system. The Hugo build will fail if there is a checksum mismatch, which would be an indication of [dependency tampering](https://julienrenaux.fr/2019/12/20/github-actions-security-risk/).
## Web application security
## Web Application Security
These are the security threats as defined by [OWASP](https://en.wikipedia.org/wiki/OWASP).
+5 -5
View File
@@ -5,8 +5,8 @@ layout: single
menu:
docs:
parent: about
weight: 20
weight: 20
weight: 10
weight: 10
aliases: [/overview/introduction/,/about/why-i-built-hugo/]
toc: true
---
@@ -17,15 +17,15 @@ Websites built with Hugo are extremely fast and secure. Hugo sites can be hosted
We think of Hugo as the ideal website creation tool with nearly instant build times, able to rebuild whenever a change is made.
## How fast is Hugo?
## How Fast is Hugo?
{{< youtube "CdiDYZ51a2o" >}}
## What does Hugo do?
## What Does Hugo Do?
In technical terms, Hugo takes a source directory of files and templates and uses these as input to create a complete website.
## Who should use Hugo?
## Who Should Use Hugo?
Hugo is for people that prefer writing in a text editor over a browser.
+1 -1
View File
@@ -27,7 +27,7 @@ hugo [flags]
-D, --buildDrafts include content marked as draft
-E, --buildExpired include expired content
-F, --buildFuture include content with publishdate in the future
--cacheDir string filesystem path to cache directory
--cacheDir string filesystem path to cache directory. Defaults: $TMPDIR/hugo_cache_$USER/
--cleanDestinationDir remove files from destination not found in static directories
--clock string set the clock used by Hugo, e.g. --clock 2021-11-06T22:30:00.00+09:00
--config string config file (default is hugo.yaml|json|toml)
+1 -1
View File
@@ -19,7 +19,7 @@ hugo config [command] [flags]
```
-b, --baseURL string hostname (and path) to the root, e.g. https://spf13.com/
--cacheDir string filesystem path to cache directory
--cacheDir string filesystem path to cache directory. Defaults: $TMPDIR/hugo_cache_$USER/
-c, --contentDir string filesystem path to content directory
--format string preferred file format (toml, yaml or json) (default "toml")
-h, --help help for config
@@ -15,7 +15,7 @@ hugo config mounts [flags] [args]
```
-b, --baseURL string hostname (and path) to the root, e.g. https://spf13.com/
--cacheDir string filesystem path to cache directory
--cacheDir string filesystem path to cache directory. Defaults: $TMPDIR/hugo_cache_$USER/
-c, --contentDir string filesystem path to content directory
-h, --help help for mounts
-t, --theme strings themes to use (located in /themes/THEMENAME/)
+4
View File
@@ -13,6 +13,10 @@ Convert your content (e.g. front matter) to different formats.
See convert's subcommands toJSON, toTOML and toYAML for more information.
```
hugo convert [command] [flags]
```
### Options
```
+4
View File
@@ -7,6 +7,10 @@ url: /commands/hugo_gen/
A collection of several useful generators.
```
hugo gen [command] [flags]
```
### Options
```
+4
View File
@@ -13,6 +13,10 @@ Import your site from other web site generators like Jekyll.
Import requires a subcommand, e.g. `hugo import jekyll jekyll_root_path target_path`.
```
hugo import [command] [flags]
```
### Options
```
+4
View File
@@ -13,6 +13,10 @@ Listing out various types of content.
List requires a subcommand, e.g. hugo list drafts
```
hugo list [command] [flags]
```
### Options
```
+1 -1
View File
@@ -20,7 +20,7 @@ hugo mod clean [flags] [args]
```
--all clean entire module cache
-b, --baseURL string hostname (and path) to the root, e.g. https://spf13.com/
--cacheDir string filesystem path to cache directory
--cacheDir string filesystem path to cache directory. Defaults: $TMPDIR/hugo_cache_$USER/
-c, --contentDir string filesystem path to content directory
-h, --help help for clean
--pattern string pattern matching module paths to clean (all if not set), e.g. "**hugo*"

Some files were not shown because too many files have changed in this diff Show More