mirror of
https://github.com/gohugoio/hugo.git
synced 2026-08-31 18:52:38 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7d976efdda |
@@ -4,7 +4,7 @@ parameters:
|
||||
defaults: &defaults
|
||||
resource_class: large
|
||||
docker:
|
||||
- image: bepsays/ci-hugoreleaser:1.22500.20400
|
||||
- image: bepsays/ci-hugoreleaser:1.22500.20300
|
||||
environment: &buildenv
|
||||
GOMODCACHE: /root/project/gomodcache
|
||||
version: 2
|
||||
@@ -58,7 +58,7 @@ jobs:
|
||||
environment:
|
||||
<<: [*buildenv]
|
||||
docker:
|
||||
- image: bepsays/ci-hugoreleaser-linux-arm64:1.22500.20400
|
||||
- image: bepsays/ci-hugoreleaser-linux-arm64:1.22500.20300
|
||||
steps:
|
||||
- *restore-cache
|
||||
- &attach-workspace
|
||||
|
||||
+4
-4
@@ -2,12 +2,12 @@ have_fun: false
|
||||
memory_config:
|
||||
disabled: false
|
||||
code_review:
|
||||
disable: false
|
||||
disable: true
|
||||
comment_severity_threshold: HIGH
|
||||
max_review_comments: -1
|
||||
pull_request_opened:
|
||||
help: true
|
||||
summary: false
|
||||
code_review: false
|
||||
help: false
|
||||
summary: true
|
||||
code_review: true
|
||||
include_drafts: false
|
||||
ignore_patterns: []
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
You are an expert at detecting AI-generated content. Your main tasks is to analyze pull requests and determine if they were likely generated by AI and if this is disclosed in the pull request description.
|
||||
|
||||
Important: You must start your response with a confidence score line in exactly this format:
|
||||
Confidence Score: X% where X is a number between 0 and 100.
|
||||
|
||||
Then provide your analysis in this format:
|
||||
Reasoning: (explain your analysis)
|
||||
Key Indicators: (list specific elements that suggest AI or human authorship)
|
||||
|
||||
A high confidence score (>80%) means you are very confident the content was AI-generated.
|
||||
A low confidence score (<20%) means you are very confident the content was human-generated.
|
||||
Use scores between 20-80% when there is uncertainty.
|
||||
|
||||
If there's a high confidence score:
|
||||
|
||||
* Add the label "Suspect AI" to the PR
|
||||
* If it's not disclosed that it's AI generated, add a link to [AI Assistance Notice](../CONTRIBUTING.md#ai-assistance-notice) in the contribution gudelines.
|
||||
@@ -1,10 +0,0 @@
|
||||
🛑 Before submitting this PR
|
||||
|
||||
All PRs must be linked to an Issue in this repository, and that Issue must be approved by a project maintainer:
|
||||
|
||||
- For a bug, approval means that the "needs triage" label is removed.
|
||||
- For a proposal, approval means that the "proposal" label is replaced by an "enhancement" label.
|
||||
|
||||
PRs without a linked, approved Issue will be closed immediately.
|
||||
|
||||
Please review the contribution guide (CONTRIBUTING.md) to understand commit message guidelines and AI assistance disclosures.
|
||||
@@ -2,21 +2,16 @@ name: AI Detection
|
||||
on:
|
||||
# Use pull_request_target instead of pull_request (we need the secrets.OPENAI_API_KEY to be available for forks)
|
||||
pull_request_target:
|
||||
types: [opened, ready_for_review]
|
||||
types: [opened, reopened, ready_for_review, synchronize]
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
jobs:
|
||||
detect-ai:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ !github.event.pull_request.draft }}
|
||||
steps:
|
||||
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1
|
||||
- name: AI Watchdog
|
||||
uses: bep/ai-watchdog@995475dd81767f8035dc2c943e9230918d06caca # temporary fork (probably)
|
||||
uses: Citric-Sheep/ai-watchdog@0db4a635d309db0f8d82642130dfc33e91cf33fa # v0.2.3
|
||||
with:
|
||||
openai-api-key: ${{ secrets.OPENAI_API_KEY }}
|
||||
pr-label: AI Suspect
|
||||
fail-when-confident: false
|
||||
# CSV list.
|
||||
pr-user-logins-skip: dependabot[bot],bep,jmooring
|
||||
|
||||
@@ -24,7 +24,9 @@ jobs:
|
||||
name: Free Disk Space (Ubuntu)
|
||||
uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be # v1.3.1
|
||||
with:
|
||||
tool-cache: true
|
||||
# this might remove tools that are actually needed,
|
||||
# if set to "true" but frees about 6 GB
|
||||
tool-cache: false
|
||||
android: true
|
||||
dotnet: true
|
||||
haskell: true
|
||||
@@ -46,12 +48,19 @@ jobs:
|
||||
uses: ruby/setup-ruby@8aeb6ff8030dd539317f8e1769a044873b56ea71 # v1.268.0
|
||||
with:
|
||||
ruby-version: "3.4.5"
|
||||
- name: Install Ruby gems
|
||||
- name: Install gems
|
||||
run: |
|
||||
gem install asciidoctor -v "2.0.26"
|
||||
gem install asciidoctor-diagram -v "3.1.0"
|
||||
gem install asciidoctor-diagram-ditaamini -v "1.0.3"
|
||||
- name: Install GoAT
|
||||
run: go install github.com/blampe/goat/cmd/goat@177de93b192b8ffae608e5d9ec421cc99bf68402
|
||||
- name: Install Java # required by asciidoctor-diagram-ditaamini
|
||||
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: "25"
|
||||
java-package: jre
|
||||
- name: Install Python
|
||||
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
|
||||
with:
|
||||
@@ -106,10 +115,7 @@ jobs:
|
||||
run: go install honnef.co/go/tools/cmd/staticcheck@latest
|
||||
- if: matrix.os == 'ubuntu-latest'
|
||||
name: Run staticcheck
|
||||
run: |
|
||||
export STATICCHECK_CACHE="${{ runner.temp }}/staticcheck"
|
||||
staticcheck ./...
|
||||
rm -rf ${{ runner.temp }}/staticcheck
|
||||
run: staticcheck ./...
|
||||
- if: matrix.os != 'windows-latest'
|
||||
name: Check
|
||||
run: |
|
||||
@@ -121,14 +127,16 @@ 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
|
||||
|
||||
+1
-2
@@ -3,5 +3,4 @@
|
||||
imports.*
|
||||
dist/
|
||||
public/
|
||||
.DS_Store
|
||||
cache/filecache/_gen/
|
||||
.DS_Store
|
||||
@@ -1 +0,0 @@
|
||||
tpl/tplimpl/embedded/templates/**
|
||||
@@ -1,14 +0,0 @@
|
||||
* 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 `./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/...`.
|
||||
* 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.
|
||||
* 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 metadata
|
||||
- Image processing – Convert, resize, crop, rotate, adjust colors, apply filters, overlay text and images, and extract EXIF data
|
||||
- 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
|
||||
@@ -65,6 +65,8 @@ See the [features] section of the documentation for a comprehensive summary of H
|
||||
|
||||
<p> </p>
|
||||
<p float="left">
|
||||
<a href="https://www.linode.com/?utm_campaign=hugosponsor&utm_medium=banner&utm_source=hugogithub" target="_blank"><img src="https://raw.githubusercontent.com/gohugoio/hugoDocs/master/assets/images/sponsors/linode-logo_standard_light_medium.png" width="200" alt="Linode"></a>
|
||||
|
||||
<a href="https://www.jetbrains.com/go/?utm_source=OSS&utm_medium=referral&utm_campaign=hugo" target="_blank"><img src="https://raw.githubusercontent.com/gohugoio/hugoDocs/master/assets/images/sponsors/goland.svg" width="200" alt="The complete IDE crafted for professional Go developers."></a>
|
||||
|
||||
<a href="https://cloudcannon.com/hugo-cms/?utm_campaign=HugoSponsorship&utm_source=sponsor&utm_content=gohugo" target="_blank"><img src="https://raw.githubusercontent.com/gohugoio/hugoDocs/master/assets/images/sponsors/cloudcannon-cms-logo.svg" width="200" alt="CloudCannon"></a>
|
||||
@@ -72,17 +74,21 @@ See the [features] section of the documentation for a comprehensive summary of H
|
||||
|
||||
## Editions
|
||||
|
||||
Hugo offers a standard edition with core features, plus extended and extended/deploy editions with more. Use the standard edition unless you need the features below.
|
||||
Hugo is available in three editions: standard, extended, and extended/deploy. While the standard edition provides core functionality, the extended and extended/deploy editions offer advanced features.
|
||||
|
||||
Feature|extended edition|extended/deploy edition
|
||||
:--|:-:|:-:
|
||||
[Transpile Sass to CSS] via embedded LibSass. Note that embedded LibSass was deprecated in v0.153.0 and will be removed in a future release. Use the [Dart Sass] transpiler instead, which is compatible with any edition.|:heavy_check_mark:|:heavy_check_mark:
|
||||
Encode to the WebP format when [processing images]. You can decode WebP images with any edition.|:heavy_check_mark:|:heavy_check_mark:
|
||||
[Transpile Sass to CSS] using the embedded LibSass transpiler. You can use the [Dart Sass] transpiler with any edition.|:heavy_check_mark:|:heavy_check_mark:
|
||||
Deploy your site directly to a Google Cloud Storage bucket, an AWS S3 bucket, or an Azure Storage container. See [details].|:x:|:heavy_check_mark:
|
||||
|
||||
[dart sass]: https://gohugo.io/functions/css/sass/#dart-sass
|
||||
[processing images]: https://gohugo.io/content-management/image-processing/
|
||||
[transpile sass to css]: https://gohugo.io/functions/css/sass/
|
||||
[details]: https://gohugo.io/hosting-and-deployment/hugo-deploy/
|
||||
|
||||
Unless your specific deployment needs require the extended/deploy edition, we recommend the extended edition.
|
||||
|
||||
## Installation
|
||||
|
||||
Install Hugo from a [prebuilt binary], package manager, or package repository. Please see the installation instructions for your operating system:
|
||||
@@ -156,16 +162,6 @@ If there is sufficient interest, [create a proposal]. Do not submit a pull reque
|
||||
|
||||
For a complete guide to contributing to Hugo, see the [Contribution Guide](CONTRIBUTING.md).
|
||||
|
||||
## License
|
||||
|
||||
For the Hugo source code, see [LICENSE](/LICENSE).
|
||||
|
||||
We also bundle some libraries in binary/WASM form:
|
||||
|
||||
* [libwebp](https://github.com/webmproject/libwebp), [BSD-3-Clause license](https://github.com/webmproject/libwebp?tab=BSD-3-Clause-1-ov-file#readme)
|
||||
* [Katex](https://github.com/KaTeX/KaTeX), [MIT license](https://github.com/KaTeX/KaTeX?tab=MIT-1-ov-file#readme)
|
||||
* [QuickJS](https://github.com/bellard/quickjs?tab=License-1-ov-file#readme), [License](https://github.com/bellard/quickjs?tab=License-1-ov-file#readme)
|
||||
|
||||
## Dependencies
|
||||
|
||||
Hugo stands on the shoulders of great open source libraries. Run `hugo env --logLevel info` to display a list of dependencies.
|
||||
@@ -175,55 +171,51 @@ Hugo stands on the shoulders of great open source libraries. Run `hugo env --log
|
||||
|
||||
```text
|
||||
github.com/BurntSushi/locker="v0.0.0-20171006230638-a6e239ea1c69"
|
||||
github.com/JohannesKaufmann/dom="v0.2.0"
|
||||
github.com/JohannesKaufmann/html-to-markdown/v2="v2.5.0"
|
||||
github.com/alecthomas/chroma/v2="v2.21.1"
|
||||
github.com/aymerick/douceur="v0.2.0"
|
||||
github.com/PuerkitoBio/goquery="v1.10.1"
|
||||
github.com/alecthomas/chroma/v2="v2.15.0"
|
||||
github.com/andybalholm/cascadia="v1.3.3"
|
||||
github.com/armon/go-radix="v1.0.1-0.20221118154546-54df44f2176c"
|
||||
github.com/bep/clocks="v0.5.0"
|
||||
github.com/bep/debounce="v1.2.0"
|
||||
github.com/bep/gitmap="v1.9.0"
|
||||
github.com/bep/gitmap="v1.6.0"
|
||||
github.com/bep/goat="v0.5.0"
|
||||
github.com/bep/godartsass/v2="v2.5.0"
|
||||
github.com/bep/godartsass/v2="v2.3.2"
|
||||
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.0"
|
||||
github.com/bep/lazycache="v0.8.0"
|
||||
github.com/bep/gowebp="v0.3.0"
|
||||
github.com/bep/imagemeta="v0.8.4"
|
||||
github.com/bep/lazycache="v0.7.0"
|
||||
github.com/bep/logg="v0.4.0"
|
||||
github.com/bep/mclib="v1.20400.20402"
|
||||
github.com/bep/overlayfs="v0.10.0"
|
||||
github.com/bep/simplecobra="v0.6.1"
|
||||
github.com/bep/textandbinarywriter="v0.0.0-20251212174530-cd9f0732f60f"
|
||||
github.com/bep/overlayfs="v0.9.2"
|
||||
github.com/bep/simplecobra="v0.5.0"
|
||||
github.com/bep/tmc="v0.5.1"
|
||||
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/clipperhouse/displaywidth="v0.6.0"
|
||||
github.com/clipperhouse/stringish="v0.1.1"
|
||||
github.com/clipperhouse/uax29/v2="v2.3.0"
|
||||
github.com/cpuguy83/go-md2man/v2="v2.0.6"
|
||||
github.com/cpuguy83/go-md2man/v2="v2.0.4"
|
||||
github.com/disintegration/gift="v1.2.1"
|
||||
github.com/dlclark/regexp2="v1.11.5"
|
||||
github.com/evanw/esbuild="v0.27.2"
|
||||
github.com/dop251/goja="v0.0.0-20250125213203-5ef83b82af17"
|
||||
github.com/evanw/esbuild="v0.24.2"
|
||||
github.com/fatih/color="v1.18.0"
|
||||
github.com/frankban/quicktest="v1.14.6"
|
||||
github.com/fsnotify/fsnotify="v1.9.0"
|
||||
github.com/getkin/kin-openapi="v0.133.0"
|
||||
github.com/fsnotify/fsnotify="v1.8.0"
|
||||
github.com/getkin/kin-openapi="v0.129.0"
|
||||
github.com/ghodss/yaml="v1.0.0"
|
||||
github.com/go-openapi/jsonpointer="v0.21.0"
|
||||
github.com/go-openapi/swag="v0.23.0"
|
||||
github.com/go-sourcemap/sourcemap="v2.1.4+incompatible"
|
||||
github.com/gobuffalo/flect="v1.0.3"
|
||||
github.com/gobwas/glob="v0.2.3"
|
||||
github.com/goccy/go-yaml="v1.19.1"
|
||||
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"
|
||||
github.com/gohugoio/httpcache="v0.8.0"
|
||||
github.com/gohugoio/hugo-goldmark-extensions/extras="v0.5.0"
|
||||
github.com/gohugoio/hugo-goldmark-extensions/passthrough="v0.3.1"
|
||||
github.com/gohugoio/go-i18n/v2="v2.1.3-0.20230805085216-e63c13218d0e"
|
||||
github.com/gohugoio/hashstructure="v0.5.0"
|
||||
github.com/gohugoio/httpcache="v0.7.0"
|
||||
github.com/gohugoio/hugo-goldmark-extensions/extras="v0.2.0"
|
||||
github.com/gohugoio/hugo-goldmark-extensions/passthrough="v0.3.0"
|
||||
github.com/gohugoio/locales="v0.14.0"
|
||||
github.com/gohugoio/localescompressed="v1.0.1"
|
||||
github.com/google/go-cmp="v0.7.0"
|
||||
github.com/gorilla/css="v1.0.1"
|
||||
github.com/golang/freetype="v0.0.0-20170609003504-e2365dfdc4a0"
|
||||
github.com/google/go-cmp="v0.6.0"
|
||||
github.com/google/pprof="v0.0.0-20250208200701-d0013a598941"
|
||||
github.com/gorilla/websocket="v1.5.3"
|
||||
github.com/hairyhenderson/go-codeowners="v0.7.0"
|
||||
github.com/hashicorp/golang-lru/v2="v2.0.7"
|
||||
@@ -232,57 +224,58 @@ github.com/josharian/intern="v1.0.0"
|
||||
github.com/kr/pretty="v0.3.1"
|
||||
github.com/kr/text="v0.2.0"
|
||||
github.com/kyokomi/emoji/v2="v2.2.13"
|
||||
github.com/lucasb-eyer/go-colorful="v1.2.0"
|
||||
github.com/mailru/easyjson="v0.7.7"
|
||||
github.com/makeworld-the-better-one/dither/v2="v2.4.0"
|
||||
github.com/marekm4/color-extractor="v1.2.1"
|
||||
github.com/mattn/go-colorable="v0.1.13"
|
||||
github.com/mattn/go-isatty="v0.0.20"
|
||||
github.com/mattn/go-runewidth="v0.0.19"
|
||||
github.com/microcosm-cc/bluemonday="v1.0.27"
|
||||
github.com/mattn/go-runewidth="v0.0.9"
|
||||
github.com/mazznoer/csscolorparser="v0.1.5"
|
||||
github.com/mitchellh/mapstructure="v1.5.1-0.20231216201459-8508981c8b6c"
|
||||
github.com/mohae/deepcopy="v0.0.0-20170929034955-c48cc78d4826"
|
||||
github.com/muesli/smartcrop="v0.3.0"
|
||||
github.com/niklasfasching/go-org="v1.9.1"
|
||||
github.com/oasdiff/yaml3="v0.0.0-20250309153720-d2182401db90"
|
||||
github.com/oasdiff/yaml="v0.0.0-20250309154309-f31be36b4037"
|
||||
github.com/olekukonko/cat="v0.0.0-20250911104152-50322a0618f6"
|
||||
github.com/olekukonko/errors="v1.1.0"
|
||||
github.com/olekukonko/ll="v0.1.3"
|
||||
github.com/olekukonko/tablewriter="v1.1.2"
|
||||
github.com/niklasfasching/go-org="v1.7.0"
|
||||
github.com/oasdiff/yaml3="v0.0.0-20241210130736-a94c01f36349"
|
||||
github.com/oasdiff/yaml="v0.0.0-20241210131133-6b86fb107d80"
|
||||
github.com/olekukonko/tablewriter="v0.0.5"
|
||||
github.com/pbnjay/memory="v0.0.0-20210728143218-7b4eea64cf58"
|
||||
github.com/pelletier/go-toml/v2="v2.2.4"
|
||||
github.com/pelletier/go-toml/v2="v2.2.3"
|
||||
github.com/perimeterx/marshmallow="v1.1.5"
|
||||
github.com/pkg/browser="v0.0.0-20240102092130-5ac0b6a4141c"
|
||||
github.com/pkg/errors="v0.9.1"
|
||||
github.com/rogpeppe/go-internal="v1.14.1"
|
||||
github.com/rivo/uniseg="v0.4.7"
|
||||
github.com/rogpeppe/go-internal="v1.13.1"
|
||||
github.com/russross/blackfriday/v2="v2.1.0"
|
||||
github.com/sass/dart-sass/compiler="1.97.1"
|
||||
github.com/sass/dart-sass/implementation="1.97.1"
|
||||
github.com/sass/dart-sass/protocol="3.2.0"
|
||||
github.com/spf13/afero="v1.15.0"
|
||||
github.com/spf13/cast="v1.10.0"
|
||||
github.com/spf13/cobra="v1.10.2"
|
||||
github.com/sass/libsass="3.6.6"
|
||||
github.com/spf13/afero="v1.11.0"
|
||||
github.com/spf13/cast="v1.7.1"
|
||||
github.com/spf13/cobra="v1.8.1"
|
||||
github.com/spf13/fsync="v0.10.1"
|
||||
github.com/spf13/pflag="v1.0.9"
|
||||
github.com/tdewolff/minify/v2="v2.24.8"
|
||||
github.com/tdewolff/parse/v2="v2.8.5"
|
||||
github.com/tetratelabs/wazero="v1.10.1"
|
||||
github.com/webmproject/libwebp="v1.6.0"
|
||||
github.com/woodsbury/decimal128="v1.3.0"
|
||||
github.com/yuin/goldmark-emoji="v1.0.6"
|
||||
github.com/yuin/goldmark="v1.7.13"
|
||||
github.com/spf13/pflag="v1.0.6"
|
||||
github.com/tdewolff/minify/v2="v2.20.37"
|
||||
github.com/tdewolff/parse/v2="v2.7.15"
|
||||
github.com/tetratelabs/wazero="v1.8.2"
|
||||
github.com/webmproject/libwebp="v1.3.2"
|
||||
github.com/yuin/goldmark-emoji="v1.0.4"
|
||||
github.com/yuin/goldmark="v1.7.8"
|
||||
go.uber.org/automaxprocs="v1.5.3"
|
||||
go.yaml.in/yaml/v3="v3.0.4"
|
||||
golang.org/x/crypto="v0.46.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/sync="v0.19.0"
|
||||
golang.org/x/sys="v0.39.0"
|
||||
golang.org/x/text="v0.32.0"
|
||||
golang.org/x/tools="v0.40.0"
|
||||
google.golang.org/protobuf="v1.36.10"
|
||||
golang.org/x/crypto="v0.33.0"
|
||||
golang.org/x/exp="v0.0.0-20250210185358-939b2ce775ac"
|
||||
golang.org/x/image="v0.24.0"
|
||||
golang.org/x/mod="v0.23.0"
|
||||
golang.org/x/net="v0.35.0"
|
||||
golang.org/x/sync="v0.11.0"
|
||||
golang.org/x/sys="v0.30.0"
|
||||
golang.org/x/text="v0.22.0"
|
||||
golang.org/x/tools="v0.30.0"
|
||||
golang.org/x/xerrors="v0.0.0-20240903120638-7835f813f4da"
|
||||
gonum.org/v1/plot="v0.15.0"
|
||||
google.golang.org/protobuf="v1.36.5"
|
||||
gopkg.in/yaml.v2="v2.4.0"
|
||||
gopkg.in/yaml.v3="v3.0.1"
|
||||
oss.terrastruct.com/d2="v0.6.9"
|
||||
oss.terrastruct.com/util-go="v0.0.0-20241005222610-44c011a04896"
|
||||
rsc.io/qr="v0.2.0"
|
||||
software.sslmate.com/src/go-pkcs12="v0.2.0"
|
||||
```
|
||||
|
||||
Vendored
+2
-2
@@ -69,7 +69,7 @@ func New(opts Options) *Cache {
|
||||
|
||||
infol := opts.Log.InfoCommand("dynacache")
|
||||
|
||||
evictedIdentities := collections.NewStackThreadSafe[KeyIdentity]()
|
||||
evictedIdentities := collections.NewStack[KeyIdentity]()
|
||||
|
||||
onEvict := func(k, v any) {
|
||||
if !opts.Watching {
|
||||
@@ -129,7 +129,7 @@ type Cache struct {
|
||||
partitions map[string]PartitionManager
|
||||
|
||||
onEvict func(k, v any)
|
||||
evictedIdentities *collections.StackThreadSafe[KeyIdentity]
|
||||
evictedIdentities *collections.Stack[KeyIdentity]
|
||||
|
||||
opts Options
|
||||
infol logg.LevelLogger
|
||||
|
||||
Vendored
+11
-55
@@ -16,7 +16,6 @@ package filecache
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@@ -55,11 +54,7 @@ type Cache struct {
|
||||
|
||||
nlocker *lockTracker
|
||||
|
||||
isResourceDir bool
|
||||
baseDir string
|
||||
|
||||
initOnce sync.Once
|
||||
isInited bool
|
||||
initErr error
|
||||
}
|
||||
|
||||
@@ -114,14 +109,9 @@ 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
|
||||
}
|
||||
})
|
||||
@@ -296,32 +286,8 @@ 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) ([]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) {
|
||||
func (c *Cache) GetBytes(id string) (ItemInfo, []byte, error) {
|
||||
if err := c.init(); err != nil {
|
||||
return ItemInfo{}, nil, err
|
||||
}
|
||||
@@ -451,17 +417,6 @@ 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)]
|
||||
@@ -469,19 +424,24 @@ func (f Caches) Get(name string) *Cache {
|
||||
|
||||
// NewCaches creates a new set of file caches from the given
|
||||
// configuration.
|
||||
func NewCaches(dcfg Configs, sourceFs afero.Fs) (Caches, error) {
|
||||
// dcfg := p.Cfg.GetConfigSection("caches").(Configs)
|
||||
fs := sourceFs
|
||||
func NewCaches(p *helpers.PathSpec) (Caches, error) {
|
||||
dcfg := p.Cfg.GetConfigSection("caches").(Configs)
|
||||
fs := p.Fs.Source
|
||||
|
||||
m := make(Caches)
|
||||
for k, v := range dcfg {
|
||||
var cfs afero.Fs
|
||||
|
||||
if v.IsResourceDir {
|
||||
cfs = nil // Set later. TODO(bep) this needs to be cleanded up.
|
||||
cfs = p.BaseFs.ResourcesCache
|
||||
} else {
|
||||
cfs = fs
|
||||
}
|
||||
|
||||
if cfs == nil {
|
||||
panic("nil fs")
|
||||
}
|
||||
|
||||
baseDir := v.DirCompiled
|
||||
|
||||
bfs := hugofs.NewBasePathFs(cfs, baseDir)
|
||||
@@ -491,11 +451,7 @@ func NewCaches(dcfg Configs, sourceFs afero.Fs) (Caches, error) {
|
||||
pruneAllRootDir = "pkg"
|
||||
}
|
||||
|
||||
c := NewCache(bfs, v.MaxAge, pruneAllRootDir)
|
||||
c.isResourceDir = v.IsResourceDir
|
||||
c.baseDir = baseDir
|
||||
|
||||
m[k] = c
|
||||
m[k] = NewCache(bfs, v.MaxAge, pruneAllRootDir)
|
||||
}
|
||||
|
||||
return m, nil
|
||||
|
||||
Vendored
+9
-49
@@ -15,7 +15,6 @@
|
||||
package filecache
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"path"
|
||||
@@ -23,7 +22,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gohugoio/hugo/common/hmaps"
|
||||
"github.com/gohugoio/hugo/common/maps"
|
||||
"github.com/gohugoio/hugo/config"
|
||||
|
||||
"github.com/mitchellh/mapstructure"
|
||||
@@ -41,39 +40,27 @@ var defaultCacheConfig = FileCacheConfig{
|
||||
}
|
||||
|
||||
const (
|
||||
CacheKeyGetJSON = "getjson"
|
||||
CacheKeyGetCSV = "getcsv"
|
||||
CacheKeyImages = "images"
|
||||
CacheKeyAssets = "assets"
|
||||
CacheKeyModules = "modules"
|
||||
CacheKeyModuleQueries = "modulequeries"
|
||||
CacheKeyGetResource = "getresource"
|
||||
CacheKeyMisc = "misc"
|
||||
CacheKeyGetJSON = "getjson"
|
||||
CacheKeyGetCSV = "getcsv"
|
||||
CacheKeyImages = "images"
|
||||
CacheKeyAssets = "assets"
|
||||
CacheKeyModules = "modules"
|
||||
CacheKeyGetResource = "getresource"
|
||||
CacheKeyMisc = "misc"
|
||||
)
|
||||
|
||||
type Configs map[string]FileCacheConfig
|
||||
|
||||
// CacheDirModules returns the compiled path to the modules cache.
|
||||
// For internal use.
|
||||
func (c Configs) CacheDirModules() string {
|
||||
return c[CacheKeyModules].DirCompiled
|
||||
}
|
||||
|
||||
// CacheDirMisc returns the compiled path to the misc cache.
|
||||
// For internal use.
|
||||
func (c Configs) CacheDirMisc() string {
|
||||
return c[CacheKeyMisc].DirCompiled
|
||||
}
|
||||
|
||||
var defaultCacheConfigs = Configs{
|
||||
CacheKeyModules: {
|
||||
MaxAge: -1,
|
||||
Dir: ":cacheDir/modules",
|
||||
},
|
||||
CacheKeyModuleQueries: {
|
||||
MaxAge: 24 * time.Hour,
|
||||
Dir: ":cacheDir/modules",
|
||||
},
|
||||
CacheKeyGetJSON: defaultCacheConfig,
|
||||
CacheKeyGetCSV: defaultCacheConfig,
|
||||
CacheKeyImages: {
|
||||
@@ -113,23 +100,6 @@ 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]
|
||||
@@ -150,16 +120,6 @@ 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]
|
||||
@@ -187,7 +147,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.(hmaps.Params); !ok {
|
||||
if _, ok := v.(maps.Params); !ok {
|
||||
continue
|
||||
}
|
||||
cc := defaultCacheConfig
|
||||
|
||||
+3
-30
@@ -14,7 +14,6 @@
|
||||
package filecache_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"testing"
|
||||
@@ -60,7 +59,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, 8)
|
||||
c.Assert(len(decoded), qt.Equals, 7)
|
||||
|
||||
c2 := decoded["getcsv"]
|
||||
c.Assert(c2.MaxAge.String(), qt.Equals, "11h0m0s")
|
||||
@@ -107,7 +106,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, 8)
|
||||
c.Assert(len(decoded), qt.Equals, 7)
|
||||
|
||||
for _, v := range decoded {
|
||||
c.Assert(v.MaxAge, qt.Equals, time.Duration(0))
|
||||
@@ -130,7 +129,7 @@ func TestDecodeConfigDefault(t *testing.T) {
|
||||
|
||||
fs := afero.NewMemMapFs()
|
||||
decoded := testconfig.GetTestConfigs(fs, cfg).Base.Caches
|
||||
c.Assert(len(decoded), qt.Equals, 8)
|
||||
c.Assert(len(decoded), qt.Equals, 7)
|
||||
|
||||
imgConfig := decoded[filecache.CacheKeyImages]
|
||||
jsonConfig := decoded[filecache.CacheKeyGetJSON]
|
||||
@@ -145,29 +144,3 @@ 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`)
|
||||
}
|
||||
|
||||
+1
-1
@@ -67,7 +67,7 @@ title: "Home"
|
||||
---
|
||||
-- assets/a/pixel.png --
|
||||
iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==
|
||||
-- layouts/home.html --
|
||||
-- layouts/index.html --
|
||||
{{ warnf "HOME!" }}
|
||||
{{ $img := resources.GetMatch "**.png" }}
|
||||
{{ $img = $img.Resize "3x3" }}
|
||||
|
||||
+3
-7
@@ -55,12 +55,9 @@ dir = ":resourceDir/_gen"
|
||||
|
||||
for _, name := range []string{filecache.CacheKeyGetCSV, filecache.CacheKeyGetJSON, filecache.CacheKeyAssets, filecache.CacheKeyImages} {
|
||||
msg := qt.Commentf("cache: %s", name)
|
||||
fs := afero.NewMemMapFs()
|
||||
p := newPathsSpec(t, fs, configStr)
|
||||
fileCachConfig := p.Cfg.GetConfigSection("caches").(filecache.Configs)
|
||||
caches, err := filecache.NewCaches(fileCachConfig, fs)
|
||||
p := newPathsSpec(t, afero.NewMemMapFs(), configStr)
|
||||
caches, err := filecache.NewCaches(p)
|
||||
c.Assert(err, qt.IsNil)
|
||||
caches.SetResourceFs(fs)
|
||||
cache := caches[name]
|
||||
for i := range 10 {
|
||||
id := fmt.Sprintf("i%d", i)
|
||||
@@ -87,9 +84,8 @@ dir = ":resourceDir/_gen"
|
||||
}
|
||||
}
|
||||
|
||||
caches, err = filecache.NewCaches(fileCachConfig, fs)
|
||||
caches, err = filecache.NewCaches(p)
|
||||
c.Assert(err, qt.IsNil)
|
||||
caches.SetResourceFs(fs)
|
||||
cache = caches[name]
|
||||
// Touch one and then prune.
|
||||
cache.GetOrCreateBytes("i5", func() ([]byte, error) {
|
||||
|
||||
Vendored
+4
-10
@@ -18,8 +18,6 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/gohugoio/hugo/htesting"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -80,11 +78,9 @@ 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(fileCachConfig, p.Fs.Source)
|
||||
caches, err := filecache.NewCaches(p)
|
||||
c.Assert(err, qt.IsNil)
|
||||
caches.SetResourceFs(p.SourceFs)
|
||||
|
||||
cache := caches.Get("GetJSON")
|
||||
c.Assert(cache, qt.Not(qt.IsNil))
|
||||
@@ -153,7 +149,7 @@ dir = ":cacheDir/c"
|
||||
r.Close()
|
||||
c.Assert(string(b), qt.Equals, "Hugo is great!")
|
||||
|
||||
info, b, err = caches.ImageCache().GetItemBytes("mykey")
|
||||
info, b, err = caches.ImageCache().GetBytes("mykey")
|
||||
c.Assert(err, qt.IsNil)
|
||||
c.Assert(info.Name, qt.Equals, "mykey")
|
||||
c.Assert(string(b), qt.Equals, "Hugo is great!")
|
||||
@@ -162,7 +158,6 @@ dir = ":cacheDir/c"
|
||||
}
|
||||
|
||||
func TestFileCacheConcurrent(t *testing.T) {
|
||||
htesting.SkipSlowTestUnlessCI(t)
|
||||
t.Parallel()
|
||||
|
||||
c := qt.New(t)
|
||||
@@ -184,10 +179,9 @@ dir = "/cache/c"
|
||||
`
|
||||
|
||||
p := newPathsSpec(t, afero.NewMemMapFs(), configStr)
|
||||
fileCachConfig := p.Cfg.GetConfigSection("caches").(filecache.Configs)
|
||||
caches, err := filecache.NewCaches(fileCachConfig, p.Fs.Source)
|
||||
|
||||
caches, err := filecache.NewCaches(p)
|
||||
c.Assert(err, qt.IsNil)
|
||||
caches.SetResourceFs(p.Fs.Source)
|
||||
|
||||
const cacheName = "getjson"
|
||||
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
#!/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"
|
||||
@@ -401,7 +401,9 @@ func (r *rootCommand) Run(ctx context.Context, cd *simplecobra.Commandeer, args
|
||||
|
||||
watchGroups := helpers.ExtractAndGroupRootPaths(watchDirs)
|
||||
|
||||
r.Printf("Watching for changes in %s\n", strings.Join(watchGroups, ", "))
|
||||
for _, group := range watchGroups {
|
||||
r.Printf("Watching for changes in %s\n", group)
|
||||
}
|
||||
watcher, err := b.newWatcher(r.poll, watchDirs...)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
+2
-2
@@ -23,7 +23,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/bep/simplecobra"
|
||||
"github.com/gohugoio/hugo/common/hmaps"
|
||||
"github.com/gohugoio/hugo/common/maps"
|
||||
"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
|
||||
}
|
||||
hmaps.ConvertFloat64WithNoDecimalsToInt(m)
|
||||
maps.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", hmaps.Params{
|
||||
cfg.Set("internal", maps.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, _ := hmaps.ToStringMapE(m)
|
||||
metadata, _ := maps.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 := hmaps.ToStringMapE(m)
|
||||
metadata, err := maps.ToStringMapE(m)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
+3
-8
@@ -49,7 +49,6 @@ import (
|
||||
"github.com/fsnotify/fsnotify"
|
||||
"github.com/gohugoio/hugo/common/herrors"
|
||||
"github.com/gohugoio/hugo/common/hugo"
|
||||
"github.com/gohugoio/hugo/common/paths"
|
||||
"github.com/gohugoio/hugo/langs"
|
||||
"github.com/gohugoio/hugo/tpl/tplimpl"
|
||||
|
||||
@@ -371,12 +370,6 @@ func (f *fileServer) createEndpoint(i int) (*http.ServeMux, net.Listener, string
|
||||
|
||||
if f.c.fastRenderMode && f.c.errState.buildErr() == nil {
|
||||
if isNavigation(requestURI, r) {
|
||||
// See issue 14240.
|
||||
// Hugo escapes the URL paths when generating them,
|
||||
// that may not be the case when we receive it back from the browser.
|
||||
// PathEscape will escape if it is not already escaped.
|
||||
requestURI = paths.PathEscape(requestURI)
|
||||
|
||||
if !f.c.visitedURLs.Contains(requestURI) {
|
||||
// If not already on stack, re-render that single page.
|
||||
if err := f.c.partialReRender(requestURI); err != nil {
|
||||
@@ -499,7 +492,9 @@ func (c *serverCommand) Run(ctx context.Context, cd *simplecobra.Commandeer, arg
|
||||
|
||||
watchGroups := helpers.ExtractAndGroupRootPaths(watchDirs)
|
||||
|
||||
c.r.Printf("Watching for changes in %s\n", strings.Join(watchGroups, ", "))
|
||||
for _, group := range watchGroups {
|
||||
c.r.Printf("Watching for changes in %s\n", group)
|
||||
}
|
||||
watcher, err := c.newWatcher(c.r.poll, watchDirs...)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
+11
-55
@@ -21,24 +21,24 @@ import (
|
||||
"github.com/gohugoio/hugo/common/hiter"
|
||||
)
|
||||
|
||||
// StackThreadSafe is a simple LIFO stack that is safe for concurrent use.
|
||||
type StackThreadSafe[T any] struct {
|
||||
// Stack is a simple LIFO stack that is safe for concurrent use.
|
||||
type Stack[T any] struct {
|
||||
items []T
|
||||
zero T
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
func NewStackThreadSafe[T any]() *StackThreadSafe[T] {
|
||||
return &StackThreadSafe[T]{}
|
||||
func NewStack[T any]() *Stack[T] {
|
||||
return &Stack[T]{}
|
||||
}
|
||||
|
||||
func (s *StackThreadSafe[T]) Push(item T) {
|
||||
func (s *Stack[T]) Push(item T) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
s.items = append(s.items, item)
|
||||
}
|
||||
|
||||
func (s *StackThreadSafe[T]) Pop() (T, bool) {
|
||||
func (s *Stack[T]) Pop() (T, bool) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
if len(s.items) == 0 {
|
||||
@@ -49,7 +49,7 @@ func (s *StackThreadSafe[T]) Pop() (T, bool) {
|
||||
return item, true
|
||||
}
|
||||
|
||||
func (s *StackThreadSafe[T]) Peek() (T, bool) {
|
||||
func (s *Stack[T]) Peek() (T, bool) {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
if len(s.items) == 0 {
|
||||
@@ -58,18 +58,18 @@ func (s *StackThreadSafe[T]) Peek() (T, bool) {
|
||||
return s.items[len(s.items)-1], true
|
||||
}
|
||||
|
||||
func (s *StackThreadSafe[T]) Len() int {
|
||||
func (s *Stack[T]) Len() int {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
return len(s.items)
|
||||
}
|
||||
|
||||
// All returns all items in the stack, from bottom to top.
|
||||
func (s *StackThreadSafe[T]) All() iter.Seq2[int, T] {
|
||||
func (s *Stack[T]) All() iter.Seq2[int, T] {
|
||||
return hiter.Lock2(slices.All(s.items), s.mu.RLock, s.mu.RUnlock)
|
||||
}
|
||||
|
||||
func (s *StackThreadSafe[T]) Drain() []T {
|
||||
func (s *Stack[T]) Drain() []T {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
items := s.items
|
||||
@@ -77,7 +77,7 @@ func (s *StackThreadSafe[T]) Drain() []T {
|
||||
return items
|
||||
}
|
||||
|
||||
func (s *StackThreadSafe[T]) DrainMatching(predicate func(T) bool) []T {
|
||||
func (s *Stack[T]) DrainMatching(predicate func(T) bool) []T {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
var items []T
|
||||
@@ -89,47 +89,3 @@ func (s *StackThreadSafe[T]) DrainMatching(predicate func(T) bool) []T {
|
||||
}
|
||||
return items
|
||||
}
|
||||
|
||||
// Stack is a simple LIFO stack that is not safe for concurrent use.
|
||||
type Stack[T any] struct {
|
||||
items []T
|
||||
zero T
|
||||
}
|
||||
|
||||
func NewStack[T any]() *Stack[T] {
|
||||
return &Stack[T]{}
|
||||
}
|
||||
|
||||
func (s *Stack[T]) Push(item T) {
|
||||
s.items = append(s.items, item)
|
||||
}
|
||||
|
||||
func (s *Stack[T]) Pop() (T, bool) {
|
||||
if len(s.items) == 0 {
|
||||
return s.zero, false
|
||||
}
|
||||
item := s.items[len(s.items)-1]
|
||||
s.items = s.items[:len(s.items)-1]
|
||||
return item, true
|
||||
}
|
||||
|
||||
func (s *Stack[T]) Peek() (T, bool) {
|
||||
if len(s.items) == 0 {
|
||||
return s.zero, false
|
||||
}
|
||||
return s.items[len(s.items)-1], true
|
||||
}
|
||||
|
||||
func (s *Stack[T]) Len() int {
|
||||
return len(s.items)
|
||||
}
|
||||
|
||||
func (s *Stack[T]) All() iter.Seq2[int, T] {
|
||||
return slices.All(s.items)
|
||||
}
|
||||
|
||||
func (s *Stack[T]) Drain() []T {
|
||||
items := s.items
|
||||
s.items = nil
|
||||
return items
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ func TestNewStack(t *testing.T) {
|
||||
t.Parallel()
|
||||
c := qt.New(t)
|
||||
|
||||
s := NewStackThreadSafe[int]()
|
||||
s := NewStack[int]()
|
||||
|
||||
c.Assert(s, qt.IsNotNil)
|
||||
}
|
||||
@@ -19,7 +19,7 @@ func TestStackBasic(t *testing.T) {
|
||||
t.Parallel()
|
||||
c := qt.New(t)
|
||||
|
||||
s := NewStackThreadSafe[int]()
|
||||
s := NewStack[int]()
|
||||
|
||||
c.Assert(s.Len(), qt.Equals, 0)
|
||||
|
||||
@@ -50,7 +50,7 @@ func TestStackDrain(t *testing.T) {
|
||||
t.Parallel()
|
||||
c := qt.New(t)
|
||||
|
||||
s := NewStackThreadSafe[string]()
|
||||
s := NewStack[string]()
|
||||
s.Push("a")
|
||||
s.Push("b")
|
||||
|
||||
@@ -64,7 +64,7 @@ func TestStackDrainMatching(t *testing.T) {
|
||||
t.Parallel()
|
||||
c := qt.New(t)
|
||||
|
||||
s := NewStackThreadSafe[int]()
|
||||
s := NewStack[int]()
|
||||
s.Push(1)
|
||||
s.Push(2)
|
||||
s.Push(3)
|
||||
|
||||
@@ -87,13 +87,11 @@ func XXHashFromString(s string) (uint64, error) {
|
||||
return h.Sum64(), nil
|
||||
}
|
||||
|
||||
// XxHashFromStringHexEncoded calculates the xxHash for the given strings
|
||||
// XxHashFromStringHexEncoded calculates the xxHash for the given string
|
||||
// and returns the hash as a hex encoded string.
|
||||
func XxHashFromStringHexEncoded(s ...string) string {
|
||||
func XxHashFromStringHexEncoded(f string) string {
|
||||
h := xxhash.New()
|
||||
for _, f := range s {
|
||||
h.WriteString(f)
|
||||
}
|
||||
h.WriteString(f)
|
||||
hash := h.Sum(nil)
|
||||
return hex.EncodeToString(hash)
|
||||
}
|
||||
|
||||
@@ -288,50 +288,6 @@ func Unwrap(err error) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// UnwrapFileErrors returns all FileError contained in err.
|
||||
func UnwrapFileErrors(err error) []FileError {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
errs := Errors(err)
|
||||
var fileErrors []FileError
|
||||
for _, e := range errs {
|
||||
if v, ok := e.(FileError); ok {
|
||||
fileErrors = append(fileErrors, v)
|
||||
}
|
||||
fileErrors = append(fileErrors, UnwrapFileErrors(errors.Unwrap(e))...)
|
||||
}
|
||||
return fileErrors
|
||||
}
|
||||
|
||||
// UnwrapFileErrorsWithErrorContext tries to unwrap all FileError in err that has an ErrorContext.
|
||||
func UnwrapFileErrorsWithErrorContext(err error) []FileError {
|
||||
errs := UnwrapFileErrors(err)
|
||||
var n int
|
||||
for _, e := range errs {
|
||||
if e.ErrorContext() != nil {
|
||||
errs[n] = e
|
||||
n++
|
||||
}
|
||||
}
|
||||
return errs[:n]
|
||||
}
|
||||
|
||||
// Errors returns the list of errors contained in err.
|
||||
func Errors(err error) []error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
type unwrapper interface {
|
||||
Unwrap() []error
|
||||
}
|
||||
if u, ok := err.(unwrapper); ok {
|
||||
return u.Unwrap()
|
||||
}
|
||||
return []error{err}
|
||||
}
|
||||
|
||||
func extractFileTypePos(err error) (string, text.Position) {
|
||||
err = Unwrap(err)
|
||||
|
||||
@@ -394,6 +350,30 @@ func UnwrapFileError(err error) FileError {
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnwrapFileErrors tries to unwrap all FileError.
|
||||
func UnwrapFileErrors(err error) []FileError {
|
||||
var errs []FileError
|
||||
for err != nil {
|
||||
if v, ok := err.(FileError); ok {
|
||||
errs = append(errs, v)
|
||||
}
|
||||
err = errors.Unwrap(err)
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
||||
// UnwrapFileErrorsWithErrorContext tries to unwrap all FileError in err that has an ErrorContext.
|
||||
func UnwrapFileErrorsWithErrorContext(err error) []FileError {
|
||||
var errs []FileError
|
||||
for err != nil {
|
||||
if v, ok := err.(FileError); ok && v.ErrorContext() != nil {
|
||||
errs = append(errs, v)
|
||||
}
|
||||
err = errors.Unwrap(err)
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
||||
func extractOffsetAndType(e error) (int, string) {
|
||||
switch v := e.(type) {
|
||||
case *json.UnmarshalTypeError:
|
||||
|
||||
@@ -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: hmaps.NewCache[string, func(arg ...any) (Runner, error)](),
|
||||
newNPXRunnerCache: maps.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 *hmaps.Cache[string, func(arg ...any) (Runner, error)]
|
||||
newNPXRunnerCache *maps.Cache[string, func(arg ...any) (Runner, error)]
|
||||
npxInit sync.Once
|
||||
npxAvailable bool
|
||||
}
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
// Copyright 2025 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 himage provides some high level image types and interfaces.
|
||||
package himage
|
||||
|
||||
import "image"
|
||||
|
||||
// AnimatedImage represents an animated image.
|
||||
// This is currently supported for GIF and WebP images.
|
||||
type AnimatedImage interface {
|
||||
image.Image // The first frame.
|
||||
GetRaw() any // *gif.GIF or *WEBP.
|
||||
GetLoopCount() int // Number of times to loop the animation. 0 means infinite.
|
||||
ImageFrames
|
||||
}
|
||||
|
||||
// ImageFrames provides access to the frames of an animated image.
|
||||
type ImageFrames interface {
|
||||
GetFrames() []image.Image
|
||||
|
||||
// Frame durations in milliseconds.
|
||||
// Note that Gif frame durations are in 100ths of a second,
|
||||
// so they need to be multiplied by 10 to get milliseconds and vice versa.
|
||||
GetFrameDurations() []int
|
||||
|
||||
SetFrames(frames []image.Image)
|
||||
SetWidthHeight(width, height int)
|
||||
}
|
||||
|
||||
// ImageConfigProvider provides access to the image.Config of an image.
|
||||
type ImageConfigProvider interface {
|
||||
GetImageConfig() image.Config
|
||||
}
|
||||
|
||||
// FrameDurationsToGifDelays converts frame durations in milliseconds to
|
||||
// GIF delays in 100ths of a second.
|
||||
func FrameDurationsToGifDelays(frameDurations []int) []int {
|
||||
delays := make([]int, len(frameDurations))
|
||||
for i, fd := range frameDurations {
|
||||
delays[i] = fd / 10
|
||||
if delays[i] == 0 && fd > 0 {
|
||||
delays[i] = 1
|
||||
}
|
||||
}
|
||||
return delays
|
||||
}
|
||||
|
||||
// GifDelaysToFrameDurations converts GIF delays in 100ths of a second to
|
||||
// frame durations in milliseconds.
|
||||
func GifDelaysToFrameDurations(delays []int) []int {
|
||||
frameDurations := make([]int, len(delays))
|
||||
for i, d := range delays {
|
||||
frameDurations[i] = d * 10
|
||||
}
|
||||
return frameDurations
|
||||
}
|
||||
@@ -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 = hmaps.NewCache[reflect.Type, bool]()
|
||||
var isContextCache = maps.NewCache[reflect.Type, bool]()
|
||||
|
||||
type k string
|
||||
|
||||
|
||||
@@ -97,16 +97,6 @@ func GetOrCompileRegexp(pattern string) (re *regexp.Regexp, err error) {
|
||||
return reCache.getOrCompileRegexp(pattern)
|
||||
}
|
||||
|
||||
// HasAnyPrefix checks if the string s has any of the prefixes given.
|
||||
func HasAnyPrefix(s string, prefixes ...string) bool {
|
||||
for _, p := range prefixes {
|
||||
if strings.HasPrefix(s, p) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// InSlice checks if a string is an element of a slice of strings
|
||||
// and returns a boolean value.
|
||||
func InSlice(arr []string, el string) bool {
|
||||
|
||||
@@ -24,9 +24,9 @@ func TestApplyWithContext(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
files := `
|
||||
-- hugo.toml --
|
||||
-- config.toml --
|
||||
defaultContentLanguage = 'it'
|
||||
-- layouts/home.html --
|
||||
-- layouts/index.html --
|
||||
{{ $dates := slice
|
||||
"2022-01-03"
|
||||
"2022-02-01"
|
||||
|
||||
@@ -32,30 +32,6 @@ type ReadSeekCloser interface {
|
||||
io.Closer
|
||||
}
|
||||
|
||||
// Sizer provides the size of, typically, a io.Reader.
|
||||
// As implemented by e.g. os.File and io.SectionReader.
|
||||
type Sizer interface {
|
||||
Size() int64
|
||||
}
|
||||
|
||||
type SizeReader interface {
|
||||
io.Reader
|
||||
Sizer
|
||||
}
|
||||
|
||||
// ToSizeReader converts the given io.Reader to a SizeReader.
|
||||
// Note that if r is not a SizeReader, the entire content will be read into memory
|
||||
func ToSizeReader(r io.Reader) (SizeReader, error) {
|
||||
if sr, ok := r.(SizeReader); ok {
|
||||
return sr, nil
|
||||
}
|
||||
b, err := io.ReadAll(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return bytes.NewReader(b), nil
|
||||
}
|
||||
|
||||
// CloserFunc is an adapter to allow the use of ordinary functions as io.Closers.
|
||||
type CloserFunc func() error
|
||||
|
||||
|
||||
+2
-1
@@ -310,12 +310,13 @@ func GetDependencyList() []string {
|
||||
|
||||
// GetDependencyListNonGo returns a list of non-Go dependencies.
|
||||
func GetDependencyListNonGo() []string {
|
||||
deps := []string{formatDep("github.com/webmproject/libwebp", "v1.6.0")} // via WASM. TODO(bep) get versions from the plugin setup.
|
||||
var deps []string
|
||||
|
||||
if IsExtended {
|
||||
deps = append(
|
||||
deps,
|
||||
formatDep("github.com/sass/libsass", "3.6.6"),
|
||||
formatDep("github.com/webmproject/libwebp", "v1.3.2"),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ baseURL = 'https://en.example.org/'
|
||||
---
|
||||
title: home
|
||||
---
|
||||
-- layouts/home.html --
|
||||
-- layouts/index.html --
|
||||
multilingual={{ hugo.IsMultilingual }}
|
||||
multihost={{ hugo.IsMultihost }}
|
||||
`
|
||||
|
||||
@@ -19,7 +19,7 @@ import "github.com/gohugoio/hugo/common/version"
|
||||
// This should be the only one.
|
||||
var CurrentVersion = version.Version{
|
||||
Major: 0,
|
||||
Minor: 155,
|
||||
PatchLevel: 1,
|
||||
Suffix: "",
|
||||
Minor: 153,
|
||||
PatchLevel: 0,
|
||||
Suffix: "-DEV",
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2026 The Hugo Authors. All rights reserved.
|
||||
// Copyright 2024 The Hugo Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@@ -11,7 +11,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package hmaps
|
||||
package maps
|
||||
|
||||
import (
|
||||
"sync"
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2026 The Hugo Authors. All rights reserved.
|
||||
// Copyright 2025 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 hmaps
|
||||
package maps
|
||||
|
||||
import (
|
||||
"testing"
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2026 The Hugo Authors. All rights reserved.
|
||||
// Copyright 2025 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 hmaps
|
||||
package maps
|
||||
|
||||
import (
|
||||
"iter"
|
||||
@@ -73,23 +73,11 @@ func (m *Map[K, T]) Set(key K, value T) {
|
||||
m.mu.Unlock()
|
||||
}
|
||||
|
||||
// Delete deletes the given key from the map.
|
||||
// It returns true if the key was found and deleted, false otherwise.
|
||||
func (m *Map[K, T]) Delete(key K) bool {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
if _, found := m.m[key]; found {
|
||||
delete(m.m, key)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// WithWriteLock executes the given function with a write lock on the map.
|
||||
func (m *Map[K, T]) WithWriteLock(f func(m map[K]T) error) error {
|
||||
func (m *Map[K, T]) WithWriteLock(f func(m map[K]T)) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
return f(m.m)
|
||||
f(m.m)
|
||||
}
|
||||
|
||||
// SetIfAbsent sets the given key to the given value if the key does not already exist in the map.
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2026 The Hugo Authors. All rights reserved.
|
||||
// Copyright 2025 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 hmaps
|
||||
package maps
|
||||
|
||||
import (
|
||||
"testing"
|
||||
@@ -62,9 +62,8 @@ func TestMap(t *testing.T) {
|
||||
c.Assert(found, qt.Equals, true)
|
||||
c.Assert(v, qt.Equals, 300)
|
||||
|
||||
m.WithWriteLock(func(m map[string]int) error {
|
||||
m.WithWriteLock(func(m map[string]int) {
|
||||
m["f"] = 500
|
||||
return nil
|
||||
})
|
||||
v, found = m.Lookup("f")
|
||||
c.Assert(found, qt.Equals, true)
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2026 The Hugo Authors. All rights reserved.
|
||||
// Copyright 2018 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 hmaps
|
||||
package maps
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2026 The Hugo Authors. All rights reserved.
|
||||
// Copyright 2018 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 hmaps
|
||||
package maps
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2026 The Hugo Authors. All rights reserved.
|
||||
// Copyright 2024 The Hugo Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@@ -11,7 +11,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package hmaps
|
||||
package maps
|
||||
|
||||
import (
|
||||
"slices"
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2026 The Hugo Authors. All rights reserved.
|
||||
// Copyright 2024 The Hugo Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@@ -11,7 +11,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package hmaps
|
||||
package maps
|
||||
|
||||
import (
|
||||
"testing"
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2026 The Hugo Authors. All rights reserved.
|
||||
// Copyright 2025 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 hmaps
|
||||
package maps
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2026 The Hugo Authors. All rights reserved.
|
||||
// Copyright 2025 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 hmaps
|
||||
package maps
|
||||
|
||||
import (
|
||||
"testing"
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2026 The Hugo Authors. All rights reserved.
|
||||
// Copyright 2019 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 hmaps
|
||||
package maps
|
||||
|
||||
import (
|
||||
"errors"
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2026 The Hugo Authors. All rights reserved.
|
||||
// Copyright 2019 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 hmaps
|
||||
package maps
|
||||
|
||||
import (
|
||||
"testing"
|
||||
@@ -347,25 +347,3 @@ func BenchmarkAddLeadingSlash(b *testing.B) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestPathEscape(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
|
||||
for _, this := range []struct {
|
||||
input string
|
||||
expected string
|
||||
}{
|
||||
{"/tags/欢迎", "/tags/%E6%AC%A2%E8%BF%8E"},
|
||||
{"/path with spaces", "/path%20with%20spaces"},
|
||||
{"/simple-path", "/simple-path"},
|
||||
{"/path/with/slash", "/path/with/slash"},
|
||||
{"/path/with special&chars", "/path/with%20special&chars"},
|
||||
} {
|
||||
in := this.input
|
||||
for range 2 {
|
||||
result := PathEscape(in)
|
||||
c.Assert(result, qt.Equals, this.expected, qt.Commentf("input: %q", this.input))
|
||||
in = result // test idempotency
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/gohugoio/hugo/common/hmaps"
|
||||
"github.com/gohugoio/hugo/common/maps"
|
||||
"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 *hmaps.Cache[string, sitesmatrix.VectorStore] // Maps language index to sites matrix vector store.
|
||||
sitesMatrixCache *maps.Cache[string, sitesmatrix.VectorStore] // Maps language index to sites matrix vector store.
|
||||
}
|
||||
|
||||
func (pp *PathParser) init() {
|
||||
pp.initOnce.Do(func() {
|
||||
pp.sitesMatrixCache = hmaps.NewCache[string, sitesmatrix.VectorStore]()
|
||||
pp.sitesMatrixCache = maps.NewCache[string, sitesmatrix.VectorStore]()
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -35,9 +35,9 @@ weight = 2
|
||||
removePathAccents = true
|
||||
-- content/διακριτικός.md --
|
||||
-- content/διακριτικός.fr.md --
|
||||
-- layouts/single.html --
|
||||
-- layouts/_default/single.html --
|
||||
{{ .Language.Lang }}|Single.
|
||||
-- layouts/list.html --
|
||||
-- layouts/_default/list.html --
|
||||
List
|
||||
`
|
||||
b := hugolib.Test(t, files)
|
||||
@@ -64,9 +64,9 @@ disablePathToLower = true
|
||||
-- content/MySection/MyPage.fr.md --
|
||||
-- content/MySection/MyBundle/index.md --
|
||||
-- content/MySection/MyBundle/index.fr.md --
|
||||
-- layouts/single.html --
|
||||
-- layouts/_default/single.html --
|
||||
{{ .Language.Lang }}|Single.
|
||||
-- layouts/list.html --
|
||||
-- layouts/_default/list.html --
|
||||
{{ .Language.Lang }}|List.
|
||||
`
|
||||
b := hugolib.Test(t, files)
|
||||
|
||||
@@ -153,35 +153,6 @@ 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) {
|
||||
@@ -216,86 +187,6 @@ func NewStringPredicateFromGlobs(patterns []string, getGlob func(pattern string)
|
||||
return p.BoolFunc(), nil
|
||||
}
|
||||
|
||||
// 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)
|
||||
IndexMatch(match P[string]) (iter.Seq[int], error)
|
||||
}
|
||||
|
||||
@@ -146,107 +146,6 @@ 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
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
// 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,9 +37,6 @@ 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 (
|
||||
@@ -47,10 +44,6 @@ var (
|
||||
_ compare.Comparer = (*VersionString)(nil)
|
||||
)
|
||||
|
||||
func (v Version) IsZero() bool {
|
||||
return v.Major == 0 && v.Minor == 0 && v.PatchLevel == 0 && v.Suffix == ""
|
||||
}
|
||||
|
||||
func (v Version) String() string {
|
||||
return version(v.Major, v.Minor, v.PatchLevel, v.Suffix)
|
||||
}
|
||||
@@ -109,7 +102,6 @@ func ParseVersion(s string) (Version, error) {
|
||||
vv.Suffix = suffix
|
||||
}
|
||||
vv.Major, vv.Minor, vv.PatchLevel = parseVersion(s)
|
||||
vv.source = s
|
||||
|
||||
return vv, nil
|
||||
}
|
||||
@@ -177,10 +169,6 @@ 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)
|
||||
}
|
||||
@@ -205,13 +193,11 @@ func CompareVersions(v1 Version, v2 any) int {
|
||||
return -1
|
||||
}
|
||||
|
||||
v2v, _ := ParseVersion(s)
|
||||
if v1.IsZero() && v2v.IsZero() {
|
||||
// Fall back to source comparison.
|
||||
return strings.Compare(v1.source, v2v.source)
|
||||
v, err := ParseVersion(s)
|
||||
if err != nil {
|
||||
return -1
|
||||
}
|
||||
|
||||
return v1.Compare(v2v)
|
||||
return v1.Compare(v)
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -50,11 +50,6 @@ 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)
|
||||
@@ -74,15 +69,6 @@ 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 hmaps.Params `mapstructure:"-"`
|
||||
Params maps.Params `mapstructure:"-"`
|
||||
|
||||
// UglyURLs configuration. Either a boolean or a sections map.
|
||||
UglyURLs any `mapstructure:"-"`
|
||||
@@ -471,10 +471,10 @@ func (c *Config) CompileConfig(logger loggers.Logger) error {
|
||||
gc.RenderHookUseEmbeddedNever,
|
||||
}
|
||||
if !slices.Contains(renderHookUseEmbeddedModes, c.Markup.Goldmark.RenderHooks.Image.UseEmbedded) {
|
||||
return fmt.Errorf("site config markup.goldmark.renderHooks.image.useEmbedded must be one of %s", helpers.StringSliceToList(renderHookUseEmbeddedModes, "or"))
|
||||
return fmt.Errorf("site config markup.goldmark.renderHooks.image must be one of %s", helpers.StringSliceToList(renderHookUseEmbeddedModes, "or"))
|
||||
}
|
||||
if !slices.Contains(renderHookUseEmbeddedModes, c.Markup.Goldmark.RenderHooks.Link.UseEmbedded) {
|
||||
return fmt.Errorf("site config markup.goldmark.renderHooks.link.useEmbedded must be one of %s", helpers.StringSliceToList(renderHookUseEmbeddedModes, "or"))
|
||||
return fmt.Errorf("site config markup.goldmark.renderHooks.link must be one of %s", helpers.StringSliceToList(renderHookUseEmbeddedModes, "or"))
|
||||
}
|
||||
|
||||
c.C = &ConfigCompiled{
|
||||
@@ -607,14 +607,8 @@ 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 DisableDefaultSiteRedirect introduced in v0.154.5.
|
||||
// It's not obvious how a more fine grained setup would work.
|
||||
DisableDefaultLanguageRedirect 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
|
||||
|
||||
@@ -822,7 +816,6 @@ type Configs struct {
|
||||
|
||||
Modules modules.Modules
|
||||
ModulesClient *modules.Client
|
||||
FileCaches filecache.Caches
|
||||
|
||||
// All below is set in Init.
|
||||
Languages langs.Languages
|
||||
@@ -853,7 +846,7 @@ func (c *Configs) IsZero() bool {
|
||||
return c == nil || len(c.Languages) == 0
|
||||
}
|
||||
|
||||
func (c *Configs) Init(sourceFs afero.Fs, logger loggers.Logger) error {
|
||||
func (c *Configs) Init(logger loggers.Logger) error {
|
||||
var languages langs.Languages
|
||||
|
||||
for _, f := range c.Base.Languages.Config.Sorted {
|
||||
@@ -922,9 +915,10 @@ func (c *Configs) Init(sourceFs afero.Fs, logger loggers.Logger) error {
|
||||
// avoid initializing the same config more than once.
|
||||
for i, l := range c.Languages {
|
||||
langConfig := c.LanguageConfigMap[l.Lang]
|
||||
sitesMatrix := sitesmatrix.NewIntSetsBuilder(c.ConfiguredDimensions).WithLanguageIndices(i).WithAllIfNotSet().Build()
|
||||
for _, s := range allDecoderSetups {
|
||||
if getInitializer := s.getInitializer; getInitializer != nil {
|
||||
if err := getInitializer(langConfig).InitConfig(logger, nil, c.ConfiguredDimensions); err != nil {
|
||||
if err := getInitializer(langConfig).InitConfig(logger, sitesMatrix, c.ConfiguredDimensions); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -1024,7 +1018,7 @@ func fromLoadConfigResult(fs afero.Fs, logger loggers.Logger, res config.LoadCon
|
||||
if lang == "" {
|
||||
lang = "en"
|
||||
}
|
||||
res.Cfg.Set("languages", hmaps.Params{lang: hmaps.Params{}})
|
||||
res.Cfg.Set("languages", maps.Params{lang: maps.Params{}})
|
||||
}
|
||||
bcfg := res.BaseConfig
|
||||
cfg := res.Cfg
|
||||
@@ -1051,11 +1045,11 @@ func fromLoadConfigResult(fs afero.Fs, logger loggers.Logger, res config.LoadCon
|
||||
var differentRootKeys []string
|
||||
switch x := v.(type) {
|
||||
case nil:
|
||||
case hmaps.Params:
|
||||
case maps.Params:
|
||||
_, found := x["params"]
|
||||
if !found {
|
||||
x["params"] = hmaps.Params{
|
||||
hmaps.MergeStrategyKey: hmaps.ParamsMergeStrategyDeep,
|
||||
x["params"] = maps.Params{
|
||||
maps.MergeStrategyKey: maps.ParamsMergeStrategyDeep,
|
||||
}
|
||||
}
|
||||
for kk, vv := range x {
|
||||
@@ -1067,16 +1061,16 @@ func fromLoadConfigResult(fs afero.Fs, logger loggers.Logger, res config.LoadCon
|
||||
isMultihost = true
|
||||
}
|
||||
|
||||
if p, ok := vv.(hmaps.Params); ok {
|
||||
if p, ok := vv.(maps.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 = hmaps.CloneParamsDeep(p)
|
||||
vv = maps.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.(hmaps.Params))
|
||||
page.AddLangToCascadeTargetMap(k, vv.(maps.Params))
|
||||
// Always clone cascade config to get the sites matrix right.
|
||||
differentRootKeys = append(differentRootKeys, kk)
|
||||
}
|
||||
@@ -1087,14 +1081,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 hmaps.Params:
|
||||
case maps.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.
|
||||
hmaps.MergeParams(mergedConfigEntry, rootv.(hmaps.Params))
|
||||
maps.MergeParams(mergedConfigEntry, rootv.(maps.Params))
|
||||
|
||||
mergedConfig.Set(kk, mergedConfigEntry)
|
||||
default:
|
||||
@@ -1104,7 +1098,7 @@ func fromLoadConfigResult(fs afero.Fs, logger loggers.Logger, res config.LoadCon
|
||||
}
|
||||
} else {
|
||||
switch vv.(type) {
|
||||
case hmaps.Params:
|
||||
case maps.Params:
|
||||
differentRootKeys = append(differentRootKeys, kk)
|
||||
default:
|
||||
// Apply new values to the root.
|
||||
@@ -1140,7 +1134,7 @@ func fromLoadConfigResult(fs afero.Fs, logger loggers.Logger, res config.LoadCon
|
||||
}
|
||||
|
||||
langConfigMap[k] = clone
|
||||
case hmaps.ParamsMergeStrategy:
|
||||
case maps.ParamsMergeStrategy:
|
||||
|
||||
default:
|
||||
panic(fmt.Sprintf("unknown type in languages config: %T", v))
|
||||
@@ -1155,16 +1149,10 @@ 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,
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ title: "p1"
|
||||
---
|
||||
title: "p1"
|
||||
---
|
||||
-- layouts/single.html --
|
||||
-- layouts/_default/single.html --
|
||||
Title: {{ .Title }}
|
||||
`
|
||||
|
||||
@@ -141,7 +141,7 @@ disableKinds = ["taxonomy", "term"]
|
||||
[pagination]
|
||||
disableAliases = true
|
||||
pagerSize = 2
|
||||
-- layouts/list.html --
|
||||
-- layouts/_default/list.html --
|
||||
{{ $paginator := .Paginate site.RegularPages }}
|
||||
{{ template "_internal/pagination.html" . }}
|
||||
{{ range $paginator.Pages }}
|
||||
@@ -191,7 +191,7 @@ func TestInvalidOutputFormat(t *testing.T) {
|
||||
disableKinds = ['page','rss','section','sitemap','taxonomy','term']
|
||||
[outputs]
|
||||
home = ['html','foo']
|
||||
-- layouts/home.html --
|
||||
-- layouts/index.html --
|
||||
x
|
||||
`
|
||||
|
||||
|
||||
@@ -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 := hmaps.CleanConfigStringMap(p.p.GetStringMap("outputs"))
|
||||
m := maps.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 := hmaps.CleanConfigStringMap(p.p.GetStringMap(d.key))
|
||||
m := maps.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 hmaps.Params
|
||||
var first maps.Params
|
||||
var ok bool
|
||||
for _, v := range m {
|
||||
first, ok = v.(hmaps.Params)
|
||||
first, ok = v.(maps.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 := hmaps.CleanConfigStringMap(p.p.GetStringMap(d.key))
|
||||
m := maps.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 := hmaps.CleanConfigStringMap(p.p.GetStringMap(d.key))
|
||||
m := maps.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 = hmaps.CleanConfigStringMap(p.p.GetStringMap("params"))
|
||||
p.c.Params = maps.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 = hmaps.CleanConfigStringMapString(p.p.GetStringMapString(d.key))
|
||||
p.c.Taxonomies = maps.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 = hmaps.CleanConfigStringMap(p.p.GetStringMap(d.key))
|
||||
p.c.Author = maps.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 = hmaps.CleanConfigStringMapString(p.p.GetStringMapString(d.key))
|
||||
p.c.Social = maps.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 hmaps.Params:
|
||||
p.c.UglyURLs = cast.ToStringMapBool(hmaps.CleanConfigStringMap(vv))
|
||||
case maps.Params:
|
||||
p.c.UglyURLs = cast.ToStringMapBool(maps.CleanConfigStringMap(vv))
|
||||
default:
|
||||
p.c.UglyURLs = cast.ToStringMapBool(v)
|
||||
}
|
||||
|
||||
@@ -25,8 +25,9 @@ import (
|
||||
)
|
||||
|
||||
type ConfigLanguage struct {
|
||||
config *Config
|
||||
baseConfig config.BaseConfig
|
||||
config *Config
|
||||
baseConfig config.BaseConfig
|
||||
|
||||
m *Configs
|
||||
language *langs.Language
|
||||
languageIndex int
|
||||
@@ -122,10 +123,6 @@ 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
|
||||
}
|
||||
@@ -138,10 +135,6 @@ func (c ConfigLanguage) WorkingDir() string {
|
||||
return c.m.Base.WorkingDir
|
||||
}
|
||||
|
||||
func (c ConfigLanguage) CacheDirMisc() string {
|
||||
return c.config.Caches.CacheDirMisc()
|
||||
}
|
||||
|
||||
func (c ConfigLanguage) Quiet() bool {
|
||||
return c.m.Base.Internal.Quiet
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
package allconfig
|
||||
|
||||
import (
|
||||
"github.com/gohugoio/hugo/common/hmaps"
|
||||
"github.com/gohugoio/hugo/common/maps"
|
||||
"github.com/gohugoio/hugo/config"
|
||||
"github.com/gohugoio/hugo/docshelper"
|
||||
)
|
||||
@@ -27,12 +27,12 @@ func init() {
|
||||
if v.internalOrDeprecated {
|
||||
continue
|
||||
}
|
||||
cfg.Set(configRoot, make(hmaps.Params))
|
||||
cfg.Set(configRoot, make(maps.Params))
|
||||
}
|
||||
lang := hmaps.Params{
|
||||
"en": hmaps.Params{
|
||||
"menus": hmaps.Params{},
|
||||
"params": hmaps.Params{},
|
||||
lang := maps.Params{
|
||||
"en": maps.Params{
|
||||
"menus": maps.Params{},
|
||||
"params": maps.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.Fs, d.Logger); err != nil {
|
||||
if err := configs.Init(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 := hmaps.Params{
|
||||
defaultSettings := maps.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", hmaps.Params{"minifyOutput": true})
|
||||
cfg.Set("minify", maps.Params{"minifyOutput": true})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -240,7 +240,7 @@ func (l configLoader) applyOsEnvOverrides(environ []string) error {
|
||||
}
|
||||
|
||||
for _, env := range hugoEnv {
|
||||
existing, nestedKey, owner, err := hmaps.GetNestedParamFn(env.Key, delim, l.cfg.Get)
|
||||
existing, nestedKey, owner, err := maps.GetNestedParamFn(env.Key, delim, l.cfg.Get)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -477,7 +477,6 @@ 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,
|
||||
@@ -548,7 +547,7 @@ func (l configLoader) loadConfig(configName string) (string, error) {
|
||||
}
|
||||
|
||||
func (l configLoader) deleteMergeStrategies() (err error) {
|
||||
l.cfg.WalkParams(func(params ...hmaps.KeyParams) bool {
|
||||
l.cfg.WalkParams(func(params ...maps.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 hmaps.KeyRenamer
|
||||
var keyAliases maps.KeyRenamer
|
||||
|
||||
func init() {
|
||||
var err error
|
||||
keyAliases, err = hmaps.NewKeyRenamer(
|
||||
keyAliases, err = maps.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/hmaps"
|
||||
"github.com/gohugoio/hugo/common/maps"
|
||||
"github.com/gohugoio/hugo/common/paths"
|
||||
"github.com/gohugoio/hugo/common/types"
|
||||
"github.com/gohugoio/hugo/common/urls"
|
||||
@@ -41,7 +41,6 @@ type AllProvider interface {
|
||||
Dirs() CommonDirs
|
||||
Quiet() bool
|
||||
DirsBase() CommonDirs
|
||||
FileCaches() any
|
||||
ContentTypes() ContentTypesProvider
|
||||
GetConfigSection(string) any
|
||||
GetConfig() any
|
||||
@@ -80,7 +79,6 @@ type AllProvider interface {
|
||||
WorkingDir() string
|
||||
EnableEmoji() bool
|
||||
ConfiguredDimensions() *sitesmatrix.ConfiguredDimensions
|
||||
CacheDirMisc() string
|
||||
}
|
||||
|
||||
// We cannot import the media package as that would create a circular dependency.
|
||||
@@ -97,7 +95,7 @@ type Provider interface {
|
||||
GetString(key string) string
|
||||
GetInt(key string) int
|
||||
GetBool(key string) bool
|
||||
GetParams(key string) hmaps.Params
|
||||
GetParams(key string) maps.Params
|
||||
GetStringMap(key string) map[string]any
|
||||
GetStringMapString(key string) map[string]string
|
||||
GetStringSlice(key string) []string
|
||||
@@ -105,9 +103,9 @@ type Provider interface {
|
||||
Set(key string, value any)
|
||||
Keys() []string
|
||||
Merge(key string, value any)
|
||||
SetDefaults(params hmaps.Params)
|
||||
SetDefaults(params maps.Params)
|
||||
SetDefaultMergeStrategy()
|
||||
WalkParams(walkFn func(params ...hmaps.KeyParams) bool)
|
||||
WalkParams(walkFn func(params ...maps.KeyParams) bool)
|
||||
IsSet(key string) bool
|
||||
}
|
||||
|
||||
|
||||
@@ -20,20 +20,21 @@ 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 hmaps.Params.
|
||||
// New creates a Provider backed by an empty maps.Params.
|
||||
func New() Provider {
|
||||
return &defaultConfigProvider{
|
||||
root: make(hmaps.Params),
|
||||
root: make(maps.Params),
|
||||
}
|
||||
}
|
||||
|
||||
// NewFrom creates a Provider backed by params.
|
||||
func NewFrom(params hmaps.Params) Provider {
|
||||
hmaps.PrepareParams(params)
|
||||
func NewFrom(params maps.Params) Provider {
|
||||
maps.PrepareParams(params)
|
||||
return &defaultConfigProvider{
|
||||
root: params,
|
||||
}
|
||||
@@ -43,7 +44,7 @@ func NewFrom(params hmaps.Params) Provider {
|
||||
// All methods are thread safe.
|
||||
type defaultConfigProvider struct {
|
||||
mu sync.RWMutex
|
||||
root hmaps.Params
|
||||
root maps.Params
|
||||
|
||||
keyCache sync.Map
|
||||
}
|
||||
@@ -89,22 +90,22 @@ func (c *defaultConfigProvider) GetString(k string) string {
|
||||
return cast.ToString(v)
|
||||
}
|
||||
|
||||
func (c *defaultConfigProvider) GetParams(k string) hmaps.Params {
|
||||
func (c *defaultConfigProvider) GetParams(k string) maps.Params {
|
||||
v := c.Get(k)
|
||||
if v == nil {
|
||||
return nil
|
||||
}
|
||||
return v.(hmaps.Params)
|
||||
return v.(maps.Params)
|
||||
}
|
||||
|
||||
func (c *defaultConfigProvider) GetStringMap(k string) map[string]any {
|
||||
v := c.Get(k)
|
||||
return hmaps.ToStringMap(v)
|
||||
return maps.ToStringMap(v)
|
||||
}
|
||||
|
||||
func (c *defaultConfigProvider) GetStringMapString(k string) map[string]string {
|
||||
v := c.Get(k)
|
||||
return hmaps.ToStringMapString(v)
|
||||
return maps.ToStringMapString(v)
|
||||
}
|
||||
|
||||
func (c *defaultConfigProvider) GetStringSlice(k string) []string {
|
||||
@@ -119,9 +120,9 @@ func (c *defaultConfigProvider) Set(k string, v any) {
|
||||
k = strings.ToLower(k)
|
||||
|
||||
if k == "" {
|
||||
if p, err := hmaps.ToParamsAndPrepare(v); err == nil {
|
||||
if p, err := maps.ToParamsAndPrepare(v); err == nil {
|
||||
// Set the values directly in root.
|
||||
hmaps.SetParams(c.root, p)
|
||||
maps.SetParams(c.root, p)
|
||||
} else {
|
||||
c.root[k] = v
|
||||
}
|
||||
@@ -131,7 +132,7 @@ func (c *defaultConfigProvider) Set(k string, v any) {
|
||||
|
||||
switch vv := v.(type) {
|
||||
case map[string]any, map[any]any, map[string]string:
|
||||
p := hmaps.MustToParamsAndPrepare(vv)
|
||||
p := maps.MustToParamsAndPrepare(vv)
|
||||
v = p
|
||||
}
|
||||
|
||||
@@ -141,9 +142,9 @@ func (c *defaultConfigProvider) Set(k string, v any) {
|
||||
}
|
||||
|
||||
if existing, found := m[key]; found {
|
||||
if p1, ok := existing.(hmaps.Params); ok {
|
||||
if p2, ok := v.(hmaps.Params); ok {
|
||||
hmaps.SetParams(p1, p2)
|
||||
if p1, ok := existing.(maps.Params); ok {
|
||||
if p2, ok := v.(maps.Params); ok {
|
||||
maps.SetParams(p1, p2)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -153,8 +154,8 @@ func (c *defaultConfigProvider) Set(k string, v any) {
|
||||
}
|
||||
|
||||
// SetDefaults will set values from params if not already set.
|
||||
func (c *defaultConfigProvider) SetDefaults(params hmaps.Params) {
|
||||
hmaps.PrepareParams(params)
|
||||
func (c *defaultConfigProvider) SetDefaults(params maps.Params) {
|
||||
maps.PrepareParams(params)
|
||||
for k, v := range params {
|
||||
if _, found := c.root[k]; !found {
|
||||
c.root[k] = v
|
||||
@@ -169,28 +170,28 @@ func (c *defaultConfigProvider) Merge(k string, v any) {
|
||||
|
||||
if k == "" {
|
||||
rs, f := c.root.GetMergeStrategy()
|
||||
if f && rs == hmaps.ParamsMergeStrategyNone {
|
||||
if f && rs == maps.ParamsMergeStrategyNone {
|
||||
// The user has set a "no merge" strategy on this,
|
||||
// nothing more to do.
|
||||
return
|
||||
}
|
||||
|
||||
if p, err := hmaps.ToParamsAndPrepare(v); err == nil {
|
||||
if p, err := maps.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.(hmaps.Params); ok {
|
||||
if pp, ok := vv.(maps.Params); ok {
|
||||
if pppi, ok := c.root[kk]; ok {
|
||||
ppp := pppi.(hmaps.Params)
|
||||
hmaps.MergeParamsWithStrategy("", ppp, pp)
|
||||
ppp := pppi.(maps.Params)
|
||||
maps.MergeParamsWithStrategy("", ppp, pp)
|
||||
} else {
|
||||
// We need to use the default merge strategy for
|
||||
// this key.
|
||||
np := make(hmaps.Params)
|
||||
strategy := c.determineMergeStrategy(hmaps.KeyParams{Key: "", Params: c.root}, hmaps.KeyParams{Key: kk, Params: np})
|
||||
np := make(maps.Params)
|
||||
strategy := c.determineMergeStrategy(maps.KeyParams{Key: "", Params: c.root}, maps.KeyParams{Key: kk, Params: np})
|
||||
np.SetMergeStrategy(strategy)
|
||||
hmaps.MergeParamsWithStrategy("", np, pp)
|
||||
maps.MergeParamsWithStrategy("", np, pp)
|
||||
c.root[kk] = np
|
||||
if np.IsZero() {
|
||||
// Just keep it until merge is done.
|
||||
@@ -200,7 +201,7 @@ func (c *defaultConfigProvider) Merge(k string, v any) {
|
||||
}
|
||||
}
|
||||
// Merge the rest.
|
||||
hmaps.MergeParams(c.root, p)
|
||||
maps.MergeParams(c.root, p)
|
||||
for _, k := range keysToDelete {
|
||||
delete(c.root, k)
|
||||
}
|
||||
@@ -213,7 +214,7 @@ func (c *defaultConfigProvider) Merge(k string, v any) {
|
||||
|
||||
switch vv := v.(type) {
|
||||
case map[string]any, map[any]any, map[string]string:
|
||||
p := hmaps.MustToParamsAndPrepare(vv)
|
||||
p := maps.MustToParamsAndPrepare(vv)
|
||||
v = p
|
||||
}
|
||||
|
||||
@@ -223,9 +224,9 @@ func (c *defaultConfigProvider) Merge(k string, v any) {
|
||||
}
|
||||
|
||||
if existing, found := m[key]; found {
|
||||
if p1, ok := existing.(hmaps.Params); ok {
|
||||
if p2, ok := v.(hmaps.Params); ok {
|
||||
hmaps.MergeParamsWithStrategy("", p1, p2)
|
||||
if p1, ok := existing.(maps.Params); ok {
|
||||
if p2, ok := v.(maps.Params); ok {
|
||||
maps.MergeParamsWithStrategy("", p1, p2)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -244,10 +245,10 @@ func (c *defaultConfigProvider) Keys() []string {
|
||||
return keys
|
||||
}
|
||||
|
||||
func (c *defaultConfigProvider) WalkParams(walkFn func(params ...hmaps.KeyParams) bool) {
|
||||
func (c *defaultConfigProvider) WalkParams(walkFn func(params ...maps.KeyParams) bool) {
|
||||
maxDepth := 1000
|
||||
var walk func(depth int, params ...hmaps.KeyParams)
|
||||
walk = func(depth int, params ...hmaps.KeyParams) {
|
||||
var walk func(depth int, params ...maps.KeyParams)
|
||||
walk = func(depth int, params ...maps.KeyParams) {
|
||||
if depth > maxDepth {
|
||||
panic(errors.New("max depth exceeded"))
|
||||
}
|
||||
@@ -257,24 +258,24 @@ func (c *defaultConfigProvider) WalkParams(walkFn func(params ...hmaps.KeyParams
|
||||
p1 := params[len(params)-1]
|
||||
i := len(params)
|
||||
for k, v := range p1.Params {
|
||||
if p2, ok := v.(hmaps.Params); ok {
|
||||
paramsplus1 := make([]hmaps.KeyParams, i+1)
|
||||
if p2, ok := v.(maps.Params); ok {
|
||||
paramsplus1 := make([]maps.KeyParams, i+1)
|
||||
copy(paramsplus1, params)
|
||||
paramsplus1[i] = hmaps.KeyParams{Key: k, Params: p2}
|
||||
paramsplus1[i] = maps.KeyParams{Key: k, Params: p2}
|
||||
walk(depth+1, paramsplus1...)
|
||||
}
|
||||
}
|
||||
}
|
||||
walk(0, hmaps.KeyParams{Key: "", Params: c.root})
|
||||
walk(0, maps.KeyParams{Key: "", Params: c.root})
|
||||
}
|
||||
|
||||
func (c *defaultConfigProvider) determineMergeStrategy(params ...hmaps.KeyParams) hmaps.ParamsMergeStrategy {
|
||||
func (c *defaultConfigProvider) determineMergeStrategy(params ...maps.KeyParams) maps.ParamsMergeStrategy {
|
||||
if len(params) == 0 {
|
||||
return hmaps.ParamsMergeStrategyNone
|
||||
return maps.ParamsMergeStrategyNone
|
||||
}
|
||||
|
||||
var (
|
||||
strategy hmaps.ParamsMergeStrategy
|
||||
strategy maps.ParamsMergeStrategy
|
||||
prevIsRoot bool
|
||||
curr = params[len(params)-1]
|
||||
)
|
||||
@@ -298,10 +299,10 @@ func (c *defaultConfigProvider) determineMergeStrategy(params ...hmaps.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 = hmaps.ParamsMergeStrategyDeep
|
||||
strategy = maps.ParamsMergeStrategyDeep
|
||||
case "outputformats", "mediatypes":
|
||||
if prevIsRoot {
|
||||
strategy = hmaps.ParamsMergeStrategyShallow
|
||||
strategy = maps.ParamsMergeStrategyShallow
|
||||
}
|
||||
case "menus":
|
||||
isMenuKey := prevIsRoot
|
||||
@@ -313,11 +314,11 @@ func (c *defaultConfigProvider) determineMergeStrategy(params ...hmaps.KeyParams
|
||||
}
|
||||
}
|
||||
if isMenuKey {
|
||||
strategy = hmaps.ParamsMergeStrategyShallow
|
||||
strategy = maps.ParamsMergeStrategyShallow
|
||||
}
|
||||
default:
|
||||
if strategy == "" {
|
||||
strategy = hmaps.ParamsMergeStrategyNone
|
||||
strategy = maps.ParamsMergeStrategyNone
|
||||
}
|
||||
}
|
||||
|
||||
@@ -325,7 +326,7 @@ func (c *defaultConfigProvider) determineMergeStrategy(params ...hmaps.KeyParams
|
||||
}
|
||||
|
||||
func (c *defaultConfigProvider) SetDefaultMergeStrategy() {
|
||||
c.WalkParams(func(params ...hmaps.KeyParams) bool {
|
||||
c.WalkParams(func(params ...maps.KeyParams) bool {
|
||||
if len(params) == 0 {
|
||||
return false
|
||||
}
|
||||
@@ -343,7 +344,7 @@ func (c *defaultConfigProvider) SetDefaultMergeStrategy() {
|
||||
})
|
||||
}
|
||||
|
||||
func (c *defaultConfigProvider) getNestedKeyAndMap(key string, create bool) (string, hmaps.Params) {
|
||||
func (c *defaultConfigProvider) getNestedKeyAndMap(key string, create bool) (string, maps.Params) {
|
||||
var parts []string
|
||||
v, ok := c.keyCache.Load(key)
|
||||
if ok {
|
||||
@@ -357,14 +358,14 @@ func (c *defaultConfigProvider) getNestedKeyAndMap(key string, create bool) (str
|
||||
next, found := current[parts[i]]
|
||||
if !found {
|
||||
if create {
|
||||
next = make(hmaps.Params)
|
||||
next = make(maps.Params)
|
||||
current[parts[i]] = next
|
||||
} else {
|
||||
return "", nil
|
||||
}
|
||||
}
|
||||
var ok bool
|
||||
current, ok = next.(hmaps.Params)
|
||||
current, ok = next.(maps.Params)
|
||||
if !ok {
|
||||
// E.g. a string, not a map that we can store values in.
|
||||
return "", nil
|
||||
|
||||
@@ -22,9 +22,10 @@ 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"
|
||||
)
|
||||
|
||||
@@ -47,7 +48,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, hmaps.Params{
|
||||
c.Assert(cfg.Get(""), qt.DeepEquals, maps.Params{
|
||||
"foo": 42,
|
||||
})
|
||||
})
|
||||
@@ -59,7 +60,7 @@ func TestDefaultConfigProvider(t *testing.T) {
|
||||
"bar": "baz",
|
||||
})
|
||||
|
||||
c.Assert(cfg.Get("foo"), qt.DeepEquals, hmaps.Params{
|
||||
c.Assert(cfg.Get("foo"), qt.DeepEquals, maps.Params{
|
||||
"bar": "baz",
|
||||
})
|
||||
|
||||
@@ -75,14 +76,14 @@ func TestDefaultConfigProvider(t *testing.T) {
|
||||
})
|
||||
cfg.Set("a.c", "cv")
|
||||
|
||||
c.Assert(cfg.Get("a"), qt.DeepEquals, hmaps.Params{
|
||||
c.Assert(cfg.Get("a"), qt.DeepEquals, maps.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, hmaps.Params{
|
||||
c.Assert(cfg.Get("b"), qt.DeepEquals, maps.Params{
|
||||
"a": "av",
|
||||
})
|
||||
|
||||
@@ -90,7 +91,7 @@ func TestDefaultConfigProvider(t *testing.T) {
|
||||
"b": "bv",
|
||||
})
|
||||
|
||||
c.Assert(cfg.Get("b"), qt.DeepEquals, hmaps.Params{
|
||||
c.Assert(cfg.Get("b"), qt.DeepEquals, maps.Params{
|
||||
"a": "av",
|
||||
"b": "bv",
|
||||
})
|
||||
@@ -104,7 +105,7 @@ func TestDefaultConfigProvider(t *testing.T) {
|
||||
"b": "bv2",
|
||||
})
|
||||
|
||||
c.Assert(cfg.Get(""), qt.DeepEquals, hmaps.Params{
|
||||
c.Assert(cfg.Get(""), qt.DeepEquals, maps.Params{
|
||||
"a": "av2",
|
||||
"b": "bv2",
|
||||
})
|
||||
@@ -117,7 +118,7 @@ func TestDefaultConfigProvider(t *testing.T) {
|
||||
"b": "bv2",
|
||||
})
|
||||
|
||||
c.Assert(cfg.Get(""), qt.DeepEquals, hmaps.Params{
|
||||
c.Assert(cfg.Get(""), qt.DeepEquals, maps.Params{
|
||||
"a": "av",
|
||||
"b": "bv2",
|
||||
})
|
||||
@@ -136,7 +137,7 @@ func TestDefaultConfigProvider(t *testing.T) {
|
||||
},
|
||||
})
|
||||
|
||||
c.Assert(cfg.Get("foo"), qt.DeepEquals, hmaps.Params{
|
||||
c.Assert(cfg.Get("foo"), qt.DeepEquals, maps.Params{
|
||||
"a": "av",
|
||||
"b": "bv2",
|
||||
})
|
||||
@@ -154,7 +155,7 @@ func TestDefaultConfigProvider(t *testing.T) {
|
||||
"c": "cv2",
|
||||
})
|
||||
|
||||
c.Assert(cfg.Get("a"), qt.DeepEquals, hmaps.Params{
|
||||
c.Assert(cfg.Get("a"), qt.DeepEquals, maps.Params{
|
||||
"b": "bv",
|
||||
"c": "cv2",
|
||||
})
|
||||
@@ -168,7 +169,7 @@ func TestDefaultConfigProvider(t *testing.T) {
|
||||
"b": "bv2",
|
||||
})
|
||||
|
||||
c.Assert(cfg.Get(""), qt.DeepEquals, hmaps.Params{
|
||||
c.Assert(cfg.Get(""), qt.DeepEquals, maps.Params{
|
||||
"a": "av",
|
||||
})
|
||||
})
|
||||
@@ -191,11 +192,11 @@ func TestDefaultConfigProvider(t *testing.T) {
|
||||
"e": "ev2",
|
||||
})
|
||||
|
||||
c.Assert(cfg.Get("a"), qt.DeepEquals, hmaps.Params{
|
||||
c.Assert(cfg.Get("a"), qt.DeepEquals, maps.Params{
|
||||
"e": "ev2",
|
||||
"_merge": hmaps.ParamsMergeStrategyShallow,
|
||||
"_merge": maps.ParamsMergeStrategyShallow,
|
||||
"b": "bv",
|
||||
"c": hmaps.Params{
|
||||
"c": maps.Params{
|
||||
"b": "bv",
|
||||
},
|
||||
})
|
||||
@@ -220,15 +221,15 @@ func TestDefaultConfigProvider(t *testing.T) {
|
||||
"b": left,
|
||||
})
|
||||
|
||||
cfg.Merge("", hmaps.Params{
|
||||
"b": hmaps.Params{
|
||||
cfg.Merge("", maps.Params{
|
||||
"b": maps.Params{
|
||||
"c": "cv2",
|
||||
"d": "dv2",
|
||||
},
|
||||
})
|
||||
|
||||
c.Assert(cfg.Get(""), qt.DeepEquals, hmaps.Params{
|
||||
"b": hmaps.Params{
|
||||
c.Assert(cfg.Get(""), qt.DeepEquals, maps.Params{
|
||||
"b": maps.Params{
|
||||
"c": "cv1",
|
||||
"d": "dv2",
|
||||
},
|
||||
@@ -266,8 +267,8 @@ func TestDefaultConfigProvider(t *testing.T) {
|
||||
|
||||
cfg.Merge("a", right)
|
||||
|
||||
c.Assert(cfg.Get(""), qt.DeepEquals, hmaps.Params{
|
||||
"a": hmaps.Params{
|
||||
c.Assert(cfg.Get(""), qt.DeepEquals, maps.Params{
|
||||
"a": maps.Params{
|
||||
"b": "bv1",
|
||||
"c": "cv2",
|
||||
},
|
||||
@@ -291,7 +292,7 @@ func TestDefaultConfigProvider(t *testing.T) {
|
||||
},
|
||||
})
|
||||
|
||||
c.Assert(cfg.Get(""), qt.DeepEquals, hmaps.Params{
|
||||
c.Assert(cfg.Get(""), qt.DeepEquals, maps.Params{
|
||||
"b": "bv",
|
||||
})
|
||||
})
|
||||
@@ -340,7 +341,7 @@ func TestDefaultConfigProvider(t *testing.T) {
|
||||
return err
|
||||
}
|
||||
|
||||
m := hmaps.Params{
|
||||
m := maps.Params{
|
||||
"new": 42,
|
||||
}
|
||||
|
||||
@@ -370,8 +371,8 @@ func TestDefaultConfigProvider(t *testing.T) {
|
||||
cfg := New()
|
||||
k := "foo"
|
||||
|
||||
cfg.Set(k, hmaps.Params{k: true})
|
||||
c.Assert(cfg.GetParams(k), qt.DeepEquals, hmaps.Params{
|
||||
cfg.Set(k, maps.Params{k: true})
|
||||
c.Assert(cfg.GetParams(k), qt.DeepEquals, maps.Params{
|
||||
k: true,
|
||||
})
|
||||
|
||||
@@ -383,8 +384,8 @@ func TestDefaultConfigProvider(t *testing.T) {
|
||||
k := "foo"
|
||||
k2 := "bar"
|
||||
|
||||
cfg.Set(k, hmaps.Params{k: struct{}{}})
|
||||
cfg.Set(k2, hmaps.Params{k2: struct{}{}})
|
||||
cfg.Set(k, maps.Params{k: struct{}{}})
|
||||
cfg.Set(k2, maps.Params{k2: struct{}{}})
|
||||
|
||||
c.Assert(len(cfg.Keys()), qt.Equals, 2)
|
||||
|
||||
@@ -400,11 +401,11 @@ func TestDefaultConfigProvider(t *testing.T) {
|
||||
c.Run("WalkParams", func(c *qt.C) {
|
||||
cfg := New()
|
||||
|
||||
cfg.Set("x", hmaps.Params{})
|
||||
cfg.Set("y", hmaps.Params{})
|
||||
cfg.Set("x", maps.Params{})
|
||||
cfg.Set("y", maps.Params{})
|
||||
|
||||
var got []string
|
||||
cfg.WalkParams(func(params ...hmaps.KeyParams) bool {
|
||||
cfg.WalkParams(func(params ...maps.KeyParams) bool {
|
||||
got = append(got, params[len(params)-1].Key)
|
||||
return false
|
||||
})
|
||||
@@ -416,7 +417,7 @@ func TestDefaultConfigProvider(t *testing.T) {
|
||||
c.Assert(got, qt.DeepEquals, want)
|
||||
|
||||
cfg = New()
|
||||
cfg.WalkParams(func(params ...hmaps.KeyParams) bool {
|
||||
cfg.WalkParams(func(params ...maps.KeyParams) bool {
|
||||
return true
|
||||
})
|
||||
|
||||
@@ -428,7 +429,7 @@ func TestDefaultConfigProvider(t *testing.T) {
|
||||
c.Run("SetDefaults", func(c *qt.C) {
|
||||
cfg := New()
|
||||
|
||||
cfg.SetDefaults(hmaps.Params{
|
||||
cfg.SetDefaults(maps.Params{
|
||||
"foo": "bar",
|
||||
"bar": "baz",
|
||||
})
|
||||
|
||||
@@ -18,7 +18,7 @@ import (
|
||||
"testing"
|
||||
|
||||
qt "github.com/frankban/quicktest"
|
||||
"github.com/gohugoio/hugo/common/hmaps"
|
||||
"github.com/gohugoio/hugo/common/maps"
|
||||
"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 := hmaps.ToStringMapE(v)
|
||||
m, err := maps.ToStringMapE(v)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
@@ -112,8 +112,12 @@ type X struct {
|
||||
|
||||
// DecodeConfig creates a privacy Config from a given Hugo configuration.
|
||||
func DecodeConfig(cfg config.Provider) (pc Config, err error) {
|
||||
pc.GoogleAnalytics.RespectDoNotTrack = true
|
||||
if !cfg.IsSet(privacyConfigKey) {
|
||||
return
|
||||
}
|
||||
|
||||
m := cfg.GetStringMap(privacyConfigKey)
|
||||
|
||||
err = mapstructure.WeakDecode(m, &pc)
|
||||
|
||||
return
|
||||
|
||||
@@ -17,12 +17,11 @@ package testconfig
|
||||
import (
|
||||
_ "unsafe"
|
||||
|
||||
"github.com/gohugoio/hugo/common/hmaps"
|
||||
"github.com/gohugoio/hugo/common/maps"
|
||||
"github.com/gohugoio/hugo/config"
|
||||
"github.com/gohugoio/hugo/config/allconfig"
|
||||
"github.com/gohugoio/hugo/deps"
|
||||
"github.com/gohugoio/hugo/hugofs"
|
||||
"github.com/gohugoio/hugo/internal/warpc"
|
||||
toml "github.com/pelletier/go-toml/v2"
|
||||
"github.com/spf13/afero"
|
||||
)
|
||||
@@ -61,14 +60,6 @@ func GetTestDeps(fs afero.Fs, cfg config.Provider, beforeInit ...func(*deps.Deps
|
||||
d := &deps.Deps{
|
||||
Conf: conf,
|
||||
Fs: hugofs.NewFrom(fs, conf.BaseConfig()),
|
||||
WasmDispatchers: warpc.AllDispatchers(
|
||||
warpc.Options{
|
||||
PoolSize: 1,
|
||||
},
|
||||
warpc.Options{
|
||||
PoolSize: 1,
|
||||
},
|
||||
),
|
||||
}
|
||||
for _, f := range beforeInit {
|
||||
f(d)
|
||||
@@ -84,7 +75,7 @@ func GetTestConfigSectionFromStruct(section string, v any) config.AllProvider {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
p := hmaps.Params{
|
||||
p := maps.Params{
|
||||
section: config.FromTOMLConfigString(string(data)).Get(""),
|
||||
}
|
||||
cfg := config.NewFrom(p)
|
||||
|
||||
Vendored
+12
-28
@@ -1,16 +1,3 @@
|
||||
// Copyright 2025 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 deps
|
||||
|
||||
import (
|
||||
@@ -28,8 +15,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 +160,8 @@ func (d *Deps) Init() error {
|
||||
d.BuildState.DeferredExecutionsGroupedByRenderingContext = make(map[tpl.RenderingContext]*DeferredExecutions)
|
||||
}
|
||||
d.BuildState.DeferredExecutions = &DeferredExecutions{
|
||||
Executions: hmaps.NewCache[string, *tpl.DeferredExecution](),
|
||||
FilenamesWithPostPrefix: hmaps.NewCache[string, bool](),
|
||||
Executions: maps.NewCache[string, *tpl.DeferredExecution](),
|
||||
FilenamesWithPostPrefix: maps.NewCache[string, bool](),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -260,12 +247,12 @@ func (d *Deps) Init() error {
|
||||
common = d.ResourceSpec.SpecCommon
|
||||
}
|
||||
|
||||
d.Cfg.BaseConfig()
|
||||
fileCaches, err := filecache.NewCaches(d.PathSpec)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create file caches from configuration: %w", err)
|
||||
}
|
||||
|
||||
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)
|
||||
resourceSpec, err := resources.NewSpec(d.PathSpec, common, fileCaches, d.MemCache, d.BuildState, d.Log, d, d.ExecHelper, d.BuildClosers, d.BuildState)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create resource spec: %w", err)
|
||||
}
|
||||
@@ -430,9 +417,6 @@ type DepsCfg struct {
|
||||
// i18n handling.
|
||||
TranslationProvider ResourceProvider
|
||||
|
||||
// Build triggered by the IntegrationTest framework.
|
||||
IsIntegrationTest bool
|
||||
|
||||
// ChangesFromBuild for changes passed back to the server/watch process.
|
||||
ChangesFromBuild chan []identity.Identity
|
||||
}
|
||||
@@ -464,10 +448,10 @@ type Counters struct {
|
||||
type DeferredExecutions struct {
|
||||
// A set of filenames in /public that
|
||||
// contains a post-processing prefix.
|
||||
FilenamesWithPostPrefix *hmaps.Cache[string, bool]
|
||||
FilenamesWithPostPrefix *maps.Cache[string, bool]
|
||||
|
||||
// Maps a placeholder to a deferred execution.
|
||||
Executions *hmaps.Cache[string, *tpl.DeferredExecution]
|
||||
Executions *maps.Cache[string, *tpl.DeferredExecution]
|
||||
}
|
||||
|
||||
var _ identity.SignalRebuilder = (*BuildState)(nil)
|
||||
@@ -480,8 +464,8 @@ func (b *BuildState) StartStageRender(stage tpl.RenderingContext) {
|
||||
func (b *BuildState) StopStageRender(stage tpl.RenderingContext) {
|
||||
b.DeferredExecutionsGroupedByRenderingContext[stage] = b.DeferredExecutions
|
||||
b.DeferredExecutions = &DeferredExecutions{
|
||||
Executions: hmaps.NewCache[string, *tpl.DeferredExecution](),
|
||||
FilenamesWithPostPrefix: hmaps.NewCache[string, bool](),
|
||||
Executions: maps.NewCache[string, *tpl.DeferredExecution](),
|
||||
FilenamesWithPostPrefix: maps.NewCache[string, bool](),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-6
@@ -23,8 +23,7 @@
|
||||
"**/emojis.md",
|
||||
"**/commands/*",
|
||||
"**/showcase/*",
|
||||
"**/tools/*",
|
||||
"data/docs.yaml"
|
||||
"**/tools/*"
|
||||
],
|
||||
"ignoreRegExpList": [
|
||||
"# cspell: ignore fenced code blocks",
|
||||
@@ -60,14 +59,12 @@
|
||||
"marshal",
|
||||
"marshaling",
|
||||
"multihost",
|
||||
"multiplatform",
|
||||
"multiplatfom",
|
||||
"performantly",
|
||||
"preconfigured",
|
||||
"prerendering",
|
||||
"redirection",
|
||||
"redirections",
|
||||
"slugified",
|
||||
"slugify",
|
||||
"subexpression",
|
||||
"suppressible",
|
||||
"synchronisation",
|
||||
@@ -116,6 +113,7 @@
|
||||
"libros",
|
||||
"mercredi",
|
||||
"miesiąc",
|
||||
"miesiąc",
|
||||
"miesiąca",
|
||||
"miesiące",
|
||||
"miesięcy",
|
||||
@@ -146,7 +144,6 @@
|
||||
"Samsa",
|
||||
"Stucki",
|
||||
"Thénardier",
|
||||
"Vitter",
|
||||
"WASI",
|
||||
"# ----------------------------------------------------------------------",
|
||||
"# cspell: ignore operating systems and software packages",
|
||||
|
||||
@@ -77,7 +77,7 @@ config:
|
||||
full: true
|
||||
inline: true
|
||||
shortcut: true
|
||||
url_inline: false
|
||||
url_inline: true
|
||||
MD055:
|
||||
style: consistent
|
||||
MD056: true
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
**/news/**
|
||||
**/showcase/**
|
||||
**/zh/**
|
||||
@@ -129,8 +129,3 @@ body {
|
||||
text-decoration: none;
|
||||
padding-left: .0625em;
|
||||
}
|
||||
|
||||
/* Code spans within paragraphs, tables cells, list items, etc. */
|
||||
:not(pre) > code {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 13 KiB |
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 13 KiB |
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 13 KiB |
@@ -0,0 +1,6 @@
|
||||
import { initColorScheme } from './alpinejs/stores/index';
|
||||
|
||||
(function () {
|
||||
// This allows us to initialize the color scheme before AlpineJS etc. is loaded.
|
||||
initColorScheme();
|
||||
})();
|
||||
@@ -1,10 +1,6 @@
|
||||
import { scrollToActive } from 'js/helpers/index';
|
||||
import { initColorScheme } from './alpinejs/stores/index';
|
||||
|
||||
(function () {
|
||||
// This allows us to initialize the color scheme before AlpineJS etc. is loaded.
|
||||
initColorScheme();
|
||||
|
||||
// Now we know that the browser has JS enabled.
|
||||
document.documentElement.classList.remove('no-js');
|
||||
|
||||
|
||||
@@ -8,6 +8,14 @@ import focus from '@alpinejs/focus';
|
||||
|
||||
var debug = 0 ? console.log.bind(console, '[index]') : function () {};
|
||||
|
||||
// Turbolinks init.
|
||||
(function () {
|
||||
document.addEventListener('turbo:render', function (e) {
|
||||
// This is also called right after the body start. This is added to prevent flicker on navigation.
|
||||
initColorScheme();
|
||||
});
|
||||
})();
|
||||
|
||||
// Set up and start Alpine.
|
||||
(function () {
|
||||
// Register AlpineJS plugins.
|
||||
|
||||
@@ -29,7 +29,6 @@ Please refer to the relevant documentation for installation instructions:
|
||||
|
||||
[cloudcannon]: https://cloudcannon.com/
|
||||
[cloudflare pages]: https://pages.cloudflare.com/
|
||||
[commit information]: /methods/page/GitInfo
|
||||
[dart sass install]: /functions/css/sass/#dart-sass
|
||||
[dart sass]: https://sass-lang.com/dart-sass
|
||||
[git install]: https://git-scm.com/book/en/v2/Getting-Started-Installing-Git
|
||||
@@ -38,5 +37,4 @@ Please refer to the relevant documentation for installation instructions:
|
||||
[gitlab pages]: https://docs.gitlab.com/ee/user/project/pages/
|
||||
[go install]: https://go.dev/doc/install
|
||||
[go]: https://go.dev/
|
||||
[hugo modules]: /hugo-modules/
|
||||
[netlify]: https://www.netlify.com/
|
||||
|
||||
@@ -15,5 +15,3 @@ Prebuilt binaries are available for a variety of operating systems and architect
|
||||
Please consult your operating system documentation if you need help setting file permissions or modifying your PATH environment variable.
|
||||
|
||||
If you do not see a prebuilt binary for the desired edition, operating system, and architecture, install Hugo using one of the methods described below.
|
||||
|
||||
[latest release]: https://github.com/gohugoio/hugo/releases/latest
|
||||
|
||||
@@ -7,7 +7,7 @@ _comment: Do not remove front matter.
|
||||
To build the extended or extended/deploy edition from source you must:
|
||||
|
||||
1. Install [Git]
|
||||
1. Install [Go] version 1.24.0 or later
|
||||
1. Install [Go] version 1.23.0 or later
|
||||
1. Install a C compiler, either [GCC] or [Clang]
|
||||
1. Update your `PATH` environment variable as described in the [Go documentation]
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ _comment: Do not remove front matter.
|
||||
|
||||
### Homebrew
|
||||
|
||||
[Homebrew] is a free and open-source package manager for macOS and Linux. To install the extended/deploy edition of Hugo:
|
||||
[Homebrew] is a free and open-source package manager for macOS and Linux. To install the extended edition of Hugo:
|
||||
|
||||
```sh
|
||||
brew install hugo
|
||||
|
||||
@@ -27,14 +27,12 @@ _comment: Do not remove front matter.
|
||||
: The content's section.
|
||||
|
||||
`:sectionslug`
|
||||
: {{< new-in 0.149.0 />}}
|
||||
: The content's section using slugified section name. The slugified section name is the `slug` as defined in front matter, else the `title` as defined in front matter, else the automatic title.
|
||||
|
||||
`:sections`
|
||||
: The content's sections hierarchy. You can use a selection of the sections using _slice syntax_: `:sections[1:]` includes all but the first, `:sections[:last]` includes all but the last, `:sections[last]` includes only the last, `:sections[1:2]` includes section 2 and 3. Note that this slice access will not throw any out-of-bounds errors, so you don't have to be exact.
|
||||
|
||||
`:sectionslugs`
|
||||
: {{< new-in 0.149.0 />}}
|
||||
: The content's sections hierarchy using slugified section names. The slugified section name is the `slug` as defined in front matter, else the `title` as defined in front matter, else the automatic title. You can use a selection of the sections using _slice syntax_: `:sectionslugs[1:]` includes all but the first, `:sectionslugs[:last]` includes all but the last, `:sectionslugs[last]` includes only the last, `:sectionslugs[1:2]` includes section 2 and 3. Note that this slice access will not throw any out-of-bounds errors, so you don't have to be exact.
|
||||
|
||||
`:title`
|
||||
|
||||
@@ -43,5 +43,5 @@ As a practical example, Hugo's embedded link and image render hooks use the `Pag
|
||||
|
||||
[`RenderShortcodes`]: /methods/page/rendershortcodes/
|
||||
[Markdown notation]: /content-management/shortcodes/#notation
|
||||
[Embedded link render hook]: <{{% eturl render-link %}}>
|
||||
[Embedded image render hook]: <{{% eturl render-image %}}>
|
||||
[Embedded link render hook]: {{% eturl render-link %}}
|
||||
[Embedded image render hook]: {{% eturl render-image %}}
|
||||
|
||||
@@ -28,7 +28,7 @@ Learn more about Hugo's [features], [privacy protections], and [security model].
|
||||
[Hugo Modules]: /hugo-modules/
|
||||
[static site generator]: https://en.wikipedia.org/wiki/Static_site_generator
|
||||
[features]: /about/features/
|
||||
[security model]: /about/security/
|
||||
[security model]: about/security/
|
||||
[privacy protections]: /configuration/privacy
|
||||
|
||||
{{< youtube 0RKpf3rK57I >}}
|
||||
|
||||
@@ -24,8 +24,6 @@ hugo gen chromastyles [flags] [args]
|
||||
--highlightStyle string foreground and background colors for highlighted lines, e.g. --highlightStyle "#fff000 bg:#000fff"
|
||||
--lineNumbersInlineStyle string foreground and background colors for inline line numbers, e.g. --lineNumbersInlineStyle "#fff000 bg:#000fff"
|
||||
--lineNumbersTableStyle string foreground and background colors for table line numbers, e.g. --lineNumbersTableStyle "#fff000 bg:#000fff"
|
||||
--omitClassComments omit CSS class comment prefixes in the generated CSS
|
||||
--omitEmpty omit empty CSS rules (deprecated, no longer needed)
|
||||
--style string highlighter style (see https://xyproto.github.io/splash/docs/) (default "friendly")
|
||||
```
|
||||
|
||||
|
||||
@@ -45,6 +45,6 @@ Ensure you run this within the root directory of your site.
|
||||
|
||||
* [hugo](/commands/hugo/) - Build your site
|
||||
* [hugo new content](/commands/hugo_new_content/) - Create new content
|
||||
* [hugo new site](/commands/hugo_new_site/) - Create a new site
|
||||
* [hugo new theme](/commands/hugo_new_theme/) - Create a new theme
|
||||
* [hugo new site](/commands/hugo_new_site/) - Create a new site (skeleton)
|
||||
* [hugo new theme](/commands/hugo_new_theme/) - Create a new theme (skeleton)
|
||||
|
||||
|
||||
@@ -5,11 +5,13 @@ url: /commands/hugo_new_site/
|
||||
---
|
||||
## hugo new site
|
||||
|
||||
Create a new site
|
||||
Create a new site (skeleton)
|
||||
|
||||
### Synopsis
|
||||
|
||||
Create a new site at the specified path.
|
||||
Create a new site in the provided directory.
|
||||
The new site will have the correct structure, but no content or theme yet.
|
||||
Use `hugo new [contentPath]` to create new content.
|
||||
|
||||
```
|
||||
hugo new site [path] [flags]
|
||||
|
||||
@@ -5,12 +5,14 @@ url: /commands/hugo_new_theme/
|
||||
---
|
||||
## hugo new theme
|
||||
|
||||
Create a new theme
|
||||
Create a new theme (skeleton)
|
||||
|
||||
### Synopsis
|
||||
|
||||
Create a new theme with the specified name in the ./themes directory.
|
||||
This generates a functional theme including template examples and sample content.
|
||||
Create a new theme (skeleton) called [name] in ./themes.
|
||||
New theme is a skeleton. Please add content to the touched files. Add your
|
||||
name to the copyright line in the license and adjust the theme.toml file
|
||||
according to your needs.
|
||||
|
||||
```
|
||||
hugo new theme [name] [flags]
|
||||
@@ -19,8 +21,7 @@ hugo new theme [name] [flags]
|
||||
### Options
|
||||
|
||||
```
|
||||
--format string preferred file format (toml, yaml or json) (default "toml")
|
||||
-h, --help help for theme
|
||||
-h, --help help for theme
|
||||
```
|
||||
|
||||
### Options inherited from parent commands
|
||||
|
||||
@@ -47,7 +47,7 @@ cascade
|
||||
: See [configure cascade](/configuration/cascade/).
|
||||
|
||||
cleanDestinationDir
|
||||
: (`bool`) Whether to remove files from the [`publishDir`](#publishdir) that do not exist in the [`staticDir`](#staticdir) when building the site. This setting will not take effect if the `staticDir` does not exist. Note that `.gitignore` and `.gitattributes` files, along with directories named `.git`, are always preserved in the `publishDir`. Default is `false`.
|
||||
: (`bool`) Whether to remove files from the site's destination directory that do not have corresponding files in the `static` directory during the build. Default is `false`.
|
||||
|
||||
contentDir
|
||||
: (`string`) The designated directory for content files. Default is `content`. {{% module-mounts-note %}}
|
||||
@@ -262,7 +262,7 @@ staticDir
|
||||
: (`string`) The designated directory for static files. Default is `static`. {{% module-mounts-note %}}
|
||||
|
||||
summaryLength
|
||||
: (`int`) Applicable to [automatic summaries], the minimum number of words returned by the [`Summary`] method on a `Page` object. The `Summary` method will return content truncated at the paragraph boundary closest to the specified `summaryLength`, but at least this minimum number of words. Default is `70`.
|
||||
: (`int`) Applicable to [automatic summaries], the minimum number of words returned by the [`Summary`] method on a `Page` object. The `Summary` method will return content truncated at the paragraph boundary closest to the specified `summaryLength`, but at least this minimum number of words.
|
||||
|
||||
taxonomies
|
||||
: See [configure taxonomies](/configuration/taxonomies/).
|
||||
@@ -350,9 +350,9 @@ Some configuration settings, such as menus and custom parameters, can be defined
|
||||
[Chicago Manual of Style]: https://www.chicagomanualofstyle.org/home.html
|
||||
[default front matter configuration]: /configuration/front-matter/
|
||||
[duration]: https://pkg.go.dev/time#Duration
|
||||
[embedded alias template]: <{{% eturl alias %}}>
|
||||
[embedded Open Graph template]: <{{% eturl opengraph %}}>
|
||||
[embedded RSS template]: <{{% eturl rss %}}>
|
||||
[embedded alias template]: {{% eturl alias %}}
|
||||
[embedded Open Graph template]: {{% eturl opengraph %}}
|
||||
[embedded RSS template]: {{% eturl rss %}}
|
||||
[IANA Time Zone Database]: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
|
||||
[module mounts]: /configuration/module/#mounts
|
||||
[os.UserCacheDir]: https://pkg.go.dev/os#UserCacheDir
|
||||
|
||||
@@ -14,6 +14,7 @@ You can configure your site to cascade front matter values to the home page and
|
||||
For example, to cascade a "color" parameter to the home page and all its descendants:
|
||||
|
||||
{{< code-toggle file=hugo >}}
|
||||
title = 'Home'
|
||||
[cascade.params]
|
||||
color = 'red'
|
||||
{{< /code-toggle >}}
|
||||
@@ -60,14 +61,14 @@ Define an array of cascade parameters to apply different values to different tar
|
||||
[cascade.params]
|
||||
color = 'red'
|
||||
[cascade.target]
|
||||
path = '/books/**'
|
||||
path = '{/books/**}'
|
||||
kind = 'page'
|
||||
lang = '{en,de}'
|
||||
[[cascade]]
|
||||
[cascade.params]
|
||||
color = 'blue'
|
||||
[cascade.target]
|
||||
path = '/films/**'
|
||||
path = '{/films/**}'
|
||||
kind = 'page'
|
||||
environment = 'production'
|
||||
{{< /code-toggle >}}
|
||||
|
||||
@@ -90,11 +90,10 @@ Consider this site configuration:
|
||||
{{< code-toggle file=hugo >}}
|
||||
[frontmatter]
|
||||
date = [':filename', ':default']
|
||||
publishDate = [':filename', ':default']
|
||||
lastmod = ['lastmod', ':fileModTime']
|
||||
{{< /code-toggle >}}
|
||||
|
||||
To determine `date` and `publishDate`, Hugo tries to extract the value from the file name, falling back to the default ordered sequence of date fields.
|
||||
To determine `date`, Hugo tries to extract the date from the file name, falling back to the default ordered sequence of date fields.
|
||||
|
||||
To determine `lastmod`, Hugo looks for a `lastmod` field in front matter, falling back to the file's last modification timestamp.
|
||||
|
||||
|
||||
@@ -44,42 +44,20 @@ The HTTP cache involves two key aspects: determining which content to cache (the
|
||||
|
||||
The HTTP cache behavior is defined for a configured set of resources. Stale resources will be refreshed from the file cache, even if their configured Time-To-Live (TTL) has not expired. If HTTP caching is disabled for a resource, Hugo will bypass the cache and access the file directly.
|
||||
|
||||
This is the default configuration for HTTP caching:
|
||||
The default configuration disables everything:
|
||||
|
||||
{{< code-toggle config=HTTPCache />}}
|
||||
|
||||
respectCacheControlNoStoreInRequest
|
||||
: {{< new-in 0.151.0 />}}
|
||||
: (`bool`) Whether to respect the `no-store` directive in the server's `Cache-Control` request header when fetching remote resources via the [`resources.GetRemote`][] function. Default is `true`.
|
||||
|
||||
respectCacheControlNoStoreInResponse
|
||||
: {{< new-in 0.151.0 />}}
|
||||
: (`bool`) Whether to respect the `no-store` directive in the server's `Cache-Control` response header when fetching remote resources via the [`resources.GetRemote`][] function. Default is `false`.
|
||||
{{< code-toggle file=hugo >}}
|
||||
[HTTPCache.cache.for]
|
||||
excludes = ['**']
|
||||
includes = []
|
||||
{{< /code-toggle >}}
|
||||
|
||||
cache.for.excludes
|
||||
: (`string`) A list of [glob](g) patterns to exclude from caching. In its default configuration HTTP caching excludes all files.
|
||||
: (`string`) A list of [glob](g) patterns to exclude from caching.
|
||||
|
||||
cache.for.includes
|
||||
: (`string`) A list of [glob](g) patterns to cache.
|
||||
|
||||
polls
|
||||
: A slice of polling configurations.
|
||||
|
||||
polls.disable
|
||||
: (`bool`) Whether to disable polling for this configuration. Default is `true`.
|
||||
|
||||
polls.high
|
||||
: (`string`) The maximum polling interval expressed as a [duration](g). This is used when the resource is considered stable. Default is `0s`.
|
||||
|
||||
polls.low
|
||||
: (`string`) The minimum polling interval expressed as a [duration](g). This is used after a recent change and gradually increases towards `polls.high`. Default is `0s`.
|
||||
|
||||
polls.for.excludes
|
||||
: (`string`) A list of [glob](g) patterns to exclude from polling for this configuration.
|
||||
|
||||
polls.for.includes
|
||||
: (`string`) A list of [glob](g) patterns to include in polling for this configuration.
|
||||
|
||||
## HTTP polling
|
||||
|
||||
Polling is used in watch mode (e.g., `hugo server`) to detect changes in remote resources. Polling can be enabled even if HTTP caching is disabled. Detected changes trigger a rebuild of pages using the affected resource. Polling can be disabled for specific resources, typically those known to be static.
|
||||
@@ -100,13 +78,13 @@ polls
|
||||
: A slice of polling configurations.
|
||||
|
||||
polls.disable
|
||||
: (`bool`) Whether to disable polling for this configuration. Default is `true`.
|
||||
|
||||
polls.high
|
||||
: (`string`) The maximum polling interval expressed as a [duration](g). This is used when the resource is considered stable. Default is `0s`.
|
||||
: (`bool`) Whether to disable polling for this configuration.
|
||||
|
||||
polls.low
|
||||
: (`string`) The minimum polling interval expressed as a [duration](g). This is used after a recent change and gradually increases towards `polls.high`. Default is `0s`.
|
||||
: (`string`) The minimum polling interval expressed as a [duration](g). This is used after a recent change and gradually increases towards `polls.high`.
|
||||
|
||||
polls.high
|
||||
: (`string`) The maximum polling interval expressed as a [duration](g). This is used when the resource is considered stable.
|
||||
|
||||
polls.for.excludes
|
||||
: (`string`) A list of [glob](g) patterns to exclude from polling for this configuration.
|
||||
|
||||
@@ -185,9 +185,9 @@ public
|
||||
[`Language.LanguageName`]: /methods/site/language/#languagename
|
||||
[`Language.Weight`]: /methods/site/language/#weight
|
||||
[`Title`]: /methods/site/title/
|
||||
[embedded alias template]: <{{% eturl alias %}}>
|
||||
[embedded OpenGraph template]: <{{% eturl opengraph %}}>
|
||||
[embedded RSS template]: <{{% eturl rss %}}>
|
||||
[embedded alias template]: {{% eturl alias %}}
|
||||
[embedded OpenGraph template]: {{% eturl opengraph %}}
|
||||
[embedded RSS template]: {{% eturl rss %}}
|
||||
[RFC 5646]: https://datatracker.ietf.org/doc/html/rfc5646#section-2.1
|
||||
[RFC 5646 § 2.2.7]: https://datatracker.ietf.org/doc/html/rfc5646#section-2.2.7
|
||||
[translating by file name]: /content-management/multilingual/#translation-by-file-name
|
||||
|
||||
@@ -94,24 +94,10 @@ enable = true
|
||||
|
||||
With this configuration, to format text as deleted, wrap it with double-tildes.
|
||||
|
||||
#### Footnote
|
||||
|
||||
Enabled by default, the Footnote extension enables inclusion of footnotes in Markdown.
|
||||
|
||||
enable
|
||||
: {{< new-in 0.151.0 />}}
|
||||
: (`bool`) Whether to enable the Footnotes extension. Default is `true`.
|
||||
|
||||
backlinkHTML
|
||||
: {{< new-in 0.151.0 />}}
|
||||
: (`string`) The HTML to be displayed at the end of a footnote that links the user back to the corresponding reference in the main text. The default is ↩︎ (a return arrow symbol).
|
||||
|
||||
enableAutoIDPrefix
|
||||
: {{< new-in 0.151.0 />}}
|
||||
: (`bool`) Whether to prepend a unique prefix to footnote IDs, preventing clashes when multiple documents are rendered together. This prefix is unique to each logical path, which means that the prefix is not unique across content dimensions such as language. Default is `false`.
|
||||
|
||||
#### Passthrough
|
||||
|
||||
{{< new-in 0.122.0 />}}
|
||||
|
||||
Enable the Passthrough extension to include mathematical equations and expressions in Markdown using LaTeX markup. See [mathematics in Markdown] for details.
|
||||
|
||||
#### Typographer
|
||||
@@ -216,7 +202,7 @@ backend
|
||||
: (`string`) The backend output file format. Default is `html5`.
|
||||
|
||||
extensions
|
||||
: (`string array`) An array of enabled extensions, such as `asciidoctor-html5s`, `asciidoctor-bibtex`, or `asciidoctor-diagram`.
|
||||
: (`string array`) An array of enabled extensions, one or more of `asciidoctor-html5s`, `asciidoctor-bibtex`, `asciidoctor-diagram`, `asciidoctor-interdoc-reftext`, `asciidoctor-katex`, `asciidoctor-latex`, `asciidoctor-mathematical`, or `asciidoctor-question`.
|
||||
|
||||
> [!note]
|
||||
> To mitigate security risks, entries in the extension array may not contain forward slashes (`/`), backslashes (`\`), or periods. Due to this restriction, extensions must be in Ruby's `$LOAD_PATH`.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user