mirror of
https://github.com/gohugoio/hugo.git
synced 2026-09-02 03:32:38 +00:00
Compare commits
61 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 10352335e0 | |||
| f23576f2fb | |||
| b5d43cdc17 | |||
| 6ef8017f60 | |||
| d67925f5a1 | |||
| 48dd4f469a | |||
| b1e1eede50 | |||
| f522a7282b | |||
| 6ac72dd3bf | |||
| 74c0bbfc6a | |||
| e66a33d369 | |||
| 8a979d54d1 | |||
| fd49df8f7a | |||
| c7b35c8704 | |||
| 5916b61be9 | |||
| 7eafef2269 | |||
| 00c4228f61 | |||
| 5f5b2f378f | |||
| b3ea2a5fab | |||
| 67b543549b | |||
| ef7a22a2ff | |||
| 8dfcece805 | |||
| 9a6bfe2667 | |||
| 7d45614c6d | |||
| 7f12c0900d | |||
| dab2c332dc | |||
| 5a64551a07 | |||
| 0fc63fbf57 | |||
| 576d55d009 | |||
| b9400b8a95 | |||
| ce0c7f42c1 | |||
| f472dd48a7 | |||
| 50973e7272 | |||
| 48566b6f37 | |||
| b441472b69 | |||
| ac2c3fb20f | |||
| ee91c707ee | |||
| 11f7f39913 | |||
| 192e3c453e | |||
| e569dd59a0 | |||
| 5ba03bf657 | |||
| c1b2e58bfb | |||
| 77214117ae | |||
| 1a94731669 | |||
| 18784711b5 | |||
| 2c611091fd | |||
| 8e9e04e395 | |||
| 32334d098e | |||
| 8e2e60dd45 | |||
| 2bc54df622 | |||
| 608ed09a0a | |||
| 94f1ede3aa | |||
| ab374e3d22 | |||
| 1a9133075c | |||
| d36a8f5601 | |||
| 487b8e3af3 | |||
| a6f99cca22 | |||
| a775488304 | |||
| 66ba63cd5f | |||
| eb06a3cd0c | |||
| a798e3e724 |
@@ -106,7 +106,10 @@ jobs:
|
||||
run: go install honnef.co/go/tools/cmd/staticcheck@latest
|
||||
- if: matrix.os == 'ubuntu-latest'
|
||||
name: Run staticcheck
|
||||
run: staticcheck ./...
|
||||
run: |
|
||||
export STATICCHECK_CACHE="${{ runner.temp }}/staticcheck"
|
||||
staticcheck ./...
|
||||
rm -rf ${{ runner.temp }}/staticcheck
|
||||
- if: matrix.os != 'windows-latest'
|
||||
name: Check
|
||||
run: |
|
||||
@@ -118,16 +121,14 @@ jobs:
|
||||
# See issue #11052. We limit the build to regular test (no -race flag) on Windows for now.
|
||||
name: Test
|
||||
run: |
|
||||
mage -v test;
|
||||
mage -v test
|
||||
env:
|
||||
HUGO_BUILD_TAGS: extended,withdeploy
|
||||
- name: Build tags
|
||||
run: |
|
||||
go install -tags extended
|
||||
- if: matrix.os == 'ubuntu-latest'
|
||||
name: Build for dragonfly
|
||||
run: |
|
||||
go install
|
||||
go clean -i -cache
|
||||
env:
|
||||
GOARCH: amd64
|
||||
GOOS: dragonfly
|
||||
|
||||
+2
-1
@@ -3,4 +3,5 @@
|
||||
imports.*
|
||||
dist/
|
||||
public/
|
||||
.DS_Store
|
||||
.DS_Store
|
||||
cache/filecache/_gen/
|
||||
@@ -0,0 +1 @@
|
||||
tpl/tplimpl/embedded/templates/**
|
||||
@@ -0,0 +1,14 @@
|
||||
* Brevity is good.
|
||||
* Assume that the maintainers and readers of the code you write are Go experts:
|
||||
* Don't use comments to explain the obvious.
|
||||
* Use self-explanatory variable and function names.
|
||||
* Use short variable names when the context is clear.
|
||||
* If you need to add temporary debug printing, use `hdebug.Printf`.[^1]
|
||||
* Never export symbols that's not needed outside of the package.
|
||||
* Avoid global state at (almost) all cost.
|
||||
* This is a project with a long history; assume that a similiar problem has been solved before, look hard for helper functions before creating new ones.
|
||||
* Use `./check.sh ./somepackage/...` when iterating.
|
||||
* Use `./check.sh` when you're done.
|
||||
|
||||
|
||||
[^1]: CI build fail if you forget to remove the debug printing.
|
||||
+1
-1
@@ -77,7 +77,7 @@ To make the contribution process as seamless as possible, we ask for the followi
|
||||
* Run `go fmt`.
|
||||
* Add documentation if you are adding new features or changing functionality. The docs site lives in `/docs`.
|
||||
* Squash your commits into a single commit. `git rebase -i`. It’s okay to force update your pull request with `git push -f`.
|
||||
* Ensure that `mage check` succeeds. [Travis CI](https://travis-ci.org/gohugoio/hugo) (Windows, Linux and macOS) will fail the build if `mage check` fails.
|
||||
* Ensure that `./check.sh` succeeds. Note that some tests are skipped when running locally, some because they are slow. To run these locally, do `CI_LOCAL=true ./check.sh ./somepackage/...`.
|
||||
* Follow the **Git Commit Message Guidelines** below.
|
||||
|
||||
## AI Assistance Notice
|
||||
|
||||
@@ -52,7 +52,7 @@ Use Hugo's embedded web server during development to instantly see changes to co
|
||||
|
||||
Hugo's fast asset pipelines include:
|
||||
|
||||
- Image processing – Convert, resize, crop, rotate, adjust colors, apply filters, overlay text and images, and extract EXIF data
|
||||
- Image processing – Convert, resize, crop, rotate, adjust colors, apply filters, overlay text and images, and extract metadata
|
||||
- JavaScript bundling – Transpile TypeScript and JSX to JavaScript, bundle, tree shake, minify, create source maps, and perform SRI hashing.
|
||||
- Sass processing – Transpile Sass to CSS, bundle, tree shake, minify, create source maps, perform SRI hashing, and integrate with PostCSS
|
||||
- Tailwind CSS processing – Compile Tailwind CSS utility classes into standard CSS, bundle, tree shake, optimize, minify, perform SRI hashing, and integrate with PostCSS
|
||||
|
||||
Vendored
+55
-11
@@ -16,6 +16,7 @@ package filecache
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@@ -54,7 +55,11 @@ type Cache struct {
|
||||
|
||||
nlocker *lockTracker
|
||||
|
||||
isResourceDir bool
|
||||
baseDir string
|
||||
|
||||
initOnce sync.Once
|
||||
isInited bool
|
||||
initErr error
|
||||
}
|
||||
|
||||
@@ -109,9 +114,14 @@ func (l *lockedFile) Close() error {
|
||||
}
|
||||
|
||||
func (c *Cache) init() error {
|
||||
if c == nil {
|
||||
panic("cache is nil")
|
||||
}
|
||||
c.initOnce.Do(func() {
|
||||
c.isInited = true
|
||||
// Create the base dir if it does not exist.
|
||||
if err := c.Fs.MkdirAll("", 0o777); err != nil && !os.IsExist(err) {
|
||||
err = fmt.Errorf("failled to create base cache directory: %s", err)
|
||||
c.initErr = err
|
||||
}
|
||||
})
|
||||
@@ -286,8 +296,32 @@ func (c *Cache) GetOrCreateBytes(id string, create func() ([]byte, error)) (Item
|
||||
return info, b, nil
|
||||
}
|
||||
|
||||
// SetBytes sets the file content with the given id in the cache.
|
||||
func (c *Cache) SetBytes(id string, data []byte) error {
|
||||
if err := c.init(); err != nil {
|
||||
return err
|
||||
}
|
||||
id = cleanID(id)
|
||||
|
||||
c.nlocker.Lock(id)
|
||||
defer c.nlocker.Unlock(id)
|
||||
|
||||
if c.maxAge == 0 {
|
||||
// No caching.
|
||||
return nil
|
||||
}
|
||||
|
||||
return c.writeReader(id, bytes.NewReader(data))
|
||||
}
|
||||
|
||||
// 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) {
|
||||
func (c *Cache) GetBytes(id string) ([]byte, error) {
|
||||
_, b, err := c.GetItemBytes(id)
|
||||
return b, err
|
||||
}
|
||||
|
||||
// GetItemBytes gets the ItemInfo and file content with the given id from the cache, nil if none found.
|
||||
func (c *Cache) GetItemBytes(id string) (ItemInfo, []byte, error) {
|
||||
if err := c.init(); err != nil {
|
||||
return ItemInfo{}, nil, err
|
||||
}
|
||||
@@ -417,6 +451,17 @@ func (c *Cache) GetString(id string) string {
|
||||
// Caches is a named set of caches.
|
||||
type Caches map[string]*Cache
|
||||
|
||||
func (f Caches) SetResourceFs(fs afero.Fs) {
|
||||
for _, c := range f {
|
||||
if c.isResourceDir {
|
||||
if c.isInited {
|
||||
panic("cannot set resource fs after init")
|
||||
}
|
||||
c.Fs = hugofs.NewBasePathFs(fs, c.baseDir)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get gets a named cache, nil if none found.
|
||||
func (f Caches) Get(name string) *Cache {
|
||||
return f[strings.ToLower(name)]
|
||||
@@ -424,24 +469,19 @@ func (f Caches) Get(name string) *Cache {
|
||||
|
||||
// NewCaches creates a new set of file caches from the given
|
||||
// configuration.
|
||||
func NewCaches(p *helpers.PathSpec) (Caches, error) {
|
||||
dcfg := p.Cfg.GetConfigSection("caches").(Configs)
|
||||
fs := p.Fs.Source
|
||||
func NewCaches(dcfg Configs, sourceFs afero.Fs) (Caches, error) {
|
||||
// dcfg := p.Cfg.GetConfigSection("caches").(Configs)
|
||||
fs := sourceFs
|
||||
|
||||
m := make(Caches)
|
||||
for k, v := range dcfg {
|
||||
var cfs afero.Fs
|
||||
|
||||
if v.IsResourceDir {
|
||||
cfs = p.BaseFs.ResourcesCache
|
||||
cfs = nil // Set later. TODO(bep) this needs to be cleanded up.
|
||||
} else {
|
||||
cfs = fs
|
||||
}
|
||||
|
||||
if cfs == nil {
|
||||
panic("nil fs")
|
||||
}
|
||||
|
||||
baseDir := v.DirCompiled
|
||||
|
||||
bfs := hugofs.NewBasePathFs(cfs, baseDir)
|
||||
@@ -451,7 +491,11 @@ func NewCaches(p *helpers.PathSpec) (Caches, error) {
|
||||
pruneAllRootDir = "pkg"
|
||||
}
|
||||
|
||||
m[k] = NewCache(bfs, v.MaxAge, pruneAllRootDir)
|
||||
c := NewCache(bfs, v.MaxAge, pruneAllRootDir)
|
||||
c.isResourceDir = v.IsResourceDir
|
||||
c.baseDir = baseDir
|
||||
|
||||
m[k] = c
|
||||
}
|
||||
|
||||
return m, nil
|
||||
|
||||
Vendored
+42
-9
@@ -15,6 +15,7 @@
|
||||
package filecache
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"path"
|
||||
@@ -22,7 +23,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gohugoio/hugo/common/maps"
|
||||
"github.com/gohugoio/hugo/common/hmaps"
|
||||
"github.com/gohugoio/hugo/config"
|
||||
|
||||
"github.com/mitchellh/mapstructure"
|
||||
@@ -40,13 +41,14 @@ var defaultCacheConfig = FileCacheConfig{
|
||||
}
|
||||
|
||||
const (
|
||||
CacheKeyGetJSON = "getjson"
|
||||
CacheKeyGetCSV = "getcsv"
|
||||
CacheKeyImages = "images"
|
||||
CacheKeyAssets = "assets"
|
||||
CacheKeyModules = "modules"
|
||||
CacheKeyGetResource = "getresource"
|
||||
CacheKeyMisc = "misc"
|
||||
CacheKeyGetJSON = "getjson"
|
||||
CacheKeyGetCSV = "getcsv"
|
||||
CacheKeyImages = "images"
|
||||
CacheKeyAssets = "assets"
|
||||
CacheKeyModules = "modules"
|
||||
CacheKeyModuleQueries = "modulequeries"
|
||||
CacheKeyGetResource = "getresource"
|
||||
CacheKeyMisc = "misc"
|
||||
)
|
||||
|
||||
type Configs map[string]FileCacheConfig
|
||||
@@ -68,6 +70,10 @@ var defaultCacheConfigs = Configs{
|
||||
MaxAge: -1,
|
||||
Dir: ":cacheDir/modules",
|
||||
},
|
||||
CacheKeyModuleQueries: {
|
||||
MaxAge: 24 * time.Hour,
|
||||
Dir: ":cacheDir/modules",
|
||||
},
|
||||
CacheKeyGetJSON: defaultCacheConfig,
|
||||
CacheKeyGetCSV: defaultCacheConfig,
|
||||
CacheKeyImages: {
|
||||
@@ -107,6 +113,23 @@ type FileCacheConfig struct {
|
||||
IsResourceDir bool `json:"-"`
|
||||
}
|
||||
|
||||
// MarshalJSON marshals FileCacheConfig to JSON with MaxAge as a human-readable string.
|
||||
func (c FileCacheConfig) MarshalJSON() ([]byte, error) {
|
||||
var maxAge any
|
||||
if c.MaxAge == -1 {
|
||||
maxAge = -1
|
||||
} else {
|
||||
maxAge = strings.TrimSuffix(c.MaxAge.String(), "0m0s")
|
||||
}
|
||||
return json.Marshal(&struct {
|
||||
MaxAge any `json:"maxAge"`
|
||||
Dir string `json:"dir"`
|
||||
}{
|
||||
MaxAge: maxAge,
|
||||
Dir: c.Dir,
|
||||
})
|
||||
}
|
||||
|
||||
// GetJSONCache gets the file cache for getJSON.
|
||||
func (f Caches) GetJSONCache() *Cache {
|
||||
return f[CacheKeyGetJSON]
|
||||
@@ -127,6 +150,16 @@ func (f Caches) ModulesCache() *Cache {
|
||||
return f[CacheKeyModules]
|
||||
}
|
||||
|
||||
// ModuleQueriesCache gets the file cache for Hugo Module version queries.
|
||||
// Returns nil if not found.
|
||||
func (f Caches) ModuleQueriesCache() *Cache {
|
||||
c, ok := f[CacheKeyModuleQueries]
|
||||
if !ok {
|
||||
panic("module queries cache not set")
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// AssetsCache gets the file cache for assets (processed resources, SCSS etc.).
|
||||
func (f Caches) AssetsCache() *Cache {
|
||||
return f[CacheKeyAssets]
|
||||
@@ -154,7 +187,7 @@ func DecodeConfig(fs afero.Fs, bcfg config.BaseConfig, m map[string]any) (Config
|
||||
_, isOsFs := fs.(*afero.OsFs)
|
||||
|
||||
for k, v := range m {
|
||||
if _, ok := v.(maps.Params); !ok {
|
||||
if _, ok := v.(hmaps.Params); !ok {
|
||||
continue
|
||||
}
|
||||
cc := defaultCacheConfig
|
||||
|
||||
+30
-3
@@ -14,6 +14,7 @@
|
||||
package filecache_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"testing"
|
||||
@@ -59,7 +60,7 @@ dir = "/path/to/c4"
|
||||
c.Assert(err, qt.IsNil)
|
||||
fs := afero.NewMemMapFs()
|
||||
decoded := testconfig.GetTestConfigs(fs, cfg).Base.Caches
|
||||
c.Assert(len(decoded), qt.Equals, 7)
|
||||
c.Assert(len(decoded), qt.Equals, 8)
|
||||
|
||||
c2 := decoded["getcsv"]
|
||||
c.Assert(c2.MaxAge.String(), qt.Equals, "11h0m0s")
|
||||
@@ -106,7 +107,7 @@ dir = "/path/to/c4"
|
||||
c.Assert(err, qt.IsNil)
|
||||
fs := afero.NewMemMapFs()
|
||||
decoded := testconfig.GetTestConfigs(fs, cfg).Base.Caches
|
||||
c.Assert(len(decoded), qt.Equals, 7)
|
||||
c.Assert(len(decoded), qt.Equals, 8)
|
||||
|
||||
for _, v := range decoded {
|
||||
c.Assert(v.MaxAge, qt.Equals, time.Duration(0))
|
||||
@@ -129,7 +130,7 @@ func TestDecodeConfigDefault(t *testing.T) {
|
||||
|
||||
fs := afero.NewMemMapFs()
|
||||
decoded := testconfig.GetTestConfigs(fs, cfg).Base.Caches
|
||||
c.Assert(len(decoded), qt.Equals, 7)
|
||||
c.Assert(len(decoded), qt.Equals, 8)
|
||||
|
||||
imgConfig := decoded[filecache.CacheKeyImages]
|
||||
jsonConfig := decoded[filecache.CacheKeyGetJSON]
|
||||
@@ -144,3 +145,29 @@ func TestDecodeConfigDefault(t *testing.T) {
|
||||
c.Assert(imgConfig.IsResourceDir, qt.Equals, true)
|
||||
c.Assert(jsonConfig.IsResourceDir, qt.Equals, false)
|
||||
}
|
||||
|
||||
func TestFileCacheConfigMarshalJSON(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
|
||||
cfg := config.New()
|
||||
cfg.Set("cacheDir", "/cache")
|
||||
cfg.Set("workingDir", "/my/project")
|
||||
|
||||
fs := afero.NewMemMapFs()
|
||||
decoded := testconfig.GetTestConfigs(fs, cfg).Base.Caches
|
||||
|
||||
moduleQueriesConfig := decoded[filecache.CacheKeyModuleQueries]
|
||||
c.Assert(moduleQueriesConfig.MaxAge, qt.Equals, 24*time.Hour)
|
||||
|
||||
b, err := json.Marshal(moduleQueriesConfig)
|
||||
c.Assert(err, qt.IsNil)
|
||||
|
||||
c.Assert(string(b), qt.Contains, `"maxAge":"24h"`)
|
||||
c.Assert(string(b), qt.Not(qt.Contains), "86400000000000")
|
||||
c.Assert(string(b), qt.Not(qt.Contains), "8.64e")
|
||||
|
||||
moduleQueriesConfig.MaxAge = -1
|
||||
b, err = json.Marshal(moduleQueriesConfig)
|
||||
c.Assert(err, qt.IsNil)
|
||||
c.Assert(string(b), qt.Contains, `"maxAge":-1`)
|
||||
}
|
||||
|
||||
+7
-3
@@ -55,9 +55,12 @@ dir = ":resourceDir/_gen"
|
||||
|
||||
for _, name := range []string{filecache.CacheKeyGetCSV, filecache.CacheKeyGetJSON, filecache.CacheKeyAssets, filecache.CacheKeyImages} {
|
||||
msg := qt.Commentf("cache: %s", name)
|
||||
p := newPathsSpec(t, afero.NewMemMapFs(), configStr)
|
||||
caches, err := filecache.NewCaches(p)
|
||||
fs := afero.NewMemMapFs()
|
||||
p := newPathsSpec(t, fs, configStr)
|
||||
fileCachConfig := p.Cfg.GetConfigSection("caches").(filecache.Configs)
|
||||
caches, err := filecache.NewCaches(fileCachConfig, fs)
|
||||
c.Assert(err, qt.IsNil)
|
||||
caches.SetResourceFs(fs)
|
||||
cache := caches[name]
|
||||
for i := range 10 {
|
||||
id := fmt.Sprintf("i%d", i)
|
||||
@@ -84,8 +87,9 @@ dir = ":resourceDir/_gen"
|
||||
}
|
||||
}
|
||||
|
||||
caches, err = filecache.NewCaches(p)
|
||||
caches, err = filecache.NewCaches(fileCachConfig, fs)
|
||||
c.Assert(err, qt.IsNil)
|
||||
caches.SetResourceFs(fs)
|
||||
cache = caches[name]
|
||||
// Touch one and then prune.
|
||||
cache.GetOrCreateBytes("i5", func() ([]byte, error) {
|
||||
|
||||
Vendored
+10
-4
@@ -18,6 +18,8 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/gohugoio/hugo/htesting"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -78,9 +80,11 @@ dir = ":cacheDir/c"
|
||||
configStr = strings.Replace(configStr, "\\", winPathSep, -1)
|
||||
|
||||
p := newPathsSpec(t, osfs, configStr)
|
||||
fileCachConfig := p.Cfg.GetConfigSection("caches").(filecache.Configs)
|
||||
|
||||
caches, err := filecache.NewCaches(p)
|
||||
caches, err := filecache.NewCaches(fileCachConfig, p.Fs.Source)
|
||||
c.Assert(err, qt.IsNil)
|
||||
caches.SetResourceFs(p.SourceFs)
|
||||
|
||||
cache := caches.Get("GetJSON")
|
||||
c.Assert(cache, qt.Not(qt.IsNil))
|
||||
@@ -149,7 +153,7 @@ dir = ":cacheDir/c"
|
||||
r.Close()
|
||||
c.Assert(string(b), qt.Equals, "Hugo is great!")
|
||||
|
||||
info, b, err = caches.ImageCache().GetBytes("mykey")
|
||||
info, b, err = caches.ImageCache().GetItemBytes("mykey")
|
||||
c.Assert(err, qt.IsNil)
|
||||
c.Assert(info.Name, qt.Equals, "mykey")
|
||||
c.Assert(string(b), qt.Equals, "Hugo is great!")
|
||||
@@ -158,6 +162,7 @@ dir = ":cacheDir/c"
|
||||
}
|
||||
|
||||
func TestFileCacheConcurrent(t *testing.T) {
|
||||
htesting.SkipSlowTestUnlessCI(t)
|
||||
t.Parallel()
|
||||
|
||||
c := qt.New(t)
|
||||
@@ -179,9 +184,10 @@ dir = "/cache/c"
|
||||
`
|
||||
|
||||
p := newPathsSpec(t, afero.NewMemMapFs(), configStr)
|
||||
|
||||
caches, err := filecache.NewCaches(p)
|
||||
fileCachConfig := p.Cfg.GetConfigSection("caches").(filecache.Configs)
|
||||
caches, err := filecache.NewCaches(fileCachConfig, p.Fs.Source)
|
||||
c.Assert(err, qt.IsNil)
|
||||
caches.SetResourceFs(p.Fs.Source)
|
||||
|
||||
const cacheName = "getjson"
|
||||
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
# Default to all packages if none specified
|
||||
PACKAGES="${1:-./...}"
|
||||
|
||||
echo "==> Checking packages: $PACKAGES"
|
||||
|
||||
# Timing arrays
|
||||
declare -a STEP_NAMES
|
||||
declare -a STEP_TIMES
|
||||
|
||||
time_step() {
|
||||
local name="$1"
|
||||
shift
|
||||
local start=$(date +%s.%N)
|
||||
"$@"
|
||||
local end=$(date +%s.%N)
|
||||
local elapsed=$(echo "$end - $start" | bc)
|
||||
STEP_NAMES+=("$name")
|
||||
STEP_TIMES+=("$elapsed")
|
||||
}
|
||||
|
||||
# Check gofmt
|
||||
run_gofmt() {
|
||||
echo "==> Running gofmt..."
|
||||
# Convert package pattern to path (e.g., ./hugolib/... -> ./hugolib)
|
||||
local path="${PACKAGES%/...}"
|
||||
GOFMT_OUTPUT=$(gofmt -l "$path" 2>&1) || true
|
||||
if [ -n "$GOFMT_OUTPUT" ]; then
|
||||
echo "gofmt found issues in:"
|
||||
echo "$GOFMT_OUTPUT"
|
||||
exit 1
|
||||
fi
|
||||
echo " OK"
|
||||
}
|
||||
|
||||
# Run staticcheck
|
||||
run_staticcheck() {
|
||||
# Check if staticcheck is installed, install if not
|
||||
if ! command -v staticcheck &> /dev/null; then
|
||||
echo "==> Installing staticcheck..."
|
||||
go install honnef.co/go/tools/cmd/staticcheck@latest
|
||||
fi
|
||||
echo "==> Running staticcheck..."
|
||||
staticcheck $PACKAGES
|
||||
echo " OK"
|
||||
}
|
||||
|
||||
# Run tests
|
||||
run_tests() {
|
||||
echo "==> Running tests..."
|
||||
local output
|
||||
if ! output=$(go test $PACKAGES 2>&1); then
|
||||
echo "$output"
|
||||
exit 1
|
||||
fi
|
||||
echo " OK"
|
||||
}
|
||||
|
||||
# Run all steps with timing
|
||||
TOTAL_START=$(date +%s.%N)
|
||||
|
||||
time_step "gofmt" run_gofmt
|
||||
time_step "staticcheck" run_staticcheck
|
||||
time_step "tests" run_tests
|
||||
|
||||
TOTAL_END=$(date +%s.%N)
|
||||
TOTAL_ELAPSED=$(echo "$TOTAL_END - $TOTAL_START" | bc)
|
||||
|
||||
# Print timing summary
|
||||
echo ""
|
||||
echo "==> All checks passed!"
|
||||
echo ""
|
||||
echo "Timing summary:"
|
||||
echo "---------------"
|
||||
for i in "${!STEP_NAMES[@]}"; do
|
||||
printf " %-15s %6.2fs\n" "${STEP_NAMES[$i]}" "${STEP_TIMES[$i]}"
|
||||
done
|
||||
echo "---------------"
|
||||
printf " %-15s %6.2fs\n" "Total" "$TOTAL_ELAPSED"
|
||||
+2
-2
@@ -23,7 +23,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/bep/simplecobra"
|
||||
"github.com/gohugoio/hugo/common/maps"
|
||||
"github.com/gohugoio/hugo/common/hmaps"
|
||||
"github.com/gohugoio/hugo/config/allconfig"
|
||||
"github.com/gohugoio/hugo/hugolib/sitesmatrix"
|
||||
"github.com/gohugoio/hugo/modules"
|
||||
@@ -95,7 +95,7 @@ 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)
|
||||
hmaps.ConvertFloat64WithNoDecimalsToInt(m)
|
||||
switch format {
|
||||
case "yaml":
|
||||
return parser.InterfaceToConfig(m, metadecoders.YAML, os.Stdout)
|
||||
|
||||
@@ -31,11 +31,11 @@ import (
|
||||
"github.com/bep/simplecobra"
|
||||
"github.com/fsnotify/fsnotify"
|
||||
"github.com/gohugoio/hugo/common/herrors"
|
||||
"github.com/gohugoio/hugo/common/hmaps"
|
||||
"github.com/gohugoio/hugo/common/hstrings"
|
||||
"github.com/gohugoio/hugo/common/htime"
|
||||
"github.com/gohugoio/hugo/common/hugo"
|
||||
"github.com/gohugoio/hugo/common/loggers"
|
||||
"github.com/gohugoio/hugo/common/maps"
|
||||
"github.com/gohugoio/hugo/common/paths"
|
||||
"github.com/gohugoio/hugo/common/terminal"
|
||||
"github.com/gohugoio/hugo/common/types"
|
||||
@@ -1077,7 +1077,7 @@ func (c *hugoBuilder) loadConfig(cd *simplecobra.Commandeer, running bool) error
|
||||
}
|
||||
cfg.Set("environment", c.r.environment)
|
||||
|
||||
cfg.Set("internal", maps.Params{
|
||||
cfg.Set("internal", hmaps.Params{
|
||||
"running": running,
|
||||
"watch": watch,
|
||||
"verbose": c.r.isVerbose(),
|
||||
|
||||
+3
-3
@@ -29,9 +29,9 @@ import (
|
||||
"unicode"
|
||||
|
||||
"github.com/bep/simplecobra"
|
||||
"github.com/gohugoio/hugo/common/hmaps"
|
||||
"github.com/gohugoio/hugo/common/htime"
|
||||
"github.com/gohugoio/hugo/common/hugio"
|
||||
"github.com/gohugoio/hugo/common/maps"
|
||||
"github.com/gohugoio/hugo/helpers"
|
||||
"github.com/gohugoio/hugo/hugofs"
|
||||
"github.com/gohugoio/hugo/parser"
|
||||
@@ -190,7 +190,7 @@ func (c *importCommand) createSiteFromJekyll(jekyllRoot, targetDir string, jekyl
|
||||
}
|
||||
|
||||
func (c *importCommand) convertJekyllContent(m any, content string) (string, error) {
|
||||
metadata, _ := maps.ToStringMapE(m)
|
||||
metadata, _ := hmaps.ToStringMapE(m)
|
||||
|
||||
lines := strings.Split(content, "\n")
|
||||
var resultLines []string
|
||||
@@ -246,7 +246,7 @@ func (c *importCommand) convertJekyllContent(m any, content string) (string, err
|
||||
}
|
||||
|
||||
func (c *importCommand) convertJekyllMetaData(m any, postName string, postDate time.Time, draft bool) (any, error) {
|
||||
metadata, err := maps.ToStringMapE(m)
|
||||
metadata, err := hmaps.ToStringMapE(m)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
+1
-3
@@ -28,14 +28,13 @@ func newReleaseCommand() simplecobra.Commander {
|
||||
step int
|
||||
skipPush bool
|
||||
try bool
|
||||
version string
|
||||
)
|
||||
|
||||
return &simpleCommand{
|
||||
name: "release",
|
||||
short: "Release a new version of Hugo",
|
||||
run: func(ctx context.Context, cd *simplecobra.Commandeer, r *rootCommand, args []string) error {
|
||||
rel, err := releaser.New(skipPush, try, step, version)
|
||||
rel, err := releaser.New(skipPush, try, step)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -48,7 +47,6 @@ func newReleaseCommand() simplecobra.Commander {
|
||||
cmd.PersistentFlags().BoolVarP(&skipPush, "skip-push", "", false, "skip pushing to remote")
|
||||
cmd.PersistentFlags().BoolVarP(&try, "try", "", false, "no changes")
|
||||
cmd.PersistentFlags().IntVarP(&step, "step", "", 0, "step to run (1: set new version 2: prepare next dev version)")
|
||||
cmd.PersistentFlags().StringVarP(&version, "version", "", "", "version to release (derived from branch name if not set)")
|
||||
_ = cmd.RegisterFlagCompletionFunc("step", cobra.FixedCompletions([]string{"1", "2"}, cobra.ShellCompDirectiveNoFileComp))
|
||||
},
|
||||
}
|
||||
|
||||
@@ -87,11 +87,13 @@ func XXHashFromString(s string) (uint64, error) {
|
||||
return h.Sum64(), nil
|
||||
}
|
||||
|
||||
// XxHashFromStringHexEncoded calculates the xxHash for the given string
|
||||
// XxHashFromStringHexEncoded calculates the xxHash for the given strings
|
||||
// and returns the hash as a hex encoded string.
|
||||
func XxHashFromStringHexEncoded(f string) string {
|
||||
func XxHashFromStringHexEncoded(s ...string) string {
|
||||
h := xxhash.New()
|
||||
h.WriteString(f)
|
||||
for _, f := range s {
|
||||
h.WriteString(f)
|
||||
}
|
||||
hash := h.Sum(nil)
|
||||
return hex.EncodeToString(hash)
|
||||
}
|
||||
|
||||
@@ -27,8 +27,8 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/bep/logg"
|
||||
"github.com/gohugoio/hugo/common/hmaps"
|
||||
"github.com/gohugoio/hugo/common/loggers"
|
||||
"github.com/gohugoio/hugo/common/maps"
|
||||
"github.com/gohugoio/hugo/config"
|
||||
"github.com/gohugoio/hugo/config/security"
|
||||
)
|
||||
@@ -102,7 +102,7 @@ func New(cfg security.Config, workingDir string, log loggers.Logger) *Exec {
|
||||
workingDir: workingDir,
|
||||
infol: log.InfoCommand("exec"),
|
||||
baseEnviron: baseEnviron,
|
||||
newNPXRunnerCache: maps.NewCache[string, func(arg ...any) (Runner, error)](),
|
||||
newNPXRunnerCache: hmaps.NewCache[string, func(arg ...any) (Runner, error)](),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,7 +121,7 @@ type Exec struct {
|
||||
// os.Environ filtered by the Exec.OsEnviron whitelist filter.
|
||||
baseEnviron []string
|
||||
|
||||
newNPXRunnerCache *maps.Cache[string, func(arg ...any) (Runner, error)]
|
||||
newNPXRunnerCache *hmaps.Cache[string, func(arg ...any) (Runner, error)]
|
||||
npxInit sync.Once
|
||||
npxAvailable bool
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2024 The Hugo Authors. All rights reserved.
|
||||
// Copyright 2026 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,7 +11,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package maps
|
||||
package hmaps
|
||||
|
||||
import (
|
||||
"sync"
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2025 The Hugo Authors. All rights reserved.
|
||||
// Copyright 2026 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,7 +11,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package maps
|
||||
package hmaps
|
||||
|
||||
import (
|
||||
"testing"
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2025 The Hugo Authors. All rights reserved.
|
||||
// Copyright 2026 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,7 +11,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package maps
|
||||
package hmaps
|
||||
|
||||
import (
|
||||
"iter"
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2025 The Hugo Authors. All rights reserved.
|
||||
// Copyright 2026 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,7 +11,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package maps
|
||||
package hmaps
|
||||
|
||||
import (
|
||||
"testing"
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2018 The Hugo Authors. All rights reserved.
|
||||
// Copyright 2026 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,7 +11,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package maps
|
||||
package hmaps
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2018 The Hugo Authors. All rights reserved.
|
||||
// Copyright 2026 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,7 +11,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package maps
|
||||
package hmaps
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2024 The Hugo Authors. All rights reserved.
|
||||
// Copyright 2026 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,7 +11,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package maps
|
||||
package hmaps
|
||||
|
||||
import (
|
||||
"slices"
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2024 The Hugo Authors. All rights reserved.
|
||||
// Copyright 2026 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,7 +11,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package maps
|
||||
package hmaps
|
||||
|
||||
import (
|
||||
"testing"
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2025 The Hugo Authors. All rights reserved.
|
||||
// Copyright 2026 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,7 +11,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package maps
|
||||
package hmaps
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2025 The Hugo Authors. All rights reserved.
|
||||
// Copyright 2026 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,7 +11,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package maps
|
||||
package hmaps
|
||||
|
||||
import (
|
||||
"testing"
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019 The Hugo Authors. All rights reserved.
|
||||
// Copyright 2026 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,7 +11,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package maps
|
||||
package hmaps
|
||||
|
||||
import (
|
||||
"errors"
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019 The Hugo Authors. All rights reserved.
|
||||
// Copyright 2026 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,7 +11,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package maps
|
||||
package hmaps
|
||||
|
||||
import (
|
||||
"testing"
|
||||
@@ -20,8 +20,8 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/gohugoio/hugo/common/hmaps"
|
||||
"github.com/gohugoio/hugo/common/htime"
|
||||
"github.com/gohugoio/hugo/common/maps"
|
||||
"github.com/gohugoio/hugo/common/types"
|
||||
)
|
||||
|
||||
@@ -355,7 +355,7 @@ func IsNil(v reflect.Value) bool {
|
||||
|
||||
var contextInterface = reflect.TypeOf((*context.Context)(nil)).Elem()
|
||||
|
||||
var isContextCache = maps.NewCache[reflect.Type, bool]()
|
||||
var isContextCache = hmaps.NewCache[reflect.Type, bool]()
|
||||
|
||||
type k string
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ import "github.com/gohugoio/hugo/common/version"
|
||||
// This should be the only one.
|
||||
var CurrentVersion = version.Version{
|
||||
Major: 0,
|
||||
Minor: 154,
|
||||
PatchLevel: 4,
|
||||
Suffix: "",
|
||||
Minor: 156,
|
||||
PatchLevel: 0,
|
||||
Suffix: "-DEV",
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/gohugoio/hugo/common/maps"
|
||||
"github.com/gohugoio/hugo/common/hmaps"
|
||||
"github.com/gohugoio/hugo/common/types"
|
||||
"github.com/gohugoio/hugo/hugofs/files"
|
||||
"github.com/gohugoio/hugo/hugolib/sitesmatrix"
|
||||
@@ -54,12 +54,12 @@ type PathParser struct {
|
||||
|
||||
// Below gets created on demand.
|
||||
initOnce sync.Once
|
||||
sitesMatrixCache *maps.Cache[string, sitesmatrix.VectorStore] // Maps language index to sites matrix vector store.
|
||||
sitesMatrixCache *hmaps.Cache[string, sitesmatrix.VectorStore] // Maps language index to sites matrix vector store.
|
||||
}
|
||||
|
||||
func (pp *PathParser) init() {
|
||||
pp.initOnce.Do(func() {
|
||||
pp.sitesMatrixCache = maps.NewCache[string, sitesmatrix.VectorStore]()
|
||||
pp.sitesMatrixCache = hmaps.NewCache[string, sitesmatrix.VectorStore]()
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -153,6 +153,35 @@ func (p PR[T]) FilterCopy(s []T) []T {
|
||||
return result
|
||||
}
|
||||
|
||||
const (
|
||||
rangeOpNone = iota
|
||||
rangeOpLT
|
||||
rangeOpLTE
|
||||
rangeOpGT
|
||||
rangeOpGTE
|
||||
rangeOpEQ
|
||||
rangeOpNE
|
||||
)
|
||||
|
||||
func cutRangeOp(s string) (op int, rest string) {
|
||||
switch {
|
||||
case strings.HasPrefix(s, ">= "):
|
||||
return rangeOpGTE, s[3:]
|
||||
case strings.HasPrefix(s, "<= "):
|
||||
return rangeOpLTE, s[3:]
|
||||
case strings.HasPrefix(s, "== "):
|
||||
return rangeOpEQ, s[3:]
|
||||
case strings.HasPrefix(s, "!= "):
|
||||
return rangeOpNE, s[3:]
|
||||
case strings.HasPrefix(s, "> "):
|
||||
return rangeOpGT, s[2:]
|
||||
case strings.HasPrefix(s, "< "):
|
||||
return rangeOpLT, s[2:]
|
||||
default:
|
||||
return rangeOpNone, s
|
||||
}
|
||||
}
|
||||
|
||||
// NewStringPredicateFromGlobs creates a string predicate from the given glob patterns.
|
||||
// A glob pattern starting with "!" is a negation pattern which will be ANDed with the rest.
|
||||
func NewStringPredicateFromGlobs(patterns []string, getGlob func(pattern string) (glob.Glob, error)) (P[string], error) {
|
||||
@@ -187,6 +216,86 @@ func NewStringPredicateFromGlobs(patterns []string, getGlob func(pattern string)
|
||||
return p.BoolFunc(), nil
|
||||
}
|
||||
|
||||
type IndexMatcher interface {
|
||||
IndexMatch(match P[string]) (iter.Seq[int], error)
|
||||
// NewIndexStringPredicateFromGlobsAndRanges creates an IndexString predicate from the given glob patterns and range patterns.
|
||||
// A glob pattern starting with "!" is a negation pattern which will be ANDed with the rest.
|
||||
// A range pattern is one of "> value", ">= value", "< value" or "<= value".
|
||||
func NewIndexStringPredicateFromGlobsAndRanges(patterns []string, getIndex func(s string) int, getGlob func(pattern string) (glob.Glob, error)) (P[IndexString], error) {
|
||||
var p PR[IndexString]
|
||||
for _, pattern := range patterns {
|
||||
pattern = strings.TrimSpace(pattern)
|
||||
if pattern == "" {
|
||||
continue
|
||||
}
|
||||
negate := strings.HasPrefix(pattern, hglob.NegationPrefix)
|
||||
if negate {
|
||||
pattern = pattern[2:]
|
||||
g, err := getGlob(pattern)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p = p.And(func(s IndexString) Match {
|
||||
return BoolMatch(!g.Match(s.String))
|
||||
})
|
||||
} else {
|
||||
// This can be either a glob or a value prefixed with one of >, >=, < or <=.
|
||||
o, v := cutRangeOp(pattern)
|
||||
if o != rangeOpNone {
|
||||
i := getIndex(v)
|
||||
if i == -1 {
|
||||
// No match possible.
|
||||
p = p.And(func(s IndexString) Match {
|
||||
return BoolMatch(false)
|
||||
})
|
||||
continue
|
||||
}
|
||||
switch o {
|
||||
// The greater values starts at the top with index 0.
|
||||
case rangeOpGT:
|
||||
p = p.And(func(s IndexString) Match {
|
||||
return BoolMatch(s.Index < i)
|
||||
})
|
||||
case rangeOpGTE:
|
||||
p = p.And(func(s IndexString) Match {
|
||||
return BoolMatch(s.Index <= i)
|
||||
})
|
||||
case rangeOpLT:
|
||||
p = p.And(func(s IndexString) Match {
|
||||
return BoolMatch(s.Index > i)
|
||||
})
|
||||
case rangeOpLTE:
|
||||
p = p.And(func(s IndexString) Match {
|
||||
return BoolMatch(s.Index >= i)
|
||||
})
|
||||
case rangeOpEQ:
|
||||
p = p.And(func(s IndexString) Match {
|
||||
return BoolMatch(s.Index == i)
|
||||
})
|
||||
case rangeOpNE:
|
||||
p = p.And(func(s IndexString) Match {
|
||||
return BoolMatch(s.Index != i)
|
||||
})
|
||||
}
|
||||
} else {
|
||||
g, err := getGlob(pattern)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p = p.Or(func(s IndexString) Match {
|
||||
return BoolMatch(g.Match(s.String))
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return p.BoolFunc(), nil
|
||||
}
|
||||
|
||||
type IndexString struct {
|
||||
Index int
|
||||
String string
|
||||
}
|
||||
|
||||
type IndexMatcher interface {
|
||||
IndexMatch(match P[IndexString]) (iter.Seq[int], error)
|
||||
}
|
||||
|
||||
@@ -146,6 +146,107 @@ func TestNewStringPredicateFromGlobs(t *testing.T) {
|
||||
c.Assert(m("anything"), qt.IsFalse)
|
||||
}
|
||||
|
||||
func TestNewIndexStringPredicateFromGlobsAndRanges(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
|
||||
// Simulate versions: v4.0.0=0, v3.0.0=1, v2.0.0=2, v1.0.0=3
|
||||
// Lower index = greater value.
|
||||
versions := []string{"v4.0.0", "v3.0.0", "v2.0.0", "v1.0.0"}
|
||||
getIndex := func(s string) int {
|
||||
for i, v := range versions {
|
||||
if v == s {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
getGlob := func(pattern string) (glob.Glob, error) {
|
||||
return glob.Compile(pattern)
|
||||
}
|
||||
|
||||
n := func(patterns ...string) predicate.P[predicate.IndexString] {
|
||||
p, err := predicate.NewIndexStringPredicateFromGlobsAndRanges(patterns, getIndex, getGlob)
|
||||
c.Assert(err, qt.IsNil)
|
||||
return p
|
||||
}
|
||||
|
||||
is := func(i int) predicate.IndexString {
|
||||
return predicate.IndexString{Index: i, String: versions[i]}
|
||||
}
|
||||
|
||||
// Test >= v2.0.0 (index 2): should match indices <= 2
|
||||
m := n(">= v2.0.0")
|
||||
c.Assert(m(is(0)), qt.IsTrue) // v4.0.0
|
||||
c.Assert(m(is(1)), qt.IsTrue) // v3.0.0
|
||||
c.Assert(m(is(2)), qt.IsTrue) // v2.0.0
|
||||
c.Assert(m(is(3)), qt.IsFalse) // v1.0.0
|
||||
|
||||
// Test > v2.0.0 (index 2): should match indices < 2
|
||||
m = n("> v2.0.0")
|
||||
c.Assert(m(is(0)), qt.IsTrue) // v4.0.0
|
||||
c.Assert(m(is(1)), qt.IsTrue) // v3.0.0
|
||||
c.Assert(m(is(2)), qt.IsFalse) // v2.0.0
|
||||
c.Assert(m(is(3)), qt.IsFalse) // v1.0.0
|
||||
|
||||
// Test < v3.0.0 (index 1): should match indices > 1
|
||||
m = n("< v3.0.0")
|
||||
c.Assert(m(is(0)), qt.IsFalse) // v4.0.0
|
||||
c.Assert(m(is(1)), qt.IsFalse) // v3.0.0
|
||||
c.Assert(m(is(2)), qt.IsTrue) // v2.0.0
|
||||
c.Assert(m(is(3)), qt.IsTrue) // v1.0.0
|
||||
|
||||
// Test range: >= v2.0.0 AND <= v3.0.0
|
||||
m = n(">= v2.0.0", "<= v3.0.0")
|
||||
c.Assert(m(is(0)), qt.IsFalse) // v4.0.0 - too high
|
||||
c.Assert(m(is(1)), qt.IsTrue) // v3.0.0
|
||||
c.Assert(m(is(2)), qt.IsTrue) // v2.0.0
|
||||
c.Assert(m(is(3)), qt.IsFalse) // v1.0.0 - too low
|
||||
|
||||
// Test glob pattern
|
||||
m = n("v2.*.*")
|
||||
c.Assert(m(is(0)), qt.IsFalse) // v4.0.0
|
||||
c.Assert(m(is(2)), qt.IsTrue) // v2.0.0
|
||||
|
||||
// Test glob with negation
|
||||
m = n("v*.*.*", "! v3.*.*")
|
||||
c.Assert(m(is(0)), qt.IsTrue) // v4.0.0
|
||||
c.Assert(m(is(1)), qt.IsFalse) // v3.0.0 - negated
|
||||
c.Assert(m(is(2)), qt.IsTrue) // v2.0.0
|
||||
|
||||
// Test range with negation: >= v2.0.0 but not v3.0.0
|
||||
m = n(">= v2.0.0", "! v3.0.0")
|
||||
c.Assert(m(is(0)), qt.IsTrue) // v4.0.0
|
||||
c.Assert(m(is(1)), qt.IsFalse) // v3.0.0 - negated
|
||||
c.Assert(m(is(2)), qt.IsTrue) // v2.0.0
|
||||
c.Assert(m(is(3)), qt.IsFalse) // v1.0.0 - out of range
|
||||
|
||||
// Test unknown value in range returns no match
|
||||
m = n(">= v99.0.0")
|
||||
c.Assert(m(is(0)), qt.IsFalse)
|
||||
c.Assert(m(is(3)), qt.IsFalse)
|
||||
|
||||
// Test == v2.0.0: should only match v2.0.0
|
||||
m = n("== v2.0.0")
|
||||
c.Assert(m(is(0)), qt.IsFalse) // v4.0.0
|
||||
c.Assert(m(is(1)), qt.IsFalse) // v3.0.0
|
||||
c.Assert(m(is(2)), qt.IsTrue) // v2.0.0
|
||||
c.Assert(m(is(3)), qt.IsFalse) // v1.0.0
|
||||
|
||||
// Test != v2.0.0: should match everything except v2.0.0
|
||||
m = n("!= v2.0.0")
|
||||
c.Assert(m(is(0)), qt.IsTrue) // v4.0.0
|
||||
c.Assert(m(is(1)), qt.IsTrue) // v3.0.0
|
||||
c.Assert(m(is(2)), qt.IsFalse) // v2.0.0
|
||||
c.Assert(m(is(3)), qt.IsTrue) // v1.0.0
|
||||
|
||||
// Test != with range: >= v2.0.0 AND != v3.0.0
|
||||
m = n(">= v2.0.0", "!= v3.0.0")
|
||||
c.Assert(m(is(0)), qt.IsTrue) // v4.0.0
|
||||
c.Assert(m(is(1)), qt.IsFalse) // v3.0.0 - excluded by !=
|
||||
c.Assert(m(is(2)), qt.IsTrue) // v2.0.0
|
||||
c.Assert(m(is(3)), qt.IsFalse) // v1.0.0 - out of range
|
||||
}
|
||||
|
||||
func BenchmarkPredicate(b *testing.B) {
|
||||
b.Run("and or no match", func(b *testing.B) {
|
||||
var p predicate.PR[int] = intP1
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
// Copyright 2026 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 predicate
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
qt "github.com/frankban/quicktest"
|
||||
)
|
||||
|
||||
func TestCutRangeOp(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
|
||||
op, rest := cutRangeOp(">= value")
|
||||
c.Assert(op, qt.Equals, rangeOpGTE)
|
||||
c.Assert(rest, qt.Equals, "value")
|
||||
|
||||
op, rest = cutRangeOp("<= value")
|
||||
c.Assert(op, qt.Equals, rangeOpLTE)
|
||||
c.Assert(rest, qt.Equals, "value")
|
||||
|
||||
op, rest = cutRangeOp("> value")
|
||||
c.Assert(op, qt.Equals, rangeOpGT)
|
||||
c.Assert(rest, qt.Equals, "value")
|
||||
|
||||
op, rest = cutRangeOp("< value")
|
||||
c.Assert(op, qt.Equals, rangeOpLT)
|
||||
c.Assert(rest, qt.Equals, "value")
|
||||
|
||||
op, rest = cutRangeOp("== value")
|
||||
c.Assert(op, qt.Equals, rangeOpEQ)
|
||||
c.Assert(rest, qt.Equals, "value")
|
||||
|
||||
op, rest = cutRangeOp("!= value")
|
||||
c.Assert(op, qt.Equals, rangeOpNE)
|
||||
c.Assert(rest, qt.Equals, "value")
|
||||
|
||||
op, rest = cutRangeOp("value")
|
||||
c.Assert(op, qt.Equals, rangeOpNone)
|
||||
c.Assert(rest, qt.Equals, "value")
|
||||
}
|
||||
@@ -37,6 +37,9 @@ type Version struct {
|
||||
// HugoVersionSuffix is the suffix used in the Hugo version string.
|
||||
// It will be blank for release versions.
|
||||
Suffix string
|
||||
|
||||
// Set when parsed from a string,
|
||||
source string
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -44,11 +47,8 @@ var (
|
||||
_ compare.Comparer = (*VersionString)(nil)
|
||||
)
|
||||
|
||||
// IsAlphaBetaOrRC returns whether this version is an alpha, beta, or release candidate.
|
||||
func (v Version) IsAlphaBetaOrRC() bool {
|
||||
s := strings.ToLower(v.Suffix)
|
||||
// e.g. "alpha.1", "beta.2", "rc.3"
|
||||
return strings.Contains(s, "alpha.") || strings.Contains(s, "beta.") || strings.Contains(s, "rc.")
|
||||
func (v Version) IsZero() bool {
|
||||
return v.Major == 0 && v.Minor == 0 && v.PatchLevel == 0 && v.Suffix == ""
|
||||
}
|
||||
|
||||
func (v Version) String() string {
|
||||
@@ -109,6 +109,7 @@ func ParseVersion(s string) (Version, error) {
|
||||
vv.Suffix = suffix
|
||||
}
|
||||
vv.Major, vv.Minor, vv.PatchLevel = parseVersion(s)
|
||||
vv.source = s
|
||||
|
||||
return vv, nil
|
||||
}
|
||||
@@ -176,6 +177,10 @@ func CompareVersions(v1 Version, v2 any) int {
|
||||
case int64:
|
||||
c = compareFloatWithVersion(float64(d), v1)
|
||||
case Version:
|
||||
if v1.IsZero() && d.IsZero() {
|
||||
// Fall back to source comparison.
|
||||
return strings.Compare(v1.source, d.source)
|
||||
}
|
||||
if d.Major == v1.Major && d.Minor == v1.Minor && d.PatchLevel == v1.PatchLevel {
|
||||
return strings.Compare(v1.Suffix, d.Suffix)
|
||||
}
|
||||
@@ -200,11 +205,13 @@ func CompareVersions(v1 Version, v2 any) int {
|
||||
return -1
|
||||
}
|
||||
|
||||
v, err := ParseVersion(s)
|
||||
if err != nil {
|
||||
return -1
|
||||
v2v, _ := ParseVersion(s)
|
||||
if v1.IsZero() && v2v.IsZero() {
|
||||
// Fall back to source comparison.
|
||||
return strings.Compare(v1.source, v2v.source)
|
||||
}
|
||||
return v1.Compare(v)
|
||||
|
||||
return v1.Compare(v2v)
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -50,6 +50,11 @@ func TestHugoVersion(t *testing.T) {
|
||||
func TestCompareVersions(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
|
||||
parseIgnoreErr := func(s string) Version {
|
||||
v, _ := ParseVersion(s)
|
||||
return v
|
||||
}
|
||||
|
||||
c.Assert(CompareVersions(MustParseVersion("0.20.0"), 0.20), qt.Equals, 0)
|
||||
c.Assert(CompareVersions(MustParseVersion("0.20.0"), float32(0.20)), qt.Equals, 0)
|
||||
c.Assert(CompareVersions(MustParseVersion("0.20.0"), float64(0.20)), qt.Equals, 0)
|
||||
@@ -69,6 +74,15 @@ func TestCompareVersions(t *testing.T) {
|
||||
c.Assert(CompareVersions(MustParseVersion("0.22.0-DEV"), "0.22"), qt.Equals, 1)
|
||||
c.Assert(CompareVersions(MustParseVersion("0.22.1-DEV"), "0.22"), qt.Equals, -1)
|
||||
c.Assert(CompareVersions(MustParseVersion("0.22.1-DEV"), "0.22.1-DEV"), qt.Equals, 0)
|
||||
|
||||
c.Assert(CompareVersions(parseIgnoreErr("foobar"), "v1.0.0"), qt.Equals, 1)
|
||||
c.Assert(CompareVersions(parseIgnoreErr("v1.0.0"), "foobar"), qt.Equals, -1)
|
||||
c.Assert(CompareVersions(parseIgnoreErr("foobar"), "foobar"), qt.Equals, 0)
|
||||
c.Assert(CompareVersions(parseIgnoreErr("foobar"), parseIgnoreErr("foobar")), qt.Equals, 0)
|
||||
c.Assert(CompareVersions(parseIgnoreErr("a"), "b"), qt.Equals, -1)
|
||||
c.Assert(CompareVersions(parseIgnoreErr("a"), parseIgnoreErr("b")), qt.Equals, -1)
|
||||
c.Assert(CompareVersions(parseIgnoreErr("b"), "a"), qt.Equals, 1)
|
||||
c.Assert(CompareVersions(parseIgnoreErr("b"), parseIgnoreErr("a")), qt.Equals, 1)
|
||||
}
|
||||
|
||||
func TestParseHugoVersion(t *testing.T) {
|
||||
|
||||
@@ -29,10 +29,10 @@ import (
|
||||
|
||||
"github.com/gohugoio/hugo/cache/filecache"
|
||||
"github.com/gohugoio/hugo/cache/httpcache"
|
||||
"github.com/gohugoio/hugo/common/hmaps"
|
||||
"github.com/gohugoio/hugo/common/hstrings"
|
||||
"github.com/gohugoio/hugo/common/hugo"
|
||||
"github.com/gohugoio/hugo/common/loggers"
|
||||
"github.com/gohugoio/hugo/common/maps"
|
||||
"github.com/gohugoio/hugo/common/paths"
|
||||
"github.com/gohugoio/hugo/common/urls"
|
||||
"github.com/gohugoio/hugo/config"
|
||||
@@ -212,7 +212,7 @@ type Config struct {
|
||||
|
||||
// User provided parameters.
|
||||
// <docsmeta>{"refs": ["config:languages:params"] }</docsmeta>
|
||||
Params maps.Params `mapstructure:"-"`
|
||||
Params hmaps.Params `mapstructure:"-"`
|
||||
|
||||
// UglyURLs configuration. Either a boolean or a sections map.
|
||||
UglyURLs any `mapstructure:"-"`
|
||||
@@ -607,12 +607,13 @@ type RootConfig struct {
|
||||
DefaultOutputFormat string
|
||||
|
||||
// Disable generation of redirect to the default language when DefaultContentLanguageInSubdir is enabled.
|
||||
// Note that this currently is an alias for DisableDefaultDimensionRedirect introduced in v0.154.4.
|
||||
// Note that this currently is an alias for DisableDefaultSiteRedirect introduced in v0.154.5.
|
||||
// It's not obvious how a more fine grained setup would work.
|
||||
DisableDefaultLanguageRedirect bool
|
||||
|
||||
// Disable generation of redirect to the default dimension when DefaultContentRoleInSubdir or DefaultContentVersionInSubdir or DefaultContentLanguageInSubdir is enabled.
|
||||
DisableDefaultDimensionRedirect bool
|
||||
// Disable generation of redirects to the default site when DefaultContentRoleInSubdir or DefaultContentVersionInSubdir or DefaultContentLanguageInSubdir is enabled.
|
||||
// The default site is the site is the combination of defaultContentLanguage, defaultContentVersion and defaultContentRole.
|
||||
DisableDefaultSiteRedirect bool
|
||||
|
||||
// Disable creation of alias redirect pages.
|
||||
DisableAliases bool
|
||||
@@ -821,6 +822,7 @@ type Configs struct {
|
||||
|
||||
Modules modules.Modules
|
||||
ModulesClient *modules.Client
|
||||
FileCaches filecache.Caches
|
||||
|
||||
// All below is set in Init.
|
||||
Languages langs.Languages
|
||||
@@ -851,7 +853,7 @@ func (c *Configs) IsZero() bool {
|
||||
return c == nil || len(c.Languages) == 0
|
||||
}
|
||||
|
||||
func (c *Configs) Init(logger loggers.Logger) error {
|
||||
func (c *Configs) Init(sourceFs afero.Fs, logger loggers.Logger) error {
|
||||
var languages langs.Languages
|
||||
|
||||
for _, f := range c.Base.Languages.Config.Sorted {
|
||||
@@ -1022,7 +1024,7 @@ func fromLoadConfigResult(fs afero.Fs, logger loggers.Logger, res config.LoadCon
|
||||
if lang == "" {
|
||||
lang = "en"
|
||||
}
|
||||
res.Cfg.Set("languages", maps.Params{lang: maps.Params{}})
|
||||
res.Cfg.Set("languages", hmaps.Params{lang: hmaps.Params{}})
|
||||
}
|
||||
bcfg := res.BaseConfig
|
||||
cfg := res.Cfg
|
||||
@@ -1049,11 +1051,11 @@ func fromLoadConfigResult(fs afero.Fs, logger loggers.Logger, res config.LoadCon
|
||||
var differentRootKeys []string
|
||||
switch x := v.(type) {
|
||||
case nil:
|
||||
case maps.Params:
|
||||
case hmaps.Params:
|
||||
_, found := x["params"]
|
||||
if !found {
|
||||
x["params"] = maps.Params{
|
||||
maps.MergeStrategyKey: maps.ParamsMergeStrategyDeep,
|
||||
x["params"] = hmaps.Params{
|
||||
hmaps.MergeStrategyKey: hmaps.ParamsMergeStrategyDeep,
|
||||
}
|
||||
}
|
||||
for kk, vv := range x {
|
||||
@@ -1065,16 +1067,16 @@ func fromLoadConfigResult(fs afero.Fs, logger loggers.Logger, res config.LoadCon
|
||||
isMultihost = true
|
||||
}
|
||||
|
||||
if p, ok := vv.(maps.Params); ok {
|
||||
if p, ok := vv.(hmaps.Params); ok {
|
||||
// With the introduction of YAML anchor and alias support, language config entries
|
||||
// may be contain shared references.
|
||||
// This also break potential cycles.
|
||||
vv = maps.CloneParamsDeep(p)
|
||||
vv = hmaps.CloneParamsDeep(p)
|
||||
}
|
||||
|
||||
if kk == "cascade" {
|
||||
// If not set, add the current language to make sure it does not get applied to other languages.
|
||||
page.AddLangToCascadeTargetMap(k, vv.(maps.Params))
|
||||
page.AddLangToCascadeTargetMap(k, vv.(hmaps.Params))
|
||||
// Always clone cascade config to get the sites matrix right.
|
||||
differentRootKeys = append(differentRootKeys, kk)
|
||||
}
|
||||
@@ -1085,14 +1087,14 @@ func fromLoadConfigResult(fs afero.Fs, logger loggers.Logger, res config.LoadCon
|
||||
// This overrides a root key and potentially needs a merge.
|
||||
if !reflect.DeepEqual(rootv, vv) {
|
||||
switch vvv := vv.(type) {
|
||||
case maps.Params:
|
||||
case hmaps.Params:
|
||||
differentRootKeys = append(differentRootKeys, kk)
|
||||
|
||||
// Use the language value as base.
|
||||
// Note that this is already cloned above.
|
||||
mergedConfigEntry := vvv
|
||||
// Merge in the root value.
|
||||
maps.MergeParams(mergedConfigEntry, rootv.(maps.Params))
|
||||
hmaps.MergeParams(mergedConfigEntry, rootv.(hmaps.Params))
|
||||
|
||||
mergedConfig.Set(kk, mergedConfigEntry)
|
||||
default:
|
||||
@@ -1102,7 +1104,7 @@ func fromLoadConfigResult(fs afero.Fs, logger loggers.Logger, res config.LoadCon
|
||||
}
|
||||
} else {
|
||||
switch vv.(type) {
|
||||
case maps.Params:
|
||||
case hmaps.Params:
|
||||
differentRootKeys = append(differentRootKeys, kk)
|
||||
default:
|
||||
// Apply new values to the root.
|
||||
@@ -1138,7 +1140,7 @@ func fromLoadConfigResult(fs afero.Fs, logger loggers.Logger, res config.LoadCon
|
||||
}
|
||||
|
||||
langConfigMap[k] = clone
|
||||
case maps.ParamsMergeStrategy:
|
||||
case hmaps.ParamsMergeStrategy:
|
||||
|
||||
default:
|
||||
panic(fmt.Sprintf("unknown type in languages config: %T", v))
|
||||
@@ -1153,10 +1155,16 @@ func fromLoadConfigResult(fs afero.Fs, logger loggers.Logger, res config.LoadCon
|
||||
l.CommonDirs.CacheDir = bcfg.CacheDir
|
||||
}
|
||||
|
||||
caches, err := filecache.NewCaches(all.Caches, fs)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create file caches from configuration: %w", err)
|
||||
}
|
||||
|
||||
cm := &Configs{
|
||||
Base: all,
|
||||
LanguageConfigMap: langConfigMap,
|
||||
LoadingInfo: res,
|
||||
FileCaches: caches,
|
||||
IsMultihost: isMultihost,
|
||||
}
|
||||
|
||||
|
||||
@@ -22,9 +22,9 @@ import (
|
||||
"github.com/gohugoio/hugo/langs"
|
||||
|
||||
"github.com/gohugoio/hugo/cache/httpcache"
|
||||
"github.com/gohugoio/hugo/common/hmaps"
|
||||
"github.com/gohugoio/hugo/common/hstrings"
|
||||
"github.com/gohugoio/hugo/common/loggers"
|
||||
"github.com/gohugoio/hugo/common/maps"
|
||||
"github.com/gohugoio/hugo/common/types"
|
||||
"github.com/gohugoio/hugo/config"
|
||||
"github.com/gohugoio/hugo/config/privacy"
|
||||
@@ -196,7 +196,7 @@ var allDecoderSetups = map[string]decodeWeight{
|
||||
key: "outputs",
|
||||
decode: func(d decodeWeight, p decodeConfig) error {
|
||||
defaults := createDefaultOutputFormats(p.c.OutputFormats.Config)
|
||||
m := maps.CleanConfigStringMap(p.p.GetStringMap("outputs"))
|
||||
m := hmaps.CleanConfigStringMap(p.p.GetStringMap("outputs"))
|
||||
p.c.Outputs = make(map[string][]string)
|
||||
for k, v := range m {
|
||||
s := types.ToStringSlicePreserveString(v)
|
||||
@@ -225,13 +225,13 @@ var allDecoderSetups = map[string]decodeWeight{
|
||||
"languages": {
|
||||
key: "languages",
|
||||
decode: func(d decodeWeight, p decodeConfig) error {
|
||||
m := maps.CleanConfigStringMap(p.p.GetStringMap(d.key))
|
||||
m := hmaps.CleanConfigStringMap(p.p.GetStringMap(d.key))
|
||||
if len(m) == 1 {
|
||||
// In v0.112.4 we moved this to the language config, but it's very commmon for mono language sites to have this at the top level.
|
||||
var first maps.Params
|
||||
var first hmaps.Params
|
||||
var ok bool
|
||||
for _, v := range m {
|
||||
first, ok = v.(maps.Params)
|
||||
first, ok = v.(hmaps.Params)
|
||||
if ok {
|
||||
break
|
||||
}
|
||||
@@ -266,7 +266,7 @@ var allDecoderSetups = map[string]decodeWeight{
|
||||
key: "versions",
|
||||
decode: func(d decodeWeight, p decodeConfig) error {
|
||||
var err error
|
||||
m := maps.CleanConfigStringMap(p.p.GetStringMap(d.key))
|
||||
m := hmaps.CleanConfigStringMap(p.p.GetStringMap(d.key))
|
||||
p.c.Versions, err = versions.DecodeConfig(p.c.RootConfig.DefaultContentVersion, m)
|
||||
return err
|
||||
},
|
||||
@@ -278,7 +278,7 @@ var allDecoderSetups = map[string]decodeWeight{
|
||||
err error
|
||||
defaultContentRole string
|
||||
)
|
||||
m := maps.CleanConfigStringMap(p.p.GetStringMap(d.key))
|
||||
m := hmaps.CleanConfigStringMap(p.p.GetStringMap(d.key))
|
||||
p.c.Roles, defaultContentRole, err = roles.DecodeConfig(p.c.RootConfig.DefaultContentRole, m)
|
||||
p.c.RootConfig.DefaultContentRole = defaultContentRole
|
||||
|
||||
@@ -289,7 +289,7 @@ var allDecoderSetups = map[string]decodeWeight{
|
||||
"params": {
|
||||
key: "params",
|
||||
decode: func(d decodeWeight, p decodeConfig) error {
|
||||
p.c.Params = maps.CleanConfigStringMap(p.p.GetStringMap("params"))
|
||||
p.c.Params = hmaps.CleanConfigStringMap(p.p.GetStringMap("params"))
|
||||
if p.c.Params == nil {
|
||||
p.c.Params = make(map[string]any)
|
||||
}
|
||||
@@ -335,7 +335,7 @@ var allDecoderSetups = map[string]decodeWeight{
|
||||
key: "taxonomies",
|
||||
decode: func(d decodeWeight, p decodeConfig) error {
|
||||
if p.p.IsSet(d.key) {
|
||||
p.c.Taxonomies = maps.CleanConfigStringMapString(p.p.GetStringMapString(d.key))
|
||||
p.c.Taxonomies = hmaps.CleanConfigStringMapString(p.p.GetStringMapString(d.key))
|
||||
}
|
||||
return nil
|
||||
},
|
||||
@@ -447,7 +447,7 @@ var allDecoderSetups = map[string]decodeWeight{
|
||||
"author": {
|
||||
key: "author",
|
||||
decode: func(d decodeWeight, p decodeConfig) error {
|
||||
p.c.Author = maps.CleanConfigStringMap(p.p.GetStringMap(d.key))
|
||||
p.c.Author = hmaps.CleanConfigStringMap(p.p.GetStringMap(d.key))
|
||||
return nil
|
||||
},
|
||||
internalOrDeprecated: true,
|
||||
@@ -455,7 +455,7 @@ var allDecoderSetups = map[string]decodeWeight{
|
||||
"social": {
|
||||
key: "social",
|
||||
decode: func(d decodeWeight, p decodeConfig) error {
|
||||
p.c.Social = maps.CleanConfigStringMapString(p.p.GetStringMapString(d.key))
|
||||
p.c.Social = hmaps.CleanConfigStringMapString(p.p.GetStringMapString(d.key))
|
||||
return nil
|
||||
},
|
||||
internalOrDeprecated: true,
|
||||
@@ -469,8 +469,8 @@ var allDecoderSetups = map[string]decodeWeight{
|
||||
p.c.UglyURLs = vv
|
||||
case string:
|
||||
p.c.UglyURLs = vv == "true"
|
||||
case maps.Params:
|
||||
p.c.UglyURLs = cast.ToStringMapBool(maps.CleanConfigStringMap(vv))
|
||||
case hmaps.Params:
|
||||
p.c.UglyURLs = cast.ToStringMapBool(hmaps.CleanConfigStringMap(vv))
|
||||
default:
|
||||
p.c.UglyURLs = cast.ToStringMapBool(v)
|
||||
}
|
||||
|
||||
@@ -25,9 +25,8 @@ import (
|
||||
)
|
||||
|
||||
type ConfigLanguage struct {
|
||||
config *Config
|
||||
baseConfig config.BaseConfig
|
||||
|
||||
config *Config
|
||||
baseConfig config.BaseConfig
|
||||
m *Configs
|
||||
language *langs.Language
|
||||
languageIndex int
|
||||
@@ -123,6 +122,10 @@ func (c ConfigLanguage) BaseConfig() config.BaseConfig {
|
||||
return c.baseConfig
|
||||
}
|
||||
|
||||
func (c ConfigLanguage) FileCaches() any {
|
||||
return c.m.FileCaches
|
||||
}
|
||||
|
||||
func (c ConfigLanguage) Dirs() config.CommonDirs {
|
||||
return c.config.CommonDirs
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
package allconfig
|
||||
|
||||
import (
|
||||
"github.com/gohugoio/hugo/common/maps"
|
||||
"github.com/gohugoio/hugo/common/hmaps"
|
||||
"github.com/gohugoio/hugo/config"
|
||||
"github.com/gohugoio/hugo/docshelper"
|
||||
)
|
||||
@@ -27,12 +27,12 @@ func init() {
|
||||
if v.internalOrDeprecated {
|
||||
continue
|
||||
}
|
||||
cfg.Set(configRoot, make(maps.Params))
|
||||
cfg.Set(configRoot, make(hmaps.Params))
|
||||
}
|
||||
lang := maps.Params{
|
||||
"en": maps.Params{
|
||||
"menus": maps.Params{},
|
||||
"params": maps.Params{},
|
||||
lang := hmaps.Params{
|
||||
"en": hmaps.Params{
|
||||
"menus": hmaps.Params{},
|
||||
"params": hmaps.Params{},
|
||||
},
|
||||
}
|
||||
cfg.Set("languages", lang)
|
||||
|
||||
@@ -25,9 +25,9 @@ import (
|
||||
"github.com/gobwas/glob"
|
||||
"github.com/gohugoio/hugo/common/herrors"
|
||||
"github.com/gohugoio/hugo/common/hexec"
|
||||
"github.com/gohugoio/hugo/common/hmaps"
|
||||
"github.com/gohugoio/hugo/common/hugo"
|
||||
"github.com/gohugoio/hugo/common/loggers"
|
||||
"github.com/gohugoio/hugo/common/maps"
|
||||
"github.com/gohugoio/hugo/common/paths"
|
||||
"github.com/gohugoio/hugo/common/types"
|
||||
"github.com/gohugoio/hugo/config"
|
||||
@@ -95,7 +95,7 @@ func LoadConfig(d ConfigSourceDescriptor) (configs *Configs, err error) {
|
||||
configs.Modules = moduleConfig.AllModules
|
||||
configs.ModulesClient = modulesClient
|
||||
|
||||
if err := configs.Init(d.Logger); err != nil {
|
||||
if err := configs.Init(d.Fs, d.Logger); err != nil {
|
||||
return nil, fmt.Errorf("failed to init config: %w", err)
|
||||
}
|
||||
|
||||
@@ -166,7 +166,7 @@ func (l configLoader) applyConfigAliases() error {
|
||||
}
|
||||
|
||||
func (l configLoader) applyDefaultConfig() error {
|
||||
defaultSettings := maps.Params{
|
||||
defaultSettings := hmaps.Params{
|
||||
// These dirs are used early/before we build the config struct.
|
||||
"themesDir": "themes",
|
||||
"configDir": "config",
|
||||
@@ -186,7 +186,7 @@ func (l configLoader) normalizeCfg(cfg config.Provider) error {
|
||||
} else if b, ok := cfg.Get("minify").(bool); ok {
|
||||
hugo.Deprecate("site config minify", "Use minify.minifyOutput instead.", "v0.150.0")
|
||||
if b {
|
||||
cfg.Set("minify", maps.Params{"minifyOutput": true})
|
||||
cfg.Set("minify", hmaps.Params{"minifyOutput": true})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -240,7 +240,7 @@ func (l configLoader) applyOsEnvOverrides(environ []string) error {
|
||||
}
|
||||
|
||||
for _, env := range hugoEnv {
|
||||
existing, nestedKey, owner, err := maps.GetNestedParamFn(env.Key, delim, l.cfg.Get)
|
||||
existing, nestedKey, owner, err := hmaps.GetNestedParamFn(env.Key, delim, l.cfg.Get)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -477,6 +477,7 @@ func (l *configLoader) loadModules(configs *Configs, ignoreModuleDoesNotExist bo
|
||||
PublishDir: publishDir,
|
||||
Environment: l.Environment,
|
||||
CacheDir: conf.Caches.CacheDirModules(),
|
||||
ModuleQueriesCache: configs.FileCaches.ModuleQueriesCache(),
|
||||
ModuleConfig: conf.Module,
|
||||
IgnoreVendor: ignoreVendor,
|
||||
IgnoreModuleDoesNotExist: ignoreModuleDoesNotExist,
|
||||
@@ -547,7 +548,7 @@ func (l configLoader) loadConfig(configName string) (string, error) {
|
||||
}
|
||||
|
||||
func (l configLoader) deleteMergeStrategies() (err error) {
|
||||
l.cfg.WalkParams(func(params ...maps.KeyParams) bool {
|
||||
l.cfg.WalkParams(func(params ...hmaps.KeyParams) bool {
|
||||
params[len(params)-1].Params.DeleteMergeStrategy()
|
||||
return false
|
||||
})
|
||||
|
||||
@@ -437,7 +437,7 @@ func (c *CacheBuster) CompileConfig(logger loggers.Logger) error {
|
||||
return nil
|
||||
}
|
||||
return func(ss string) bool {
|
||||
match = targetRe.MatchString(ss)
|
||||
match := targetRe.MatchString(ss)
|
||||
matchString := "no match"
|
||||
if match {
|
||||
matchString = "match!"
|
||||
|
||||
@@ -20,11 +20,11 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/gohugoio/hugo/common/herrors"
|
||||
"github.com/gohugoio/hugo/common/hmaps"
|
||||
"github.com/gohugoio/hugo/parser"
|
||||
|
||||
"github.com/gohugoio/hugo/common/paths"
|
||||
|
||||
"github.com/gohugoio/hugo/common/maps"
|
||||
"github.com/gohugoio/hugo/parser/metadecoders"
|
||||
"github.com/spf13/afero"
|
||||
)
|
||||
@@ -222,11 +222,11 @@ func LoadConfigFromDir(sourceFs afero.Fs, configDir, environment string) (Provid
|
||||
return cfg, dirnames, nil
|
||||
}
|
||||
|
||||
var keyAliases maps.KeyRenamer
|
||||
var keyAliases hmaps.KeyRenamer
|
||||
|
||||
func init() {
|
||||
var err error
|
||||
keyAliases, err = maps.NewKeyRenamer(
|
||||
keyAliases, err = hmaps.NewKeyRenamer(
|
||||
// Before 0.53 we used singular for "menu".
|
||||
"{menu,languages/*/menu}", "menus",
|
||||
)
|
||||
|
||||
@@ -16,7 +16,7 @@ package config
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/gohugoio/hugo/common/maps"
|
||||
"github.com/gohugoio/hugo/common/hmaps"
|
||||
"github.com/gohugoio/hugo/common/paths"
|
||||
"github.com/gohugoio/hugo/common/types"
|
||||
"github.com/gohugoio/hugo/common/urls"
|
||||
@@ -41,6 +41,7 @@ type AllProvider interface {
|
||||
Dirs() CommonDirs
|
||||
Quiet() bool
|
||||
DirsBase() CommonDirs
|
||||
FileCaches() any
|
||||
ContentTypes() ContentTypesProvider
|
||||
GetConfigSection(string) any
|
||||
GetConfig() any
|
||||
@@ -96,7 +97,7 @@ type Provider interface {
|
||||
GetString(key string) string
|
||||
GetInt(key string) int
|
||||
GetBool(key string) bool
|
||||
GetParams(key string) maps.Params
|
||||
GetParams(key string) hmaps.Params
|
||||
GetStringMap(key string) map[string]any
|
||||
GetStringMapString(key string) map[string]string
|
||||
GetStringSlice(key string) []string
|
||||
@@ -104,9 +105,9 @@ type Provider interface {
|
||||
Set(key string, value any)
|
||||
Keys() []string
|
||||
Merge(key string, value any)
|
||||
SetDefaults(params maps.Params)
|
||||
SetDefaults(params hmaps.Params)
|
||||
SetDefaultMergeStrategy()
|
||||
WalkParams(walkFn func(params ...maps.KeyParams) bool)
|
||||
WalkParams(walkFn func(params ...hmaps.KeyParams) bool)
|
||||
IsSet(key string) bool
|
||||
}
|
||||
|
||||
|
||||
@@ -20,21 +20,20 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/gohugoio/hugo/common/hmaps"
|
||||
"github.com/spf13/cast"
|
||||
|
||||
"github.com/gohugoio/hugo/common/maps"
|
||||
)
|
||||
|
||||
// New creates a Provider backed by an empty maps.Params.
|
||||
// New creates a Provider backed by an empty hmaps.Params.
|
||||
func New() Provider {
|
||||
return &defaultConfigProvider{
|
||||
root: make(maps.Params),
|
||||
root: make(hmaps.Params),
|
||||
}
|
||||
}
|
||||
|
||||
// NewFrom creates a Provider backed by params.
|
||||
func NewFrom(params maps.Params) Provider {
|
||||
maps.PrepareParams(params)
|
||||
func NewFrom(params hmaps.Params) Provider {
|
||||
hmaps.PrepareParams(params)
|
||||
return &defaultConfigProvider{
|
||||
root: params,
|
||||
}
|
||||
@@ -44,7 +43,7 @@ func NewFrom(params maps.Params) Provider {
|
||||
// All methods are thread safe.
|
||||
type defaultConfigProvider struct {
|
||||
mu sync.RWMutex
|
||||
root maps.Params
|
||||
root hmaps.Params
|
||||
|
||||
keyCache sync.Map
|
||||
}
|
||||
@@ -90,22 +89,22 @@ func (c *defaultConfigProvider) GetString(k string) string {
|
||||
return cast.ToString(v)
|
||||
}
|
||||
|
||||
func (c *defaultConfigProvider) GetParams(k string) maps.Params {
|
||||
func (c *defaultConfigProvider) GetParams(k string) hmaps.Params {
|
||||
v := c.Get(k)
|
||||
if v == nil {
|
||||
return nil
|
||||
}
|
||||
return v.(maps.Params)
|
||||
return v.(hmaps.Params)
|
||||
}
|
||||
|
||||
func (c *defaultConfigProvider) GetStringMap(k string) map[string]any {
|
||||
v := c.Get(k)
|
||||
return maps.ToStringMap(v)
|
||||
return hmaps.ToStringMap(v)
|
||||
}
|
||||
|
||||
func (c *defaultConfigProvider) GetStringMapString(k string) map[string]string {
|
||||
v := c.Get(k)
|
||||
return maps.ToStringMapString(v)
|
||||
return hmaps.ToStringMapString(v)
|
||||
}
|
||||
|
||||
func (c *defaultConfigProvider) GetStringSlice(k string) []string {
|
||||
@@ -120,9 +119,9 @@ func (c *defaultConfigProvider) Set(k string, v any) {
|
||||
k = strings.ToLower(k)
|
||||
|
||||
if k == "" {
|
||||
if p, err := maps.ToParamsAndPrepare(v); err == nil {
|
||||
if p, err := hmaps.ToParamsAndPrepare(v); err == nil {
|
||||
// Set the values directly in root.
|
||||
maps.SetParams(c.root, p)
|
||||
hmaps.SetParams(c.root, p)
|
||||
} else {
|
||||
c.root[k] = v
|
||||
}
|
||||
@@ -132,7 +131,7 @@ func (c *defaultConfigProvider) Set(k string, v any) {
|
||||
|
||||
switch vv := v.(type) {
|
||||
case map[string]any, map[any]any, map[string]string:
|
||||
p := maps.MustToParamsAndPrepare(vv)
|
||||
p := hmaps.MustToParamsAndPrepare(vv)
|
||||
v = p
|
||||
}
|
||||
|
||||
@@ -142,9 +141,9 @@ func (c *defaultConfigProvider) Set(k string, v any) {
|
||||
}
|
||||
|
||||
if existing, found := m[key]; found {
|
||||
if p1, ok := existing.(maps.Params); ok {
|
||||
if p2, ok := v.(maps.Params); ok {
|
||||
maps.SetParams(p1, p2)
|
||||
if p1, ok := existing.(hmaps.Params); ok {
|
||||
if p2, ok := v.(hmaps.Params); ok {
|
||||
hmaps.SetParams(p1, p2)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -154,8 +153,8 @@ func (c *defaultConfigProvider) Set(k string, v any) {
|
||||
}
|
||||
|
||||
// SetDefaults will set values from params if not already set.
|
||||
func (c *defaultConfigProvider) SetDefaults(params maps.Params) {
|
||||
maps.PrepareParams(params)
|
||||
func (c *defaultConfigProvider) SetDefaults(params hmaps.Params) {
|
||||
hmaps.PrepareParams(params)
|
||||
for k, v := range params {
|
||||
if _, found := c.root[k]; !found {
|
||||
c.root[k] = v
|
||||
@@ -170,28 +169,28 @@ func (c *defaultConfigProvider) Merge(k string, v any) {
|
||||
|
||||
if k == "" {
|
||||
rs, f := c.root.GetMergeStrategy()
|
||||
if f && rs == maps.ParamsMergeStrategyNone {
|
||||
if f && rs == hmaps.ParamsMergeStrategyNone {
|
||||
// The user has set a "no merge" strategy on this,
|
||||
// nothing more to do.
|
||||
return
|
||||
}
|
||||
|
||||
if p, err := maps.ToParamsAndPrepare(v); err == nil {
|
||||
if p, err := hmaps.ToParamsAndPrepare(v); err == nil {
|
||||
// As there may be keys in p not in root, we need to handle
|
||||
// those as a special case.
|
||||
var keysToDelete []string
|
||||
for kk, vv := range p {
|
||||
if pp, ok := vv.(maps.Params); ok {
|
||||
if pp, ok := vv.(hmaps.Params); ok {
|
||||
if pppi, ok := c.root[kk]; ok {
|
||||
ppp := pppi.(maps.Params)
|
||||
maps.MergeParamsWithStrategy("", ppp, pp)
|
||||
ppp := pppi.(hmaps.Params)
|
||||
hmaps.MergeParamsWithStrategy("", ppp, pp)
|
||||
} else {
|
||||
// We need to use the default merge strategy for
|
||||
// this key.
|
||||
np := make(maps.Params)
|
||||
strategy := c.determineMergeStrategy(maps.KeyParams{Key: "", Params: c.root}, maps.KeyParams{Key: kk, Params: np})
|
||||
np := make(hmaps.Params)
|
||||
strategy := c.determineMergeStrategy(hmaps.KeyParams{Key: "", Params: c.root}, hmaps.KeyParams{Key: kk, Params: np})
|
||||
np.SetMergeStrategy(strategy)
|
||||
maps.MergeParamsWithStrategy("", np, pp)
|
||||
hmaps.MergeParamsWithStrategy("", np, pp)
|
||||
c.root[kk] = np
|
||||
if np.IsZero() {
|
||||
// Just keep it until merge is done.
|
||||
@@ -201,7 +200,7 @@ func (c *defaultConfigProvider) Merge(k string, v any) {
|
||||
}
|
||||
}
|
||||
// Merge the rest.
|
||||
maps.MergeParams(c.root, p)
|
||||
hmaps.MergeParams(c.root, p)
|
||||
for _, k := range keysToDelete {
|
||||
delete(c.root, k)
|
||||
}
|
||||
@@ -214,7 +213,7 @@ func (c *defaultConfigProvider) Merge(k string, v any) {
|
||||
|
||||
switch vv := v.(type) {
|
||||
case map[string]any, map[any]any, map[string]string:
|
||||
p := maps.MustToParamsAndPrepare(vv)
|
||||
p := hmaps.MustToParamsAndPrepare(vv)
|
||||
v = p
|
||||
}
|
||||
|
||||
@@ -224,9 +223,9 @@ func (c *defaultConfigProvider) Merge(k string, v any) {
|
||||
}
|
||||
|
||||
if existing, found := m[key]; found {
|
||||
if p1, ok := existing.(maps.Params); ok {
|
||||
if p2, ok := v.(maps.Params); ok {
|
||||
maps.MergeParamsWithStrategy("", p1, p2)
|
||||
if p1, ok := existing.(hmaps.Params); ok {
|
||||
if p2, ok := v.(hmaps.Params); ok {
|
||||
hmaps.MergeParamsWithStrategy("", p1, p2)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -245,10 +244,10 @@ func (c *defaultConfigProvider) Keys() []string {
|
||||
return keys
|
||||
}
|
||||
|
||||
func (c *defaultConfigProvider) WalkParams(walkFn func(params ...maps.KeyParams) bool) {
|
||||
func (c *defaultConfigProvider) WalkParams(walkFn func(params ...hmaps.KeyParams) bool) {
|
||||
maxDepth := 1000
|
||||
var walk func(depth int, params ...maps.KeyParams)
|
||||
walk = func(depth int, params ...maps.KeyParams) {
|
||||
var walk func(depth int, params ...hmaps.KeyParams)
|
||||
walk = func(depth int, params ...hmaps.KeyParams) {
|
||||
if depth > maxDepth {
|
||||
panic(errors.New("max depth exceeded"))
|
||||
}
|
||||
@@ -258,24 +257,24 @@ func (c *defaultConfigProvider) WalkParams(walkFn func(params ...maps.KeyParams)
|
||||
p1 := params[len(params)-1]
|
||||
i := len(params)
|
||||
for k, v := range p1.Params {
|
||||
if p2, ok := v.(maps.Params); ok {
|
||||
paramsplus1 := make([]maps.KeyParams, i+1)
|
||||
if p2, ok := v.(hmaps.Params); ok {
|
||||
paramsplus1 := make([]hmaps.KeyParams, i+1)
|
||||
copy(paramsplus1, params)
|
||||
paramsplus1[i] = maps.KeyParams{Key: k, Params: p2}
|
||||
paramsplus1[i] = hmaps.KeyParams{Key: k, Params: p2}
|
||||
walk(depth+1, paramsplus1...)
|
||||
}
|
||||
}
|
||||
}
|
||||
walk(0, maps.KeyParams{Key: "", Params: c.root})
|
||||
walk(0, hmaps.KeyParams{Key: "", Params: c.root})
|
||||
}
|
||||
|
||||
func (c *defaultConfigProvider) determineMergeStrategy(params ...maps.KeyParams) maps.ParamsMergeStrategy {
|
||||
func (c *defaultConfigProvider) determineMergeStrategy(params ...hmaps.KeyParams) hmaps.ParamsMergeStrategy {
|
||||
if len(params) == 0 {
|
||||
return maps.ParamsMergeStrategyNone
|
||||
return hmaps.ParamsMergeStrategyNone
|
||||
}
|
||||
|
||||
var (
|
||||
strategy maps.ParamsMergeStrategy
|
||||
strategy hmaps.ParamsMergeStrategy
|
||||
prevIsRoot bool
|
||||
curr = params[len(params)-1]
|
||||
)
|
||||
@@ -299,10 +298,10 @@ func (c *defaultConfigProvider) determineMergeStrategy(params ...maps.KeyParams)
|
||||
// Don't set a merge strategy on the root unless set by user.
|
||||
// This will be handled as a special case.
|
||||
case "params":
|
||||
strategy = maps.ParamsMergeStrategyDeep
|
||||
strategy = hmaps.ParamsMergeStrategyDeep
|
||||
case "outputformats", "mediatypes":
|
||||
if prevIsRoot {
|
||||
strategy = maps.ParamsMergeStrategyShallow
|
||||
strategy = hmaps.ParamsMergeStrategyShallow
|
||||
}
|
||||
case "menus":
|
||||
isMenuKey := prevIsRoot
|
||||
@@ -314,11 +313,11 @@ func (c *defaultConfigProvider) determineMergeStrategy(params ...maps.KeyParams)
|
||||
}
|
||||
}
|
||||
if isMenuKey {
|
||||
strategy = maps.ParamsMergeStrategyShallow
|
||||
strategy = hmaps.ParamsMergeStrategyShallow
|
||||
}
|
||||
default:
|
||||
if strategy == "" {
|
||||
strategy = maps.ParamsMergeStrategyNone
|
||||
strategy = hmaps.ParamsMergeStrategyNone
|
||||
}
|
||||
}
|
||||
|
||||
@@ -326,7 +325,7 @@ func (c *defaultConfigProvider) determineMergeStrategy(params ...maps.KeyParams)
|
||||
}
|
||||
|
||||
func (c *defaultConfigProvider) SetDefaultMergeStrategy() {
|
||||
c.WalkParams(func(params ...maps.KeyParams) bool {
|
||||
c.WalkParams(func(params ...hmaps.KeyParams) bool {
|
||||
if len(params) == 0 {
|
||||
return false
|
||||
}
|
||||
@@ -344,7 +343,7 @@ func (c *defaultConfigProvider) SetDefaultMergeStrategy() {
|
||||
})
|
||||
}
|
||||
|
||||
func (c *defaultConfigProvider) getNestedKeyAndMap(key string, create bool) (string, maps.Params) {
|
||||
func (c *defaultConfigProvider) getNestedKeyAndMap(key string, create bool) (string, hmaps.Params) {
|
||||
var parts []string
|
||||
v, ok := c.keyCache.Load(key)
|
||||
if ok {
|
||||
@@ -358,14 +357,14 @@ func (c *defaultConfigProvider) getNestedKeyAndMap(key string, create bool) (str
|
||||
next, found := current[parts[i]]
|
||||
if !found {
|
||||
if create {
|
||||
next = make(maps.Params)
|
||||
next = make(hmaps.Params)
|
||||
current[parts[i]] = next
|
||||
} else {
|
||||
return "", nil
|
||||
}
|
||||
}
|
||||
var ok bool
|
||||
current, ok = next.(maps.Params)
|
||||
current, ok = next.(hmaps.Params)
|
||||
if !ok {
|
||||
// E.g. a string, not a map that we can store values in.
|
||||
return "", nil
|
||||
|
||||
@@ -22,10 +22,9 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/gohugoio/hugo/common/hmaps"
|
||||
"github.com/gohugoio/hugo/common/para"
|
||||
|
||||
"github.com/gohugoio/hugo/common/maps"
|
||||
|
||||
qt "github.com/frankban/quicktest"
|
||||
)
|
||||
|
||||
@@ -48,7 +47,7 @@ func TestDefaultConfigProvider(t *testing.T) {
|
||||
c.Assert(cfg.Get(k), qt.Equals, v)
|
||||
c.Assert(cfg.GetInt(k), qt.Equals, v)
|
||||
|
||||
c.Assert(cfg.Get(""), qt.DeepEquals, maps.Params{
|
||||
c.Assert(cfg.Get(""), qt.DeepEquals, hmaps.Params{
|
||||
"foo": 42,
|
||||
})
|
||||
})
|
||||
@@ -60,7 +59,7 @@ func TestDefaultConfigProvider(t *testing.T) {
|
||||
"bar": "baz",
|
||||
})
|
||||
|
||||
c.Assert(cfg.Get("foo"), qt.DeepEquals, maps.Params{
|
||||
c.Assert(cfg.Get("foo"), qt.DeepEquals, hmaps.Params{
|
||||
"bar": "baz",
|
||||
})
|
||||
|
||||
@@ -76,14 +75,14 @@ func TestDefaultConfigProvider(t *testing.T) {
|
||||
})
|
||||
cfg.Set("a.c", "cv")
|
||||
|
||||
c.Assert(cfg.Get("a"), qt.DeepEquals, maps.Params{
|
||||
c.Assert(cfg.Get("a"), qt.DeepEquals, hmaps.Params{
|
||||
"b": "bv",
|
||||
"c": "cv",
|
||||
})
|
||||
c.Assert(cfg.Get("a.c"), qt.Equals, "cv")
|
||||
|
||||
cfg.Set("b.a", "av")
|
||||
c.Assert(cfg.Get("b"), qt.DeepEquals, maps.Params{
|
||||
c.Assert(cfg.Get("b"), qt.DeepEquals, hmaps.Params{
|
||||
"a": "av",
|
||||
})
|
||||
|
||||
@@ -91,7 +90,7 @@ func TestDefaultConfigProvider(t *testing.T) {
|
||||
"b": "bv",
|
||||
})
|
||||
|
||||
c.Assert(cfg.Get("b"), qt.DeepEquals, maps.Params{
|
||||
c.Assert(cfg.Get("b"), qt.DeepEquals, hmaps.Params{
|
||||
"a": "av",
|
||||
"b": "bv",
|
||||
})
|
||||
@@ -105,7 +104,7 @@ func TestDefaultConfigProvider(t *testing.T) {
|
||||
"b": "bv2",
|
||||
})
|
||||
|
||||
c.Assert(cfg.Get(""), qt.DeepEquals, maps.Params{
|
||||
c.Assert(cfg.Get(""), qt.DeepEquals, hmaps.Params{
|
||||
"a": "av2",
|
||||
"b": "bv2",
|
||||
})
|
||||
@@ -118,7 +117,7 @@ func TestDefaultConfigProvider(t *testing.T) {
|
||||
"b": "bv2",
|
||||
})
|
||||
|
||||
c.Assert(cfg.Get(""), qt.DeepEquals, maps.Params{
|
||||
c.Assert(cfg.Get(""), qt.DeepEquals, hmaps.Params{
|
||||
"a": "av",
|
||||
"b": "bv2",
|
||||
})
|
||||
@@ -137,7 +136,7 @@ func TestDefaultConfigProvider(t *testing.T) {
|
||||
},
|
||||
})
|
||||
|
||||
c.Assert(cfg.Get("foo"), qt.DeepEquals, maps.Params{
|
||||
c.Assert(cfg.Get("foo"), qt.DeepEquals, hmaps.Params{
|
||||
"a": "av",
|
||||
"b": "bv2",
|
||||
})
|
||||
@@ -155,7 +154,7 @@ func TestDefaultConfigProvider(t *testing.T) {
|
||||
"c": "cv2",
|
||||
})
|
||||
|
||||
c.Assert(cfg.Get("a"), qt.DeepEquals, maps.Params{
|
||||
c.Assert(cfg.Get("a"), qt.DeepEquals, hmaps.Params{
|
||||
"b": "bv",
|
||||
"c": "cv2",
|
||||
})
|
||||
@@ -169,7 +168,7 @@ func TestDefaultConfigProvider(t *testing.T) {
|
||||
"b": "bv2",
|
||||
})
|
||||
|
||||
c.Assert(cfg.Get(""), qt.DeepEquals, maps.Params{
|
||||
c.Assert(cfg.Get(""), qt.DeepEquals, hmaps.Params{
|
||||
"a": "av",
|
||||
})
|
||||
})
|
||||
@@ -192,11 +191,11 @@ func TestDefaultConfigProvider(t *testing.T) {
|
||||
"e": "ev2",
|
||||
})
|
||||
|
||||
c.Assert(cfg.Get("a"), qt.DeepEquals, maps.Params{
|
||||
c.Assert(cfg.Get("a"), qt.DeepEquals, hmaps.Params{
|
||||
"e": "ev2",
|
||||
"_merge": maps.ParamsMergeStrategyShallow,
|
||||
"_merge": hmaps.ParamsMergeStrategyShallow,
|
||||
"b": "bv",
|
||||
"c": maps.Params{
|
||||
"c": hmaps.Params{
|
||||
"b": "bv",
|
||||
},
|
||||
})
|
||||
@@ -221,15 +220,15 @@ func TestDefaultConfigProvider(t *testing.T) {
|
||||
"b": left,
|
||||
})
|
||||
|
||||
cfg.Merge("", maps.Params{
|
||||
"b": maps.Params{
|
||||
cfg.Merge("", hmaps.Params{
|
||||
"b": hmaps.Params{
|
||||
"c": "cv2",
|
||||
"d": "dv2",
|
||||
},
|
||||
})
|
||||
|
||||
c.Assert(cfg.Get(""), qt.DeepEquals, maps.Params{
|
||||
"b": maps.Params{
|
||||
c.Assert(cfg.Get(""), qt.DeepEquals, hmaps.Params{
|
||||
"b": hmaps.Params{
|
||||
"c": "cv1",
|
||||
"d": "dv2",
|
||||
},
|
||||
@@ -267,8 +266,8 @@ func TestDefaultConfigProvider(t *testing.T) {
|
||||
|
||||
cfg.Merge("a", right)
|
||||
|
||||
c.Assert(cfg.Get(""), qt.DeepEquals, maps.Params{
|
||||
"a": maps.Params{
|
||||
c.Assert(cfg.Get(""), qt.DeepEquals, hmaps.Params{
|
||||
"a": hmaps.Params{
|
||||
"b": "bv1",
|
||||
"c": "cv2",
|
||||
},
|
||||
@@ -292,7 +291,7 @@ func TestDefaultConfigProvider(t *testing.T) {
|
||||
},
|
||||
})
|
||||
|
||||
c.Assert(cfg.Get(""), qt.DeepEquals, maps.Params{
|
||||
c.Assert(cfg.Get(""), qt.DeepEquals, hmaps.Params{
|
||||
"b": "bv",
|
||||
})
|
||||
})
|
||||
@@ -341,7 +340,7 @@ func TestDefaultConfigProvider(t *testing.T) {
|
||||
return err
|
||||
}
|
||||
|
||||
m := maps.Params{
|
||||
m := hmaps.Params{
|
||||
"new": 42,
|
||||
}
|
||||
|
||||
@@ -371,8 +370,8 @@ func TestDefaultConfigProvider(t *testing.T) {
|
||||
cfg := New()
|
||||
k := "foo"
|
||||
|
||||
cfg.Set(k, maps.Params{k: true})
|
||||
c.Assert(cfg.GetParams(k), qt.DeepEquals, maps.Params{
|
||||
cfg.Set(k, hmaps.Params{k: true})
|
||||
c.Assert(cfg.GetParams(k), qt.DeepEquals, hmaps.Params{
|
||||
k: true,
|
||||
})
|
||||
|
||||
@@ -384,8 +383,8 @@ func TestDefaultConfigProvider(t *testing.T) {
|
||||
k := "foo"
|
||||
k2 := "bar"
|
||||
|
||||
cfg.Set(k, maps.Params{k: struct{}{}})
|
||||
cfg.Set(k2, maps.Params{k2: struct{}{}})
|
||||
cfg.Set(k, hmaps.Params{k: struct{}{}})
|
||||
cfg.Set(k2, hmaps.Params{k2: struct{}{}})
|
||||
|
||||
c.Assert(len(cfg.Keys()), qt.Equals, 2)
|
||||
|
||||
@@ -401,11 +400,11 @@ func TestDefaultConfigProvider(t *testing.T) {
|
||||
c.Run("WalkParams", func(c *qt.C) {
|
||||
cfg := New()
|
||||
|
||||
cfg.Set("x", maps.Params{})
|
||||
cfg.Set("y", maps.Params{})
|
||||
cfg.Set("x", hmaps.Params{})
|
||||
cfg.Set("y", hmaps.Params{})
|
||||
|
||||
var got []string
|
||||
cfg.WalkParams(func(params ...maps.KeyParams) bool {
|
||||
cfg.WalkParams(func(params ...hmaps.KeyParams) bool {
|
||||
got = append(got, params[len(params)-1].Key)
|
||||
return false
|
||||
})
|
||||
@@ -417,7 +416,7 @@ func TestDefaultConfigProvider(t *testing.T) {
|
||||
c.Assert(got, qt.DeepEquals, want)
|
||||
|
||||
cfg = New()
|
||||
cfg.WalkParams(func(params ...maps.KeyParams) bool {
|
||||
cfg.WalkParams(func(params ...hmaps.KeyParams) bool {
|
||||
return true
|
||||
})
|
||||
|
||||
@@ -429,7 +428,7 @@ func TestDefaultConfigProvider(t *testing.T) {
|
||||
c.Run("SetDefaults", func(c *qt.C) {
|
||||
cfg := New()
|
||||
|
||||
cfg.SetDefaults(maps.Params{
|
||||
cfg.SetDefaults(hmaps.Params{
|
||||
"foo": "bar",
|
||||
"bar": "baz",
|
||||
})
|
||||
|
||||
@@ -18,7 +18,7 @@ import (
|
||||
"testing"
|
||||
|
||||
qt "github.com/frankban/quicktest"
|
||||
"github.com/gohugoio/hugo/common/maps"
|
||||
"github.com/gohugoio/hugo/common/hmaps"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
)
|
||||
|
||||
@@ -32,7 +32,7 @@ func TestNamespace(t *testing.T) {
|
||||
map[string]any{"foo": "bar"},
|
||||
func(v any) (*tstNsExt, any, error) {
|
||||
t := &tstNsExt{}
|
||||
m, err := maps.ToStringMapE(v)
|
||||
m, err := hmaps.ToStringMapE(v)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ package testconfig
|
||||
import (
|
||||
_ "unsafe"
|
||||
|
||||
"github.com/gohugoio/hugo/common/maps"
|
||||
"github.com/gohugoio/hugo/common/hmaps"
|
||||
"github.com/gohugoio/hugo/config"
|
||||
"github.com/gohugoio/hugo/config/allconfig"
|
||||
"github.com/gohugoio/hugo/deps"
|
||||
@@ -84,7 +84,7 @@ func GetTestConfigSectionFromStruct(section string, v any) config.AllProvider {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
p := maps.Params{
|
||||
p := hmaps.Params{
|
||||
section: config.FromTOMLConfigString(string(data)).Get(""),
|
||||
}
|
||||
cfg := config.NewFrom(p)
|
||||
|
||||
Vendored
+11
-11
@@ -28,8 +28,8 @@ import (
|
||||
"github.com/gohugoio/hugo/cache/dynacache"
|
||||
"github.com/gohugoio/hugo/cache/filecache"
|
||||
"github.com/gohugoio/hugo/common/hexec"
|
||||
"github.com/gohugoio/hugo/common/hmaps"
|
||||
"github.com/gohugoio/hugo/common/loggers"
|
||||
"github.com/gohugoio/hugo/common/maps"
|
||||
"github.com/gohugoio/hugo/common/types"
|
||||
"github.com/gohugoio/hugo/config"
|
||||
"github.com/gohugoio/hugo/config/allconfig"
|
||||
@@ -173,8 +173,8 @@ func (d *Deps) Init() error {
|
||||
d.BuildState.DeferredExecutionsGroupedByRenderingContext = make(map[tpl.RenderingContext]*DeferredExecutions)
|
||||
}
|
||||
d.BuildState.DeferredExecutions = &DeferredExecutions{
|
||||
Executions: maps.NewCache[string, *tpl.DeferredExecution](),
|
||||
FilenamesWithPostPrefix: maps.NewCache[string, bool](),
|
||||
Executions: hmaps.NewCache[string, *tpl.DeferredExecution](),
|
||||
FilenamesWithPostPrefix: hmaps.NewCache[string, bool](),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -260,10 +260,10 @@ func (d *Deps) Init() error {
|
||||
common = d.ResourceSpec.SpecCommon
|
||||
}
|
||||
|
||||
fileCaches, err := filecache.NewCaches(d.PathSpec)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create file caches from configuration: %w", err)
|
||||
}
|
||||
d.Cfg.BaseConfig()
|
||||
|
||||
fileCaches := d.Cfg.FileCaches().(filecache.Caches)
|
||||
fileCaches.SetResourceFs(d.BaseFs.ResourcesCache)
|
||||
|
||||
resourceSpec, err := resources.NewSpec(d.PathSpec, common, d.WasmDispatchers, fileCaches, d.MemCache, d.BuildState, d.Log, d, d.ExecHelper, d.BuildClosers, d.BuildState)
|
||||
if err != nil {
|
||||
@@ -464,10 +464,10 @@ type Counters struct {
|
||||
type DeferredExecutions struct {
|
||||
// A set of filenames in /public that
|
||||
// contains a post-processing prefix.
|
||||
FilenamesWithPostPrefix *maps.Cache[string, bool]
|
||||
FilenamesWithPostPrefix *hmaps.Cache[string, bool]
|
||||
|
||||
// Maps a placeholder to a deferred execution.
|
||||
Executions *maps.Cache[string, *tpl.DeferredExecution]
|
||||
Executions *hmaps.Cache[string, *tpl.DeferredExecution]
|
||||
}
|
||||
|
||||
var _ identity.SignalRebuilder = (*BuildState)(nil)
|
||||
@@ -480,8 +480,8 @@ func (b *BuildState) StartStageRender(stage tpl.RenderingContext) {
|
||||
func (b *BuildState) StopStageRender(stage tpl.RenderingContext) {
|
||||
b.DeferredExecutionsGroupedByRenderingContext[stage] = b.DeferredExecutions
|
||||
b.DeferredExecutions = &DeferredExecutions{
|
||||
Executions: maps.NewCache[string, *tpl.DeferredExecution](),
|
||||
FilenamesWithPostPrefix: maps.NewCache[string, bool](),
|
||||
Executions: hmaps.NewCache[string, *tpl.DeferredExecution](),
|
||||
FilenamesWithPostPrefix: hmaps.NewCache[string, bool](),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+813
-567
File diff suppressed because it is too large
Load Diff
@@ -3,9 +3,9 @@ module github.com/gohugoio/hugo
|
||||
require (
|
||||
github.com/BurntSushi/locker v0.0.0-20171006230638-a6e239ea1c69
|
||||
github.com/JohannesKaufmann/html-to-markdown/v2 v2.5.0
|
||||
github.com/alecthomas/chroma/v2 v2.21.1
|
||||
github.com/aws/aws-sdk-go-v2 v1.41.0
|
||||
github.com/aws/aws-sdk-go-v2/service/cloudfront v1.58.3
|
||||
github.com/alecthomas/chroma/v2 v2.23.1
|
||||
github.com/aws/aws-sdk-go-v2 v1.41.1
|
||||
github.com/aws/aws-sdk-go-v2/service/cloudfront v1.59.0
|
||||
github.com/bep/clocks v0.5.0
|
||||
github.com/bep/debounce v1.2.0
|
||||
github.com/bep/gitmap v1.9.0
|
||||
@@ -14,8 +14,8 @@ require (
|
||||
github.com/bep/golibsass v1.2.0
|
||||
github.com/bep/goportabletext v0.1.0
|
||||
github.com/bep/helpers v0.6.0
|
||||
github.com/bep/imagemeta v0.12.1
|
||||
github.com/bep/lazycache v0.8.0
|
||||
github.com/bep/imagemeta v0.14.0
|
||||
github.com/bep/lazycache v0.8.1
|
||||
github.com/bep/logg v0.4.0
|
||||
github.com/bep/mclib v1.20400.20402
|
||||
github.com/bep/overlayfs v0.10.0
|
||||
@@ -25,7 +25,6 @@ require (
|
||||
github.com/bits-and-blooms/bitset v1.24.4
|
||||
github.com/cespare/xxhash/v2 v2.3.0
|
||||
github.com/clbanning/mxj/v2 v2.7.0
|
||||
github.com/disintegration/gift v1.2.1
|
||||
github.com/dustin/go-humanize v1.0.1
|
||||
github.com/evanw/esbuild v0.27.2
|
||||
github.com/fatih/color v1.18.0
|
||||
@@ -36,6 +35,7 @@ require (
|
||||
github.com/gobuffalo/flect v1.0.3
|
||||
github.com/gobwas/glob v0.2.3
|
||||
github.com/goccy/go-yaml v1.19.2
|
||||
github.com/gohugoio/gift v0.2.0
|
||||
github.com/gohugoio/go-i18n/v2 v2.1.3-0.20251018145728-cfcc22d823c6
|
||||
github.com/gohugoio/go-radix v1.2.0
|
||||
github.com/gohugoio/hashstructure v0.6.0
|
||||
@@ -57,7 +57,7 @@ require (
|
||||
github.com/mitchellh/mapstructure v1.5.1-0.20231216201459-8508981c8b6c
|
||||
github.com/muesli/smartcrop v0.3.0
|
||||
github.com/niklasfasching/go-org v1.9.1
|
||||
github.com/olekukonko/tablewriter v1.1.2
|
||||
github.com/olekukonko/tablewriter v1.1.3
|
||||
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58
|
||||
github.com/pelletier/go-toml/v2 v2.2.4
|
||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c
|
||||
@@ -74,12 +74,12 @@ require (
|
||||
github.com/yuin/goldmark-emoji v1.0.6
|
||||
go.uber.org/automaxprocs v1.5.3
|
||||
gocloud.dev v0.44.0
|
||||
golang.org/x/image v0.34.0
|
||||
golang.org/x/mod v0.31.0
|
||||
golang.org/x/net v0.48.0
|
||||
golang.org/x/image v0.35.0
|
||||
golang.org/x/mod v0.32.0
|
||||
golang.org/x/net v0.49.0
|
||||
golang.org/x/sync v0.19.0
|
||||
golang.org/x/text v0.32.0
|
||||
golang.org/x/tools v0.40.0
|
||||
golang.org/x/text v0.33.0
|
||||
golang.org/x/tools v0.41.0
|
||||
google.golang.org/api v0.255.0
|
||||
rsc.io/qr v0.2.0
|
||||
)
|
||||
@@ -109,8 +109,8 @@ require (
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.18.21 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.13 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.20.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.16 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.16 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.17 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.17 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.13 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.3 // indirect
|
||||
@@ -123,7 +123,7 @@ require (
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.39.1 // indirect
|
||||
github.com/aws/smithy-go v1.24.0 // indirect
|
||||
github.com/aymerick/douceur v0.2.0 // indirect
|
||||
github.com/clipperhouse/displaywidth v0.6.0 // indirect
|
||||
github.com/clipperhouse/displaywidth v0.6.2 // indirect
|
||||
github.com/clipperhouse/stringish v0.1.1 // indirect
|
||||
github.com/clipperhouse/uax29/v2 v2.3.0 // indirect
|
||||
github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 // indirect
|
||||
@@ -151,7 +151,7 @@ require (
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/kylelemons/godebug v1.1.0 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.19 // indirect
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
|
||||
@@ -159,7 +159,7 @@ require (
|
||||
github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect
|
||||
github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 // indirect
|
||||
github.com/olekukonko/errors v1.1.0 // indirect
|
||||
github.com/olekukonko/ll v0.1.3 // indirect
|
||||
github.com/olekukonko/ll v0.1.4-0.20260115111900-9e59c2286df0 // indirect
|
||||
github.com/perimeterx/marshmallow v1.1.5 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
|
||||
@@ -177,9 +177,9 @@ require (
|
||||
go.opentelemetry.io/otel/sdk/metric v1.37.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.37.0 // indirect
|
||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||
golang.org/x/crypto v0.46.0 // indirect
|
||||
golang.org/x/crypto v0.47.0 // indirect
|
||||
golang.org/x/oauth2 v0.32.0 // indirect
|
||||
golang.org/x/sys v0.39.0 // indirect
|
||||
golang.org/x/sys v0.40.0 // indirect
|
||||
golang.org/x/time v0.14.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect
|
||||
google.golang.org/genproto v0.0.0-20250715232539-7130f93afb79 // indirect
|
||||
|
||||
@@ -98,12 +98,12 @@ github.com/JohannesKaufmann/html-to-markdown/v2 v2.5.0 h1:mklaPbT4f/EiDr1Q+zPrEt
|
||||
github.com/JohannesKaufmann/html-to-markdown/v2 v2.5.0/go.mod h1:D56Cl9r8M5i3UwAchE+LlLc5hPN3kJtdZNVJn06lSHU=
|
||||
github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0=
|
||||
github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
|
||||
github.com/alecthomas/chroma/v2 v2.21.1 h1:FaSDrp6N+3pphkNKU6HPCiYLgm8dbe5UXIXcoBhZSWA=
|
||||
github.com/alecthomas/chroma/v2 v2.21.1/go.mod h1:NqVhfBR0lte5Ouh3DcthuUCTUpDC9cxBOfyMbMQPs3o=
|
||||
github.com/alecthomas/chroma/v2 v2.23.1 h1:nv2AVZdTyClGbVQkIzlDm/rnhk1E9bU9nXwmZ/Vk/iY=
|
||||
github.com/alecthomas/chroma/v2 v2.23.1/go.mod h1:NqVhfBR0lte5Ouh3DcthuUCTUpDC9cxBOfyMbMQPs3o=
|
||||
github.com/alecthomas/repr v0.5.2 h1:SU73FTI9D1P5UNtvseffFSGmdNci/O6RsqzeXJtP0Qs=
|
||||
github.com/alecthomas/repr v0.5.2/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
|
||||
github.com/aws/aws-sdk-go-v2 v1.41.0 h1:tNvqh1s+v0vFYdA1xq0aOJH+Y5cRyZ5upu6roPgPKd4=
|
||||
github.com/aws/aws-sdk-go-v2 v1.41.0/go.mod h1:MayyLB8y+buD9hZqkCW3kX1AKq07Y5pXxtgB+rRFhz0=
|
||||
github.com/aws/aws-sdk-go-v2 v1.41.1 h1:ABlyEARCDLN034NhxlRUSZr4l71mh+T5KAeGh6cerhU=
|
||||
github.com/aws/aws-sdk-go-v2 v1.41.1/go.mod h1:MayyLB8y+buD9hZqkCW3kX1AKq07Y5pXxtgB+rRFhz0=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.3 h1:DHctwEM8P8iTXFxC/QK0MRjwEpWQeM9yzidCRjldUz0=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.3/go.mod h1:xdCzcZEtnSTKVDOmUZs4l/j3pSV6rpo1WXl5ugNsL8Y=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.31.17 h1:QFl8lL6RgakNK86vusim14P2k8BFSxjvUkcWLDjgz9Y=
|
||||
@@ -114,16 +114,16 @@ github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.13 h1:T1brd5dR3/fzNFAQch/iBK
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.13/go.mod h1:Peg/GBAQ6JDt+RoBf4meB1wylmAipb7Kg2ZFakZTlwk=
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.20.3 h1:4GNV1lhyELGjMz5ILMRxDvxvOaeo3Ux9Z69S1EgVMMQ=
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.20.3/go.mod h1:br7KA6edAAqDGUYJ+zVVPAyMrPhnN+zdt17yTUT6FPw=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.16 h1:rgGwPzb82iBYSvHMHXc8h9mRoOUBZIGFgKb9qniaZZc=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.16/go.mod h1:L/UxsGeKpGoIj6DxfhOWHWQ/kGKcd4I1VncE4++IyKA=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.16 h1:1jtGzuV7c82xnqOVfx2F0xmJcOw5374L7N6juGW6x6U=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.16/go.mod h1:M2E5OQf+XLe+SZGmmpaI2yy+J326aFf6/+54PoxSANc=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.17 h1:xOLELNKGp2vsiteLsvLPwxC+mYmO6OZ8PYgiuPJzF8U=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.17/go.mod h1:5M5CI3D12dNOtH3/mk6minaRwI2/37ifCURZISxA/IQ=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.17 h1:WWLqlh79iO48yLkj1v3ISRNiv+3KdQoZ6JWyfcsyQik=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.17/go.mod h1:EhG22vHRrvF8oXSTYStZhJc1aUgKtnJe+aOiFEV90cM=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 h1:WKuaxf++XKWlHWu9ECbMlha8WOEGm0OUEZqm4K/Gcfk=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4/go.mod h1:ZWy7j6v1vWGmPReu0iSGvRiise4YI5SkR3OHKTZ6Wuc=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.13 h1:eg/WYAa12vqTphzIdWMzqYRVKKnCboVPRlvaybNCqPA=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.13/go.mod h1:/FDdxWhz1486obGrKKC1HONd7krpk38LBt+dutLcN9k=
|
||||
github.com/aws/aws-sdk-go-v2/service/cloudfront v1.58.3 h1:/nyo0QD97D5VQQL/UE+rKGNKz+BesiqJgjdmp0qtTOQ=
|
||||
github.com/aws/aws-sdk-go-v2/service/cloudfront v1.58.3/go.mod h1:Jp0zmzn87l3dKarpDT/qbHNyISst5OnmzMACKuiyMvY=
|
||||
github.com/aws/aws-sdk-go-v2/service/cloudfront v1.59.0 h1:evSZnlPGyDgStAmjLK9LcSoLvEk3oSUyJz4KIFfzJEs=
|
||||
github.com/aws/aws-sdk-go-v2/service/cloudfront v1.59.0/go.mod h1:9Hd/cqshF4zl13KGLkWtRfITbvKR6m6FZHwhL2BYDSY=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.3 h1:x2Ibm/Af8Fi+BH+Hsn9TXGdT+hKbDd5XOTZxTMxDk7o=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.3/go.mod h1:IW1jwyrQgMdhisceG8fQLmQIydcT/jWY21rFhzgaKwo=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.4 h1:NvMjwvv8hpGUILarKw7Z4Q0w1H9anXKsesMxtw++MA4=
|
||||
@@ -160,10 +160,10 @@ github.com/bep/goportabletext v0.1.0 h1:8dqym2So1cEqVZiBa4ZnMM1R9l/DnC1h4ONg4J5k
|
||||
github.com/bep/goportabletext v0.1.0/go.mod h1:6lzSTsSue75bbcyvVc0zqd1CdApuT+xkZQ6Re5DzZFg=
|
||||
github.com/bep/helpers v0.6.0 h1:qtqMCK8XPFNM9hp5Ztu9piPjxNNkk8PIyUVjg6v8Bsw=
|
||||
github.com/bep/helpers v0.6.0/go.mod h1:IOZlgx5PM/R/2wgyCatfsgg5qQ6rNZJNDpWGXqDR044=
|
||||
github.com/bep/imagemeta v0.12.1 h1:43sIg/XJhXLVOo6troJFj9dyUr1jH+VN2UjO4/l26cQ=
|
||||
github.com/bep/imagemeta v0.12.1/go.mod h1:23AF6O+4fUi9avjiydpKLStUNtJr5hJB4rarG18JpN8=
|
||||
github.com/bep/lazycache v0.8.0 h1:lE5frnRjxaOFbkPZ1YL6nijzOPPz6zeXasJq8WpG4L8=
|
||||
github.com/bep/lazycache v0.8.0/go.mod h1:BQ5WZepss7Ko91CGdWz8GQZi/fFnCcyWupv8gyTeKwk=
|
||||
github.com/bep/imagemeta v0.14.0 h1:xmeB/XPmhrXJmSxTiE7KT4C56xfcSrcaGjVsNe+t6Ro=
|
||||
github.com/bep/imagemeta v0.14.0/go.mod h1:3psQjuZwn53rPCa86ai0p4KKnO+QArpuWLRdi5/30q8=
|
||||
github.com/bep/lazycache v0.8.1 h1:ko6ASLjkPxyV5DMWoNNZ8B2M0weyjqXX8IZkjBoBtvg=
|
||||
github.com/bep/lazycache v0.8.1/go.mod h1:pbEiFsZoq7cLXvrTll0AHOPEurB1aGGxx4jKjOtlx9w=
|
||||
github.com/bep/logg v0.4.0 h1:luAo5mO4ZkhA5M1iDVDqDqnBBnlHjmtZF6VAyTp+nCQ=
|
||||
github.com/bep/logg v0.4.0/go.mod h1:Ccp9yP3wbR1mm++Kpxet91hAZBEQgmWgFgnXX3GkIV0=
|
||||
github.com/bep/mclib v1.20400.20402 h1:olpCE2WSPpOAbFE1R4hnftSEmQ34+xzy2HRzd0m69rA=
|
||||
@@ -189,8 +189,8 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMn
|
||||
github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=
|
||||
github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/clipperhouse/displaywidth v0.6.0 h1:k32vueaksef9WIKCNcoqRNyKbyvkvkysNYnAWz2fN4s=
|
||||
github.com/clipperhouse/displaywidth v0.6.0/go.mod h1:R+kHuzaYWFkTm7xoMmK1lFydbci4X2CicfbGstSGg0o=
|
||||
github.com/clipperhouse/displaywidth v0.6.2 h1:ZDpTkFfpHOKte4RG5O/BOyf3ysnvFswpyYrV7z2uAKo=
|
||||
github.com/clipperhouse/displaywidth v0.6.2/go.mod h1:R+kHuzaYWFkTm7xoMmK1lFydbci4X2CicfbGstSGg0o=
|
||||
github.com/clipperhouse/stringish v0.1.1 h1:+NSqMOr3GR6k1FdRhhnXrLfztGzuG+VuFDfatpWHKCs=
|
||||
github.com/clipperhouse/stringish v0.1.1/go.mod h1:v/WhFtE1q0ovMta2+m+UbpZ+2/HEXNWYXQgCt4hdOzA=
|
||||
github.com/clipperhouse/uax29/v2 v2.3.0 h1:SNdx9DVUqMoBuBoW3iLOj4FQv3dN5mDtuqwuhIGpJy4=
|
||||
@@ -209,8 +209,6 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||
github.com/disintegration/gift v1.2.1 h1:Y005a1X4Z7Uc+0gLpSAsKhWi4qLtsdEcMIbbdvdZ6pc=
|
||||
github.com/disintegration/gift v1.2.1/go.mod h1:Jh2i7f7Q2BM7Ezno3PhfezbR1xpUg9dUg3/RlKGr4HI=
|
||||
github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ=
|
||||
github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||
@@ -270,6 +268,8 @@ github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
||||
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
||||
github.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM=
|
||||
github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
|
||||
github.com/gohugoio/gift v0.2.0 h1:vA31pP0rTVmBxBrhpY3WEt+4zM4g+1sDqYeemwsYeqc=
|
||||
github.com/gohugoio/gift v0.2.0/go.mod h1:1Mrm5CjF33KpD749Dwj+UAjWZ3LC6cBXGuTMa5XwoP4=
|
||||
github.com/gohugoio/go-i18n/v2 v2.1.3-0.20251018145728-cfcc22d823c6 h1:pxlAea9eRwuAnt/zKbGqlFO2ZszpIe24YpOVLf+N+4I=
|
||||
github.com/gohugoio/go-i18n/v2 v2.1.3-0.20251018145728-cfcc22d823c6/go.mod h1:m5hu1im5Qc7LDycVLvee6MPobJiRLBYHklypFJR0/aE=
|
||||
github.com/gohugoio/go-radix v1.2.0 h1:D5GTk8jIoeXirBSc2P4E4NdHKDrenk9k9N0ctU5Yrhg=
|
||||
@@ -412,9 +412,8 @@ github.com/makeworld-the-better-one/dither/v2 v2.4.0 h1:Az/dYXiTcwcRSe59Hzw4RI1r
|
||||
github.com/makeworld-the-better-one/dither/v2 v2.4.0/go.mod h1:VBtN8DXO7SNtyGmLiGA7IsFeKrBkQPze1/iAeM95arc=
|
||||
github.com/marekm4/color-extractor v1.2.1 h1:3Zb2tQsn6bITZ8MBVhc33Qn1k5/SEuZ18mrXGUqIwn0=
|
||||
github.com/marekm4/color-extractor v1.2.1/go.mod h1:90VjmiHI6M8ez9eYUaXLdcKnS+BAOp7w+NpwBdkJmpA=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
|
||||
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-runewidth v0.0.19 h1:v++JhqYnZuu5jSKrk9RbgF5v4CGUjqRfBm05byFGLdw=
|
||||
@@ -441,10 +440,10 @@ github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 h1:zrbMGy9YXpIeTnGj
|
||||
github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6/go.mod h1:rEKTHC9roVVicUIfZK7DYrdIoM0EOr8mK1Hj5s3JjH0=
|
||||
github.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM=
|
||||
github.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=
|
||||
github.com/olekukonko/ll v0.1.3 h1:sV2jrhQGq5B3W0nENUISCR6azIPf7UBUpVq0x/y70Fg=
|
||||
github.com/olekukonko/ll v0.1.3/go.mod h1:b52bVQRRPObe+yyBl0TxNfhesL0nedD4Cht0/zx55Ew=
|
||||
github.com/olekukonko/tablewriter v1.1.2 h1:L2kI1Y5tZBct/O/TyZK1zIE9GlBj/TVs+AY5tZDCDSc=
|
||||
github.com/olekukonko/tablewriter v1.1.2/go.mod h1:z7SYPugVqGVavWoA2sGsFIoOVNmEHxUAAMrhXONtfkg=
|
||||
github.com/olekukonko/ll v0.1.4-0.20260115111900-9e59c2286df0 h1:jrYnow5+hy3WRDCBypUFvVKNSPPCdqgSXIE9eJDD8LM=
|
||||
github.com/olekukonko/ll v0.1.4-0.20260115111900-9e59c2286df0/go.mod h1:b52bVQRRPObe+yyBl0TxNfhesL0nedD4Cht0/zx55Ew=
|
||||
github.com/olekukonko/tablewriter v1.1.3 h1:VSHhghXxrP0JHl+0NnKid7WoEmd9/urKRJLysb70nnA=
|
||||
github.com/olekukonko/tablewriter v1.1.3/go.mod h1:9VU0knjhmMkXjnMKrZ3+L2JhhtsQ/L38BbL3CRNE8tM=
|
||||
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0=
|
||||
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y=
|
||||
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
|
||||
@@ -570,8 +569,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
|
||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
|
||||
golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
|
||||
golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8=
|
||||
golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
@@ -584,8 +583,8 @@ golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EH
|
||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.34.0 h1:33gCkyw9hmwbZJeZkct8XyR11yH889EQt/QH4VmXMn8=
|
||||
golang.org/x/image v0.34.0/go.mod h1:2RNFBZRB+vnwwFil8GkMdRvrJOFd1AzdZI6vOY+eJVU=
|
||||
golang.org/x/image v0.35.0 h1:LKjiHdgMtO8z7Fh18nGY6KDcoEtVfsgLDPeLyguqb7I=
|
||||
golang.org/x/image v0.35.0/go.mod h1:MwPLTVgvxSASsxdLzKrl8BRFuyqMyGhLwmC+TO1Sybk=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
@@ -608,8 +607,8 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI=
|
||||
golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg=
|
||||
golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c=
|
||||
golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -643,8 +642,8 @@ golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU=
|
||||
golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY=
|
||||
golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o=
|
||||
golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@@ -707,11 +706,10 @@ golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
|
||||
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ=
|
||||
golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -720,8 +718,8 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
|
||||
golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
|
||||
golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE=
|
||||
golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
@@ -775,8 +773,8 @@ golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4f
|
||||
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA=
|
||||
golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc=
|
||||
golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc=
|
||||
golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
||||
@@ -105,6 +105,14 @@ func DiffStrings(s1, s2 string) []string {
|
||||
return DiffStringSlices(strings.Fields(s1), strings.Fields(s2))
|
||||
}
|
||||
|
||||
// SkipSlowTestUnlessCI skips the test unless we're running in a CI server.
|
||||
// Note that you can set CI_LOCAL=1 to run slow tests locally in a CI-like setup.
|
||||
func SkipSlowTestUnlessCI(t testing.TB) {
|
||||
if !IsCI() {
|
||||
t.Skip("skipping slow test in CI")
|
||||
}
|
||||
}
|
||||
|
||||
// IsCI reports whether we're running in a CI server.
|
||||
func IsCI() bool {
|
||||
return (os.Getenv("CI") != "" || os.Getenv("CI_LOCAL") != "") && os.Getenv("CIRCLE_BRANCH") == ""
|
||||
|
||||
@@ -133,6 +133,10 @@ func (f *componentFsDir) ReadDirWithContext(ctx context.Context, count int) ([]i
|
||||
|
||||
bi, bj := fimim.PathInfo.Base(), fimjm.PathInfo.Base()
|
||||
if bi == bj {
|
||||
// Check mount weight first for same module (earlier mounts should win).
|
||||
if fimim.ModuleOrdinal == fimjm.ModuleOrdinal && fimim.Weight != fimjm.Weight {
|
||||
return fimim.Weight > fimjm.Weight
|
||||
}
|
||||
matrixi, matrixj := fimim.SitesMatrix, fimjm.SitesMatrix
|
||||
l1, l2 := matrixi.LenVectors(), matrixj.LenVectors()
|
||||
if l1 != l2 {
|
||||
|
||||
@@ -22,7 +22,7 @@ import (
|
||||
|
||||
"github.com/gobwas/glob"
|
||||
"github.com/gobwas/glob/syntax"
|
||||
"github.com/gohugoio/hugo/common/maps"
|
||||
"github.com/gohugoio/hugo/common/hmaps"
|
||||
"github.com/gohugoio/hugo/identity"
|
||||
)
|
||||
|
||||
@@ -32,9 +32,9 @@ var (
|
||||
isWindows = runtime.GOOS == "windows"
|
||||
defaultGlobCache = &pathGlobCache{
|
||||
isWindows: isWindows,
|
||||
cache: maps.NewCache[string, globErr](),
|
||||
cache: hmaps.NewCache[string, globErr](),
|
||||
}
|
||||
dotGlobCache = maps.NewCache[string, globErr]()
|
||||
dotGlobCache = hmaps.NewCache[string, globErr]()
|
||||
)
|
||||
|
||||
type globErr struct {
|
||||
@@ -47,7 +47,7 @@ type pathGlobCache struct {
|
||||
isWindows bool
|
||||
|
||||
// Cache
|
||||
cache *maps.Cache[string, globErr]
|
||||
cache *hmaps.Cache[string, globErr]
|
||||
}
|
||||
|
||||
// GetGlobDot returns a glob.Glob that matches the given pattern, using '.' as the path separator.
|
||||
|
||||
@@ -21,7 +21,7 @@ import (
|
||||
|
||||
iofs "io/fs"
|
||||
|
||||
"github.com/gohugoio/hugo/common/maps"
|
||||
"github.com/gohugoio/hugo/common/hmaps"
|
||||
"github.com/gohugoio/hugo/config"
|
||||
"github.com/gohugoio/hugo/hugofs/hglob"
|
||||
"github.com/gohugoio/hugo/hugolib/sitesmatrix"
|
||||
@@ -556,5 +556,5 @@ func TestRootMappingFileFilter(t *testing.T) {
|
||||
var testDims = sitesmatrix.NewTestingDimensions([]string{"en", "no"}, []string{"v1", "v2", "v3"}, []string{"admin", "editor", "viewer", "guest"})
|
||||
|
||||
func sitesMatrixForLangs(langs ...int) *sitesmatrix.IntSets {
|
||||
return sitesmatrix.NewIntSetsBuilder(testDims).WithSets(maps.NewOrderedIntSet(langs...), nil, nil).Build()
|
||||
return sitesmatrix.NewIntSetsBuilder(testDims).WithSets(hmaps.NewOrderedIntSet(langs...), nil, nil).Build()
|
||||
}
|
||||
|
||||
@@ -191,3 +191,495 @@ aliases:
|
||||
|
||||
b.AssertPublishDir("n/index.html", "yes/index.html", "no/index.html", "yes/index.html")
|
||||
}
|
||||
|
||||
// Issue 14381
|
||||
func TestIssue14381(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
files := `
|
||||
-- hugo.toml --
|
||||
baseURL = 'https://example.org'
|
||||
disableKinds = ['home', 'rss', 'sitemap', 'taxonomy', 'term']
|
||||
|
||||
[outputFormats.print]
|
||||
isHTML = IS_HTML
|
||||
permalinkable = true
|
||||
mediaType = 'text/html'
|
||||
path = 'print'
|
||||
|
||||
[outputs]
|
||||
page = ['html', 'print']
|
||||
section = ['html', 'print']
|
||||
-- content/foo/s1/_index.md --
|
||||
---
|
||||
title: s1
|
||||
aliases: [s1-alias]
|
||||
---
|
||||
-- content/foo/s1/p1.md --
|
||||
---
|
||||
title: p1
|
||||
aliases: [p1-alias]
|
||||
---
|
||||
-- content/foo/s2/_index.md --
|
||||
---
|
||||
title: s2
|
||||
aliases: [/s2-alias]
|
||||
---
|
||||
-- content/foo/s2/p2.md --
|
||||
---
|
||||
title: p2
|
||||
aliases: [/p2-alias]
|
||||
---
|
||||
-- layouts/all.html --
|
||||
{{ .Title }}
|
||||
`
|
||||
// ------------------------------------------------------------------------
|
||||
// Test 1: Create aliases for the html output format only
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
// public/
|
||||
// ├── foo/
|
||||
// │ ├── s1/
|
||||
// │ │ ├── p1/
|
||||
// │ │ │ └── index.html
|
||||
// │ │ ├── p1-alias/
|
||||
// │ │ │ └── index.html
|
||||
// │ │ └── index.html
|
||||
// │ ├── s1-alias/
|
||||
// │ │ └── index.html
|
||||
// │ ├── s2/
|
||||
// │ │ ├── p2/
|
||||
// │ │ │ └── index.html
|
||||
// │ │ └── index.html
|
||||
// │ └── index.html
|
||||
// ├── p2-alias/
|
||||
// │ └── index.html
|
||||
// ├── print/
|
||||
// │ └── foo/
|
||||
// │ ├── s1/
|
||||
// │ │ ├── p1/
|
||||
// │ │ │ └── index.html
|
||||
// │ │ └── index.html
|
||||
// │ ├── s2/
|
||||
// │ │ ├── p2/
|
||||
// │ │ │ └── index.html
|
||||
// │ │ └── index.html
|
||||
// │ └── index.html
|
||||
// └── s2-alias/
|
||||
// └── index.html
|
||||
|
||||
f := strings.ReplaceAll(files, "IS_HTML", "false")
|
||||
b := Test(t, f)
|
||||
|
||||
// output format: html
|
||||
b.AssertFileContent("public/foo/s1-alias/index.html",
|
||||
`<title>https://example.org/foo/s1/</title>`,
|
||||
`<link rel="canonical" href="https://example.org/foo/s1/">`,
|
||||
`<meta http-equiv="refresh" content="0; url=https://example.org/foo/s1/">`,
|
||||
)
|
||||
b.AssertFileContent("public/foo/s1/p1-alias/index.html",
|
||||
`<title>https://example.org/foo/s1/p1/</title>`,
|
||||
`<link rel="canonical" href="https://example.org/foo/s1/p1/">`,
|
||||
`<meta http-equiv="refresh" content="0; url=https://example.org/foo/s1/p1/">`,
|
||||
)
|
||||
b.AssertFileContent("public/s2-alias/index.html",
|
||||
`<title>https://example.org/foo/s2/</title>`,
|
||||
`<link rel="canonical" href="https://example.org/foo/s2/">`,
|
||||
`<meta http-equiv="refresh" content="0; url=https://example.org/foo/s2/">`,
|
||||
)
|
||||
b.AssertFileContent("public/p2-alias/index.html",
|
||||
`<title>https://example.org/foo/s2/p2/</title>`,
|
||||
`<link rel="canonical" href="https://example.org/foo/s2/p2/">`,
|
||||
`<meta http-equiv="refresh" content="0; url=https://example.org/foo/s2/p2/">`,
|
||||
)
|
||||
|
||||
// output format: print
|
||||
b.AssertFileExists("public/print/foo/s1-alias/index.html", false)
|
||||
b.AssertFileExists("public/print/foo/s1/p1-alias/index.html", false)
|
||||
b.AssertFileExists("public/print/s2-alias/index.html", false)
|
||||
b.AssertFileExists("public/print/p2-alias/index.html", false)
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Test 2: Create aliases for the html and print output formats
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
// public/
|
||||
// ├── foo/
|
||||
// │ ├── s1/
|
||||
// │ │ ├── p1/
|
||||
// │ │ │ └── index.html
|
||||
// │ │ ├── p1-alias/
|
||||
// │ │ │ └── index.html
|
||||
// │ │ └── index.html
|
||||
// │ ├── s1-alias/
|
||||
// │ │ └── index.html
|
||||
// │ ├── s2/
|
||||
// │ │ ├── p2/
|
||||
// │ │ │ └── index.html
|
||||
// │ │ └── index.html
|
||||
// │ └── index.html
|
||||
// ├── p2-alias/
|
||||
// │ └── index.html
|
||||
// ├── print/
|
||||
// │ ├── foo/
|
||||
// │ │ ├── s1/
|
||||
// │ │ │ ├── p1/
|
||||
// │ │ │ │ └── index.html
|
||||
// │ │ │ ├── p1-alias/
|
||||
// │ │ │ │ └── index.html
|
||||
// │ │ │ └── index.html
|
||||
// │ │ ├── s1-alias/
|
||||
// │ │ │ └── index.html
|
||||
// │ │ ├── s2/
|
||||
// │ │ │ ├── p2/
|
||||
// │ │ │ │ └── index.html
|
||||
// │ │ │ └── index.html
|
||||
// │ │ └── index.html
|
||||
// │ ├── p2-alias/
|
||||
// │ │ └── index.html
|
||||
// │ └── s2-alias/
|
||||
// │ └── index.html
|
||||
// └── s2-alias/
|
||||
// └── index.html
|
||||
|
||||
f = strings.ReplaceAll(files, "IS_HTML", "true")
|
||||
b = Test(t, f)
|
||||
|
||||
// output format: html
|
||||
b.AssertFileContent("public/foo/s1-alias/index.html",
|
||||
`<title>https://example.org/foo/s1/</title>`,
|
||||
`<link rel="canonical" href="https://example.org/foo/s1/">`,
|
||||
`<meta http-equiv="refresh" content="0; url=https://example.org/foo/s1/">`,
|
||||
)
|
||||
b.AssertFileContent("public/foo/s1/p1-alias/index.html",
|
||||
`<title>https://example.org/foo/s1/p1/</title>`,
|
||||
`<link rel="canonical" href="https://example.org/foo/s1/p1/">`,
|
||||
`<meta http-equiv="refresh" content="0; url=https://example.org/foo/s1/p1/">`,
|
||||
)
|
||||
b.AssertFileContent("public/s2-alias/index.html",
|
||||
`<title>https://example.org/foo/s2/</title>`,
|
||||
`<link rel="canonical" href="https://example.org/foo/s2/">`,
|
||||
`<meta http-equiv="refresh" content="0; url=https://example.org/foo/s2/">`,
|
||||
)
|
||||
b.AssertFileContent("public/p2-alias/index.html",
|
||||
`<title>https://example.org/foo/s2/p2/</title>`,
|
||||
`<link rel="canonical" href="https://example.org/foo/s2/p2/">`,
|
||||
`<meta http-equiv="refresh" content="0; url=https://example.org/foo/s2/p2/">`,
|
||||
)
|
||||
|
||||
// output format: print
|
||||
b.AssertFileContent("public/print/foo/s1-alias/index.html",
|
||||
`<title>https://example.org/print/foo/s1/</title>`,
|
||||
`<link rel="canonical" href="https://example.org/foo/s1/">`,
|
||||
`<meta http-equiv="refresh" content="0; url=https://example.org/print/foo/s1/">`,
|
||||
)
|
||||
b.AssertFileContent("public/print/foo/s1/p1-alias/index.html",
|
||||
`<title>https://example.org/print/foo/s1/p1/</title>`,
|
||||
`<link rel="canonical" href="https://example.org/foo/s1/p1/">`,
|
||||
`<meta http-equiv="refresh" content="0; url=https://example.org/print/foo/s1/p1/">`,
|
||||
)
|
||||
b.AssertFileContent("public/print/s2-alias/index.html",
|
||||
`<title>https://example.org/print/foo/s2/</title>`,
|
||||
`<link rel="canonical" href="https://example.org/foo/s2/">`,
|
||||
`<meta http-equiv="refresh" content="0; url=https://example.org/print/foo/s2/">`,
|
||||
)
|
||||
b.AssertFileContent("public/print/p2-alias/index.html",
|
||||
`<title>https://example.org/print/foo/s2/p2/</title>`,
|
||||
`<link rel="canonical" href="https://example.org/foo/s2/p2/">`,
|
||||
`<meta http-equiv="refresh" content="0; url=https://example.org/print/foo/s2/p2/">`,
|
||||
)
|
||||
}
|
||||
|
||||
// Issue 14388
|
||||
func TestIssue14388(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
files := `
|
||||
-- hugo.toml --
|
||||
baseURL = 'https://example.org'
|
||||
disableKinds = ['home', 'rss', 'sitemap', 'taxonomy', 'term']
|
||||
|
||||
defaultContentLanguage = 'en'
|
||||
|
||||
defaultContentLanguageInSubdir = true
|
||||
defaultContentRoleInSubdir = true
|
||||
defaultContentVersionInSubdir = true
|
||||
|
||||
[languages.en]
|
||||
weight = 1
|
||||
# baseURL = 'https://en.example.org/'
|
||||
|
||||
[languages.de]
|
||||
weight = 2
|
||||
# baseURL = 'https://de.example.org/'
|
||||
|
||||
[outputFormats.print]
|
||||
isHTML = true
|
||||
mediaType = 'text/html'
|
||||
path = 'print'
|
||||
permalinkable = true
|
||||
|
||||
[outputs]
|
||||
page = ['html', 'print']
|
||||
section = ['html', 'print']
|
||||
-- content/foo/s1/_index.de.md --
|
||||
---
|
||||
title: s1 de
|
||||
aliases: [s1-alias]
|
||||
---
|
||||
-- content/foo/s1/_index.en.md --
|
||||
---
|
||||
title: s1 en
|
||||
aliases: [s1-alias]
|
||||
---
|
||||
-- content/foo/s1/p1.de.md --
|
||||
---
|
||||
title: p1 de
|
||||
aliases: [p1-alias]
|
||||
---
|
||||
-- content/foo/s1/p1.en.md --
|
||||
---
|
||||
title: p1 en
|
||||
aliases: [p1-alias]
|
||||
---
|
||||
-- content/foo/s2/_index.de.md --
|
||||
---
|
||||
title: s2 de
|
||||
aliases: [/s2-alias]
|
||||
---
|
||||
-- content/foo/s2/_index.en.md --
|
||||
---
|
||||
title: s2 en
|
||||
aliases: [/s2-alias]
|
||||
---
|
||||
-- content/foo/s2/p2.de.md --
|
||||
---
|
||||
title: p2 de
|
||||
aliases: [/p2-alias]
|
||||
---
|
||||
-- content/foo/s2/p2.en.md --
|
||||
---
|
||||
title: p2 en
|
||||
aliases: [/p2-alias]
|
||||
---
|
||||
-- layouts/all.html --
|
||||
{{ .Title }}
|
||||
`
|
||||
// ------------------------------------------------------------------------
|
||||
// Test 1: Multilingual single-host
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
b := Test(t, files)
|
||||
|
||||
// language: de, output format: html
|
||||
b.AssertFileContent("public/guest/v1.0.0/de/foo/s1-alias/index.html",
|
||||
`<title>https://example.org/guest/v1.0.0/de/foo/s1/</title>`,
|
||||
`<link rel="canonical" href="https://example.org/guest/v1.0.0/de/foo/s1/">`,
|
||||
`<meta http-equiv="refresh" content="0; url=https://example.org/guest/v1.0.0/de/foo/s1/">`,
|
||||
)
|
||||
b.AssertFileContent("public/guest/v1.0.0/de/foo/s1/p1-alias/index.html",
|
||||
`<title>https://example.org/guest/v1.0.0/de/foo/s1/p1/</title>`,
|
||||
`<link rel="canonical" href="https://example.org/guest/v1.0.0/de/foo/s1/p1/">`,
|
||||
`<meta http-equiv="refresh" content="0; url=https://example.org/guest/v1.0.0/de/foo/s1/p1/">`,
|
||||
)
|
||||
b.AssertFileContent("public/guest/v1.0.0/de/s2-alias/index.html",
|
||||
`<title>https://example.org/guest/v1.0.0/de/foo/s2/</title>`,
|
||||
`<link rel="canonical" href="https://example.org/guest/v1.0.0/de/foo/s2/">`,
|
||||
`<meta http-equiv="refresh" content="0; url=https://example.org/guest/v1.0.0/de/foo/s2/">`,
|
||||
)
|
||||
b.AssertFileContent("public/guest/v1.0.0/de/p2-alias/index.html",
|
||||
`<title>https://example.org/guest/v1.0.0/de/foo/s2/p2/</title>`,
|
||||
`<link rel="canonical" href="https://example.org/guest/v1.0.0/de/foo/s2/p2/">`,
|
||||
`<meta http-equiv="refresh" content="0; url=https://example.org/guest/v1.0.0/de/foo/s2/p2/">`,
|
||||
)
|
||||
|
||||
// language: de, output format: print
|
||||
b.AssertFileContent("public/guest/v1.0.0/de/print/foo/s1-alias/index.html",
|
||||
`<title>https://example.org/guest/v1.0.0/de/print/foo/s1/</title>`,
|
||||
`<link rel="canonical" href="https://example.org/guest/v1.0.0/de/foo/s1/">`,
|
||||
`<meta http-equiv="refresh" content="0; url=https://example.org/guest/v1.0.0/de/print/foo/s1/">`,
|
||||
)
|
||||
b.AssertFileContent("public/guest/v1.0.0/de/print/foo/s1/p1-alias/index.html",
|
||||
`<title>https://example.org/guest/v1.0.0/de/print/foo/s1/p1/</title>`,
|
||||
`<link rel="canonical" href="https://example.org/guest/v1.0.0/de/foo/s1/p1/">`,
|
||||
`<meta http-equiv="refresh" content="0; url=https://example.org/guest/v1.0.0/de/print/foo/s1/p1/">`,
|
||||
)
|
||||
b.AssertFileContent("public/guest/v1.0.0/de/print/s2-alias/index.html",
|
||||
`<title>https://example.org/guest/v1.0.0/de/print/foo/s2/</title>`,
|
||||
`<link rel="canonical" href="https://example.org/guest/v1.0.0/de/foo/s2/">`,
|
||||
`<meta http-equiv="refresh" content="0; url=https://example.org/guest/v1.0.0/de/print/foo/s2/">`,
|
||||
)
|
||||
b.AssertFileContent("public/guest/v1.0.0/de/print/p2-alias/index.html",
|
||||
`<title>https://example.org/guest/v1.0.0/de/print/foo/s2/p2/</title>`,
|
||||
`<link rel="canonical" href="https://example.org/guest/v1.0.0/de/foo/s2/p2/">`,
|
||||
`<meta http-equiv="refresh" content="0; url=https://example.org/guest/v1.0.0/de/print/foo/s2/p2/">`,
|
||||
)
|
||||
|
||||
// language: en, output format: html
|
||||
b.AssertFileContent("public/guest/v1.0.0/en/foo/s1-alias/index.html",
|
||||
`<title>https://example.org/guest/v1.0.0/en/foo/s1/</title>`,
|
||||
`<link rel="canonical" href="https://example.org/guest/v1.0.0/en/foo/s1/">`,
|
||||
`<meta http-equiv="refresh" content="0; url=https://example.org/guest/v1.0.0/en/foo/s1/">`,
|
||||
)
|
||||
b.AssertFileContent("public/guest/v1.0.0/en/foo/s1/p1-alias/index.html",
|
||||
`<title>https://example.org/guest/v1.0.0/en/foo/s1/p1/</title>`,
|
||||
`<link rel="canonical" href="https://example.org/guest/v1.0.0/en/foo/s1/p1/">`,
|
||||
`<meta http-equiv="refresh" content="0; url=https://example.org/guest/v1.0.0/en/foo/s1/p1/">`,
|
||||
)
|
||||
b.AssertFileContent("public/guest/v1.0.0/en/s2-alias/index.html",
|
||||
`<title>https://example.org/guest/v1.0.0/en/foo/s2/</title>`,
|
||||
`<link rel="canonical" href="https://example.org/guest/v1.0.0/en/foo/s2/">`,
|
||||
`<meta http-equiv="refresh" content="0; url=https://example.org/guest/v1.0.0/en/foo/s2/">`,
|
||||
)
|
||||
b.AssertFileContent("public/guest/v1.0.0/en/p2-alias/index.html",
|
||||
`<title>https://example.org/guest/v1.0.0/en/foo/s2/p2/</title>`,
|
||||
`<link rel="canonical" href="https://example.org/guest/v1.0.0/en/foo/s2/p2/">`,
|
||||
`<meta http-equiv="refresh" content="0; url=https://example.org/guest/v1.0.0/en/foo/s2/p2/">`,
|
||||
)
|
||||
|
||||
// language: en, output format: print
|
||||
b.AssertFileContent("public/guest/v1.0.0/en/print/foo/s1-alias/index.html",
|
||||
`<title>https://example.org/guest/v1.0.0/en/print/foo/s1/</title>`,
|
||||
`<link rel="canonical" href="https://example.org/guest/v1.0.0/en/foo/s1/">`,
|
||||
`<meta http-equiv="refresh" content="0; url=https://example.org/guest/v1.0.0/en/print/foo/s1/">`,
|
||||
)
|
||||
b.AssertFileContent("public/guest/v1.0.0/en/print/foo/s1/p1-alias/index.html",
|
||||
`<title>https://example.org/guest/v1.0.0/en/print/foo/s1/p1/</title>`,
|
||||
`<link rel="canonical" href="https://example.org/guest/v1.0.0/en/foo/s1/p1/">`,
|
||||
`<meta http-equiv="refresh" content="0; url=https://example.org/guest/v1.0.0/en/print/foo/s1/p1/">`,
|
||||
)
|
||||
b.AssertFileContent("public/guest/v1.0.0/en/print/s2-alias/index.html",
|
||||
`<title>https://example.org/guest/v1.0.0/en/print/foo/s2/</title>`,
|
||||
`<link rel="canonical" href="https://example.org/guest/v1.0.0/en/foo/s2/">`,
|
||||
`<meta http-equiv="refresh" content="0; url=https://example.org/guest/v1.0.0/en/print/foo/s2/">`,
|
||||
)
|
||||
b.AssertFileContent("public/guest/v1.0.0/en/print/p2-alias/index.html",
|
||||
`<title>https://example.org/guest/v1.0.0/en/print/foo/s2/p2/</title>`,
|
||||
`<link rel="canonical" href="https://example.org/guest/v1.0.0/en/foo/s2/p2/">`,
|
||||
`<meta http-equiv="refresh" content="0; url=https://example.org/guest/v1.0.0/en/print/foo/s2/p2/">`,
|
||||
)
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Test 2: Multilingual multihost
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
files = strings.ReplaceAll(files, "# baseURL", "baseURL")
|
||||
b = Test(t, files)
|
||||
|
||||
// language: de, output format: html
|
||||
b.AssertFileContent("public/de/guest/v1.0.0/foo/s1-alias/index.html",
|
||||
`<title>https://de.example.org/guest/v1.0.0/foo/s1/</title>`,
|
||||
`<link rel="canonical" href="https://de.example.org/guest/v1.0.0/foo/s1/">`,
|
||||
`<meta http-equiv="refresh" content="0; url=https://de.example.org/guest/v1.0.0/foo/s1/">`,
|
||||
)
|
||||
b.AssertFileContent("public/de/guest/v1.0.0/foo/s1/p1-alias/index.html",
|
||||
`<title>https://de.example.org/guest/v1.0.0/foo/s1/p1/</title>`,
|
||||
`<link rel="canonical" href="https://de.example.org/guest/v1.0.0/foo/s1/p1/">`,
|
||||
`<meta http-equiv="refresh" content="0; url=https://de.example.org/guest/v1.0.0/foo/s1/p1/">`,
|
||||
)
|
||||
b.AssertFileContent("public/de/guest/v1.0.0/s2-alias/index.html",
|
||||
`<title>https://de.example.org/guest/v1.0.0/foo/s2/</title>`,
|
||||
`<link rel="canonical" href="https://de.example.org/guest/v1.0.0/foo/s2/">`,
|
||||
`<meta http-equiv="refresh" content="0; url=https://de.example.org/guest/v1.0.0/foo/s2/">`,
|
||||
)
|
||||
b.AssertFileContent("public/de/guest/v1.0.0/p2-alias/index.html",
|
||||
`<title>https://de.example.org/guest/v1.0.0/foo/s2/p2/</title>`,
|
||||
`<link rel="canonical" href="https://de.example.org/guest/v1.0.0/foo/s2/p2/">`,
|
||||
`<meta http-equiv="refresh" content="0; url=https://de.example.org/guest/v1.0.0/foo/s2/p2/">`,
|
||||
)
|
||||
|
||||
// language: de, output format: print
|
||||
b.AssertFileContent("public/de/guest/v1.0.0/print/foo/s1-alias/index.html",
|
||||
`<title>https://de.example.org/guest/v1.0.0/print/foo/s1/</title>`,
|
||||
`<link rel="canonical" href="https://de.example.org/guest/v1.0.0/foo/s1/">`,
|
||||
`<meta http-equiv="refresh" content="0; url=https://de.example.org/guest/v1.0.0/print/foo/s1/">`,
|
||||
)
|
||||
b.AssertFileContent("public/de/guest/v1.0.0/print/foo/s1/p1-alias/index.html",
|
||||
`<title>https://de.example.org/guest/v1.0.0/print/foo/s1/p1/</title>`,
|
||||
`<link rel="canonical" href="https://de.example.org/guest/v1.0.0/foo/s1/p1/">`,
|
||||
`<meta http-equiv="refresh" content="0; url=https://de.example.org/guest/v1.0.0/print/foo/s1/p1/">`,
|
||||
)
|
||||
b.AssertFileContent("public/de/guest/v1.0.0/print/s2-alias/index.html",
|
||||
`<title>https://de.example.org/guest/v1.0.0/print/foo/s2/</title>`,
|
||||
`<link rel="canonical" href="https://de.example.org/guest/v1.0.0/foo/s2/">`,
|
||||
`<meta http-equiv="refresh" content="0; url=https://de.example.org/guest/v1.0.0/print/foo/s2/">`,
|
||||
)
|
||||
b.AssertFileContent("public/de/guest/v1.0.0/print/p2-alias/index.html",
|
||||
`<title>https://de.example.org/guest/v1.0.0/print/foo/s2/p2/</title>`,
|
||||
`<link rel="canonical" href="https://de.example.org/guest/v1.0.0/foo/s2/p2/">`,
|
||||
`<meta http-equiv="refresh" content="0; url=https://de.example.org/guest/v1.0.0/print/foo/s2/p2/">`,
|
||||
)
|
||||
|
||||
// language: en, output format: html
|
||||
b.AssertFileContent("public/en/guest/v1.0.0/foo/s1-alias/index.html",
|
||||
`<title>https://en.example.org/guest/v1.0.0/foo/s1/</title>`,
|
||||
`<link rel="canonical" href="https://en.example.org/guest/v1.0.0/foo/s1/">`,
|
||||
`<meta http-equiv="refresh" content="0; url=https://en.example.org/guest/v1.0.0/foo/s1/">`,
|
||||
)
|
||||
b.AssertFileContent("public/en/guest/v1.0.0/foo/s1/p1-alias/index.html",
|
||||
`<title>https://en.example.org/guest/v1.0.0/foo/s1/p1/</title>`,
|
||||
`<link rel="canonical" href="https://en.example.org/guest/v1.0.0/foo/s1/p1/">`,
|
||||
`<meta http-equiv="refresh" content="0; url=https://en.example.org/guest/v1.0.0/foo/s1/p1/">`,
|
||||
)
|
||||
b.AssertFileContent("public/en/guest/v1.0.0/s2-alias/index.html",
|
||||
`<title>https://en.example.org/guest/v1.0.0/foo/s2/</title>`,
|
||||
`<link rel="canonical" href="https://en.example.org/guest/v1.0.0/foo/s2/">`,
|
||||
`<meta http-equiv="refresh" content="0; url=https://en.example.org/guest/v1.0.0/foo/s2/">`,
|
||||
)
|
||||
b.AssertFileContent("public/en/guest/v1.0.0/p2-alias/index.html",
|
||||
`<title>https://en.example.org/guest/v1.0.0/foo/s2/p2/</title>`,
|
||||
`<link rel="canonical" href="https://en.example.org/guest/v1.0.0/foo/s2/p2/">`,
|
||||
`<meta http-equiv="refresh" content="0; url=https://en.example.org/guest/v1.0.0/foo/s2/p2/">`,
|
||||
)
|
||||
|
||||
// language: en, output format: print
|
||||
b.AssertFileContent("public/en/guest/v1.0.0/print/foo/s1-alias/index.html",
|
||||
`<title>https://en.example.org/guest/v1.0.0/print/foo/s1/</title>`,
|
||||
`<link rel="canonical" href="https://en.example.org/guest/v1.0.0/foo/s1/">`,
|
||||
`<meta http-equiv="refresh" content="0; url=https://en.example.org/guest/v1.0.0/print/foo/s1/">`,
|
||||
)
|
||||
b.AssertFileContent("public/en/guest/v1.0.0/print/foo/s1/p1-alias/index.html",
|
||||
`<title>https://en.example.org/guest/v1.0.0/print/foo/s1/p1/</title>`,
|
||||
`<link rel="canonical" href="https://en.example.org/guest/v1.0.0/foo/s1/p1/">`,
|
||||
`<meta http-equiv="refresh" content="0; url=https://en.example.org/guest/v1.0.0/print/foo/s1/p1/">`,
|
||||
)
|
||||
b.AssertFileContent("public/en/guest/v1.0.0/print/s2-alias/index.html",
|
||||
`<title>https://en.example.org/guest/v1.0.0/print/foo/s2/</title>`,
|
||||
`<link rel="canonical" href="https://en.example.org/guest/v1.0.0/foo/s2/">`,
|
||||
`<meta http-equiv="refresh" content="0; url=https://en.example.org/guest/v1.0.0/print/foo/s2/">`,
|
||||
)
|
||||
b.AssertFileContent("public/en/guest/v1.0.0/print/p2-alias/index.html",
|
||||
`<title>https://en.example.org/guest/v1.0.0/print/foo/s2/p2/</title>`,
|
||||
`<link rel="canonical" href="https://en.example.org/guest/v1.0.0/foo/s2/p2/">`,
|
||||
`<meta http-equiv="refresh" content="0; url=https://en.example.org/guest/v1.0.0/print/foo/s2/p2/">`,
|
||||
)
|
||||
}
|
||||
|
||||
// Issue #14402.
|
||||
func TestComprehensiveAliasesRedirectsFile(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
files := `
|
||||
-- hugo.toml --
|
||||
disableAliases = true
|
||||
defaultContentLanguageInSubdir = true
|
||||
defaultContentRoleInSubdir = true
|
||||
defaultContentVersionInSubdir = true
|
||||
baseURL = "https://example.org/"
|
||||
-- content/foo/p1.md --
|
||||
---
|
||||
aliases: ["/foo/p2/", "../p3/"]
|
||||
---
|
||||
-- content/foo/p2.md --
|
||||
-- content/p3.md --
|
||||
-- layouts/home.html --
|
||||
Home.
|
||||
{{ range $p := site.RegularPages }}{{ range .Aliases }}{{ . | printf "%-35s" }}=>{{ $p.RelPermalink -}}|{{ end -}}{{ end }}
|
||||
`
|
||||
b := Test(t, files)
|
||||
|
||||
b.AssertFileContent("public/guest/v1.0.0/en/index.html",
|
||||
"/guest/v1.0.0/en/foo/p2 =>/guest/v1.0.0/en/foo/p1/|",
|
||||
"/guest/v1.0.0/en/p3 =>/guest/v1.0.0/en/foo/p1/|",
|
||||
)
|
||||
}
|
||||
|
||||
@@ -416,3 +416,66 @@ title: p1 (en)
|
||||
b.AssertFileContent("public/en/s1/p1/index.html", "|color: red (en)|size: medium|") // fails: file contains "|color: red (en)|size: |"
|
||||
b.AssertFileContent("public/de/s1/p1/index.html", "|color: red (de)|size: medium|")
|
||||
}
|
||||
|
||||
// Issue 14409
|
||||
func TestCascadeDraftTrue14409(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
files := `
|
||||
-- hugo.toml --
|
||||
disableKinds = ['rss','taxonomy','term']
|
||||
defaultContentLanguage = 'en'
|
||||
defaultContentLanguageInSubdir = true
|
||||
|
||||
[languages.en]
|
||||
weight = 1
|
||||
[languages.de]
|
||||
weight = 2
|
||||
|
||||
[[cascade]]
|
||||
draft = true
|
||||
[cascade.target.sites.matrix]
|
||||
languages = ['en']
|
||||
-- content/_index.en.md --
|
||||
---
|
||||
title: home en
|
||||
draft: false
|
||||
---
|
||||
-- content/_index.de.md --
|
||||
---
|
||||
title: home de
|
||||
draft: false
|
||||
---
|
||||
-- content/s1/_index.en.md --
|
||||
---
|
||||
title: s1 en
|
||||
draft: false
|
||||
---
|
||||
-- content/s1/_index.de.md --
|
||||
---
|
||||
title: s1 de
|
||||
draft: false
|
||||
---
|
||||
-- content/s1/p1.en.md --
|
||||
---
|
||||
title: p1 en
|
||||
---
|
||||
-- content/s1/p1.de.md --
|
||||
---
|
||||
title: p1 de
|
||||
---
|
||||
-- layouts/all.html --
|
||||
{{ .Title }}
|
||||
`
|
||||
|
||||
b := Test(t, files)
|
||||
|
||||
b.AssertFileExists("public/de/index.html", true)
|
||||
b.AssertFileExists("public/en/index.html", true)
|
||||
|
||||
b.AssertFileExists("public/de/s1/index.html", true)
|
||||
b.AssertFileExists("public/en/s1/index.html", true)
|
||||
|
||||
b.AssertFileExists("public/de/s1/p1/index.html", true)
|
||||
b.AssertFileExists("public/en/s1/p1/index.html", false)
|
||||
}
|
||||
|
||||
+14
-12
@@ -20,11 +20,12 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/bep/logg"
|
||||
"github.com/gohugoio/hugo/common/hmaps"
|
||||
"github.com/gohugoio/hugo/config"
|
||||
"github.com/gohugoio/hugo/config/allconfig"
|
||||
"github.com/gohugoio/hugo/htesting"
|
||||
|
||||
qt "github.com/frankban/quicktest"
|
||||
"github.com/gohugoio/hugo/common/maps"
|
||||
"github.com/spf13/afero"
|
||||
)
|
||||
|
||||
@@ -53,8 +54,8 @@ title = "English Comments Title"
|
||||
enSite := b.H.Sites[0]
|
||||
b.Assert(enSite.Title(), qt.Equals, "English Title")
|
||||
b.Assert(enSite.Home().Title(), qt.Equals, "English Title")
|
||||
b.Assert(enSite.Params(), qt.DeepEquals, maps.Params{
|
||||
"comments": maps.Params{
|
||||
b.Assert(enSite.Params(), qt.DeepEquals, hmaps.Params{
|
||||
"comments": hmaps.Params{
|
||||
"color": "blue",
|
||||
"title": "English Comments Title",
|
||||
},
|
||||
@@ -424,13 +425,13 @@ name = "menu-theme"
|
||||
|
||||
got := b.H.Configs.Base
|
||||
|
||||
b.Assert(got.Params, qt.DeepEquals, maps.Params{
|
||||
"b": maps.Params{
|
||||
b.Assert(got.Params, qt.DeepEquals, hmaps.Params{
|
||||
"b": hmaps.Params{
|
||||
"b1": "b1 main",
|
||||
"c": maps.Params{
|
||||
"c": hmaps.Params{
|
||||
"bc1": "bc1 main",
|
||||
"bc2": "bc2 theme",
|
||||
"d": maps.Params{"bcd1": string("bcd1 theme")},
|
||||
"d": hmaps.Params{"bcd1": string("bcd1 theme")},
|
||||
},
|
||||
"b2": "b2 theme",
|
||||
},
|
||||
@@ -447,11 +448,11 @@ name = "menu-theme"
|
||||
got := b.H.Configs.Base.Params
|
||||
|
||||
// Shallow merge, only add new keys to params.
|
||||
b.Assert(got, qt.DeepEquals, maps.Params{
|
||||
b.Assert(got, qt.DeepEquals, hmaps.Params{
|
||||
"p1": "p1 main",
|
||||
"b": maps.Params{
|
||||
"b": hmaps.Params{
|
||||
"b1": "b1 main",
|
||||
"c": maps.Params{
|
||||
"c": hmaps.Params{
|
||||
"bc1": "bc1 main",
|
||||
},
|
||||
},
|
||||
@@ -468,7 +469,7 @@ name = "menu-theme"
|
||||
|
||||
got := b.H.Configs.Base.Params
|
||||
|
||||
b.Assert(got, qt.DeepEquals, maps.Params{
|
||||
b.Assert(got, qt.DeepEquals, hmaps.Params{
|
||||
"p1": "p1 theme",
|
||||
})
|
||||
})
|
||||
@@ -534,7 +535,7 @@ t3: {{ .Site.Params.t3 }}
|
||||
|
||||
got := b.H.Configs.Base.Params
|
||||
|
||||
b.Assert(got, qt.DeepEquals, maps.Params{
|
||||
b.Assert(got, qt.DeepEquals, hmaps.Params{
|
||||
"m1": "mv1",
|
||||
"m2": "mv2",
|
||||
"t1": "tv1",
|
||||
@@ -711,6 +712,7 @@ themeconfigdirparam: {{ site.Params.themeconfigdirparam }}
|
||||
|
||||
// Issue #11089
|
||||
func TestHugoConfigSliceOverrides(t *testing.T) {
|
||||
htesting.SkipSlowTestUnlessCI(t)
|
||||
t.Parallel()
|
||||
|
||||
filesTemplate := `
|
||||
|
||||
@@ -26,6 +26,7 @@ import (
|
||||
"github.com/bep/logg"
|
||||
"github.com/gohugoio/go-radix"
|
||||
"github.com/gohugoio/hugo/cache/dynacache"
|
||||
"github.com/gohugoio/hugo/common/hmaps"
|
||||
"github.com/gohugoio/hugo/common/loggers"
|
||||
"github.com/gohugoio/hugo/common/paths"
|
||||
"github.com/gohugoio/hugo/common/predicate"
|
||||
@@ -39,8 +40,6 @@ import (
|
||||
"github.com/gohugoio/hugo/output"
|
||||
"github.com/gohugoio/hugo/resources"
|
||||
|
||||
"github.com/gohugoio/hugo/common/maps"
|
||||
|
||||
"github.com/gohugoio/hugo/resources/kinds"
|
||||
"github.com/gohugoio/hugo/resources/page"
|
||||
"github.com/gohugoio/hugo/resources/resource"
|
||||
@@ -100,7 +99,7 @@ type pageMap struct {
|
||||
cacheContentPlain *dynacache.Partition[string, *resources.StaleValue[contentPlainPlainWords]]
|
||||
contentTableOfContents *dynacache.Partition[string, *resources.StaleValue[contentTableOfContents]]
|
||||
|
||||
contentDataFileSeenItems *maps.Cache[string, map[uint64]bool]
|
||||
contentDataFileSeenItems *hmaps.Cache[string, map[uint64]bool]
|
||||
|
||||
cfg contentMapConfig
|
||||
}
|
||||
@@ -710,7 +709,7 @@ func newPageMap(s *Site, mcache *dynacache.Cache, pageTrees *pageTrees) *pageMap
|
||||
cacheContentPlain: dynacache.GetOrCreatePartition[string, *resources.StaleValue[contentPlainPlainWords]](mcache, fmt.Sprintf("/cont/pla/%s", languageVersionRole), dynacache.OptionsPartition{Weight: 70, ClearWhen: dynacache.ClearOnChange}),
|
||||
contentTableOfContents: dynacache.GetOrCreatePartition[string, *resources.StaleValue[contentTableOfContents]](mcache, fmt.Sprintf("/cont/toc/%s", languageVersionRole), dynacache.OptionsPartition{Weight: 70, ClearWhen: dynacache.ClearOnChange}),
|
||||
|
||||
contentDataFileSeenItems: maps.NewCache[string, map[uint64]bool](),
|
||||
contentDataFileSeenItems: hmaps.NewCache[string, map[uint64]bool](),
|
||||
|
||||
cfg: contentMapConfig{
|
||||
lang: s.Lang(),
|
||||
@@ -756,13 +755,13 @@ func newPageMap(s *Site, mcache *dynacache.Cache, pageTrees *pageTrees) *pageMap
|
||||
func newContentTreeTreverseIndex(init func(get func(key any) (contentNode, bool), set func(key any, val contentNode))) *contentTreeReverseIndex {
|
||||
return &contentTreeReverseIndex{
|
||||
initFn: init,
|
||||
mm: maps.NewCache[any, contentNode](),
|
||||
mm: hmaps.NewCache[any, contentNode](),
|
||||
}
|
||||
}
|
||||
|
||||
type contentTreeReverseIndex struct {
|
||||
initFn func(get func(key any) (contentNode, bool), set func(key any, val contentNode))
|
||||
mm *maps.Cache[any, contentNode]
|
||||
mm *hmaps.Cache[any, contentNode]
|
||||
}
|
||||
|
||||
func (c *contentTreeReverseIndex) Reset() {
|
||||
|
||||
@@ -22,7 +22,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/gohugoio/go-radix"
|
||||
"github.com/gohugoio/hugo/common/maps"
|
||||
"github.com/gohugoio/hugo/common/hmaps"
|
||||
"github.com/gohugoio/hugo/common/paths"
|
||||
"github.com/gohugoio/hugo/common/types"
|
||||
"github.com/gohugoio/hugo/hugofs/files"
|
||||
@@ -54,9 +54,9 @@ type allPagesAssembler struct {
|
||||
rwRoot *doctree.NodeShiftTreeWalker[contentNode] // walks resources.
|
||||
|
||||
// Walking state.
|
||||
seenTerms *maps.Map[term, sitesmatrix.Vectors]
|
||||
droppedPages *maps.Map[*Site, []string] // e.g. drafts, expired, future.
|
||||
seenRootSections *maps.Map[string, bool]
|
||||
seenTerms *hmaps.Map[term, sitesmatrix.Vectors]
|
||||
droppedPages *hmaps.Map[*Site, []string] // e.g. drafts, expired, future.
|
||||
seenRootSections *hmaps.Map[string, bool]
|
||||
seenHome bool // set before we fan out to multiple goroutines.
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ func newAllPagesAssembler(
|
||||
pw := rw.Extend()
|
||||
pw.Tree = m.treePages
|
||||
|
||||
seenRootSections := maps.NewMap[string, bool]()
|
||||
seenRootSections := hmaps.NewMap[string, bool]()
|
||||
seenRootSections.Set("", true) // home.
|
||||
|
||||
return &allPagesAssembler{
|
||||
@@ -83,10 +83,10 @@ func newAllPagesAssembler(
|
||||
h: h,
|
||||
m: m,
|
||||
assembleChanges: assembleChanges,
|
||||
seenTerms: maps.NewMap[term, sitesmatrix.Vectors](),
|
||||
droppedPages: maps.NewMap[*Site, []string](),
|
||||
seenTerms: hmaps.NewMap[term, sitesmatrix.Vectors](),
|
||||
droppedPages: hmaps.NewMap[*Site, []string](),
|
||||
seenRootSections: seenRootSections,
|
||||
assembleSectionsInParallel: true,
|
||||
assembleSectionsInParallel: !h.isRebuild(), // On partial rebuilds, there's potential data races with parallel section assembly.
|
||||
pwRoot: pw,
|
||||
rwRoot: rw,
|
||||
}
|
||||
@@ -273,27 +273,23 @@ func (a *allPagesAssembler) doCreatePages(prefix string, depth int) error {
|
||||
return false
|
||||
}
|
||||
|
||||
var drop bool
|
||||
if !site.shouldBuild(p) {
|
||||
(&p.m.pageConfig.Build).Disable()
|
||||
switch p.Kind() {
|
||||
case kinds.KindHome, kinds.KindSection, kinds.KindTaxonomy:
|
||||
// We need to keep these for the structure, but disable
|
||||
// them so they don't get listed/rendered.
|
||||
(&p.m.pageConfig.Build).Disable()
|
||||
// We need to keep these for the structure.
|
||||
default:
|
||||
// Skip this page.
|
||||
// Drop this page.
|
||||
a.droppedPages.WithWriteLock(
|
||||
func(m map[*Site][]string) error {
|
||||
m[site] = append(m[site], s)
|
||||
return nil
|
||||
},
|
||||
)
|
||||
|
||||
drop = true
|
||||
}
|
||||
}
|
||||
|
||||
if !drop && n == nil {
|
||||
if n == nil {
|
||||
if n2 == nil {
|
||||
// Avoid creating a map for one node.
|
||||
n2 = p
|
||||
|
||||
@@ -40,6 +40,18 @@ func (s *contentNodeShifter) Delete(n contentNode, vec sitesmatrix.Vector) (cont
|
||||
}
|
||||
resource.MarkStale(v)
|
||||
return v, true, true
|
||||
case contentNodes:
|
||||
var deleted contentNodes
|
||||
for i, nn := range v {
|
||||
if vv, ok, _ := s.Delete(nn, vec); ok {
|
||||
deleted = append(deleted, vv)
|
||||
v = append(v[:i], v[i+1:]...)
|
||||
}
|
||||
}
|
||||
if len(deleted) == 0 {
|
||||
return nil, false, false
|
||||
}
|
||||
return deleted, true, len(v) == 0
|
||||
default:
|
||||
v = v.(contentNodeSingle) // Ensure single node.
|
||||
resource.MarkStale(v)
|
||||
|
||||
@@ -190,7 +190,7 @@ DATA
|
||||
t.Run("Build config, no render link", func(t *testing.T) {
|
||||
files := filesForDisabledKind("")
|
||||
b := Test(t, files)
|
||||
b.AssertFileExists("public/sect/no-render/index.html", false)
|
||||
b.AssertFileExists("public/sect/no-render-link/index.html", false)
|
||||
b.AssertFileContent("public/link-alias/index.html", "refresh")
|
||||
})
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ import (
|
||||
|
||||
radix "github.com/gohugoio/go-radix"
|
||||
"github.com/gohugoio/hugo/common/collections"
|
||||
"github.com/gohugoio/hugo/common/maps"
|
||||
"github.com/gohugoio/hugo/common/hmaps"
|
||||
"github.com/gohugoio/hugo/hugolib/sitesmatrix"
|
||||
)
|
||||
|
||||
@@ -70,7 +70,7 @@ func (ctx *WalkContext[T]) Data() *SimpleThreadSafeTree[any] {
|
||||
|
||||
func (ctx *WalkContext[T]) initDataRaw() {
|
||||
ctx.dataRawInit.Do(func() {
|
||||
ctx.dataRaw = maps.NewCache[sitesmatrix.Vector, *SimpleThreadSafeTree[any]]()
|
||||
ctx.dataRaw = hmaps.NewCache[sitesmatrix.Vector, *SimpleThreadSafeTree[any]]()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -215,7 +215,7 @@ type WalkContext[T any] struct {
|
||||
data *SimpleThreadSafeTree[any]
|
||||
dataInit sync.Once
|
||||
|
||||
dataRaw *maps.Cache[sitesmatrix.Vector, *SimpleThreadSafeTree[any]]
|
||||
dataRaw *hmaps.Cache[sitesmatrix.Vector, *SimpleThreadSafeTree[any]]
|
||||
dataRawInit sync.Once
|
||||
|
||||
eventHandlersMu sync.Mutex
|
||||
|
||||
@@ -160,3 +160,31 @@ title: p10
|
||||
variant = `{{ template "_internal/pagination.html" (dict "page" . "format" "terse") }}`
|
||||
test(variant, expectedOutputTerseFormat)
|
||||
}
|
||||
|
||||
func TestOpengraphPartialIssue14433(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
files := `
|
||||
-- hugo.toml --
|
||||
baseURL = "https://example.org"
|
||||
-- content/_index.md --
|
||||
---
|
||||
title: Home
|
||||
---
|
||||
-- layouts/home.html --
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
{{- partial "opengraph.html" . }}
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
`
|
||||
b := Test(t, files)
|
||||
|
||||
b.AssertFileContent("public/index.html",
|
||||
`<meta property="og:title" content="Home">`,
|
||||
`! false`,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -38,10 +38,10 @@ import (
|
||||
"github.com/gohugoio/hugo/output"
|
||||
"github.com/gohugoio/hugo/parser/metadecoders"
|
||||
|
||||
"github.com/gohugoio/hugo/common/hmaps"
|
||||
"github.com/gohugoio/hugo/common/hsync"
|
||||
"github.com/gohugoio/hugo/common/htime"
|
||||
"github.com/gohugoio/hugo/common/hugo"
|
||||
"github.com/gohugoio/hugo/common/maps"
|
||||
"github.com/gohugoio/hugo/common/para"
|
||||
"github.com/gohugoio/hugo/common/terminal"
|
||||
"github.com/gohugoio/hugo/common/types"
|
||||
@@ -95,11 +95,11 @@ type HugoSites struct {
|
||||
// Now the different page dimensions (e.g. language) are built-in to the page trees above.
|
||||
// But we sill need to support the overridden translationKey, but that should
|
||||
// be relatively rare and low volume.
|
||||
translationKeyPages *maps.SliceCache[page.Page]
|
||||
translationKeyPages *hmaps.SliceCache[page.Page]
|
||||
|
||||
pageTrees *pageTrees
|
||||
previousPageTreesWalkContext *doctree.WalkContext[contentNode] // Set for rebuilds only.
|
||||
previousSeenTerms *maps.Map[term, sitesmatrix.Vectors] // Set for rebuilds only.
|
||||
previousPageTreesWalkContext *doctree.WalkContext[contentNode] // Set for rebuilds only.
|
||||
previousSeenTerms *hmaps.Map[term, sitesmatrix.Vectors] // Set for rebuilds only.
|
||||
|
||||
printUnusedTemplatesInit sync.Once
|
||||
printPathWarningsInit sync.Once
|
||||
|
||||
@@ -1034,7 +1034,9 @@ func (h *HugoSites) processPartialFileEvents(ctx context.Context, l logg.LevelLo
|
||||
changes = append(changes, identity.GenghisKhan)
|
||||
}
|
||||
if strings.Contains(base, "shortcodes") {
|
||||
changes = append(changes, hglob.NewGlobIdentity(fmt.Sprintf("shortcodes/%s*", pathInfo.BaseNameNoIdentifier())))
|
||||
// Add both the shortcode file itself (for template refresh) and a glob for dependent content
|
||||
changes = append(changes, pathInfo)
|
||||
changes = append(changes, hglob.NewGlobIdentity(fmt.Sprintf("/_shortcodes/%s*", pathInfo.BaseNameNoIdentifier())))
|
||||
} else {
|
||||
changes = append(changes, pathInfo)
|
||||
}
|
||||
|
||||
@@ -562,7 +562,7 @@ func TestSiteBuildTimeout(t *testing.T) {
|
||||
var filesBuilder strings.Builder
|
||||
filesBuilder.WriteString(`
|
||||
-- hugo.toml --
|
||||
timeout = 5
|
||||
timeout = '100ms'
|
||||
-- layouts/single.html --
|
||||
{{ .WordCount }}
|
||||
-- layouts/_shortcodes/c.html --
|
||||
@@ -571,7 +571,7 @@ timeout = 5
|
||||
{{ end }}
|
||||
`)
|
||||
|
||||
for i := 1; i < 100; i++ {
|
||||
for i := range 20 {
|
||||
filesBuilder.WriteString(fmt.Sprintf(`
|
||||
-- content/page%d.md --
|
||||
---
|
||||
|
||||
@@ -26,8 +26,8 @@ import (
|
||||
"github.com/gohugoio/hugo/common/herrors"
|
||||
"github.com/gohugoio/hugo/common/hexec"
|
||||
"github.com/gohugoio/hugo/common/himage"
|
||||
"github.com/gohugoio/hugo/common/hmaps"
|
||||
"github.com/gohugoio/hugo/common/loggers"
|
||||
"github.com/gohugoio/hugo/common/maps"
|
||||
"github.com/gohugoio/hugo/common/types"
|
||||
"github.com/gohugoio/hugo/config"
|
||||
"github.com/gohugoio/hugo/config/allconfig"
|
||||
@@ -858,12 +858,12 @@ func (s *IntegrationTestBuilder) initBuilder() error {
|
||||
}
|
||||
|
||||
if s.Cfg.Running {
|
||||
flags.Set("internal", maps.Params{
|
||||
flags.Set("internal", hmaps.Params{
|
||||
"running": s.Cfg.Running,
|
||||
"watch": s.Cfg.Running,
|
||||
})
|
||||
} else if s.Cfg.Watching {
|
||||
flags.Set("internal", maps.Params{
|
||||
flags.Set("internal", hmaps.Params{
|
||||
"watch": s.Cfg.Watching,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -29,9 +29,9 @@ import (
|
||||
"github.com/bep/logg"
|
||||
|
||||
"github.com/gohugoio/hugo/common/herrors"
|
||||
"github.com/gohugoio/hugo/common/hmaps"
|
||||
"github.com/gohugoio/hugo/common/hugio"
|
||||
"github.com/gohugoio/hugo/common/hugo"
|
||||
"github.com/gohugoio/hugo/common/maps"
|
||||
"github.com/gohugoio/hugo/common/predicate"
|
||||
"github.com/gohugoio/hugo/common/types/hstring"
|
||||
"github.com/gohugoio/hugo/helpers"
|
||||
@@ -114,7 +114,7 @@ func (m *pageMeta) newCachedContent(s *Site) (*cachedContent, error) {
|
||||
StaleInfo: m,
|
||||
pi: m.pi,
|
||||
enableEmoji: s.conf.EnableEmoji,
|
||||
scopes: maps.NewCache[string, *cachedContentScope](),
|
||||
scopes: hmaps.NewCache[string, *cachedContentScope](),
|
||||
}
|
||||
var hasName predicate.P[string] = m.pi.shortcodeParseInfo.hasName
|
||||
c.hasShortcode.Store(&hasName)
|
||||
@@ -136,7 +136,7 @@ type cachedContent struct {
|
||||
// Whether the content has a given shortcode name.
|
||||
hasShortcode atomic.Pointer[predicate.P[string]]
|
||||
|
||||
scopes *maps.Cache[string, *cachedContentScope]
|
||||
scopes *hmaps.Cache[string, *cachedContentScope]
|
||||
}
|
||||
|
||||
func (c *cachedContent) getOrCreateScope(scope string, pco *pageContentOutput) *cachedContentScope {
|
||||
|
||||
+12
-17
@@ -15,13 +15,12 @@ package hugolib
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"maps"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
xmaps "maps"
|
||||
|
||||
"github.com/bep/logg"
|
||||
"github.com/gobuffalo/flect"
|
||||
"github.com/gohugoio/hugo/hugofs"
|
||||
@@ -36,10 +35,10 @@ import (
|
||||
|
||||
"github.com/gohugoio/hugo/common/hashing"
|
||||
"github.com/gohugoio/hugo/common/hiter"
|
||||
"github.com/gohugoio/hugo/common/hmaps"
|
||||
"github.com/gohugoio/hugo/common/hugio"
|
||||
"github.com/gohugoio/hugo/common/hugo"
|
||||
"github.com/gohugoio/hugo/common/loggers"
|
||||
"github.com/gohugoio/hugo/common/maps"
|
||||
"github.com/gohugoio/hugo/common/paths"
|
||||
"github.com/gohugoio/hugo/config"
|
||||
"github.com/gohugoio/hugo/helpers"
|
||||
@@ -373,7 +372,7 @@ func (s *Site) newPageMetaFromPageMetasource(ms *pageMetaSource) (*pageMeta, err
|
||||
m := &pageMeta{
|
||||
pageMetaSource: ms,
|
||||
pageConfig: &pagemeta.PageConfigLate{
|
||||
Params: make(maps.Params),
|
||||
Params: make(hmaps.Params),
|
||||
},
|
||||
}
|
||||
return m, nil
|
||||
@@ -385,10 +384,6 @@ func (m *pageMeta) prepareRebuild() {
|
||||
m.pageConfig.Dates = m.datesOriginal
|
||||
}
|
||||
|
||||
func (m *pageMeta) Aliases() []string {
|
||||
return m.pageConfig.Aliases
|
||||
}
|
||||
|
||||
func (m *pageMeta) BundleType() string {
|
||||
switch m.pathInfo.Type() {
|
||||
case paths.TypeLeaf:
|
||||
@@ -470,7 +465,7 @@ func (m *pageMeta) IsPage() bool {
|
||||
return m.Kind() == kinds.KindPage
|
||||
}
|
||||
|
||||
func (m *pageMeta) Params() maps.Params {
|
||||
func (m *pageMeta) Params() hmaps.Params {
|
||||
return m.pageConfig.Params
|
||||
}
|
||||
|
||||
@@ -524,17 +519,17 @@ func (m *pageMeta) Weight() int {
|
||||
func (ps *pageState) setMetaPost(cascades *page.PageMatcherParamsConfigs) error {
|
||||
if ps.m.pageConfigSource.Frontmatter != nil {
|
||||
if ps.m.pageConfigSource.IsFromContentAdapter {
|
||||
ps.m.pageConfig.ContentAdapterData = xmaps.Clone(ps.m.pageConfigSource.Frontmatter)
|
||||
ps.m.pageConfig.ContentAdapterData = maps.Clone(ps.m.pageConfigSource.Frontmatter)
|
||||
} else {
|
||||
ps.m.pageConfig.Params = xmaps.Clone(ps.m.pageConfigSource.Frontmatter)
|
||||
ps.m.pageConfig.Params = maps.Clone(ps.m.pageConfigSource.Frontmatter)
|
||||
}
|
||||
}
|
||||
|
||||
if ps.m.pageConfig.Params == nil {
|
||||
ps.m.pageConfig.Params = make(maps.Params)
|
||||
ps.m.pageConfig.Params = make(hmaps.Params)
|
||||
}
|
||||
if ps.m.pageConfigSource.IsFromContentAdapter && ps.m.pageConfig.ContentAdapterData == nil {
|
||||
ps.m.pageConfig.ContentAdapterData = make(maps.Params)
|
||||
ps.m.pageConfig.ContentAdapterData = make(hmaps.Params)
|
||||
}
|
||||
|
||||
// Cascade defined on itself has higher priority than inherited ones.
|
||||
@@ -660,7 +655,7 @@ params:
|
||||
loki := strings.ToLower(k)
|
||||
|
||||
if loki == "params" {
|
||||
vv, err := maps.ToStringMapE(v)
|
||||
vv, err := hmaps.ToStringMapE(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -753,7 +748,7 @@ params:
|
||||
}
|
||||
pcfg.Params[loki] = pcfg.Aliases
|
||||
case "sitemap":
|
||||
pcfg.Sitemap, err = config.DecodeSitemap(ps.s.conf.Sitemap, maps.ToStringMap(v))
|
||||
pcfg.Sitemap, err = config.DecodeSitemap(ps.s.conf.Sitemap, hmaps.ToStringMap(v))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to decode sitemap config in front matter: %s", err)
|
||||
}
|
||||
@@ -771,7 +766,7 @@ params:
|
||||
switch vv := v.(type) {
|
||||
case []map[any]any:
|
||||
for _, vvv := range vv {
|
||||
resources = append(resources, maps.ToStringMap(vvv))
|
||||
resources = append(resources, hmaps.ToStringMap(vvv))
|
||||
}
|
||||
case []map[string]any:
|
||||
resources = append(resources, vv...)
|
||||
@@ -779,7 +774,7 @@ params:
|
||||
for _, vvv := range vv {
|
||||
switch vvvv := vvv.(type) {
|
||||
case map[any]any:
|
||||
resources = append(resources, maps.ToStringMap(vvvv))
|
||||
resources = append(resources, hmaps.ToStringMap(vvvv))
|
||||
case map[string]any:
|
||||
resources = append(resources, vvvv)
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@ package hugolib
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/gohugoio/hugo/identity"
|
||||
"github.com/gohugoio/hugo/output"
|
||||
@@ -113,6 +115,40 @@ type pageOutput struct {
|
||||
renderOnce bool // To make sure we at least try to render it once.
|
||||
}
|
||||
|
||||
func (po *pageOutput) Aliases() []string {
|
||||
conf := po.p.s.conf
|
||||
p := po.p
|
||||
f := po.f
|
||||
|
||||
// This is relatively cheap to create, and the common case is to call this once.
|
||||
// So avoid caching this value.
|
||||
aliases := make([]string, len(po.p.m.pageConfig.Aliases))
|
||||
for i, a := range po.p.m.pageConfig.Aliases {
|
||||
isRelative := !strings.HasPrefix(a, "/")
|
||||
var baseDir string
|
||||
if isRelative {
|
||||
// Form the baseDir by taking the resource's base target
|
||||
// and moving up one level to the parent.
|
||||
parentContext := path.Join(p.targetPaths().SubResourceBaseTarget, "..")
|
||||
baseDir = parentContext
|
||||
|
||||
} else {
|
||||
// Form the baseDir by prepending the content dimension
|
||||
// prefixes with the Output Format path.
|
||||
baseDir = path.Join("/", p.targetPathDescriptor.PrefixFilePath, f.Path)
|
||||
}
|
||||
|
||||
a = path.Join(baseDir, a)
|
||||
|
||||
if conf.C.IsUglyURLSection(p.Section()) && !strings.HasSuffix(a, ".html") {
|
||||
a += ".html"
|
||||
}
|
||||
|
||||
aliases[i] = a
|
||||
}
|
||||
return aliases
|
||||
}
|
||||
|
||||
func (po *pageOutput) incrRenderState() {
|
||||
po.renderState++
|
||||
po.renderOnce = true
|
||||
|
||||
@@ -22,7 +22,7 @@ import (
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/gohugoio/hugo/common/maps"
|
||||
"github.com/gohugoio/hugo/common/hmaps"
|
||||
"github.com/gohugoio/hugo/common/text"
|
||||
"github.com/gohugoio/hugo/identity"
|
||||
"github.com/gohugoio/hugo/tpl/tplimpl"
|
||||
@@ -67,7 +67,7 @@ func newPageContentOutput(po *pageOutput) (*pageContentOutput, error) {
|
||||
cp := &pageContentOutput{
|
||||
po: po,
|
||||
renderHooks: &renderHooks{},
|
||||
otherOutputs: maps.NewCache[uint64, *pageContentOutput](),
|
||||
otherOutputs: hmaps.NewCache[uint64, *pageContentOutput](),
|
||||
}
|
||||
return cp, nil
|
||||
}
|
||||
@@ -83,7 +83,7 @@ type pageContentOutput struct {
|
||||
|
||||
// Other pages involved in rendering of this page,
|
||||
// typically included with .RenderShortcodes.
|
||||
otherOutputs *maps.Cache[uint64, *pageContentOutput]
|
||||
otherOutputs *hmaps.Cache[uint64, *pageContentOutput]
|
||||
|
||||
contentRenderedVersion uint32 // Incremented on reset.
|
||||
contentRendered atomic.Bool // Set on content render.
|
||||
|
||||
+14
-1
@@ -571,6 +571,7 @@ date: 2012-01-12
|
||||
|
||||
func TestPageSummary(t *testing.T) {
|
||||
t.Parallel()
|
||||
htesting.SkipSlowTestUnlessCI(t)
|
||||
assertFunc := func(t *testing.T, ext string, pages page.Pages) {
|
||||
p := pages[0]
|
||||
checkPageTitle(t, p, "SimpleWithoutSummaryDelimiter")
|
||||
@@ -586,6 +587,7 @@ func TestPageSummary(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPageWithDelimiter(t *testing.T) {
|
||||
htesting.SkipSlowTestUnlessCI(t)
|
||||
t.Parallel()
|
||||
assertFunc := func(t *testing.T, ext string, pages page.Pages) {
|
||||
p := pages[0]
|
||||
@@ -600,6 +602,7 @@ func TestPageWithDelimiter(t *testing.T) {
|
||||
|
||||
func TestPageWithSummaryParameter(t *testing.T) {
|
||||
t.Parallel()
|
||||
htesting.SkipSlowTestUnlessCI(t)
|
||||
assertFunc := func(t *testing.T, ext string, pages page.Pages) {
|
||||
p := pages[0]
|
||||
checkPageTitle(t, p, "SimpleWithSummaryParameter")
|
||||
@@ -617,6 +620,9 @@ func TestPageWithSummaryParameter(t *testing.T) {
|
||||
// Issue #3854
|
||||
// Also see https://github.com/gohugoio/hugo/issues/3977
|
||||
func TestPageWithDateFields(t *testing.T) {
|
||||
t.Parallel()
|
||||
htesting.SkipSlowTestUnlessCI(t)
|
||||
|
||||
c := qt.New(t)
|
||||
pageWithDate := `---
|
||||
title: P%d
|
||||
@@ -633,7 +639,6 @@ Simple Page With Some Date`
|
||||
return fmt.Sprintf(pageWithDate, weight, weight, field)
|
||||
}
|
||||
|
||||
t.Parallel()
|
||||
assertFunc := func(t *testing.T, ext string, pages page.Pages) {
|
||||
c.Assert(len(pages) > 0, qt.Equals, true)
|
||||
for _, p := range pages {
|
||||
@@ -698,6 +703,7 @@ baseURL = "http://example.com/"
|
||||
}
|
||||
|
||||
func TestPageWithMoreTag(t *testing.T) {
|
||||
htesting.SkipSlowTestUnlessCI(t)
|
||||
t.Parallel()
|
||||
assertFunc := func(t *testing.T, ext string, pages page.Pages) {
|
||||
p := pages[0]
|
||||
@@ -797,6 +803,7 @@ Content: {{ .Content }}|
|
||||
|
||||
// #2973
|
||||
func TestSummaryWithHTMLTagsOnNextLine(t *testing.T) {
|
||||
htesting.SkipSlowTestUnlessCI(t)
|
||||
assertFunc := func(t *testing.T, ext string, pages page.Pages) {
|
||||
c := qt.New(t)
|
||||
p := pages[0]
|
||||
@@ -875,6 +882,7 @@ home = ["HTML", "JSON"]
|
||||
// Issue 8919
|
||||
func TestContentProviderWithCustomOutputFormat(t *testing.T) {
|
||||
t.Parallel()
|
||||
htesting.SkipSlowTestUnlessCI(t)
|
||||
|
||||
files := `
|
||||
-- hugo.toml --
|
||||
@@ -1150,6 +1158,7 @@ date = ["` + dateHandler + `", "date"]
|
||||
|
||||
func TestWordCountWithAllCJKRunesWithoutHasCJKLanguage(t *testing.T) {
|
||||
t.Parallel()
|
||||
htesting.SkipSlowTestUnlessCI(t)
|
||||
assertFunc := func(t *testing.T, ext string, pages page.Pages) {
|
||||
p := pages[0]
|
||||
if p.WordCount(context.Background()) != 8 {
|
||||
@@ -1162,6 +1171,7 @@ func TestWordCountWithAllCJKRunesWithoutHasCJKLanguage(t *testing.T) {
|
||||
|
||||
func TestWordCountWithAllCJKRunesHasCJKLanguage(t *testing.T) {
|
||||
t.Parallel()
|
||||
htesting.SkipSlowTestUnlessCI(t)
|
||||
settings := map[string]any{"hasCJKLanguage": true}
|
||||
|
||||
assertFunc := func(t *testing.T, ext string, pages page.Pages) {
|
||||
@@ -1175,6 +1185,7 @@ func TestWordCountWithAllCJKRunesHasCJKLanguage(t *testing.T) {
|
||||
|
||||
func TestWordCountWithMainEnglishWithCJKRunes(t *testing.T) {
|
||||
t.Parallel()
|
||||
htesting.SkipSlowTestUnlessCI(t)
|
||||
settings := map[string]any{"hasCJKLanguage": true}
|
||||
|
||||
assertFunc := func(t *testing.T, ext string, pages page.Pages) {
|
||||
@@ -1189,6 +1200,7 @@ func TestWordCountWithMainEnglishWithCJKRunes(t *testing.T) {
|
||||
|
||||
func TestWordCountWithIsCJKLanguageFalse(t *testing.T) {
|
||||
t.Parallel()
|
||||
htesting.SkipSlowTestUnlessCI(t)
|
||||
settings := map[string]any{
|
||||
"hasCJKLanguage": true,
|
||||
}
|
||||
@@ -1205,6 +1217,7 @@ func TestWordCountWithIsCJKLanguageFalse(t *testing.T) {
|
||||
|
||||
func TestWordCount(t *testing.T) {
|
||||
t.Parallel()
|
||||
htesting.SkipSlowTestUnlessCI(t)
|
||||
assertFunc := func(t *testing.T, ext string, pages page.Pages) {
|
||||
p := pages[0]
|
||||
if p.WordCount(context.Background()) != 483 {
|
||||
|
||||
@@ -20,8 +20,8 @@ import (
|
||||
"path/filepath"
|
||||
|
||||
"github.com/gohugoio/hugo/common/hashing"
|
||||
"github.com/gohugoio/hugo/common/hmaps"
|
||||
"github.com/gohugoio/hugo/common/hstore"
|
||||
"github.com/gohugoio/hugo/common/maps"
|
||||
"github.com/gohugoio/hugo/common/paths"
|
||||
"github.com/gohugoio/hugo/helpers"
|
||||
"github.com/gohugoio/hugo/hugofs"
|
||||
@@ -65,7 +65,7 @@ type pagesFromDataTemplateContext struct {
|
||||
}
|
||||
|
||||
func (p *pagesFromDataTemplateContext) toPathSitesMap(v any) (string, map[string]any, map[string]any, error) {
|
||||
m, err := maps.ToStringMapE(v)
|
||||
m, err := hmaps.ToStringMapE(v)
|
||||
if err != nil {
|
||||
return "", nil, nil, err
|
||||
}
|
||||
@@ -75,7 +75,7 @@ func (p *pagesFromDataTemplateContext) toPathSitesMap(v any) (string, map[string
|
||||
return "", nil, nil, fmt.Errorf("invalid path %q", path)
|
||||
}
|
||||
|
||||
sites := maps.ToStringMap(m["sites"])
|
||||
sites := hmaps.ToStringMap(m["sites"])
|
||||
|
||||
return path, sites, m, nil
|
||||
}
|
||||
@@ -161,7 +161,7 @@ func NewPagesFromTemplate(opts PagesFromTemplateOptions) *PagesFromTemplate {
|
||||
PagesFromTemplateOptions: opts,
|
||||
PagesFromTemplateDeps: opts.DepsFromSite(opts.Site),
|
||||
buildState: &BuildState{
|
||||
sourceInfosCurrent: maps.NewCache[string, *sourceInfo](),
|
||||
sourceInfosCurrent: hmaps.NewCache[string, *sourceInfo](),
|
||||
},
|
||||
store: hstore.NewScratch(),
|
||||
}
|
||||
@@ -231,8 +231,8 @@ type BuildState struct {
|
||||
NumPagesAdded uint64
|
||||
NumResourcesAdded uint64
|
||||
|
||||
sourceInfosCurrent *maps.Cache[string, *sourceInfo]
|
||||
sourceInfosPrevious *maps.Cache[string, *sourceInfo]
|
||||
sourceInfosCurrent *hmaps.Cache[string, *sourceInfo]
|
||||
sourceInfosPrevious *hmaps.Cache[string, *sourceInfo]
|
||||
}
|
||||
|
||||
func (b *BuildState) hash(v any) uint64 {
|
||||
@@ -304,7 +304,7 @@ func (b *BuildState) resolveDeletedPaths() {
|
||||
|
||||
func (b *BuildState) PrepareNextBuild() {
|
||||
b.sourceInfosPrevious = b.sourceInfosCurrent
|
||||
b.sourceInfosCurrent = maps.NewCache[string, *sourceInfo]()
|
||||
b.sourceInfosCurrent = hmaps.NewCache[string, *sourceInfo]()
|
||||
b.StaleVersion = 0
|
||||
b.DeletedPaths = nil
|
||||
b.ChangedIdentities = nil
|
||||
@@ -317,7 +317,7 @@ func (p PagesFromTemplate) CloneForSite(s page.Site) *PagesFromTemplate {
|
||||
p.PagesFromTemplateOptions.Site = s
|
||||
p.PagesFromTemplateDeps = p.PagesFromTemplateOptions.DepsFromSite(s)
|
||||
p.buildState = &BuildState{
|
||||
sourceInfosCurrent: maps.NewCache[string, *sourceInfo](),
|
||||
sourceInfosCurrent: hmaps.NewCache[string, *sourceInfo](),
|
||||
}
|
||||
return &p
|
||||
}
|
||||
|
||||
@@ -2093,3 +2093,39 @@ All.
|
||||
b.EditFileReplaceAll("content/mybundle/resource.txt", "This is a resource file.", "This is an edited resource file.").Build()
|
||||
b.AssertFileContent("public/mybundle/resource.txt", "This is an edited resource file.")
|
||||
}
|
||||
|
||||
// Issue #14207
|
||||
func TestRebuildAddShortcodeThenEditContentUsingIt(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
files := `
|
||||
-- hugo.toml --
|
||||
baseURL = "https://example.com"
|
||||
disableLiveReload = true
|
||||
-- layouts/single.html --
|
||||
Single: {{ .Title }}|{{ .Content }}|
|
||||
-- content/p1.md --
|
||||
---
|
||||
title: "P1"
|
||||
---
|
||||
Content before shortcode.
|
||||
`
|
||||
b := TestRunning(t, files)
|
||||
b.AssertFileContent("public/p1/index.html", "Single: P1|", "Content before shortcode.")
|
||||
|
||||
// Add a new shortcode file
|
||||
b.AddFiles(
|
||||
"layouts/_shortcodes/year.html", `{{- now.Format "2006" -}}`,
|
||||
).Build()
|
||||
|
||||
// Verify shortcode was registered
|
||||
ts := b.H.Sites[0].Deps.TemplateStore
|
||||
if ti := ts.LookupShortcodeByName("year"); ti == nil {
|
||||
t.Fatal("shortcode 'year' not found in cache after adding")
|
||||
}
|
||||
|
||||
// Now edit content to use the shortcode - this should find the shortcode
|
||||
currentYear := time.Now().Format("2006")
|
||||
b.EditFileReplaceAll("content/p1.md", "Content before shortcode.", "This is {{< year >}} wow.").Build()
|
||||
b.AssertFileContent("public/p1/index.html", "Single: P1|", fmt.Sprintf("This is %s wow.", currentYear))
|
||||
}
|
||||
|
||||
@@ -102,14 +102,14 @@ func (r RolesInternal) ResolveIndex(name string) int {
|
||||
return i
|
||||
}
|
||||
}
|
||||
panic(fmt.Sprintf("no role found for name %q", name))
|
||||
return -1
|
||||
}
|
||||
|
||||
// IndexMatch returns an iterator for the roles that match the filter.
|
||||
func (r RolesInternal) IndexMatch(match predicate.P[string]) (iter.Seq[int], error) {
|
||||
func (r RolesInternal) IndexMatch(match predicate.P[predicate.IndexString]) (iter.Seq[int], error) {
|
||||
return func(yield func(i int) bool) {
|
||||
for i, role := range r.Sorted {
|
||||
if match(role.Name) {
|
||||
if match(predicate.IndexString{Index: i, String: role.Name}) {
|
||||
if !yield(i) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -18,9 +18,9 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/gobwas/glob"
|
||||
"github.com/gohugoio/hugo/common/hmaps"
|
||||
"github.com/gohugoio/hugo/common/hugo"
|
||||
"github.com/gohugoio/hugo/common/loggers"
|
||||
"github.com/gohugoio/hugo/common/maps"
|
||||
"github.com/gohugoio/hugo/common/predicate"
|
||||
"github.com/gohugoio/hugo/config"
|
||||
hglob "github.com/gohugoio/hugo/hugofs/hglob"
|
||||
@@ -276,14 +276,14 @@ func getGlob(s string) (glob.Glob, error) {
|
||||
|
||||
func DecodeSegments(in map[string]any, segmentsToRender []string, logger loggers.Logger) (*config.ConfigNamespace[map[string]SegmentConfig, *Segments], error) {
|
||||
buildConfig := func(in any) (*Segments, any, error) {
|
||||
m, err := maps.ToStringMapE(in)
|
||||
m, err := hmaps.ToStringMapE(in)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if m == nil {
|
||||
m = map[string]any{}
|
||||
}
|
||||
m = maps.CleanConfigStringMap(m)
|
||||
m = hmaps.CleanConfigStringMap(m)
|
||||
|
||||
var segmentCfg map[string]SegmentConfig
|
||||
if err := mapstructure.WeakDecode(m, &segmentCfg); err != nil {
|
||||
|
||||
+24
-26
@@ -18,6 +18,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"maps"
|
||||
"mime"
|
||||
"net/url"
|
||||
"os"
|
||||
@@ -32,13 +33,13 @@ import (
|
||||
"github.com/bep/logg"
|
||||
"github.com/gohugoio/go-radix"
|
||||
"github.com/gohugoio/hugo/cache/dynacache"
|
||||
"github.com/gohugoio/hugo/common/hmaps"
|
||||
"github.com/gohugoio/hugo/common/hstore"
|
||||
"github.com/gohugoio/hugo/common/hsync"
|
||||
"github.com/gohugoio/hugo/common/htime"
|
||||
"github.com/gohugoio/hugo/common/hugio"
|
||||
"github.com/gohugoio/hugo/common/hugo"
|
||||
"github.com/gohugoio/hugo/common/loggers"
|
||||
"github.com/gohugoio/hugo/common/maps"
|
||||
"github.com/gohugoio/hugo/common/para"
|
||||
"github.com/gohugoio/hugo/common/types"
|
||||
"github.com/gohugoio/hugo/config"
|
||||
@@ -55,8 +56,6 @@ import (
|
||||
"github.com/gohugoio/hugo/modules"
|
||||
"github.com/gohugoio/hugo/resources"
|
||||
|
||||
xmaps "maps"
|
||||
|
||||
"github.com/gohugoio/hugo/tpl/tplimpl"
|
||||
"github.com/gohugoio/hugo/tpl/tplimplinit"
|
||||
|
||||
@@ -138,7 +137,8 @@ func (s *Site) resolveDimensionNames() types.Strings3 {
|
||||
}
|
||||
|
||||
type siteLanguageVersionRole struct {
|
||||
siteVector sitesmatrix.Vector
|
||||
siteVector sitesmatrix.Vector
|
||||
isDefaultLanguage bool
|
||||
|
||||
roleInternal roles.RoleInternal
|
||||
role roles.Role
|
||||
@@ -186,6 +186,10 @@ func (s siteLanguageVersionRole) Version() versions.Version {
|
||||
return s.version
|
||||
}
|
||||
|
||||
func (s siteLanguageVersionRole) isDefault() bool {
|
||||
return s.isDefaultLanguage && s.roleInternal.Default && s.versionInternal.Default
|
||||
}
|
||||
|
||||
func (s *Site) Debug() {
|
||||
fmt.Println("Debugging site", s.Lang(), "=>")
|
||||
// fmt.Println(s.pageMap.testDump())
|
||||
@@ -197,6 +201,15 @@ func NewHugoSites(cfg deps.DepsCfg) (*HugoSites, error) {
|
||||
rolesSorted := cfg.Configs.Base.Roles.Config.Sorted
|
||||
versionsSorted := cfg.Configs.Base.Versions.Config.Sorted
|
||||
|
||||
var (
|
||||
poolSizeKatex = 2
|
||||
poolSizeWebP = 1
|
||||
)
|
||||
if n := config.GetNumWorkerMultiplier(); n > 1 {
|
||||
poolSizeKatex = min(n, 8)
|
||||
poolSizeWebP = max(2, n/2)
|
||||
}
|
||||
|
||||
var logger loggers.Logger
|
||||
if cfg.TestLogger != nil {
|
||||
logger = cfg.TestLogger
|
||||
@@ -257,15 +270,14 @@ func NewHugoSites(cfg deps.DepsCfg) (*HugoSites, error) {
|
||||
warpc.Options{
|
||||
CompilationCacheDir: compilationCacheDir,
|
||||
|
||||
// Katex is relatively slow.
|
||||
PoolSize: 8,
|
||||
PoolSize: poolSizeKatex,
|
||||
Infof: logger.InfoCommand("katex").Logf,
|
||||
Warnf: logger.WarnCommand("katex").Logf,
|
||||
},
|
||||
// WebP options.
|
||||
warpc.Options{
|
||||
CompilationCacheDir: compilationCacheDir,
|
||||
PoolSize: 1,
|
||||
PoolSize: poolSizeWebP,
|
||||
Memory: 384, // 384 MiB (4096 MiB Max)
|
||||
Infof: logger.InfoCommand("webp").Logf,
|
||||
Warnf: logger.WarnCommand("webp").Logf,
|
||||
@@ -341,7 +353,8 @@ func NewHugoSites(cfg deps.DepsCfg) (*HugoSites, error) {
|
||||
frontmatterHandler: frontmatterHandler,
|
||||
store: hstore.NewScratch(),
|
||||
siteLanguageVersionRole: &siteLanguageVersionRole{
|
||||
siteVector: sitesmatrix.Vector{i, 0, 0},
|
||||
isDefaultLanguage: language.IsDefault(),
|
||||
siteVector: sitesmatrix.Vector{i, 0, 0},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -472,7 +485,7 @@ func newHugoSites(
|
||||
dynacache.OptionsPartition{Weight: 10, ClearWhen: dynacache.ClearOnRebuild},
|
||||
),
|
||||
cacheContentSource: dynacache.GetOrCreatePartition[uint64, *resources.StaleValue[[]byte]](d.MemCache, "/cont/src", dynacache.OptionsPartition{Weight: 70, ClearWhen: dynacache.ClearOnChange}),
|
||||
translationKeyPages: maps.NewSliceCache[page.Page](),
|
||||
translationKeyPages: hmaps.NewSliceCache[page.Page](),
|
||||
currentSite: first[0],
|
||||
skipRebuildForFilenames: make(map[string]bool),
|
||||
init: &hugoSitesInit{},
|
||||
@@ -663,7 +676,7 @@ func (s *Site) Lastmod() time.Time {
|
||||
}
|
||||
|
||||
// Returns the Params configured for this site.
|
||||
func (s *Site) Params() maps.Params {
|
||||
func (s *Site) Params() hmaps.Params {
|
||||
return s.conf.Params
|
||||
}
|
||||
|
||||
@@ -1134,7 +1147,7 @@ func (w *WhatChanged) Changes() []identity.Identity {
|
||||
if w == nil || w.ids == nil {
|
||||
return nil
|
||||
}
|
||||
return slices.Collect(xmaps.Keys(w.ids))
|
||||
return slices.Collect(maps.Keys(w.ids))
|
||||
}
|
||||
|
||||
func (w *WhatChanged) Drain() []identity.Identity {
|
||||
@@ -1747,21 +1760,6 @@ func (s *Site) render(ctx *siteRenderContext) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
if ctx.outIdx == 0 && s.h.buildCounter.Load() == 0 {
|
||||
// Note that even if disableAliases is set, the aliases themselves are
|
||||
// preserved on page. The motivation with this is to be able to generate
|
||||
// 301 redirects in a .htaccess file and similar using a custom output format.
|
||||
if !s.conf.DisableAliases {
|
||||
// Aliases must be rendered before pages.
|
||||
// Some sites, Hugo docs included, have faulty alias definitions that point
|
||||
// to itself or another real page. These will be overwritten in the next
|
||||
// step.
|
||||
if err = s.renderAliases(); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err = s.renderPages(ctx); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
+46
-78
@@ -154,6 +154,20 @@ func pageRenderer(
|
||||
}
|
||||
}
|
||||
|
||||
if !s.conf.DisableAliases && s.h.buildCounter.Load() == 0 {
|
||||
of := p.outputFormat()
|
||||
if of.IsHTML && of.Permalinkable {
|
||||
// Render any aliases for this page.
|
||||
if err := s.renderAliasesForPage(p); err != nil {
|
||||
if sendErr(err) {
|
||||
continue
|
||||
} else {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !p.render {
|
||||
// Nothing more to do for this page.
|
||||
continue
|
||||
@@ -203,8 +217,8 @@ func pageRenderer(
|
||||
}
|
||||
}
|
||||
|
||||
if p.IsHome() && p.outputFormat().IsHTML && s.siteVector.IsFirst() {
|
||||
if err = s.renderDefaultDimensionRedirect(p); err != nil {
|
||||
if p.IsHome() && p.outputFormat().IsHTML && s.isDefault() {
|
||||
if err = s.renderDefaultSiteRedirect(p); err != nil {
|
||||
if sendErr(err) {
|
||||
continue
|
||||
} else {
|
||||
@@ -300,86 +314,30 @@ func (s *Site) renderPaginator(p *pageState, templ *tplimpl.TemplInfo) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// renderAliases renders shell pages that simply have a redirect in the header.
|
||||
func (s *Site) renderAliases() error {
|
||||
w := &doctree.NodeShiftTreeWalker[contentNode]{
|
||||
Tree: s.pageMap.treePages,
|
||||
Handle: func(key string, n contentNode) (radix.WalkFlag, error) {
|
||||
p := n.(*pageState)
|
||||
|
||||
// We cannot alias a page that's not rendered.
|
||||
if p.m.noLink() || p.skipRender() {
|
||||
return radix.WalkContinue, nil
|
||||
}
|
||||
|
||||
if len(p.Aliases()) == 0 {
|
||||
return radix.WalkContinue, nil
|
||||
}
|
||||
|
||||
pathSeen := make(map[string]bool)
|
||||
for _, of := range p.OutputFormats() {
|
||||
if !of.Format.IsHTML {
|
||||
continue
|
||||
}
|
||||
|
||||
f := of.Format
|
||||
|
||||
if pathSeen[f.Path] {
|
||||
continue
|
||||
}
|
||||
pathSeen[f.Path] = true
|
||||
|
||||
plink := of.Permalink()
|
||||
|
||||
for _, a := range p.Aliases() {
|
||||
isRelative := !strings.HasPrefix(a, "/")
|
||||
|
||||
if isRelative {
|
||||
// Make alias relative, where "." will be on the
|
||||
// same directory level as the current page.
|
||||
basePath := path.Join(p.targetPaths().SubResourceBaseLink, "..")
|
||||
a = path.Join(basePath, a)
|
||||
|
||||
} else {
|
||||
// Make sure AMP and similar doesn't clash with regular aliases.
|
||||
a = path.Join(f.Path, a)
|
||||
}
|
||||
|
||||
if s.conf.C.IsUglyURLSection(p.Section()) && !strings.HasSuffix(a, ".html") {
|
||||
a += ".html"
|
||||
}
|
||||
|
||||
lang := p.Language().Lang
|
||||
|
||||
if s.h.Configs.IsMultihost && !strings.HasPrefix(a, "/"+lang) {
|
||||
// These need to be in its language root.
|
||||
a = path.Join(lang, a)
|
||||
}
|
||||
|
||||
err := s.writeDestAlias(a, plink, f, p)
|
||||
if err != nil {
|
||||
return radix.WalkStop, err
|
||||
}
|
||||
}
|
||||
}
|
||||
return radix.WalkContinue, nil
|
||||
},
|
||||
func (s *Site) renderAliasesForPage(p *pageState) error {
|
||||
po := p.pageOutput
|
||||
f := po.f
|
||||
plink := p.Permalink()
|
||||
for _, a := range p.Aliases() {
|
||||
err := s.writeDestAlias(a, plink, f, p)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return w.Walk(context.TODO())
|
||||
return nil
|
||||
}
|
||||
|
||||
// renderDefaultDimensionRedirect creates a redirect to the main dimension's home,
|
||||
// renderDefaultSiteRedirect creates a redirect to the default site's home,
|
||||
// depending on if it lives in sub folder (e.g. /en) or not.
|
||||
func (s *Site) renderDefaultDimensionRedirect(home *pageState) error {
|
||||
if s.conf.DisableDefaultLanguageRedirect || s.conf.DisableDefaultDimensionRedirect {
|
||||
// The default site is the site is the combination of defaultContentLanguage,
|
||||
// defaultContentVersion and defaultContentRole.
|
||||
func (s *Site) renderDefaultSiteRedirect(home *pageState) error {
|
||||
if s.conf.DisableDefaultLanguageRedirect || s.conf.DisableDefaultSiteRedirect {
|
||||
return nil
|
||||
}
|
||||
|
||||
shouldAdd := s.conf.DefaultContentLanguageInSubdir && !s.Conf.IsMultihost()
|
||||
shouldAdd = shouldAdd || s.conf.DefaultContentVersionInSubdir || s.conf.DefaultContentRoleInSubdir
|
||||
if !shouldAdd {
|
||||
return nil
|
||||
}
|
||||
addRedirectInRoot := s.conf.DefaultContentLanguageInSubdir && !s.Conf.IsMultihost()
|
||||
addRedirectInRoot = addRedirectInRoot || s.conf.DefaultContentVersionInSubdir || s.conf.DefaultContentRoleInSubdir
|
||||
|
||||
homeLink := home.pageOutput.targetPaths().Link // This doesn't have any baseURL paths in it.
|
||||
|
||||
@@ -388,10 +346,20 @@ func (s *Site) renderDefaultDimensionRedirect(home *pageState) error {
|
||||
|
||||
var ps []string
|
||||
if of.Path != "" {
|
||||
// For OutputFormats with a path, creating more than one alias will easily create path clashes without much value.
|
||||
ps = []string{paths.AddLeadingAndTrailingSlash(of.Path)}
|
||||
if addRedirectInRoot {
|
||||
// For OutputFormats with a path, creating more than one alias will easily create path clashes without much value.
|
||||
ps = []string{paths.AddLeadingAndTrailingSlash(of.Path)}
|
||||
}
|
||||
} else {
|
||||
ps = []string{"/"}
|
||||
if addRedirectInRoot {
|
||||
ps = append(ps, "/")
|
||||
}
|
||||
|
||||
if s.Conf.IsMultilingual() && !s.conf.DefaultContentLanguageInSubdir && !s.Conf.IsMultihost() {
|
||||
// Create redirect from e.g. /en => /
|
||||
ps = append(ps, homeLink+s.Lang()+"/")
|
||||
}
|
||||
|
||||
// /guest/v1.0.0/en/
|
||||
// /,/guest/,/guest/v1.0.0 = /guest/v1.0.0/en/
|
||||
// /guest/v1.0.0/
|
||||
|
||||
@@ -1281,8 +1281,23 @@ defaultContentLanguageInSubDir = true
|
||||
defaultContentVersionInSubDir = true
|
||||
defaultContentRoleInSubDir = true
|
||||
disableDefaultLanguageRedirect = false
|
||||
disableDefaultDimensionRedirect = false
|
||||
disableDefaultSiteRedirect = false
|
||||
defaultContentLanguage = "en"
|
||||
defaultContentVersion = "v1.0.0"
|
||||
defaultContentRole = "guest"
|
||||
[languages]
|
||||
[languages.en]
|
||||
weight = 2
|
||||
[languages.nn]
|
||||
weight = 1
|
||||
[versions]
|
||||
[versions."v1.0.0"]
|
||||
weight = 2
|
||||
[versions."v2.0.0"]
|
||||
weight = 1
|
||||
[roles]
|
||||
[roles.guest]
|
||||
[roles.member]
|
||||
[outputs]
|
||||
home = [ 'rss', 'amp', 'html']
|
||||
-- layouts/home.html --
|
||||
@@ -1334,7 +1349,7 @@ func TestSitesMatrixRedirectsDisableDefaultLanguageRedirect(t *testing.T) {
|
||||
}
|
||||
|
||||
runTest(strings.ReplaceAll(files, "disableDefaultLanguageRedirect = false", "disableDefaultLanguageRedirect = true"))
|
||||
runTest(strings.ReplaceAll(files, "disableDefaultDimensionRedirect = false", "disableDefaultDimensionRedirect = true"))
|
||||
runTest(strings.ReplaceAll(files, "disableDefaultSiteRedirect = false", "disableDefaultSiteRedirect = true"))
|
||||
}
|
||||
|
||||
func TestSitesMatrixRedirectsDefaultContentVersionInBase(t *testing.T) {
|
||||
@@ -1361,7 +1376,7 @@ defaultContentLanguageInSubDir = true
|
||||
defaultContentVersionInSubDir = true
|
||||
defaultContentRoleInSubDir = true
|
||||
disableDefaultLanguageRedirect = false
|
||||
disableDefaultDimensionRedirect = false
|
||||
disableDefaultSiteRedirect = false
|
||||
defaultContentLanguage = "en"
|
||||
[languages]
|
||||
[languages.en]
|
||||
@@ -1384,3 +1399,241 @@ Home.
|
||||
b.AssertFileContent("public/en/guest/v1.0.0/index.html", "Home.")
|
||||
b.AssertFileContent("public/en/guest/v1.0.0/amp/index.html", "Home.")
|
||||
}
|
||||
|
||||
func TestSitesMatrixRedirectsDefaultContentLanguageInBase(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
files := `
|
||||
-- hugo.yml --
|
||||
baseURL: https://example.org
|
||||
disableKinds: [taxonomy]
|
||||
defaultContentVersionInSubDir: true
|
||||
defaultContentRoleInSubDir: true
|
||||
defaultContentLanguage: en
|
||||
languages:
|
||||
en:
|
||||
languageName: English
|
||||
bn:
|
||||
languageName: Bengali
|
||||
fr:
|
||||
languageName: French
|
||||
-- layouts/all.html --
|
||||
All.
|
||||
|
||||
`
|
||||
b := hugolib.Test(t, files)
|
||||
|
||||
b.AssertFileContent("public/guest/v1.0.0/en/index.html", "url=https://example.org/guest/v1.0.0/\"", `lang="en"`)
|
||||
|
||||
files = strings.ReplaceAll(files, "defaultContentVersionInSubDir: true", "defaultContentVersionInSubDir: false")
|
||||
|
||||
b = hugolib.Test(t, files)
|
||||
b.AssertFileContent("public/guest/en/index.html", "url=https://example.org/guest/\"")
|
||||
}
|
||||
|
||||
func TestSitesMatrixRangeMatchers(t *testing.T) {
|
||||
t.Parallel()
|
||||
files := `TestSitesMatrixRangeMatchers
|
||||
-- hugo.toml --
|
||||
baseURL = "https://example.org/"
|
||||
defaultContentVersion = "v4.0.0"
|
||||
defaultContentVersionInSubDir = true
|
||||
disableKinds = ["taxonomy", "term", "rss", "sitemap"]
|
||||
|
||||
[languages]
|
||||
[languages.en]
|
||||
weight = 1
|
||||
|
||||
[versions]
|
||||
[versions."v1.0.0"]
|
||||
[versions."v2.0.0"]
|
||||
[versions."v2.1.0"]
|
||||
[versions."v3.0.0"]
|
||||
[versions."v4.0.0"]
|
||||
|
||||
-- content/_index.md --
|
||||
---
|
||||
title: "Home"
|
||||
sites:
|
||||
matrix:
|
||||
versions: ["**"]
|
||||
---
|
||||
-- content/p1.md --
|
||||
---
|
||||
title: "P1 from v2.0.0"
|
||||
sites:
|
||||
matrix:
|
||||
versions: [">= v2.0.0"]
|
||||
---
|
||||
Content for v2.0.0 and later.
|
||||
-- content/p2.md --
|
||||
---
|
||||
title: "P2 between v2 and v3"
|
||||
sites:
|
||||
matrix:
|
||||
versions: [">= v2.0.0", "<= v3.0.0"]
|
||||
---
|
||||
Content between v2.0.0 and v3.0.0 (inclusive).
|
||||
-- content/p3.md --
|
||||
---
|
||||
title: "P3 before v3"
|
||||
sites:
|
||||
matrix:
|
||||
versions: ["< v3.0.0"]
|
||||
---
|
||||
Content before v3.0.0.
|
||||
-- content/p4.md --
|
||||
---
|
||||
title: "P4 after v2"
|
||||
sites:
|
||||
matrix:
|
||||
versions: ["> v2.0.0"]
|
||||
---
|
||||
Content after v2.0.0 (exclusive).
|
||||
-- content/p5.md --
|
||||
---
|
||||
title: "P5 range with negation"
|
||||
sites:
|
||||
matrix:
|
||||
versions: [">= v2.0.0", "! v2.1.0", "<= v4.0.0"]
|
||||
---
|
||||
Content from v2.0.0 to v4.0.0 but not v2.1.0.
|
||||
-- layouts/all.html --
|
||||
Title: {{ .Title }}|
|
||||
`
|
||||
|
||||
b := hugolib.Test(t, files)
|
||||
|
||||
// P1: >= v2.0.0 should be in v2.0.0, v2.1.0, v3.0.0, v4.0.0
|
||||
b.AssertFileContent("public/v2.0.0/p1/index.html", "Title: P1 from v2.0.0|")
|
||||
b.AssertFileContent("public/v2.1.0/p1/index.html", "Title: P1 from v2.0.0|")
|
||||
b.AssertFileContent("public/v3.0.0/p1/index.html", "Title: P1 from v2.0.0|")
|
||||
b.AssertFileContent("public/v4.0.0/p1/index.html", "Title: P1 from v2.0.0|")
|
||||
b.AssertFileExists("public/v1.0.0/p1/index.html", false)
|
||||
|
||||
// P2: >= v2.0.0 AND <= v3.0.0 should be in v2.0.0, v2.1.0, v3.0.0
|
||||
b.AssertFileContent("public/v2.0.0/p2/index.html", "Title: P2 between v2 and v3|")
|
||||
b.AssertFileContent("public/v2.1.0/p2/index.html", "Title: P2 between v2 and v3|")
|
||||
b.AssertFileContent("public/v3.0.0/p2/index.html", "Title: P2 between v2 and v3|")
|
||||
b.AssertFileExists("public/v1.0.0/p2/index.html", false)
|
||||
b.AssertFileExists("public/v4.0.0/p2/index.html", false)
|
||||
|
||||
// P3: < v3.0.0 should be in v1.0.0, v2.0.0, v2.1.0
|
||||
b.AssertFileContent("public/v1.0.0/p3/index.html", "Title: P3 before v3|")
|
||||
b.AssertFileContent("public/v2.0.0/p3/index.html", "Title: P3 before v3|")
|
||||
b.AssertFileContent("public/v2.1.0/p3/index.html", "Title: P3 before v3|")
|
||||
b.AssertFileExists("public/v3.0.0/p3/index.html", false)
|
||||
b.AssertFileExists("public/v4.0.0/p3/index.html", false)
|
||||
|
||||
// P4: > v2.0.0 should be in v2.1.0, v3.0.0, v4.0.0
|
||||
b.AssertFileContent("public/v2.1.0/p4/index.html", "Title: P4 after v2|")
|
||||
b.AssertFileContent("public/v3.0.0/p4/index.html", "Title: P4 after v2|")
|
||||
b.AssertFileContent("public/v4.0.0/p4/index.html", "Title: P4 after v2|")
|
||||
b.AssertFileExists("public/v1.0.0/p4/index.html", false)
|
||||
b.AssertFileExists("public/v2.0.0/p4/index.html", false)
|
||||
|
||||
// P5: >= v2.0.0 AND ! v2.1.0 AND <= v4.0.0 should be in v2.0.0, v3.0.0, v4.0.0
|
||||
b.AssertFileContent("public/v2.0.0/p5/index.html", "Title: P5 range with negation|")
|
||||
b.AssertFileContent("public/v3.0.0/p5/index.html", "Title: P5 range with negation|")
|
||||
b.AssertFileContent("public/v4.0.0/p5/index.html", "Title: P5 range with negation|")
|
||||
b.AssertFileExists("public/v1.0.0/p5/index.html", false)
|
||||
b.AssertFileExists("public/v2.1.0/p5/index.html", false) // Excluded by negation
|
||||
}
|
||||
|
||||
func TestSitesMatrixFileMountOrder(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
files := `
|
||||
-- hugo.toml --
|
||||
baseURL = "https://example.org/"
|
||||
defaultContentVersion = "v1.0.0"
|
||||
defaultContentVersionInSubDir = true
|
||||
disableKinds = ["taxonomy", "term", "rss", "sitemap"]
|
||||
|
||||
[versions]
|
||||
[versions."v1.0.0"]
|
||||
[versions."v2.0.0"]
|
||||
|
||||
[[module.mounts]]
|
||||
source = 'content/v1'
|
||||
target = 'content'
|
||||
[module.mounts.sites.matrix]
|
||||
versions = ["**"]
|
||||
[[module.mounts]]
|
||||
source = 'content/v21'
|
||||
target = 'content'
|
||||
[module.mounts.sites.matrix]
|
||||
versions = ["v2.0.0"]
|
||||
[[module.mounts]]
|
||||
source = 'content/v22'
|
||||
target = 'content'
|
||||
[module.mounts.sites.matrix]
|
||||
versions = ["v2.0.0"]
|
||||
-- content/v1/p1.md --
|
||||
---
|
||||
title: "P1 v1"
|
||||
---
|
||||
-- content/v21/p1.md --
|
||||
---
|
||||
title: "P1 v21"
|
||||
---
|
||||
-- content/v22/p1.md --
|
||||
---
|
||||
title: "P1 v22"
|
||||
---
|
||||
-- layouts/all.html --
|
||||
Title: {{ .Title }}|
|
||||
`
|
||||
|
||||
b := hugolib.Test(t, files)
|
||||
|
||||
b.AssertFileContent("public/v1.0.0/p1/index.html", "Title: P1 v1|")
|
||||
b.AssertFileContent("public/v2.0.0/p1/index.html", "Title: P1 v1|")
|
||||
}
|
||||
|
||||
func TestSitesMatrixFileMountThemeIssue14414(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
files := `
|
||||
-- hugo.toml --
|
||||
|
||||
disableKinds = ["taxonomy", "term", "rss", "sitemap"]
|
||||
defaultContentVersion = "v1"
|
||||
defaultContentVersionInSubDir = true
|
||||
|
||||
[versions]
|
||||
[versions."v1"]
|
||||
[versions."v2"]
|
||||
|
||||
[module]
|
||||
[[module.mounts]]
|
||||
source = 'content'
|
||||
target = 'content'
|
||||
[module.mounts.sites.matrix]
|
||||
versions = '> v2.0.0'
|
||||
[[module.imports]]
|
||||
ignoreConfig = true
|
||||
path = 'mytheme'
|
||||
[[module.imports.mounts]]
|
||||
source = 'content'
|
||||
target = 'content'
|
||||
[module.imports.mounts.sites.matrix]
|
||||
versions = '<= v2.0.0'
|
||||
|
||||
-- themes/mytheme/content/p1.md --
|
||||
---
|
||||
title: "P1 from theme"
|
||||
---
|
||||
-- content/p1.md --
|
||||
---
|
||||
title: "P1 from site"
|
||||
---
|
||||
-- layouts/all.html --
|
||||
Title: {{ .Title }}|Version: {{ .Site.Version.Name }}|
|
||||
|
||||
`
|
||||
|
||||
b := hugolib.Test(t, files)
|
||||
|
||||
b.AssertFileContent("public/v1/p1/index.html", "Title: P1 from theme|Version: v1|")
|
||||
}
|
||||
|
||||
@@ -17,14 +17,14 @@ import (
|
||||
"cmp"
|
||||
"fmt"
|
||||
"iter"
|
||||
xmaps "maps"
|
||||
"maps"
|
||||
"slices"
|
||||
"sort"
|
||||
"sync"
|
||||
|
||||
"github.com/gohugoio/hashstructure"
|
||||
"github.com/gohugoio/hugo/common/hashing"
|
||||
"github.com/gohugoio/hugo/common/maps"
|
||||
"github.com/gohugoio/hugo/common/hmaps"
|
||||
"github.com/gohugoio/hugo/common/predicate"
|
||||
"github.com/gohugoio/hugo/common/types"
|
||||
"github.com/gohugoio/hugo/hugofs/hglob"
|
||||
@@ -250,7 +250,7 @@ func (s *vectorStoreMap) HasRole(i int) bool {
|
||||
func (s *vectorStoreMap) clone() *vectorStoreMap {
|
||||
c := *s
|
||||
c.h = &hashOnce{}
|
||||
c.sets = xmaps.Clone(s.sets)
|
||||
c.sets = maps.Clone(s.sets)
|
||||
return &c
|
||||
}
|
||||
|
||||
@@ -277,7 +277,7 @@ type ConfiguredDimensions struct {
|
||||
ConfiguredRoles ConfiguredDimension
|
||||
CommonSitesMatrix CommonSitestMatrix
|
||||
|
||||
singleVectorStoreCache *maps.Cache[Vector, *IntSets]
|
||||
singleVectorStoreCache *hmaps.Cache[Vector, *IntSets]
|
||||
}
|
||||
|
||||
func (c *ConfiguredDimensions) IsSingleVector() bool {
|
||||
@@ -295,7 +295,7 @@ func (c *ConfiguredDimensions) GetOrCreateSingleVectorStore(vec Vector) *IntSets
|
||||
}
|
||||
|
||||
func (c *ConfiguredDimensions) Init() error {
|
||||
c.singleVectorStoreCache = maps.NewCache[Vector, *IntSets]()
|
||||
c.singleVectorStoreCache = hmaps.NewCache[Vector, *IntSets]()
|
||||
b := NewIntSetsBuilder(c).WithDefaultsIfNotSet().Build()
|
||||
defaultVec := b.VectorSample()
|
||||
c.singleVectorStoreCache.Set(defaultVec, b)
|
||||
@@ -339,9 +339,9 @@ func (c *ConfiguredDimensions) ResolveVector(names types.Strings3) Vector {
|
||||
// IntSets holds the ordered sets of integers for the dimensions,
|
||||
// which is used for fast membership testing of files, resources and pages.
|
||||
type IntSets struct {
|
||||
languages *maps.OrderedIntSet `mapstructure:"-" json:"-"`
|
||||
versions *maps.OrderedIntSet `mapstructure:"-" json:"-"`
|
||||
roles *maps.OrderedIntSet `mapstructure:"-" json:"-"`
|
||||
languages *hmaps.OrderedIntSet `mapstructure:"-" json:"-"`
|
||||
versions *hmaps.OrderedIntSet `mapstructure:"-" json:"-"`
|
||||
roles *hmaps.OrderedIntSet `mapstructure:"-" json:"-"`
|
||||
|
||||
h *hashOnce
|
||||
}
|
||||
@@ -592,7 +592,7 @@ func (s IntSets) shallowClone() *IntSets {
|
||||
// WithLanguageIndices replaces the current language set with a single language index.
|
||||
func (s *IntSets) WithLanguageIndices(i int) VectorStore {
|
||||
c := s.shallowClone()
|
||||
c.languages = maps.NewOrderedIntSet(i)
|
||||
c.languages = hmaps.NewOrderedIntSet(i)
|
||||
return c.init()
|
||||
}
|
||||
|
||||
@@ -615,22 +615,22 @@ func (s *IntSets) MustHash() uint64 {
|
||||
// setDefaultsIfNotSet applies default values to the IntSets if they are not already set.
|
||||
func (s *IntSets) setDefaultsIfNotSet(cfg *ConfiguredDimensions) {
|
||||
if s.languages == nil {
|
||||
s.languages = maps.NewOrderedIntSet()
|
||||
s.languages = hmaps.NewOrderedIntSet()
|
||||
s.languages.Set(cfg.ConfiguredLanguages.IndexDefault())
|
||||
}
|
||||
if s.versions == nil {
|
||||
s.versions = maps.NewOrderedIntSet()
|
||||
s.versions = hmaps.NewOrderedIntSet()
|
||||
s.versions.Set(cfg.ConfiguredVersions.IndexDefault())
|
||||
}
|
||||
if s.roles == nil {
|
||||
s.roles = maps.NewOrderedIntSet()
|
||||
s.roles = hmaps.NewOrderedIntSet()
|
||||
s.roles.Set(cfg.ConfiguredRoles.IndexDefault())
|
||||
}
|
||||
}
|
||||
|
||||
func (s *IntSets) setDefaultsAndAllLAnguagesIfNotSet(cfg *ConfiguredDimensions) {
|
||||
if s.languages == nil {
|
||||
s.languages = maps.NewOrderedIntSet()
|
||||
s.languages = hmaps.NewOrderedIntSet()
|
||||
for i := range cfg.ConfiguredLanguages.ForEachIndex() {
|
||||
s.languages.Set(i)
|
||||
}
|
||||
@@ -640,19 +640,19 @@ func (s *IntSets) setDefaultsAndAllLAnguagesIfNotSet(cfg *ConfiguredDimensions)
|
||||
|
||||
func (s *IntSets) setAllIfNotSet(cfg *ConfiguredDimensions) {
|
||||
if s.languages == nil {
|
||||
s.languages = maps.NewOrderedIntSet()
|
||||
s.languages = hmaps.NewOrderedIntSet()
|
||||
for i := range cfg.ConfiguredLanguages.ForEachIndex() {
|
||||
s.languages.Set(i)
|
||||
}
|
||||
}
|
||||
if s.versions == nil {
|
||||
s.versions = maps.NewOrderedIntSet()
|
||||
s.versions = hmaps.NewOrderedIntSet()
|
||||
for i := range cfg.ConfiguredVersions.ForEachIndex() {
|
||||
s.versions.Set(i)
|
||||
}
|
||||
}
|
||||
if s.roles == nil {
|
||||
s.roles = maps.NewOrderedIntSet()
|
||||
s.roles = hmaps.NewOrderedIntSet()
|
||||
for i := range cfg.ConfiguredRoles.ForEachIndex() {
|
||||
s.roles.Set(i)
|
||||
}
|
||||
@@ -696,20 +696,20 @@ func (s *IntSets) setDimensionsFromOtherIfNotSet(other VectorIterator) {
|
||||
func (s *IntSets) setValuesInNilSets(vec Vector, setLang, setVer, setRole bool) {
|
||||
if setLang {
|
||||
if s.languages == nil {
|
||||
s.languages = maps.NewOrderedIntSet()
|
||||
s.languages = hmaps.NewOrderedIntSet()
|
||||
}
|
||||
s.languages.Set(vec.Language())
|
||||
}
|
||||
if setVer {
|
||||
if s.versions == nil {
|
||||
s.versions = maps.NewOrderedIntSet()
|
||||
s.versions = hmaps.NewOrderedIntSet()
|
||||
}
|
||||
s.versions.Set(vec.Version())
|
||||
}
|
||||
|
||||
if setRole {
|
||||
if s.roles == nil {
|
||||
s.roles = maps.NewOrderedIntSet()
|
||||
s.roles = hmaps.NewOrderedIntSet()
|
||||
}
|
||||
s.roles.Set(vec.Role())
|
||||
}
|
||||
@@ -737,12 +737,12 @@ func (b *IntSetsBuilder) Build() *IntSets {
|
||||
}
|
||||
|
||||
func (b *IntSetsBuilder) WithConfig(cfg IntSetsConfig) *IntSetsBuilder {
|
||||
applyFilter := func(what string, values []string, matcher ConfiguredDimension) (*maps.OrderedIntSet, error) {
|
||||
var result *maps.OrderedIntSet
|
||||
applyFilter := func(what string, values []string, matcher ConfiguredDimension) (*hmaps.OrderedIntSet, error) {
|
||||
var result *hmaps.OrderedIntSet
|
||||
if len(values) == 0 {
|
||||
|
||||
if cfg.ApplyDefaults > 0 {
|
||||
result = maps.NewOrderedIntSet()
|
||||
result = hmaps.NewOrderedIntSet()
|
||||
}
|
||||
switch cfg.ApplyDefaults {
|
||||
case IntSetsConfigApplyDefaultsIfNotSet:
|
||||
@@ -760,22 +760,19 @@ func (b *IntSetsBuilder) WithConfig(cfg IntSetsConfig) *IntSetsBuilder {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Dot separated globs.
|
||||
filter, err := predicate.NewStringPredicateFromGlobs(values, hglob.GetGlobDot)
|
||||
filter, err := predicate.NewIndexStringPredicateFromGlobsAndRanges(values, matcher.ResolveIndex, hglob.GetGlobDot)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create filter for %s: %w", what, err)
|
||||
}
|
||||
for _, pattern := range values {
|
||||
iter, err := matcher.IndexMatch(filter)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to match %s %q: %w", what, pattern, err)
|
||||
}
|
||||
for i := range iter {
|
||||
if result == nil {
|
||||
result = maps.NewOrderedIntSet()
|
||||
}
|
||||
result.Set(i)
|
||||
iter, err := matcher.IndexMatch(filter)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to match %s %q: %w", what, values, err)
|
||||
}
|
||||
for i := range iter {
|
||||
if result == nil {
|
||||
result = hmaps.NewOrderedIntSet()
|
||||
}
|
||||
result.Set(i)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
@@ -807,7 +804,7 @@ func (s *IntSetsBuilder) WithLanguageIndices(idxs ...int) *IntSetsBuilder {
|
||||
return s
|
||||
}
|
||||
if s.s.languages == nil {
|
||||
s.s.languages = maps.NewOrderedIntSet()
|
||||
s.s.languages = hmaps.NewOrderedIntSet()
|
||||
}
|
||||
for _, i := range idxs {
|
||||
s.s.languages.Set(i)
|
||||
@@ -835,7 +832,7 @@ func (s *IntSetsBuilder) WithDimensionsFromOtherIfNotSet(other VectorIterator) *
|
||||
return s
|
||||
}
|
||||
|
||||
func (b *IntSetsBuilder) WithSets(languages, versions, roles *maps.OrderedIntSet) *IntSetsBuilder {
|
||||
func (b *IntSetsBuilder) WithSets(languages, versions, roles *hmaps.OrderedIntSet) *IntSetsBuilder {
|
||||
b.s.languages = languages
|
||||
b.s.versions = versions
|
||||
b.s.roles = roles
|
||||
@@ -867,17 +864,17 @@ func (s *Sites) Equal(other Sites) bool {
|
||||
return s.Matrix.Equal(other.Matrix) && s.Complements.Equal(other.Complements)
|
||||
}
|
||||
|
||||
func (s *Sites) SetFromParamsIfNotSet(params maps.Params) {
|
||||
func (s *Sites) SetFromParamsIfNotSet(params hmaps.Params) {
|
||||
const (
|
||||
matrixKey = "matrix"
|
||||
complementsKey = "complements"
|
||||
)
|
||||
|
||||
if m, ok := params[matrixKey]; ok {
|
||||
s.Matrix.SetFromParamsIfNotSet(m.(maps.Params))
|
||||
s.Matrix.SetFromParamsIfNotSet(m.(hmaps.Params))
|
||||
}
|
||||
if f, ok := params[complementsKey]; ok {
|
||||
s.Complements.SetFromParamsIfNotSet(f.(maps.Params))
|
||||
s.Complements.SetFromParamsIfNotSet(f.(hmaps.Params))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -899,7 +896,7 @@ func (d StringSlices) Equal(other StringSlices) bool {
|
||||
slices.Equal(d.Roles, other.Roles)
|
||||
}
|
||||
|
||||
func (d *StringSlices) SetFromParamsIfNotSet(params maps.Params) {
|
||||
func (d *StringSlices) SetFromParamsIfNotSet(params hmaps.Params) {
|
||||
const (
|
||||
languagesKey = "languages"
|
||||
versionsKey = "versions"
|
||||
@@ -968,10 +965,10 @@ func (m *testDimension) ForEachIndex() iter.Seq[int] {
|
||||
}
|
||||
}
|
||||
|
||||
func (m *testDimension) IndexMatch(match predicate.P[string]) (iter.Seq[int], error) {
|
||||
func (m *testDimension) IndexMatch(match predicate.P[predicate.IndexString]) (iter.Seq[int], error) {
|
||||
return func(yield func(i int) bool) {
|
||||
for i, n := range m.names {
|
||||
if match(n) {
|
||||
if match(predicate.IndexString{Index: i, String: n}) {
|
||||
if !yield(i) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ import (
|
||||
|
||||
qt "github.com/frankban/quicktest"
|
||||
"github.com/gohugoio/hugo/common/hashing"
|
||||
"github.com/gohugoio/hugo/common/maps"
|
||||
"github.com/gohugoio/hugo/common/hmaps"
|
||||
"github.com/gohugoio/hugo/hugolib/sitesmatrix"
|
||||
)
|
||||
|
||||
@@ -31,27 +31,27 @@ func TestIntSets(t *testing.T) {
|
||||
testDims := newTestDims()
|
||||
|
||||
sets := sitesmatrix.NewIntSetsBuilder(testDims).WithSets(
|
||||
maps.NewOrderedIntSet(1, 2),
|
||||
maps.NewOrderedIntSet(1, 2, 3),
|
||||
maps.NewOrderedIntSet(1, 2, 3),
|
||||
hmaps.NewOrderedIntSet(1, 2),
|
||||
hmaps.NewOrderedIntSet(1, 2, 3),
|
||||
hmaps.NewOrderedIntSet(1, 2, 3),
|
||||
).Build()
|
||||
|
||||
sets2 := sitesmatrix.NewIntSetsBuilder(testDims).WithSets(
|
||||
maps.NewOrderedIntSet(1, 2),
|
||||
maps.NewOrderedIntSet(1, 2, 3),
|
||||
maps.NewOrderedIntSet(1, 2, 4),
|
||||
hmaps.NewOrderedIntSet(1, 2),
|
||||
hmaps.NewOrderedIntSet(1, 2, 3),
|
||||
hmaps.NewOrderedIntSet(1, 2, 4),
|
||||
).Build()
|
||||
|
||||
sets3 := sitesmatrix.NewIntSetsBuilder(testDims).WithSets(
|
||||
maps.NewOrderedIntSet(2, 1),
|
||||
maps.NewOrderedIntSet(1, 2, 3),
|
||||
maps.NewOrderedIntSet(2, 1, 4),
|
||||
hmaps.NewOrderedIntSet(2, 1),
|
||||
hmaps.NewOrderedIntSet(1, 2, 3),
|
||||
hmaps.NewOrderedIntSet(2, 1, 4),
|
||||
).Build()
|
||||
|
||||
sets4 := sitesmatrix.NewIntSetsBuilder(testDims).WithSets(
|
||||
maps.NewOrderedIntSet(3, 4, 5),
|
||||
maps.NewOrderedIntSet(3, 4, 5),
|
||||
maps.NewOrderedIntSet(3, 4, 5),
|
||||
hmaps.NewOrderedIntSet(3, 4, 5),
|
||||
hmaps.NewOrderedIntSet(3, 4, 5),
|
||||
hmaps.NewOrderedIntSet(3, 4, 5),
|
||||
).Build()
|
||||
|
||||
c.Assert(hashing.HashStringHex(sets), qt.Equals, "790f6004619934ff")
|
||||
@@ -68,24 +68,24 @@ func TestIntSets(t *testing.T) {
|
||||
c.Assert(sets.EqualsVector(sets), qt.Equals, true)
|
||||
c.Assert(sets.EqualsVector(
|
||||
sitesmatrix.NewIntSetsBuilder(testDims).WithSets(
|
||||
maps.NewOrderedIntSet(1, 2),
|
||||
maps.NewOrderedIntSet(1, 2, 3),
|
||||
maps.NewOrderedIntSet(1, 2, 3),
|
||||
hmaps.NewOrderedIntSet(1, 2),
|
||||
hmaps.NewOrderedIntSet(1, 2, 3),
|
||||
hmaps.NewOrderedIntSet(1, 2, 3),
|
||||
).Build(),
|
||||
), qt.Equals, true)
|
||||
c.Assert(sets.EqualsVector(
|
||||
sitesmatrix.NewIntSetsBuilder(testDims).WithSets(
|
||||
maps.NewOrderedIntSet(1, 2, 3),
|
||||
maps.NewOrderedIntSet(1, 2, 3, 4),
|
||||
maps.NewOrderedIntSet(1, 2, 3, 4),
|
||||
hmaps.NewOrderedIntSet(1, 2, 3),
|
||||
hmaps.NewOrderedIntSet(1, 2, 3, 4),
|
||||
hmaps.NewOrderedIntSet(1, 2, 3, 4),
|
||||
).Build(),
|
||||
), qt.Equals, false)
|
||||
|
||||
c.Assert(sets.EqualsVector(
|
||||
sitesmatrix.NewIntSetsBuilder(testDims).WithSets(
|
||||
maps.NewOrderedIntSet(1, 2),
|
||||
maps.NewOrderedIntSet(1, 2, 3),
|
||||
maps.NewOrderedIntSet(2, 3, 4),
|
||||
hmaps.NewOrderedIntSet(1, 2),
|
||||
hmaps.NewOrderedIntSet(1, 2, 3),
|
||||
hmaps.NewOrderedIntSet(2, 3, 4),
|
||||
).Build(),
|
||||
), qt.Equals, false)
|
||||
|
||||
@@ -126,17 +126,17 @@ func TestIntSetsComplement(t *testing.T) {
|
||||
testDims := newTestDims()
|
||||
|
||||
self := sitesmatrix.NewIntSetsBuilder(testDims).WithSets(
|
||||
maps.NewOrderedIntSet(test.left.v0...),
|
||||
maps.NewOrderedIntSet(test.left.v1...),
|
||||
maps.NewOrderedIntSet(test.left.v2...),
|
||||
hmaps.NewOrderedIntSet(test.left.v0...),
|
||||
hmaps.NewOrderedIntSet(test.left.v1...),
|
||||
hmaps.NewOrderedIntSet(test.left.v2...),
|
||||
).Build()
|
||||
|
||||
var input []sitesmatrix.VectorProvider
|
||||
for _, v := range test.input {
|
||||
input = append(input, sitesmatrix.NewIntSetsBuilder(testDims).WithSets(
|
||||
maps.NewOrderedIntSet(v.v0...),
|
||||
maps.NewOrderedIntSet(v.v1...),
|
||||
maps.NewOrderedIntSet(v.v2...),
|
||||
hmaps.NewOrderedIntSet(v.v0...),
|
||||
hmaps.NewOrderedIntSet(v.v1...),
|
||||
hmaps.NewOrderedIntSet(v.v2...),
|
||||
).Build())
|
||||
}
|
||||
|
||||
@@ -262,15 +262,15 @@ func TestIntSetsComplementOfComplement(t *testing.T) {
|
||||
testDims := newTestDims()
|
||||
|
||||
sets1 := sitesmatrix.NewIntSetsBuilder(testDims).WithSets(
|
||||
maps.NewOrderedIntSet(1),
|
||||
maps.NewOrderedIntSet(1),
|
||||
maps.NewOrderedIntSet(1),
|
||||
hmaps.NewOrderedIntSet(1),
|
||||
hmaps.NewOrderedIntSet(1),
|
||||
hmaps.NewOrderedIntSet(1),
|
||||
).Build()
|
||||
|
||||
sets2 := sitesmatrix.NewIntSetsBuilder(testDims).WithSets(
|
||||
maps.NewOrderedIntSet(1, 2),
|
||||
maps.NewOrderedIntSet(1),
|
||||
maps.NewOrderedIntSet(1, 3),
|
||||
hmaps.NewOrderedIntSet(1, 2),
|
||||
hmaps.NewOrderedIntSet(1),
|
||||
hmaps.NewOrderedIntSet(1, 3),
|
||||
).Build()
|
||||
|
||||
c1 := sets2.Complement(sets1)
|
||||
@@ -296,27 +296,27 @@ func BenchmarkIntSetsComplement(b *testing.B) {
|
||||
testDims := newTestDims()
|
||||
|
||||
sets1 := sitesmatrix.NewIntSetsBuilder(testDims).WithSets(
|
||||
maps.NewOrderedIntSet(1, 2, 3),
|
||||
maps.NewOrderedIntSet(1, 2, 3),
|
||||
maps.NewOrderedIntSet(1, 2, 3),
|
||||
hmaps.NewOrderedIntSet(1, 2, 3),
|
||||
hmaps.NewOrderedIntSet(1, 2, 3),
|
||||
hmaps.NewOrderedIntSet(1, 2, 3),
|
||||
).Build()
|
||||
|
||||
sets1Copy := sitesmatrix.NewIntSetsBuilder(testDims).WithSets(
|
||||
maps.NewOrderedIntSet(1, 2, 3),
|
||||
maps.NewOrderedIntSet(1, 2, 3),
|
||||
maps.NewOrderedIntSet(1, 2, 3),
|
||||
hmaps.NewOrderedIntSet(1, 2, 3),
|
||||
hmaps.NewOrderedIntSet(1, 2, 3),
|
||||
hmaps.NewOrderedIntSet(1, 2, 3),
|
||||
).Build()
|
||||
|
||||
sets2 := sitesmatrix.NewIntSetsBuilder(testDims).WithSets(
|
||||
maps.NewOrderedIntSet(1, 2, 3, 4),
|
||||
maps.NewOrderedIntSet(1, 2, 3, 4),
|
||||
maps.NewOrderedIntSet(1, 2, 3, 4, 6),
|
||||
hmaps.NewOrderedIntSet(1, 2, 3, 4),
|
||||
hmaps.NewOrderedIntSet(1, 2, 3, 4),
|
||||
hmaps.NewOrderedIntSet(1, 2, 3, 4, 6),
|
||||
).Build()
|
||||
|
||||
setsLanguage1 := sitesmatrix.NewIntSetsBuilder(testDims).WithSets(
|
||||
maps.NewOrderedIntSet(1),
|
||||
maps.NewOrderedIntSet(1),
|
||||
maps.NewOrderedIntSet(1),
|
||||
hmaps.NewOrderedIntSet(1),
|
||||
hmaps.NewOrderedIntSet(1),
|
||||
hmaps.NewOrderedIntSet(1),
|
||||
).Build()
|
||||
|
||||
b.ResetTimer()
|
||||
@@ -361,21 +361,21 @@ func BenchmarkSets(b *testing.B) {
|
||||
testDims := newTestDims()
|
||||
|
||||
sets1 := sitesmatrix.NewIntSetsBuilder(testDims).WithSets(
|
||||
maps.NewOrderedIntSet(1, 2),
|
||||
maps.NewOrderedIntSet(1, 2, 3),
|
||||
maps.NewOrderedIntSet(1, 2, 3),
|
||||
hmaps.NewOrderedIntSet(1, 2),
|
||||
hmaps.NewOrderedIntSet(1, 2, 3),
|
||||
hmaps.NewOrderedIntSet(1, 2, 3),
|
||||
).Build()
|
||||
|
||||
sets1Copy := sitesmatrix.NewIntSetsBuilder(testDims).WithSets(
|
||||
maps.NewOrderedIntSet(1, 2),
|
||||
maps.NewOrderedIntSet(1, 2, 3),
|
||||
maps.NewOrderedIntSet(1, 2, 3),
|
||||
hmaps.NewOrderedIntSet(1, 2),
|
||||
hmaps.NewOrderedIntSet(1, 2, 3),
|
||||
hmaps.NewOrderedIntSet(1, 2, 3),
|
||||
).Build()
|
||||
|
||||
sets2 := sitesmatrix.NewIntSetsBuilder(testDims).WithSets(
|
||||
maps.NewOrderedIntSet(1, 2, 3),
|
||||
maps.NewOrderedIntSet(1, 2, 3, 4),
|
||||
maps.NewOrderedIntSet(1, 2, 3, 4),
|
||||
hmaps.NewOrderedIntSet(1, 2, 3),
|
||||
hmaps.NewOrderedIntSet(1, 2, 3, 4),
|
||||
hmaps.NewOrderedIntSet(1, 2, 3, 4),
|
||||
).Build()
|
||||
|
||||
v1 := sitesmatrix.Vector{1, 2, 3}
|
||||
@@ -385,9 +385,9 @@ func BenchmarkSets(b *testing.B) {
|
||||
b.Run("Build", func(b *testing.B) {
|
||||
for b.Loop() {
|
||||
_ = sitesmatrix.NewIntSetsBuilder(testDims).WithSets(
|
||||
maps.NewOrderedIntSet(1, 2),
|
||||
maps.NewOrderedIntSet(1, 2, 3),
|
||||
maps.NewOrderedIntSet(1, 2, 3),
|
||||
hmaps.NewOrderedIntSet(1, 2),
|
||||
hmaps.NewOrderedIntSet(1, 2, 3),
|
||||
hmaps.NewOrderedIntSet(1, 2, 3),
|
||||
).Build()
|
||||
}
|
||||
})
|
||||
@@ -484,17 +484,17 @@ func TestVectorStoreMap(t *testing.T) {
|
||||
|
||||
c.Run("Complement", func(c *qt.C) {
|
||||
v1 := sitesmatrix.NewIntSetsBuilder(testDims).WithSets(
|
||||
maps.NewOrderedIntSet(1, 3),
|
||||
maps.NewOrderedIntSet(1),
|
||||
maps.NewOrderedIntSet(1, 3),
|
||||
hmaps.NewOrderedIntSet(1, 3),
|
||||
hmaps.NewOrderedIntSet(1),
|
||||
hmaps.NewOrderedIntSet(1, 3),
|
||||
).Build()
|
||||
|
||||
m := v1.ToVectorStoreMap()
|
||||
|
||||
v2 := sitesmatrix.NewIntSetsBuilder(testDims).WithSets(
|
||||
maps.NewOrderedIntSet(1, 2),
|
||||
maps.NewOrderedIntSet(1),
|
||||
maps.NewOrderedIntSet(1, 3),
|
||||
hmaps.NewOrderedIntSet(1, 2),
|
||||
hmaps.NewOrderedIntSet(1),
|
||||
hmaps.NewOrderedIntSet(1, 3),
|
||||
).Build()
|
||||
|
||||
complement := m.Complement(v2)
|
||||
@@ -509,9 +509,9 @@ func TestVectorStoreMap(t *testing.T) {
|
||||
func BenchmarkHasAnyVectorSingle(b *testing.B) {
|
||||
testDims := newTestDims()
|
||||
set := sitesmatrix.NewIntSetsBuilder(testDims).WithSets(
|
||||
maps.NewOrderedIntSet(0),
|
||||
maps.NewOrderedIntSet(0),
|
||||
maps.NewOrderedIntSet(0),
|
||||
hmaps.NewOrderedIntSet(0),
|
||||
hmaps.NewOrderedIntSet(0),
|
||||
hmaps.NewOrderedIntSet(0),
|
||||
).Build()
|
||||
|
||||
v := sitesmatrix.Vector{0, 0, 0}
|
||||
|
||||
@@ -64,6 +64,10 @@ type VersionInternal struct {
|
||||
// Name of the version.
|
||||
// This is the key from the config.
|
||||
Name string
|
||||
|
||||
// Parsed version of Name.
|
||||
parsedVersion version.Version
|
||||
|
||||
// Whether this version is the default version.
|
||||
// This will be by default rendered in the root.
|
||||
// There can only be one default version.
|
||||
@@ -104,14 +108,23 @@ func (r VersionsInternal) ResolveIndex(name string) int {
|
||||
return i
|
||||
}
|
||||
}
|
||||
panic(fmt.Sprintf("no version found for name %q", name))
|
||||
// Compare against parsed versions as well.
|
||||
v, err := version.ParseVersion(name)
|
||||
if err == nil {
|
||||
for i, version := range r.Sorted {
|
||||
if version.parsedVersion.Compare(v) == 0 {
|
||||
return i
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// IndexMatch returns an iterator for the versions that match the filter.
|
||||
func (r VersionsInternal) IndexMatch(match predicate.P[string]) (iter.Seq[int], error) {
|
||||
func (r VersionsInternal) IndexMatch(match predicate.P[predicate.IndexString]) (iter.Seq[int], error) {
|
||||
return func(yield func(i int) bool) {
|
||||
for i, version := range r.Sorted {
|
||||
if match(version.Name) {
|
||||
if match(predicate.IndexString{Index: i, String: version.Name}) {
|
||||
if !yield(i) {
|
||||
return
|
||||
}
|
||||
@@ -161,15 +174,17 @@ func (r *VersionsInternal) init(defaultContentVersion string) error {
|
||||
defaultSeen = true
|
||||
}
|
||||
|
||||
r.Sorted = append(r.Sorted, VersionInternal{Name: k, Default: isDefault, VersionConfig: v})
|
||||
// Ignore error, this may not be a semver version.
|
||||
parsedVersion, _ := version.ParseVersion(k)
|
||||
|
||||
r.Sorted = append(r.Sorted, VersionInternal{Name: k, parsedVersion: parsedVersion, Default: isDefault, VersionConfig: v})
|
||||
}
|
||||
|
||||
// Sort by weight if set, then semver descending.
|
||||
sort.SliceStable(r.Sorted, func(i, j int) bool {
|
||||
ri, rj := r.Sorted[i], r.Sorted[j]
|
||||
if ri.Weight == rj.Weight {
|
||||
v1, v2 := version.MustParseVersion(ri.Name), version.MustParseVersion(rj.Name)
|
||||
return v1.Compare(v2) < 0
|
||||
return ri.parsedVersion.Compare(rj.parsedVersion) < 0
|
||||
}
|
||||
if rj.Weight == 0 {
|
||||
return true
|
||||
|
||||
+6
-2
@@ -1,7 +1,11 @@
|
||||
# Release env.
|
||||
# These will be replaced by script before release.
|
||||
HUGORELEASER_TAG=v0.154.3
|
||||
HUGORELEASER_COMMITISH=b1c1bd019f4d65d4ebc979e2157279bb229b457f
|
||||
HUGORELEASER_TAG=v0.155.1
|
||||
HUGORELEASER_COMMITISH=f23576f2fb8d1b45d981a5e87e75b4cefa381592
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
+2
-2
@@ -16,14 +16,14 @@ package js
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gohugoio/hugo/common/maps"
|
||||
"github.com/gohugoio/hugo/common/hmaps"
|
||||
"github.com/gohugoio/hugo/resources/resource"
|
||||
)
|
||||
|
||||
// BatcherClient is used to do JS batch operations.
|
||||
type BatcherClient interface {
|
||||
New(id string) (Batcher, error)
|
||||
Store() *maps.Cache[string, Batcher]
|
||||
Store() *hmaps.Cache[string, Batcher]
|
||||
}
|
||||
|
||||
// BatchPackage holds a group of JavaScript resources.
|
||||
|
||||
@@ -31,9 +31,9 @@ import (
|
||||
|
||||
"github.com/evanw/esbuild/pkg/api"
|
||||
"github.com/gohugoio/hugo/cache/dynacache"
|
||||
"github.com/gohugoio/hugo/common/hmaps"
|
||||
"github.com/gohugoio/hugo/common/hsync"
|
||||
"github.com/gohugoio/hugo/common/hugio"
|
||||
"github.com/gohugoio/hugo/common/maps"
|
||||
"github.com/gohugoio/hugo/common/paths"
|
||||
"github.com/gohugoio/hugo/deps"
|
||||
"github.com/gohugoio/hugo/helpers"
|
||||
@@ -74,8 +74,8 @@ func NewBatcherClient(deps *deps.Deps) (js.BatcherClient, error) {
|
||||
d: deps,
|
||||
buildClient: NewBuildClient(deps.BaseFs.Assets, deps.ResourceSpec),
|
||||
createClient: create.New(deps.ResourceSpec),
|
||||
batcherStore: maps.NewCache[string, js.Batcher](),
|
||||
bundlesStore: maps.NewCache[string, js.BatchPackage](),
|
||||
batcherStore: hmaps.NewCache[string, js.Batcher](),
|
||||
bundlesStore: hmaps.NewCache[string, js.BatchPackage](),
|
||||
}
|
||||
|
||||
deps.BuildEndListeners.Add(func(...any) bool {
|
||||
@@ -196,8 +196,8 @@ type BatcherClient struct {
|
||||
createClient *create.Client
|
||||
buildClient *BuildClient
|
||||
|
||||
batcherStore *maps.Cache[string, js.Batcher]
|
||||
bundlesStore *maps.Cache[string, js.BatchPackage]
|
||||
batcherStore *hmaps.Cache[string, js.Batcher]
|
||||
bundlesStore *hmaps.Cache[string, js.BatchPackage]
|
||||
}
|
||||
|
||||
// New creates a new Batcher with the given ID.
|
||||
@@ -279,7 +279,7 @@ func (c *BatcherClient) New(id string) (js.Batcher, error) {
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func (c *BatcherClient) Store() *maps.Cache[string, js.Batcher] {
|
||||
func (c *BatcherClient) Store() *hmaps.Cache[string, js.Batcher] {
|
||||
return c.batcherStore
|
||||
}
|
||||
|
||||
@@ -435,15 +435,15 @@ func (b *batcher) doBuild(ctx context.Context) (*Package, error) {
|
||||
}
|
||||
|
||||
state := struct {
|
||||
importResource *maps.Cache[string, resource.Resource]
|
||||
resultResource *maps.Cache[string, resource.Resource]
|
||||
importerImportContext *maps.Cache[string, importContext]
|
||||
pathGroup *maps.Cache[string, string]
|
||||
importResource *hmaps.Cache[string, resource.Resource]
|
||||
resultResource *hmaps.Cache[string, resource.Resource]
|
||||
importerImportContext *hmaps.Cache[string, importContext]
|
||||
pathGroup *hmaps.Cache[string, string]
|
||||
}{
|
||||
importResource: maps.NewCache[string, resource.Resource](),
|
||||
resultResource: maps.NewCache[string, resource.Resource](),
|
||||
importerImportContext: maps.NewCache[string, importContext](),
|
||||
pathGroup: maps.NewCache[string, string](),
|
||||
importResource: hmaps.NewCache[string, resource.Resource](),
|
||||
resultResource: hmaps.NewCache[string, resource.Resource](),
|
||||
importerImportContext: hmaps.NewCache[string, importContext](),
|
||||
pathGroup: hmaps.NewCache[string, string](),
|
||||
}
|
||||
|
||||
multihostBasePaths := b.client.d.ResourceSpec.MultihostTargetBasePaths
|
||||
|
||||
@@ -24,6 +24,7 @@ import (
|
||||
|
||||
"github.com/bep/logg"
|
||||
"github.com/gohugoio/hugo/common/paths"
|
||||
"github.com/gohugoio/hugo/htesting"
|
||||
"github.com/gohugoio/hugo/hugolib"
|
||||
"github.com/gohugoio/hugo/internal/js/esbuild"
|
||||
)
|
||||
@@ -428,6 +429,7 @@ func TestBatchErrorScriptResourceInBundleSyntaxError(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestBatch(t *testing.T) {
|
||||
htesting.SkipSlowTestUnlessCI(t)
|
||||
files := `
|
||||
-- hugo.toml --
|
||||
disableKinds = ["taxonomy", "term"]
|
||||
|
||||
@@ -19,8 +19,8 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/gohugoio/hugo/common/hmaps"
|
||||
"github.com/gohugoio/hugo/common/hugio"
|
||||
"github.com/gohugoio/hugo/common/maps"
|
||||
"github.com/gohugoio/hugo/common/paths"
|
||||
"github.com/gohugoio/hugo/identity"
|
||||
|
||||
@@ -299,7 +299,7 @@ func (opts *Options) compile() (err error) {
|
||||
|
||||
var defines map[string]string
|
||||
if opts.Defines != nil {
|
||||
defines = maps.ToStringMapString(opts.Defines)
|
||||
defines = hmaps.ToStringMapString(opts.Defines)
|
||||
}
|
||||
|
||||
var drop api.Drop
|
||||
|
||||
@@ -18,16 +18,16 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/evanw/esbuild/pkg/api"
|
||||
"github.com/gohugoio/hugo/common/maps"
|
||||
"github.com/gohugoio/hugo/common/hmaps"
|
||||
"github.com/gohugoio/hugo/hugofs"
|
||||
"github.com/gohugoio/hugo/identity"
|
||||
"github.com/gohugoio/hugo/resources"
|
||||
"github.com/gohugoio/hugo/resources/resource"
|
||||
"github.com/spf13/afero"
|
||||
"slices"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -132,12 +132,12 @@ func ResolveResource(impPath string, resourceGetter resource.ResourceGetter) (r
|
||||
}
|
||||
|
||||
func newFSResolver(fs afero.Fs) *fsResolver {
|
||||
return &fsResolver{fs: fs, resolved: maps.NewCache[string, *hugofs.FileMeta]()}
|
||||
return &fsResolver{fs: fs, resolved: hmaps.NewCache[string, *hugofs.FileMeta]()}
|
||||
}
|
||||
|
||||
type fsResolver struct {
|
||||
fs afero.Fs
|
||||
resolved *maps.Cache[string, *hugofs.FileMeta]
|
||||
resolved *hmaps.Cache[string, *hugofs.FileMeta]
|
||||
}
|
||||
|
||||
func (r *fsResolver) resolveComponent(impPath string) *hugofs.FileMeta {
|
||||
|
||||
@@ -68,6 +68,7 @@ typedef struct
|
||||
int loopCount;
|
||||
int frameCount;
|
||||
int *frameDurations;
|
||||
bool hasAlpha;
|
||||
|
||||
} InputParams;
|
||||
|
||||
@@ -79,6 +80,7 @@ typedef struct
|
||||
int preset; // preset to use; resolved from hint.
|
||||
|
||||
bool useSharpYuv; // use sharp YUV for better quality.
|
||||
int method; // quality/speed trade-off (0=fast, 6=slower-better). Default is 2.
|
||||
|
||||
} InputOptions;
|
||||
|
||||
@@ -316,6 +318,7 @@ static uint8_t initEncoderConfig(WebPConfig *config, InputOptions opts)
|
||||
}
|
||||
|
||||
config->use_sharp_yuv = opts.useSharpYuv ? 1 : 0;
|
||||
config->method = opts.method;
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -410,6 +413,11 @@ InputMessage parse_input_message(const char *line)
|
||||
msg.data.options.hint[sizeof(msg.data.options.hint) - 1] = '\0';
|
||||
}
|
||||
msg.data.options.useSharpYuv = json_object_get_number(options_object, "useSharpYuv") != 0;
|
||||
msg.data.options.method = (int)json_object_get_number(options_object, "method");
|
||||
if (msg.data.options.method < 0 || msg.data.options.method > 6)
|
||||
{
|
||||
msg.data.options.method = 4; // default
|
||||
}
|
||||
if (msg.data.options.quality < 0 || msg.data.options.quality > 100)
|
||||
{
|
||||
msg.data.options.quality = 75; // default
|
||||
@@ -493,6 +501,7 @@ void write_output_message(const OutputMessage *msg)
|
||||
json_object_set_number(params_object, "width", msg->data.params.width);
|
||||
json_object_set_number(params_object, "height", msg->data.params.height);
|
||||
json_object_set_number(params_object, "stride", msg->data.params.stride);
|
||||
json_object_set_boolean(params_object, "hasAlpha", msg->data.params.hasAlpha);
|
||||
if (msg->data.params.frameDurations != NULL)
|
||||
{
|
||||
JSON_Value *durations_value = json_value_init_array();
|
||||
@@ -611,6 +620,7 @@ void handle_commands(FILE *stream)
|
||||
output.data.params.stride = anim_info.canvas_width * 4;
|
||||
output.data.params.frameCount = anim_info.frame_count;
|
||||
output.data.params.loopCount = anim_info.loop_count;
|
||||
output.data.params.hasAlpha = true; // Animated WebP always decoded as RGBA
|
||||
|
||||
int *frameDurations = malloc(sizeof(int) * anim_info.frame_count);
|
||||
if (frameDurations == NULL)
|
||||
@@ -680,7 +690,22 @@ void handle_commands(FILE *stream)
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t *output_buffer = WebPDecodeRGBA(blob_data, (size_t)blob_size, &output.data.params.width, &output.data.params.height);
|
||||
uint8_t *output_buffer;
|
||||
int bytesPerPixel;
|
||||
|
||||
output.data.params.hasAlpha = config.input.has_alpha;
|
||||
|
||||
if (config.input.has_alpha)
|
||||
{
|
||||
output_buffer = WebPDecodeRGBA(blob_data, (size_t)blob_size, &output.data.params.width, &output.data.params.height);
|
||||
bytesPerPixel = 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
output_buffer = WebPDecodeRGB(blob_data, (size_t)blob_size, &output.data.params.width, &output.data.params.height);
|
||||
bytesPerPixel = 3;
|
||||
}
|
||||
|
||||
if (output_buffer == NULL)
|
||||
{
|
||||
strncpy(output.header.err, "Failed to decode WebP", sizeof(output.header.err) - 1);
|
||||
@@ -688,7 +713,7 @@ void handle_commands(FILE *stream)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
output.data.params.stride = output.data.params.width * 4;
|
||||
output.data.params.stride = output.data.params.width * bytesPerPixel;
|
||||
|
||||
write_output_message(&output);
|
||||
|
||||
|
||||
@@ -30,9 +30,9 @@ import (
|
||||
|
||||
"github.com/bep/textandbinarywriter"
|
||||
|
||||
"github.com/gohugoio/hugo/common/hmaps"
|
||||
"github.com/gohugoio/hugo/common/hstrings"
|
||||
"github.com/gohugoio/hugo/common/hugio"
|
||||
"github.com/gohugoio/hugo/common/maps"
|
||||
"golang.org/x/sync/errgroup"
|
||||
|
||||
"github.com/tetratelabs/wazero"
|
||||
@@ -253,7 +253,7 @@ func (d *dispatcher[Q, R]) newCall(q Message[Q]) (*call[Q, R], error) {
|
||||
if err := q.init(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
responseKinds := maps.NewMap[string, bool]()
|
||||
responseKinds := hmaps.NewMap[string, bool]()
|
||||
for _, rk := range q.Header.ResponseKinds {
|
||||
responseKinds.Set(rk, true)
|
||||
}
|
||||
@@ -424,7 +424,7 @@ func (d *dispatcher[Q, R]) pendingCall(id uint32) *call[Q, R] {
|
||||
type call[Q, R any] struct {
|
||||
request Message[Q]
|
||||
response Message[R]
|
||||
responseKinds *maps.Map[string, bool]
|
||||
responseKinds *hmaps.Map[string, bool]
|
||||
err error
|
||||
donec chan *call[Q, R]
|
||||
}
|
||||
@@ -530,7 +530,11 @@ func Start[Q, R any](opts Options) (Dispatcher[Q, R], error) {
|
||||
opts.PoolSize = 1
|
||||
}
|
||||
|
||||
return newDispatcher[Q, R](opts)
|
||||
d, err := newDispatcher[Q, R](opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return d, nil
|
||||
}
|
||||
|
||||
type dispatcherPool[Q, R any] struct {
|
||||
|
||||
Binary file not shown.
+33
-7
@@ -34,9 +34,10 @@ var (
|
||||
)
|
||||
|
||||
type CommonImageProcessingParams struct {
|
||||
Width int `json:"width,omitempty"`
|
||||
Height int `json:"height,omitempty"`
|
||||
Stride int `json:"stride,omitempty"`
|
||||
Width int `json:"width,omitempty"`
|
||||
Height int `json:"height,omitempty"`
|
||||
Stride int `json:"stride,omitempty"`
|
||||
HasAlpha bool `json:"hasAlpha,omitempty"`
|
||||
|
||||
// For animated images.
|
||||
FrameDurations []int `json:"frameDurations,omitempty"`
|
||||
@@ -132,7 +133,7 @@ func (d *WebpCodec) Decode(r io.Reader) (image.Image, error) {
|
||||
}
|
||||
|
||||
if len(out.Data.Params.FrameDurations) > 0 {
|
||||
// Animated WebP.
|
||||
// Animated WebP (always RGBA).
|
||||
img := &WEBP{
|
||||
frameDurations: out.Data.Params.FrameDurations,
|
||||
loopCount: out.Data.Params.LoopCount,
|
||||
@@ -153,9 +154,35 @@ func (d *WebpCodec) Decode(r io.Reader) (image.Image, error) {
|
||||
return img, nil
|
||||
}
|
||||
|
||||
var pix []byte
|
||||
var nrgbaStride int
|
||||
|
||||
if out.Data.Params.HasAlpha {
|
||||
// RGBA data (4 bytes per pixel).
|
||||
pix = destination.Bytes()
|
||||
nrgbaStride = stride
|
||||
} else {
|
||||
// RGB data (3 bytes per pixel) - convert to NRGBA.
|
||||
rgbData := destination.Bytes()
|
||||
nrgbaStride = w * 4
|
||||
pix = make([]byte, nrgbaStride*h)
|
||||
for y := 0; y < h; y++ {
|
||||
srcIdx := y * stride
|
||||
dstIdx := y * nrgbaStride
|
||||
for x := 0; x < w; x++ {
|
||||
pix[dstIdx+0] = rgbData[srcIdx+0] // R
|
||||
pix[dstIdx+1] = rgbData[srcIdx+1] // G
|
||||
pix[dstIdx+2] = rgbData[srcIdx+2] // B
|
||||
pix[dstIdx+3] = 0xFF // A (fully opaque)
|
||||
srcIdx += 3
|
||||
dstIdx += 4
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
img := &image.NRGBA{
|
||||
Pix: destination.Bytes(),
|
||||
Stride: stride,
|
||||
Pix: pix,
|
||||
Stride: nrgbaStride,
|
||||
Rect: image.Rect(0, 0, w, h),
|
||||
}
|
||||
|
||||
@@ -294,7 +321,6 @@ func (d *WebpCodec) Encode(w io.Writer, img image.Image, opts map[string]any) er
|
||||
}
|
||||
|
||||
opts = maps.Clone(opts)
|
||||
opts["useSharpYuv"] = true // Use sharp (and slow) RGB->YUV conversion.
|
||||
|
||||
message := Message[WebpInput]{
|
||||
Header: Header{
|
||||
|
||||
@@ -120,3 +120,56 @@ sourcefilename: ../../resources/testdata/giphy.gif
|
||||
b.ImageHelper("public/anim_hu_edc2f24aaad2cee6.webp").AssertFormat("webp").AssertIsAnimated(true).AssertLoopCount(0).AssertFrameDurations(animFrameDurations)
|
||||
b.ImageHelper("public/anim_hu_58eb49733894e7ce.gif").AssertFormat("gif").AssertIsAnimated(true).AssertLoopCount(0).AssertFrameDurations(animFrameDurations)
|
||||
}
|
||||
|
||||
func BenchmarkWebp(b *testing.B) {
|
||||
files := `
|
||||
-- content/p1/sunrise.webp --
|
||||
sourcefilename: ../../resources/testdata/sunrise.webp
|
||||
-- content/p1/index.md --
|
||||
-- content/p2/sunrise.webp --
|
||||
sourcefilename: ../../resources/testdata/sunrise.webp
|
||||
-- content/p2/index.md --
|
||||
-- content/p3/sunrise.webp --
|
||||
sourcefilename: ../../resources/testdata/sunrise.webp
|
||||
-- content/p3/index.md --
|
||||
-- content/p4/sunrise.webp --
|
||||
sourcefilename: ../../resources/testdata/sunrise.webp
|
||||
-- content/p4/index.md --
|
||||
-- content/p5/sunrise.webp --
|
||||
sourcefilename: ../../resources/testdata/sunrise.webp
|
||||
-- content/p5/index.md --
|
||||
-- content/p6/sunrise.webp --
|
||||
sourcefilename: ../../resources/testdata/sunrise.webp
|
||||
-- content/p6/index.md --
|
||||
-- content/p7/sunrise.webp --
|
||||
sourcefilename: ../../resources/testdata/sunrise.webp
|
||||
-- content/p7/index.md --
|
||||
-- content/p8/sunrise.webp --
|
||||
sourcefilename: ../../resources/testdata/sunrise.webp
|
||||
-- content/p8/index.md --
|
||||
-- content/p9/sunrise.webp --
|
||||
sourcefilename: ../../resources/testdata/sunrise.webp
|
||||
-- content/p9/index.md --
|
||||
-- content/p10/sunrise.webp --
|
||||
sourcefilename: ../../resources/testdata/sunrise.webp
|
||||
-- content/p10/index.md --
|
||||
-- layouts/home.html --
|
||||
Home.
|
||||
-- layouts/page.html --
|
||||
{{ $image := .Resources.Get "sunrise.webp" }}
|
||||
{{ $resized := $image.Fit "400x300 webp" }}
|
||||
Resized RelPermalink: {{ $resized.RelPermalink }}|
|
||||
`
|
||||
|
||||
cfg := hugolib.IntegrationTestConfig{
|
||||
T: b,
|
||||
TxtarString: files,
|
||||
}
|
||||
|
||||
for b.Loop() {
|
||||
b.StopTimer()
|
||||
builder := hugolib.NewIntegrationTestBuilder(cfg).Init()
|
||||
b.StartTimer()
|
||||
builder.Build()
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -89,7 +89,7 @@ func (ls LanguagesInternal) ResolveIndex(name string) int {
|
||||
return i
|
||||
}
|
||||
}
|
||||
panic(fmt.Sprintf("no language found for name %q", name))
|
||||
return -1
|
||||
}
|
||||
|
||||
func (ls LanguagesInternal) Len() int {
|
||||
@@ -97,10 +97,10 @@ func (ls LanguagesInternal) Len() int {
|
||||
}
|
||||
|
||||
// IndexMatch returns an iterator for the roles that match the filter.
|
||||
func (ls LanguagesInternal) IndexMatch(match predicate.P[string]) (iter.Seq[int], error) {
|
||||
func (ls LanguagesInternal) IndexMatch(match predicate.P[predicate.IndexString]) (iter.Seq[int], error) {
|
||||
return func(yield func(i int) bool) {
|
||||
for i, l := range ls.Sorted {
|
||||
if match(l.Name) {
|
||||
if match(predicate.IndexString{Index: i, String: l.Name}) {
|
||||
if !yield(i) {
|
||||
return
|
||||
}
|
||||
|
||||
+4
-4
@@ -22,8 +22,8 @@ import (
|
||||
"golang.org/x/text/collate"
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"github.com/gohugoio/hugo/common/hmaps"
|
||||
"github.com/gohugoio/hugo/common/htime"
|
||||
"github.com/gohugoio/hugo/common/maps"
|
||||
"github.com/gohugoio/hugo/hugolib/sitesmatrix"
|
||||
"github.com/gohugoio/locales"
|
||||
translators "github.com/gohugoio/localescompressed"
|
||||
@@ -54,7 +54,7 @@ type Language struct {
|
||||
isDefault bool
|
||||
|
||||
// This is just an alias of Site.Params.
|
||||
params maps.Params
|
||||
params hmaps.Params
|
||||
}
|
||||
|
||||
// Name is an alias for Lang.
|
||||
@@ -114,7 +114,7 @@ var DeprecationFunc = func(item, alternative string, err bool) {}
|
||||
// Params returns the language params.
|
||||
// Note that this is the same as the Site.Params, but we keep it here for legacy reasons.
|
||||
// Deprecated: Use the site.Params instead.
|
||||
func (l *Language) Params() maps.Params {
|
||||
func (l *Language) Params() hmaps.Params {
|
||||
// TODO(bep) Remove this for now as it created a little too much noise. Need to think about this.
|
||||
// See https://github.com/gohugoio/hugo/issues/11025
|
||||
// DeprecationFunc(".Language.Params", paramsDeprecationWarning, false)
|
||||
@@ -167,7 +167,7 @@ func (l Languages) AsIndexSet() map[string]int {
|
||||
// Internal access to unexported Language fields.
|
||||
// This construct is to prevent them from leaking to the templates.
|
||||
|
||||
func SetParams(l *Language, params maps.Params) {
|
||||
func SetParams(l *Language, params hmaps.Params) {
|
||||
l.params = params
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user