Compare commits

...

93 Commits

Author SHA1 Message Date
hugoreleaser 3c8a471390 releaser: Bump versions for release of 0.123.0
[ci skip]
2024-02-19 16:32:38 +00:00
dependabot[bot] f54ba6f9ef build(deps): bump github.com/tdewolff/minify/v2 from 2.20.16 to 2.20.17
Bumps [github.com/tdewolff/minify/v2](https://github.com/tdewolff/minify) from 2.20.16 to 2.20.17.
- [Release notes](https://github.com/tdewolff/minify/releases)
- [Commits](https://github.com/tdewolff/minify/compare/v2.20.16...v2.20.17)

---
updated-dependencies:
- dependency-name: github.com/tdewolff/minify/v2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-19 17:21:17 +01:00
dependabot[bot] 4019b177e6 build(deps): bump github.com/evanw/esbuild from 0.20.0 to 0.20.1
Bumps [github.com/evanw/esbuild](https://github.com/evanw/esbuild) from 0.20.0 to 0.20.1.
- [Release notes](https://github.com/evanw/esbuild/releases)
- [Changelog](https://github.com/evanw/esbuild/blob/main/CHANGELOG.md)
- [Commits](https://github.com/evanw/esbuild/compare/v0.20.0...v0.20.1)

---
updated-dependencies:
- dependency-name: github.com/evanw/esbuild
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-19 17:12:14 +01:00
Bjørn Erik Pedersen 5dbc29dc6c Handle rebuilds when resources passed to transform.Unmarshal etc. changes
Fixes #12065
2024-02-19 14:50:23 +01:00
Bjørn Erik Pedersen 5ada27bf65 Fix handling of build options for term pages
Fixes #12058
2024-02-18 16:50:35 +01:00
Bjørn Erik Pedersen 60b176cb57 docs: Regen docshelper 2024-02-18 13:20:15 +01:00
Bjørn Erik Pedersen afe5b6d7df Fix sample logic when adding content files in server
The partial rebuilds works by calaulating a baseline from a change set.

For new content, this doesn't work, so to avoid rebuilding everything, we first
try to collect a sample of surrounding identities (e.g. content files in the same section).

This commit fixes a flaw in that logic that in some (many...) cases would return a too small sample set.

Fixes #12054
2024-02-18 12:24:27 +01:00
Christian Oliff 168d375784 all: Fix typos and some URLs 2024-02-18 12:16:30 +01:00
dependabot[bot] 4a53fd56b7 build(deps): bump golang.org/x/tools from 0.17.0 to 0.18.0
Bumps [golang.org/x/tools](https://github.com/golang/tools) from 0.17.0 to 0.18.0.
- [Release notes](https://github.com/golang/tools/releases)
- [Commits](https://github.com/golang/tools/compare/v0.17.0...v0.18.0)

---
updated-dependencies:
- dependency-name: golang.org/x/tools
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-17 18:27:49 +01:00
Bjørn Erik Pedersen fc6aabe938 Fix handling of draft term pages
By just removing the term page and all of its page entries.

Fixes #12055
2024-02-17 18:12:25 +01:00
Bjørn Erik Pedersen 9cc65757a1 releaser: Fix archive homepage and description
Fixes #12053
2024-02-17 13:32:15 +01:00
Bjørn Erik Pedersen 4835f9e898 commands: Fix --clock with the list command
Fixes #11888
2024-02-17 13:14:15 +01:00
Bjørn Erik Pedersen 5bdda0bdbf Don't use the same value in .Data.Term.Title as in .Title
Fixes #12041
2024-02-17 12:34:50 +01:00
Bjørn Erik Pedersen 9679443c15 Fix server panic on i18n file change
Fixes #12048
2024-02-17 11:46:45 +01:00
dependabot[bot] 2d1681d915 build(deps): bump golang.org/x/net from 0.20.0 to 0.21.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.20.0 to 0.21.0.
- [Commits](https://github.com/golang/net/compare/v0.20.0...v0.21.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-17 11:16:15 +01:00
Bjørn Erik Pedersen 68f67c9aeb Fix rebuild regression on non-default content language edits
Fixes #12043
2024-02-16 19:05:18 +01:00
Fabian Kammel 43ea2cd660 Let standard library handle charset parameter to MIME types
Fixes #10734
2024-02-16 18:24:25 +01:00
Bjørn Erik Pedersen f1491c900e Fix i18n rebuild regression
Fixes #12039
2024-02-16 16:17:57 +01:00
Bjørn Erik Pedersen 639073e4fe Fix rebuild with resources.Concat
Fixes #12017
2024-02-16 13:17:53 +01:00
Joe Mooring 21d9057dbf Add images.Dither filter
Closes #8598
2024-02-11 22:51:11 +02:00
Christian Oliff 0672b5c766 all: Fix typos 2024-02-11 13:51:33 +02:00
Rosano e309f82efe resources/page: Fix typo 2024-02-10 21:28:03 +02:00
Joe Mooring 6f59d96bba markup/goldmark: Update TOC test
- Change copyright date
- Change name of site configuration file
- Reference issue numbers in failing tests
2024-02-10 20:16:59 +02:00
Bjørn Erik Pedersen caba6ba6e7 Fix taxonomy term with backing file regression
Fixes #12020
2024-02-10 18:48:53 +02:00
Joe Mooring f4575e5f29 markup/goldmark: Improve TOC tests 2024-02-10 16:03:37 +02:00
Bjørn Erik Pedersen 0851c175ad Move the duplicate page/resource filter
Move the removal of duplicate content and resource files after we have determined if we're inside a leaf bundle or not.

Note that these would eventually have been filtered out as duplicates when  inserting them into the document store, but doing it here will preserve a consistent ordering.

Fixes #12013
2024-02-08 20:11:17 +01:00
Bjørn Erik Pedersen 676e6875da Make HTML behave exactly like other content formats (note)
Fixes #11999
2024-02-07 21:37:04 +01:00
Bjørn Erik Pedersen 068ccde4c7 docs: Regen CLI docs 2024-02-07 20:49:52 +01:00
Bjørn Erik Pedersen 7cb447ab8e docs: Regenerate docshelper 2024-02-07 20:48:25 +01:00
Bjørn Erik Pedersen b8d5090452 Merge commit '6efb279bfacbd7304cef994be8181c6f804e7dd4' 2024-02-07 20:46:41 +01:00
Bjørn Erik Pedersen 6efb279bfa Squashed 'docs/' changes from 5c085a37b..a9584e3d1
a9584e3d1 ci: bump GitHub workflow actions to latest versions
f37ee374d Fix methods related to time.After
a49214057 Correct heading render hook example
4b696f936 Update README.md
b5a6e4039 Clean up the contributing section
a5d79ed19 Fixed typo: instea → instead
6150a60e3 Remove the "local file templates" page
9395743dc Update/vendor theme
33d8c10cc Remove output format "name" parameter
7200ad97d Add security section to resources.GetRemote page
3f1e056b2 Remove erroneous front matter field
07c9a7e42 Add alpha index to glossary
6619c8aa0 Fix Page.Params example
145a92359 Simplify string concat example in math.Add
42488bb09 Add string concat example to math.Add
eb20521a2 Fix flash of unstyled content with mathematical markup
74603bebe Fix typo in 'typesetting'

git-subtree-dir: docs
git-subtree-split: a9584e3d14
2024-02-07 20:46:41 +01:00
dependabot[bot] 301bafabe0 build(deps): bump golang.org/x/mod from 0.14.0 to 0.15.0
Bumps [golang.org/x/mod](https://github.com/golang/mod) from 0.14.0 to 0.15.0.
- [Commits](https://github.com/golang/mod/compare/v0.14.0...v0.15.0)

---
updated-dependencies:
- dependency-name: golang.org/x/mod
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-07 20:44:21 +01:00
Bjørn Erik Pedersen 9571246bcc Upgrade to Go 1.22
Fixes #12010
2024-02-07 20:42:42 +01:00
Bjørn Erik Pedersen 0257eb50a4 Avoid impporting deploy from config when nodeploy tag is set
Test:

```
go list -tags nodeploy ./... | grep deploy
```

Fixes #12009
2024-02-07 20:38:13 +01:00
Bjørn Erik Pedersen a65622a13e Fix rebuild of changed bundled content files
Fixes #12000
2024-02-06 21:53:33 +01:00
Bjørn Erik Pedersen 146aedd7aa Fix site.Taxonomies for taxonomies with space in name
Fixes #12001
2024-02-06 18:17:30 +01:00
Bjørn Erik Pedersen bd0200da6e commands: Remove unused memstats flag 2024-02-05 19:06:27 +01:00
Bjørn Erik Pedersen a80c3021ba source: Remove unused Filesystem struct 2024-02-05 15:03:03 +01:00
Bjørn Erik Pedersen 9df7b295bc Filter dot files etc. in i18n
Closes #11993
2024-02-05 14:54:02 +01:00
Bjørn Erik Pedersen c37bf19c89 commands: Revert the recent changes that allowed profiling on server rebuilds
There have been indications that this may freeze the server.
2024-02-05 14:27:35 +01:00
Bjørn Erik Pedersen 9c6d377872 commands: Make the server flag --renderToDisk into --renderToMemory (note)
Fixes #11987
2024-02-05 14:04:17 +01:00
dependabot[bot] 58d7f83390 build(deps): bump github.com/yuin/goldmark from 1.6.0 to 1.7.0
Bumps [github.com/yuin/goldmark](https://github.com/yuin/goldmark) from 1.6.0 to 1.7.0.
- [Release notes](https://github.com/yuin/goldmark/releases)
- [Commits](https://github.com/yuin/goldmark/compare/v1.6.0...v1.7.0)

---
updated-dependencies:
- dependency-name: github.com/yuin/goldmark
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-05 11:48:46 +01:00
Bjørn Erik Pedersen 609d798e34 Handle resource changes when the resources is already evicted from cache
Also fix a logical flaw in the cache resizer that made it too aggressive. After this I haven't been able to reproduce #11988, but I need to look closer.

Closes #11973
Updates #11988
2024-02-04 16:55:06 +01:00
Bjørn Erik Pedersen 53f204310e all: Rename Unmormalized => Unnormalized 2024-02-03 18:10:38 +01:00
Joe Mooring 7f82461407 hugolib: Formally deprecate .Page.NextPage .Page.PrevPage
Use .Page.Next and .Page.Prev instead.
2024-02-03 17:28:52 +01:00
Bjørn Erik Pedersen b72f909725 hugio: Rename strigReadSeeker => stringReadSeeker 2024-02-03 17:25:34 +01:00
Joe Mooring 3a665ddbf9 resources/page: Formally deprecate .Site.LastChange
Use .Site.Lastmod instead.
2024-02-03 17:11:06 +01:00
Bjørn Erik Pedersen 46575baa02 Preserve file/dir name case when loading data
Fixes #11979
2024-02-03 16:30:10 +01:00
Bjørn Erik Pedersen 058f230a1b Detect now invalid path patterns in cascade
Closes #11977
2024-02-03 15:07:59 +01:00
Bjørn Erik Pedersen a66480f70c Handle build vs _build in front matter
* Throw a detailed error message in the mentioned case
* Also fixed a dropped error

Fixes #11970
2024-02-03 15:07:59 +01:00
Bjørn Erik Pedersen e33a632551 resources: Optimize reading resource Content when it's already a string 2024-02-03 15:07:59 +01:00
Bjørn Erik Pedersen 2873324898 Misc resource fixes/improvements
* Add --pprof flag to server to enable profile debugging.
* Don't cache the resource content, it seem to eat memory on bigger sites.
* Keep --printMemoryUsag running in server

Fixes #11974
2024-02-02 18:46:23 +01:00
Joe Mooring d0788b96ae tpl/tplimpl: Update embedded instagram, twitter, and vimeo shortcodes
- Replace data.GetJSON calls with resources.GetRemote
- Remove usage of Facebook’s oEmbed Read feature

Fixes #11971
2024-02-02 08:01:45 +01:00
Bjørn Erik Pedersen 034fbef50d Add some more context to error
Updates #11970
2024-02-01 21:40:32 +01:00
dependabot[bot] 54ad51e8a6 build(deps): bump github.com/getkin/kin-openapi from 0.122.0 to 0.123.0
Bumps [github.com/getkin/kin-openapi](https://github.com/getkin/kin-openapi) from 0.122.0 to 0.123.0.
- [Release notes](https://github.com/getkin/kin-openapi/releases)
- [Commits](https://github.com/getkin/kin-openapi/compare/v0.122.0...v0.123.0)

---
updated-dependencies:
- dependency-name: github.com/getkin/kin-openapi
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-01 19:56:04 +01:00
dependabot[bot] bd1bcc0f91 build(deps): bump github.com/tdewolff/minify/v2 from 2.20.13 to 2.20.16
Bumps [github.com/tdewolff/minify/v2](https://github.com/tdewolff/minify) from 2.20.13 to 2.20.16.
- [Release notes](https://github.com/tdewolff/minify/releases)
- [Commits](https://github.com/tdewolff/minify/compare/v2.20.13...v2.20.16)

---
updated-dependencies:
- dependency-name: github.com/tdewolff/minify/v2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-01 19:55:31 +01:00
Bjørn Erik Pedersen 8d42a7942a Improve nilpointer error message 2024-02-01 19:53:51 +01:00
Bjørn Erik Pedersen 4174a7866b Fix disabled languages regression
Fixes #11959
2024-02-01 19:42:55 +01:00
Joe Mooring 5dd06b4136 tpl/data: Fix GetCSV deprecation message 2024-02-01 19:21:15 +01:00
Bjørn Erik Pedersen f5ec75db36 hugolib: Adjust a test case 2024-02-01 18:20:13 +01:00
Joe Mooring 6cb3bda3d1 hugolib: Revert deprecation of .Page.Lang
Deprecation message was also emitted when calling .Page.Language.Lang.
Reverting for now, but will remove all references to .Page.Lang from
documentation.
2024-02-01 18:00:50 +01:00
Joe Mooring 963cecc12c all: Deprecate .Page.Lang and .Page.File.Lang
Use .Page.Language.Lang instead.
2024-02-01 17:12:52 +01:00
Bjørn Erik Pedersen d8f0e30715 Fix failing test on Windows 2024-02-01 15:10:52 +01:00
Joe Mooring b6def61727 config/security: Add SYSTEMDRIVE to OsEnv allowlist 2024-02-01 15:10:05 +01:00
Bjørn Erik Pedersen 1891d5e6b5 hugolib: Add some more details to the "paginator not supported" error
See #11949
2024-02-01 08:18:11 +01:00
Bjørn Erik Pedersen 156f08de35 Run go mod tidy 2024-02-01 08:08:58 +01:00
dependabot[bot] b332f243fd build(deps): bump github.com/evanw/esbuild from 0.19.12 to 0.20.0
Bumps [github.com/evanw/esbuild](https://github.com/evanw/esbuild) from 0.19.12 to 0.20.0.
- [Release notes](https://github.com/evanw/esbuild/releases)
- [Changelog](https://github.com/evanw/esbuild/blob/main/CHANGELOG.md)
- [Commits](https://github.com/evanw/esbuild/compare/v0.19.12...v0.20.0)

---
updated-dependencies:
- dependency-name: github.com/evanw/esbuild
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-31 22:13:09 +01:00
Bjørn Erik Pedersen d8c2734178 deploy: Fix CloudFront invalidation with AWS SDK2 2024-01-31 22:12:48 +01:00
Bjørn Erik Pedersen d8e1e82188 deps: Update gocloud.dev/aws 2024-01-31 22:12:48 +01:00
Franky W a1c64989df Upgrade to deploy to use AWS SDK V2 2024-01-31 22:12:48 +01:00
Bjørn Erik Pedersen 6c3b6ba3e6 Improve error message when attempting to paginate from a single page template
Fixes #11953
2024-01-31 16:54:34 +01:00
dependabot[bot] 4d98b0ed6a build(deps): bump github.com/aws/aws-sdk-go from 1.48.6 to 1.50.7
Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.48.6 to 1.50.7.
- [Release notes](https://github.com/aws/aws-sdk-go/releases)
- [Commits](https://github.com/aws/aws-sdk-go/compare/v1.48.6...v1.50.7)

---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-31 13:43:46 +01:00
dependabot[bot] 15b9976b7a build(deps): bump golang.org/x/image from 0.14.0 to 0.15.0
Bumps [golang.org/x/image](https://github.com/golang/image) from 0.14.0 to 0.15.0.
- [Commits](https://github.com/golang/image/compare/v0.14.0...v0.15.0)

---
updated-dependencies:
- dependency-name: golang.org/x/image
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-31 13:42:24 +01:00
Bjørn Erik Pedersen 34d63c8d1c Fix build error 2024-01-31 13:00:56 +01:00
Bjørn Erik Pedersen 51615440bf docs: Make null booleans falsy in the docs helper 2024-01-31 12:34:28 +01:00
Bjørn Erik Pedersen bd66d30295 Filter out duplicate content resource files
We do a slight normalisation of the content paths (lower case, replacing " " with "-") and remove andy language identifier before inserting them into the content tree.

This means that, given that that the default content language is `en`:

```
index.md
index.html
Foo Bar.txt
foo-bar.txt
foo-bar.en.txt
Foo-Bar.txt
```

The bundle above will be reduced to one content file with one resource (`foo-bar.txt`).

Before this commit, what version of the `foo-bar.txt` you ended up with was undeterministic. No  we pick the first determined by sort order.

Note that the sort order is stable, but we recommend avoiding situations like the above.

Closes #11946
2024-01-31 10:06:04 +01:00
Bjørn Erik Pedersen 7caa5b3e50 docs: Regen docs helper 2024-01-31 09:45:35 +01:00
Bjørn Erik Pedersen 309d61b220 output: Prevent setting Name directly in new output formats
Name is derived from the map key.

Closes #11947
2024-01-31 09:43:02 +01:00
Bjørn Erik Pedersen 5b7cb258ec Create default link and image render hooks
Fixes #11933
2024-01-30 20:12:19 +01:00
Bjørn Erik Pedersen 80595bbe3e Fix recent regression .Resources.Get for resources with spaces in filename
Fixes #11944
2024-01-30 20:12:03 +01:00
Bjørn Erik Pedersen afee781f03 Emit a warning that can be turned off when overwriting built-in .Params values
Fixes #11941
2024-01-30 20:12:03 +01:00
Bjørn Erik Pedersen 4e84f57efb Add warnidf template function
Also rename config `ignoreErrors` => `ignoreLogs`

But the old still works.

Closes #9189
2024-01-30 20:12:03 +01:00
Bjørn Erik Pedersen f31a6db797 Add path, kind and lang to content front matter
Note that none of these can be set via cascade (you will get an error)

Fixes #11544
2024-01-30 20:12:03 +01:00
Lars Lehtonen ec22bb31a8 hugofs/glob: Fix dropped test error 2024-01-28 23:31:10 +01:00
Bjørn Erik Pedersen a795acbcd8 all: Run gofumpt -l -w . 2024-01-28 23:14:09 +01:00
Bjørn Erik Pedersen 982d9513e7 testing: Simplify some integration tests 2024-01-28 22:17:22 +01:00
Bjørn Erik Pedersen 6dedb4efc7 Add the [params] concept to front matter
This is deliberately very simple, but should not break anything. We need to introduce this in baby steps, but this should allow us to introduce this in the documentation.

Note that the `params` section's key/values will be added to `.Params` last. This means that you can have different values for "Hugo's summary" and the custom ".Params.summary" if you want to.

Updates #11055
2024-01-28 21:38:40 +01:00
Bjørn Erik Pedersen 292626e679 tpl/data: Deprecate data.GetJSON and data.GetCSV 2024-01-28 16:37:36 +01:00
razonyang 60d954c785 modules: Print required Hugo version for incompatible modules 2024-01-28 15:23:21 +01:00
Bjørn Erik Pedersen 63e0a92894 hugolib: Remove unused test image 2024-01-28 15:14:53 +01:00
Kandula Naveen ce7daa6156 navigation: Improve menu cache 2024-01-28 15:11:57 +01:00
Bjørn Erik Pedersen 2a0329423c testing: Rename integration_test.go to PACKAGE_integration_test.go
Primary motivation making them easier to find in the code editor.
2024-01-28 11:41:59 +01:00
Bjørn Erik Pedersen 50dc327d1a Port some integration tests to new test setup
The method I'm currently using (if other want to help) is:

* Add fmt.Println(b.DumpTxtar()) after the Build step
* Add that to a files var and pass that to Test(t, files) or similar
* Then, if possible, try to reduce the files/content down to what's needed in test.

Note that if the test is small, it's probably faster just to manually re-create the test.
2024-01-28 11:29:23 +01:00
339 changed files with 4933 additions and 3176 deletions
+2 -2
View File
@@ -4,7 +4,7 @@ parameters:
defaults: &defaults defaults: &defaults
resource_class: large resource_class: large
docker: docker:
- image: bepsays/ci-hugoreleaser:1.22100.20600 - image: bepsays/ci-hugoreleaser:1.22200.20000
environment: &buildenv environment: &buildenv
GOMODCACHE: /root/project/gomodcache GOMODCACHE: /root/project/gomodcache
version: 2 version: 2
@@ -60,7 +60,7 @@ jobs:
environment: environment:
<<: [*buildenv] <<: [*buildenv]
docker: docker:
- image: bepsays/ci-hugoreleaser-linux-arm64:1.22100.20600 - image: bepsays/ci-hugoreleaser-linux-arm64:1.22200.20000
steps: steps:
- *restore-cache - *restore-cache
- &attach-workspace - &attach-workspace
+1 -1
View File
@@ -14,7 +14,7 @@ jobs:
test: test:
strategy: strategy:
matrix: matrix:
go-version: [1.21.x] go-version: [1.22.x]
os: [ubuntu-latest] os: [ubuntu-latest]
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
+1 -1
View File
@@ -16,7 +16,7 @@ jobs:
test: test:
strategy: strategy:
matrix: matrix:
go-version: [1.20.x,1.21.x] go-version: [1.21.x,1.22.x]
os: [ubuntu-latest, macos-latest, windows-latest] os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
+41 -9
View File
@@ -25,6 +25,7 @@ import (
"github.com/bep/lazycache" "github.com/bep/lazycache"
"github.com/bep/logg" "github.com/bep/logg"
"github.com/gohugoio/hugo/common/collections"
"github.com/gohugoio/hugo/common/herrors" "github.com/gohugoio/hugo/common/herrors"
"github.com/gohugoio/hugo/common/loggers" "github.com/gohugoio/hugo/common/loggers"
"github.com/gohugoio/hugo/common/paths" "github.com/gohugoio/hugo/common/paths"
@@ -63,11 +64,26 @@ func New(opts Options) *Cache {
infol := opts.Log.InfoCommand("dynacache") infol := opts.Log.InfoCommand("dynacache")
evictedIdentities := collections.NewStack[identity.Identity]()
onEvict := func(k, v any) {
if !opts.Running {
return
}
identity.WalkIdentitiesShallow(v, func(level int, id identity.Identity) bool {
evictedIdentities.Push(id)
return false
})
resource.MarkStale(v)
}
c := &Cache{ c := &Cache{
partitions: make(map[string]PartitionManager), partitions: make(map[string]PartitionManager),
opts: opts, onEvict: onEvict,
stats: stats, evictedIdentities: evictedIdentities,
infol: infol, opts: opts,
stats: stats,
infol: infol,
} }
c.stop = c.start() c.stop = c.start()
@@ -106,14 +122,23 @@ type Cache struct {
mu sync.RWMutex mu sync.RWMutex
partitions map[string]PartitionManager partitions map[string]PartitionManager
opts Options
infol logg.LevelLogger onEvict func(k, v any)
evictedIdentities *collections.Stack[identity.Identity]
opts Options
infol logg.LevelLogger
stats *stats stats *stats
stopOnce sync.Once stopOnce sync.Once
stop func() stop func()
} }
// DrainEvictedIdentities drains the evicted identities from the cache.
func (c *Cache) DrainEvictedIdentities() []identity.Identity {
return c.evictedIdentities.Drain()
}
// ClearMatching clears all partition for which the predicate returns true. // ClearMatching clears all partition for which the predicate returns true.
func (c *Cache) ClearMatching(predicate func(k, v any) bool) { func (c *Cache) ClearMatching(predicate func(k, v any) bool) {
g := rungroup.Run[PartitionManager](context.Background(), rungroup.Config[PartitionManager]{ g := rungroup.Run[PartitionManager](context.Background(), rungroup.Config[PartitionManager]{
@@ -318,9 +343,13 @@ func GetOrCreatePartition[K comparable, V any](c *Cache, name string, opts Optio
const numberOfPartitionsEstimate = 10 const numberOfPartitionsEstimate = 10
maxSize := opts.CalculateMaxSize(c.opts.MaxSize / numberOfPartitionsEstimate) maxSize := opts.CalculateMaxSize(c.opts.MaxSize / numberOfPartitionsEstimate)
onEvict := func(k K, v V) {
c.onEvict(k, v)
}
// Create a new partition and cache it. // Create a new partition and cache it.
partition := &Partition[K, V]{ partition := &Partition[K, V]{
c: lazycache.New(lazycache.Options[K, V]{MaxEntries: maxSize}), c: lazycache.New(lazycache.Options[K, V]{MaxEntries: maxSize, OnEvict: onEvict}),
maxSize: maxSize, maxSize: maxSize,
trace: c.opts.Log.Logger().WithLevel(logg.LevelTrace).WithField("partition", name), trace: c.opts.Log.Logger().WithLevel(logg.LevelTrace).WithField("partition", name),
opts: opts, opts: opts,
@@ -445,7 +474,6 @@ func (p *Partition[K, V]) clearOnRebuild(changeset ...identity.Identity) {
}, },
), ),
) )
resource.MarkStale(v)
return true return true
} }
return false return false
@@ -483,6 +511,10 @@ func (p *Partition[K, V]) adjustMaxSize(newMaxSize int) int {
if newMaxSize < minMaxSize { if newMaxSize < minMaxSize {
newMaxSize = minMaxSize newMaxSize = minMaxSize
} }
oldMaxSize := p.maxSize
if newMaxSize == oldMaxSize {
return 0
}
p.maxSize = newMaxSize p.maxSize = newMaxSize
// fmt.Println("Adjusting max size of partition from", oldMaxSize, "to", newMaxSize) // fmt.Println("Adjusting max size of partition from", oldMaxSize, "to", newMaxSize)
return p.c.Resize(newMaxSize) return p.c.Resize(newMaxSize)
@@ -535,7 +567,7 @@ type stats struct {
func (s *stats) adjustCurrentMaxSize() bool { func (s *stats) adjustCurrentMaxSize() bool {
newCurrentMaxSize := int(math.Floor(float64(s.opts.MaxSize) * s.adjustmentFactor)) newCurrentMaxSize := int(math.Floor(float64(s.opts.MaxSize) * s.adjustmentFactor))
if newCurrentMaxSize < s.opts.MaxSize { if newCurrentMaxSize < s.opts.MinMaxSize {
newCurrentMaxSize = int(s.opts.MinMaxSize) newCurrentMaxSize = int(s.opts.MinMaxSize)
} }
changed := newCurrentMaxSize != s.currentMaxSize changed := newCurrentMaxSize != s.currentMaxSize
+1 -3
View File
@@ -15,6 +15,7 @@
package filecache package filecache
import ( import (
"errors"
"fmt" "fmt"
"path" "path"
"path/filepath" "path/filepath"
@@ -24,8 +25,6 @@ import (
"github.com/gohugoio/hugo/common/maps" "github.com/gohugoio/hugo/common/maps"
"github.com/gohugoio/hugo/config" "github.com/gohugoio/hugo/config"
"errors"
"github.com/mitchellh/mapstructure" "github.com/mitchellh/mapstructure"
"github.com/spf13/afero" "github.com/spf13/afero"
) )
@@ -225,7 +224,6 @@ func DecodeConfig(fs afero.Fs, bcfg config.BaseConfig, m map[string]any) (Config
// Resolves :resourceDir => /myproject/resources etc., :cacheDir => ... // Resolves :resourceDir => /myproject/resources etc., :cacheDir => ...
func resolveDirPlaceholder(fs afero.Fs, bcfg config.BaseConfig, placeholder string) (cacheDir string, isResource bool, err error) { func resolveDirPlaceholder(fs afero.Fs, bcfg config.BaseConfig, placeholder string) (cacheDir string, isResource bool, err error) {
switch strings.ToLower(placeholder) { switch strings.ToLower(placeholder) {
case ":resourcedir": case ":resourcedir":
return "", true, nil return "", true, nil
-2
View File
@@ -60,7 +60,6 @@ func (c *Cache) Prune(force bool) (int, error) {
counter := 0 counter := 0
err := afero.Walk(c.Fs, "", func(name string, info os.FileInfo, err error) error { err := afero.Walk(c.Fs, "", func(name string, info os.FileInfo, err error) error {
if info == nil { if info == nil {
return nil return nil
} }
@@ -69,7 +68,6 @@ func (c *Cache) Prune(force bool) (int, error) {
if info.IsDir() { if info.IsDir() {
f, err := c.Fs.Open(name) f, err := c.Fs.Open(name)
if err != nil { if err != nil {
// This cache dir may not exist. // This cache dir may not exist.
return nil return nil
Executable
+2
View File
@@ -0,0 +1,2 @@
#!/usr/bin/env bash
diff <(gofmt -d .) <(printf '')
-1
View File
@@ -461,7 +461,6 @@ func collectMethodsRecursive(pkg string, f []*ast.Field) []string {
pkg, pkg,
tt.Methods.List)...) tt.Methods.List)...)
} }
} else { } else {
// Embedded, but in a different file/package. Return the // Embedded, but in a different file/package. Return the
// package.Name and deal with that later. // package.Name and deal with that later.
+10 -8
View File
@@ -22,6 +22,7 @@ import (
"os" "os"
"os/signal" "os/signal"
"path/filepath" "path/filepath"
"runtime"
"strings" "strings"
"sync" "sync"
"sync/atomic" "sync/atomic"
@@ -202,9 +203,6 @@ func (r *rootCommand) ConfigFromProvider(key int32, cfg config.Provider) (*commo
cfg = config.New() cfg = config.New()
} }
if !cfg.IsSet("renderToDisk") {
cfg.Set("renderToDisk", true)
}
if !cfg.IsSet("workingDir") { if !cfg.IsSet("workingDir") {
cfg.Set("workingDir", dir) cfg.Set("workingDir", dir)
} else { } else {
@@ -238,9 +236,7 @@ func (r *rootCommand) ConfigFromProvider(key int32, cfg config.Provider) (*commo
sourceFs := hugofs.Os sourceFs := hugofs.Os
var destinationFs afero.Fs var destinationFs afero.Fs
if cfg.GetBool("renderToDisk") { if cfg.GetBool("renderToMemory") {
destinationFs = hugofs.Os
} else {
destinationFs = afero.NewMemMapFs() destinationFs = afero.NewMemMapFs()
if renderStaticToDisk { if renderStaticToDisk {
// Hybrid, render dynamic content to Root. // Hybrid, render dynamic content to Root.
@@ -250,6 +246,8 @@ func (r *rootCommand) ConfigFromProvider(key int32, cfg config.Provider) (*commo
cfg.Set("publishDirDynamic", "/") cfg.Set("publishDirDynamic", "/")
cfg.Set("publishDirStatic", "/") cfg.Set("publishDirStatic", "/")
} }
} else {
destinationFs = hugofs.Os
} }
fs := hugofs.NewFromSourceAndDestination(sourceFs, destinationFs, cfg) fs := hugofs.NewFromSourceAndDestination(sourceFs, destinationFs, cfg)
@@ -342,7 +340,10 @@ func (r *rootCommand) Run(ctx context.Context, cd *simplecobra.Commandeer, args
defer r.timeTrack(time.Now(), "Built") defer r.timeTrack(time.Now(), "Built")
} }
err := b.build() err := b.build()
return err if err != nil {
return err
}
return nil
}() }()
if err != nil { if err != nil {
return err return err
@@ -411,6 +412,7 @@ func (r *rootCommand) PreRun(cd, runner *simplecobra.Commandeer) error {
MaxEntries: 1, MaxEntries: 1,
OnEvict: func(key int32, value *hugolib.HugoSites) { OnEvict: func(key int32, value *hugolib.HugoSites) {
value.Close() value.Close()
runtime.GC()
}, },
}) })
@@ -492,6 +494,7 @@ Complete documentation is available at https://gohugo.io/.`
cmd.PersistentFlags().StringVar(&r.cfgFile, "config", "", "config file (default is hugo.yaml|json|toml)") cmd.PersistentFlags().StringVar(&r.cfgFile, "config", "", "config file (default is hugo.yaml|json|toml)")
cmd.PersistentFlags().StringVar(&r.cfgDir, "configDir", "config", "config dir") cmd.PersistentFlags().StringVar(&r.cfgDir, "configDir", "config", "config dir")
cmd.PersistentFlags().BoolVar(&r.quiet, "quiet", false, "build in quiet mode") cmd.PersistentFlags().BoolVar(&r.quiet, "quiet", false, "build in quiet mode")
cmd.PersistentFlags().BoolVar(&r.renderToMemory, "renderToMemory", false, "render to memory (mostly useful when running the server)")
// Set bash-completion // Set bash-completion
_ = cmd.PersistentFlags().SetAnnotation("config", cobra.BashCompFilenameExt, config.ValidConfigFileExtensions) _ = cmd.PersistentFlags().SetAnnotation("config", cobra.BashCompFilenameExt, config.ValidConfigFileExtensions)
@@ -500,7 +503,6 @@ Complete documentation is available at https://gohugo.io/.`
cmd.PersistentFlags().BoolVarP(&r.debug, "debug", "", false, "debug output") cmd.PersistentFlags().BoolVarP(&r.debug, "debug", "", false, "debug output")
cmd.PersistentFlags().StringVar(&r.logLevel, "logLevel", "", "log level (debug|info|warn|error)") cmd.PersistentFlags().StringVar(&r.logLevel, "logLevel", "", "log level (debug|info|warn|error)")
cmd.Flags().BoolVarP(&r.buildWatch, "watch", "w", false, "watch filesystem for changes and recreate as needed") cmd.Flags().BoolVarP(&r.buildWatch, "watch", "w", false, "watch filesystem for changes and recreate as needed")
cmd.Flags().BoolVar(&r.renderToMemory, "renderToMemory", false, "render to memory (only useful for benchmark testing)")
// Configure local flags // Configure local flags
applyLocalFlagsBuild(cmd, r) applyLocalFlagsBuild(cmd, r)
+6 -4
View File
@@ -32,8 +32,10 @@ package commands
import ( import (
"context" "context"
"github.com/bep/simplecobra"
"github.com/gohugoio/hugo/deploy" "github.com/gohugoio/hugo/deploy"
"github.com/gohugoio/hugo/deploy/deployconfig"
"github.com/bep/simplecobra"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@@ -62,9 +64,9 @@ documentation.
cmd.Flags().Bool("confirm", false, "ask for confirmation before making changes to the target") cmd.Flags().Bool("confirm", false, "ask for confirmation before making changes to the target")
cmd.Flags().Bool("dryRun", false, "dry run") cmd.Flags().Bool("dryRun", false, "dry run")
cmd.Flags().Bool("force", false, "force upload of all files") cmd.Flags().Bool("force", false, "force upload of all files")
cmd.Flags().Bool("invalidateCDN", deploy.DefaultConfig.InvalidateCDN, "invalidate the CDN cache listed in the deployment target") cmd.Flags().Bool("invalidateCDN", deployconfig.DefaultConfig.InvalidateCDN, "invalidate the CDN cache listed in the deployment target")
cmd.Flags().Int("maxDeletes", deploy.DefaultConfig.MaxDeletes, "maximum # of files to delete, or -1 to disable") cmd.Flags().Int("maxDeletes", deployconfig.DefaultConfig.MaxDeletes, "maximum # of files to delete, or -1 to disable")
cmd.Flags().Int("workers", deploy.DefaultConfig.Workers, "number of workers to transfer files. defaults to 10") cmd.Flags().Int("workers", deployconfig.DefaultConfig.Workers, "number of workers to transfer files. defaults to 10")
}, },
} }
} }
+1 -1
View File
@@ -195,7 +195,7 @@ url: %s
configProvider := func() docshelper.DocProvider { configProvider := func() docshelper.DocProvider {
conf := hugolib.DefaultConfig() conf := hugolib.DefaultConfig()
conf.CacheDir = "" // The default value does not make sense in the docs. conf.CacheDir = "" // The default value does not make sense in the docs.
defaultConfig := parser.LowerCaseCamelJSONMarshaller{Value: conf} defaultConfig := parser.NullBoolJSONMarshaller{Wrapped: parser.LowerCaseCamelJSONMarshaller{Value: conf}}
return docshelper.DocProvider{"config": defaultConfig} return docshelper.DocProvider{"config": defaultConfig}
} }
+5 -4
View File
@@ -930,7 +930,7 @@ func (c *hugoBuilder) hugoTry() *hugolib.HugoSites {
func (c *hugoBuilder) loadConfig(cd *simplecobra.Commandeer, running bool) error { func (c *hugoBuilder) loadConfig(cd *simplecobra.Commandeer, running bool) error {
cfg := config.New() cfg := config.New()
cfg.Set("renderToDisk", (c.s == nil && !c.r.renderToMemory) || (c.s != nil && c.s.renderToDisk)) cfg.Set("renderToMemory", c.r.renderToMemory)
watch := c.r.buildWatch || (c.s != nil && c.s.serverWatch) watch := c.r.buildWatch || (c.s != nil && c.s.serverWatch)
if c.r.environment == "" { if c.r.environment == "" {
// We need to set the environment as early as possible because we need it to load the correct config. // We need to set the environment as early as possible because we need it to load the correct config.
@@ -951,9 +951,10 @@ func (c *hugoBuilder) loadConfig(cd *simplecobra.Commandeer, running bool) error
cfg.Set("environment", c.r.environment) cfg.Set("environment", c.r.environment)
cfg.Set("internal", maps.Params{ cfg.Set("internal", maps.Params{
"running": running, "running": running,
"watch": watch, "watch": watch,
"verbose": c.r.isVerbose(), "verbose": c.r.isVerbose(),
"fastRenderMode": c.fastRenderMode,
}) })
conf, err := c.r.ConfigFromProvider(c.r.configVersionID.Load(), flagsToCfg(cd, cfg)) conf, err := c.r.ConfigFromProvider(c.r.configVersionID.Load(), flagsToCfg(cd, cfg))
+1 -2
View File
@@ -23,7 +23,6 @@ import (
"time" "time"
"github.com/bep/simplecobra" "github.com/bep/simplecobra"
"github.com/gohugoio/hugo/config"
"github.com/gohugoio/hugo/hugolib" "github.com/gohugoio/hugo/hugolib"
"github.com/gohugoio/hugo/resources/page" "github.com/gohugoio/hugo/resources/page"
"github.com/gohugoio/hugo/resources/resource" "github.com/gohugoio/hugo/resources/resource"
@@ -46,7 +45,7 @@ func newListCommand() *listCommand {
list := func(cd *simplecobra.Commandeer, r *rootCommand, shouldInclude func(page.Page) bool, opts ...any) error { list := func(cd *simplecobra.Commandeer, r *rootCommand, shouldInclude func(page.Page) bool, opts ...any) error {
bcfg := hugolib.BuildCfg{SkipRender: true} bcfg := hugolib.BuildCfg{SkipRender: true}
cfg := config.New() cfg := flagsToCfg(cd, nil)
for i := 0; i < len(opts); i += 2 { for i := 0; i < len(opts); i += 2 {
cfg.Set(opts[i].(string), opts[i+1]) cfg.Set(opts[i].(string), opts[i+1])
} }
+22 -15
View File
@@ -25,6 +25,7 @@ import (
"io" "io"
"net" "net"
"net/http" "net/http"
_ "net/http/pprof"
"net/url" "net/url"
"os" "os"
"os/signal" "os/signal"
@@ -238,12 +239,14 @@ func (f *fileServer) createEndpoint(i int) (*http.ServeMux, net.Listener, string
r.Printf("Environment: %q\n", f.c.hugoTry().Deps.Site.Hugo().Environment) r.Printf("Environment: %q\n", f.c.hugoTry().Deps.Site.Hugo().Environment)
if i == 0 { if i == 0 {
if f.c.renderToDisk { mainTarget := "disk"
r.Println("Serving pages from disk") if f.c.r.renderToMemory {
} else if f.c.renderStaticToDisk { mainTarget = "memory"
r.Println("Serving pages from memory and static files from disk") }
if f.c.renderStaticToDisk {
r.Printf("Serving pages from %s and static files from disk\n", mainTarget)
} else { } else {
r.Println("Serving pages from memory") r.Printf("Serving pages from %s\n", mainTarget)
} }
} }
@@ -443,7 +446,6 @@ type serverCommand struct {
doLiveReload bool doLiveReload bool
// Flags. // Flags.
renderToDisk bool
renderStaticToDisk bool renderStaticToDisk bool
navigateToChanged bool navigateToChanged bool
serverAppend bool serverAppend bool
@@ -451,6 +453,7 @@ type serverCommand struct {
tlsCertFile string tlsCertFile string
tlsKeyFile string tlsKeyFile string
tlsAuto bool tlsAuto bool
pprof bool
serverPort int serverPort int
liveReloadPort int liveReloadPort int
serverWatch bool serverWatch bool
@@ -465,6 +468,11 @@ func (c *serverCommand) Name() string {
} }
func (c *serverCommand) Run(ctx context.Context, cd *simplecobra.Commandeer, args []string) error { func (c *serverCommand) Run(ctx context.Context, cd *simplecobra.Commandeer, args []string) error {
if c.pprof {
go func() {
http.ListenAndServe("localhost:8080", nil)
}()
}
// Watch runs its own server as part of the routine // Watch runs its own server as part of the routine
if c.serverWatch { if c.serverWatch {
@@ -489,8 +497,7 @@ func (c *serverCommand) Run(ctx context.Context, cd *simplecobra.Commandeer, arg
err := func() error { err := func() error {
defer c.r.timeTrack(time.Now(), "Built") defer c.r.timeTrack(time.Now(), "Built")
err := c.build() return c.build()
return err
}() }()
if err != nil { if err != nil {
return err return err
@@ -505,8 +512,9 @@ func (c *serverCommand) Init(cd *simplecobra.Commandeer) error {
cmd.Long = `Hugo provides its own webserver which builds and serves the site. cmd.Long = `Hugo provides its own webserver which builds and serves the site.
While hugo server is high performance, it is a webserver with limited options. While hugo server is high performance, it is a webserver with limited options.
'hugo server' will avoid writing the rendered and served content to disk, 'hugo server' will by default write and server files from disk, but you can
preferring to store it in memory. render to memory by using the '--renderToMemory' flag. This can be faster
in some cases, but it will consume more memory.
By default hugo will also watch your files for any changes you make and By default hugo will also watch your files for any changes you make and
automatically rebuild the site. It will then live reload any open browser pages automatically rebuild the site. It will then live reload any open browser pages
@@ -520,19 +528,16 @@ of a second, you will be able to save and see your changes nearly instantly.`
cmd.Flags().StringVarP(&c.tlsCertFile, "tlsCertFile", "", "", "path to TLS certificate file") cmd.Flags().StringVarP(&c.tlsCertFile, "tlsCertFile", "", "", "path to TLS certificate file")
cmd.Flags().StringVarP(&c.tlsKeyFile, "tlsKeyFile", "", "", "path to TLS key file") cmd.Flags().StringVarP(&c.tlsKeyFile, "tlsKeyFile", "", "", "path to TLS key file")
cmd.Flags().BoolVar(&c.tlsAuto, "tlsAuto", false, "generate and use locally-trusted certificates.") cmd.Flags().BoolVar(&c.tlsAuto, "tlsAuto", false, "generate and use locally-trusted certificates.")
cmd.Flags().BoolVar(&c.pprof, "pprof", false, "enable the pprof server (port 8080)")
cmd.Flags().BoolVarP(&c.serverWatch, "watch", "w", true, "watch filesystem for changes and recreate as needed") cmd.Flags().BoolVarP(&c.serverWatch, "watch", "w", true, "watch filesystem for changes and recreate as needed")
cmd.Flags().BoolVar(&c.noHTTPCache, "noHTTPCache", false, "prevent HTTP caching") cmd.Flags().BoolVar(&c.noHTTPCache, "noHTTPCache", false, "prevent HTTP caching")
cmd.Flags().BoolVarP(&c.serverAppend, "appendPort", "", true, "append port to baseURL") cmd.Flags().BoolVarP(&c.serverAppend, "appendPort", "", true, "append port to baseURL")
cmd.Flags().BoolVar(&c.disableLiveReload, "disableLiveReload", false, "watch without enabling live browser reload on rebuild") cmd.Flags().BoolVar(&c.disableLiveReload, "disableLiveReload", false, "watch without enabling live browser reload on rebuild")
cmd.Flags().BoolVar(&c.navigateToChanged, "navigateToChanged", false, "navigate to changed content file on live browser reload") cmd.Flags().BoolVar(&c.navigateToChanged, "navigateToChanged", false, "navigate to changed content file on live browser reload")
cmd.Flags().BoolVar(&c.renderToDisk, "renderToDisk", false, "serve all files from disk (default is from memory)")
cmd.Flags().BoolVar(&c.renderStaticToDisk, "renderStaticToDisk", false, "serve static files from disk and dynamic files from memory") cmd.Flags().BoolVar(&c.renderStaticToDisk, "renderStaticToDisk", false, "serve static files from disk and dynamic files from memory")
cmd.Flags().BoolVar(&c.disableFastRender, "disableFastRender", false, "enables full re-renders on changes") cmd.Flags().BoolVar(&c.disableFastRender, "disableFastRender", false, "enables full re-renders on changes")
cmd.Flags().BoolVar(&c.disableBrowserError, "disableBrowserError", false, "do not show build errors in the browser") cmd.Flags().BoolVar(&c.disableBrowserError, "disableBrowserError", false, "do not show build errors in the browser")
cmd.Flags().String("memstats", "", "log memory usage to this file")
cmd.Flags().String("meminterval", "100ms", "interval to poll memory usage (requires --memstats), valid time units are \"ns\", \"us\" (or \"µs\"), \"ms\", \"s\", \"m\", \"h\".")
cmd.Flags().SetAnnotation("tlsCertFile", cobra.BashCompSubdirsInDir, []string{}) cmd.Flags().SetAnnotation("tlsCertFile", cobra.BashCompSubdirsInDir, []string{})
cmd.Flags().SetAnnotation("tlsKeyFile", cobra.BashCompSubdirsInDir, []string{}) cmd.Flags().SetAnnotation("tlsKeyFile", cobra.BashCompSubdirsInDir, []string{})
@@ -577,7 +582,9 @@ func (c *serverCommand) PreRun(cd, runner *simplecobra.Commandeer) error {
) )
destinationFlag := cd.CobraCommand.Flags().Lookup("destination") destinationFlag := cd.CobraCommand.Flags().Lookup("destination")
c.renderToDisk = c.renderToDisk || (destinationFlag != nil && destinationFlag.Changed) if c.r.renderToMemory && (destinationFlag != nil && destinationFlag.Changed) {
return fmt.Errorf("cannot use --renderToMemory with --destination")
}
c.doLiveReload = !c.disableLiveReload c.doLiveReload = !c.disableLiveReload
c.fastRenderMode = !c.disableFastRender c.fastRenderMode = !c.disableFastRender
c.showErrorInBrowser = c.doLiveReload && !c.disableBrowserError c.showErrorInBrowser = c.doLiveReload && !c.disableBrowserError
+7 -5
View File
@@ -55,7 +55,7 @@ func TestAppend(t *testing.T) {
[]any{&tstSlicerIn1{"c"}}, []any{&tstSlicerIn1{"c"}},
testSlicerInterfaces{&tstSlicerIn1{"a"}, &tstSlicerIn1{"b"}, &tstSlicerIn1{"c"}}, testSlicerInterfaces{&tstSlicerIn1{"a"}, &tstSlicerIn1{"b"}, &tstSlicerIn1{"c"}},
}, },
//https://github.com/gohugoio/hugo/issues/5361 // https://github.com/gohugoio/hugo/issues/5361
{ {
[]string{"a", "b"}, []string{"a", "b"},
[]any{tstSlicers{&tstSlicer{"a"}, &tstSlicer{"b"}}}, []any{tstSlicers{&tstSlicer{"a"}, &tstSlicer{"b"}}},
@@ -102,14 +102,16 @@ func TestAppendToMultiDimensionalSlice(t *testing.T) {
from []any from []any
expected any expected any
}{ }{
{[][]string{{"a", "b"}}, {
[][]string{{"a", "b"}},
[]any{[]string{"c", "d"}}, []any{[]string{"c", "d"}},
[][]string{ [][]string{
{"a", "b"}, {"a", "b"},
{"c", "d"}, {"c", "d"},
}, },
}, },
{[][]string{{"a", "b"}}, {
[][]string{{"a", "b"}},
[]any{[]string{"c", "d"}, []string{"e", "f"}}, []any{[]string{"c", "d"}, []string{"e", "f"}},
[][]string{ [][]string{
{"a", "b"}, {"a", "b"},
@@ -117,7 +119,8 @@ func TestAppendToMultiDimensionalSlice(t *testing.T) {
{"e", "f"}, {"e", "f"},
}, },
}, },
{[][]string{{"a", "b"}}, {
[][]string{{"a", "b"}},
[]any{[]int{1, 2}}, []any{[]int{1, 2}},
false, false,
}, },
@@ -130,7 +133,6 @@ func TestAppendToMultiDimensionalSlice(t *testing.T) {
c.Assert(result, qt.DeepEquals, test.expected) c.Assert(result, qt.DeepEquals, test.expected)
} }
} }
} }
func TestAppendShouldMakeACopyOfTheInputSlice(t *testing.T) { func TestAppendShouldMakeACopyOfTheInputSlice(t *testing.T) {
-1
View File
@@ -73,7 +73,6 @@ func StringSliceToInterfaceSlice(ss []string) []any {
result[i] = s result[i] = s
} }
return result return result
} }
type SortedStringSlice []string type SortedStringSlice []string
-1
View File
@@ -135,5 +135,4 @@ func TestSortedStringSlice(t *testing.T) {
c.Assert(s.Count("b"), qt.Equals, 3) c.Assert(s.Count("b"), qt.Equals, 3)
c.Assert(s.Count("z"), qt.Equals, 0) c.Assert(s.Count("z"), qt.Equals, 0)
c.Assert(s.Count("a"), qt.Equals, 1) c.Assert(s.Count("a"), qt.Equals, 1)
} }
+67
View File
@@ -0,0 +1,67 @@
// Copyright 2024 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package collections
import "sync"
// 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 NewStack[T any]() *Stack[T] {
return &Stack[T]{}
}
func (s *Stack[T]) Push(item T) {
s.mu.Lock()
defer s.mu.Unlock()
s.items = append(s.items, item)
}
func (s *Stack[T]) Pop() (T, bool) {
s.mu.Lock()
defer s.mu.Unlock()
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) {
s.mu.RLock()
defer s.mu.RUnlock()
if len(s.items) == 0 {
return s.zero, false
}
return s.items[len(s.items)-1], true
}
func (s *Stack[T]) Len() int {
s.mu.RLock()
defer s.mu.RUnlock()
return len(s.items)
}
func (s *Stack[T]) Drain() []T {
s.mu.Lock()
defer s.mu.Unlock()
items := s.items
s.items = nil
return items
}
+3 -1
View File
@@ -13,12 +13,14 @@
package constants package constants
// Error IDs. // Error/Warning IDs.
// Do not change these values. // Do not change these values.
const ( const (
// IDs for remote errors in tpl/data. // IDs for remote errors in tpl/data.
ErrRemoteGetJSON = "error-remote-getjson" ErrRemoteGetJSON = "error-remote-getjson"
ErrRemoteGetCSV = "error-remote-getcsv" ErrRemoteGetCSV = "error-remote-getcsv"
WarnFrontMatterParamsOverrides = "warning-frontmatter-params-overrides"
) )
// Field/method names with special meaning. // Field/method names with special meaning.
+21
View File
@@ -19,8 +19,10 @@ import (
"fmt" "fmt"
"io" "io"
"os" "os"
"regexp"
"runtime" "runtime"
"runtime/debug" "runtime/debug"
"strings"
"time" "time"
) )
@@ -116,3 +118,22 @@ func IsNotExist(err error) bool {
return false return false
} }
var nilPointerErrRe = regexp.MustCompile(`at <(.*)>: error calling (.*?): runtime error: invalid memory address or nil pointer dereference`)
func ImproveIfNilPointer(inErr error) (outErr error) {
outErr = inErr
m := nilPointerErrRe.FindStringSubmatch(inErr.Error())
if len(m) == 0 {
return
}
call := m[1]
field := m[2]
parts := strings.Split(call, ".")
receiverName := parts[len(parts)-2]
receiver := strings.Join(parts[:len(parts)-1], ".")
s := fmt.Sprintf(" %s is nil; wrap it in if or with: {{ with %s }}{{ .%s }}{{ end }}", receiverName, receiver, field)
outErr = errors.New(nilPointerErrRe.ReplaceAllString(inErr.Error(), s))
return
}
+2 -4
View File
@@ -19,11 +19,10 @@ import (
"errors" "errors"
"fmt" "fmt"
"io" "io"
"regexp"
"strings"
"os" "os"
"os/exec" "os/exec"
"regexp"
"strings"
"github.com/cli/safeexec" "github.com/cli/safeexec"
"github.com/gohugoio/hugo/config" "github.com/gohugoio/hugo/config"
@@ -142,7 +141,6 @@ func (e *Exec) New(name string, arg ...any) (Runner, error) {
} }
return cm.command(arg...) return cm.command(arg...)
} }
// Npx is a convenience method to create a Runner running npx --no-install <name> <args. // Npx is a convenience method to create a Runner running npx --no-install <name> <args.
@@ -47,12 +47,7 @@ defaultContentLanguage = 'it'
{{ end }} {{ end }}
` `
b := hugolib.NewIntegrationTestBuilder( b := hugolib.Test(t, files)
hugolib.IntegrationTestConfig{
T: t,
TxtarString: files,
},
).Build()
b.AssertFileContent("public/index.html", ` b.AssertFileContent("public/index.html", `
month: _gennaio_ weekday: _lunedì_ month: _gennaio_ weekday: _lunedì_
-4
View File
@@ -53,7 +53,6 @@ func TestTimeFormatter(t *testing.T) {
c.Assert(f.Format(june06, ":time_long"), qt.Equals, "02:09:37 UTC") c.Assert(f.Format(june06, ":time_long"), qt.Equals, "02:09:37 UTC")
c.Assert(f.Format(june06, ":time_medium"), qt.Equals, "02:09:37") c.Assert(f.Format(june06, ":time_medium"), qt.Equals, "02:09:37")
c.Assert(f.Format(june06, ":time_short"), qt.Equals, "02:09") c.Assert(f.Format(june06, ":time_short"), qt.Equals, "02:09")
}) })
c.Run("Custom layouts English", func(c *qt.C) { c.Run("Custom layouts English", func(c *qt.C) {
@@ -68,7 +67,6 @@ func TestTimeFormatter(t *testing.T) {
c.Assert(f.Format(june06, ":time_long"), qt.Equals, "2:09:37 am UTC") c.Assert(f.Format(june06, ":time_long"), qt.Equals, "2:09:37 am UTC")
c.Assert(f.Format(june06, ":time_medium"), qt.Equals, "2:09:37 am") c.Assert(f.Format(june06, ":time_medium"), qt.Equals, "2:09:37 am")
c.Assert(f.Format(june06, ":time_short"), qt.Equals, "2:09 am") c.Assert(f.Format(june06, ":time_short"), qt.Equals, "2:09 am")
}) })
c.Run("English", func(c *qt.C) { c.Run("English", func(c *qt.C) {
@@ -107,9 +105,7 @@ func TestTimeFormatter(t *testing.T) {
c.Assert(tr.MonthWide(date.Month()), qt.Equals, monthWideNorway) c.Assert(tr.MonthWide(date.Month()), qt.Equals, monthWideNorway)
c.Assert(f.Format(date, "January"), qt.Equals, monthWideNorway) c.Assert(f.Format(date, "January"), qt.Equals, monthWideNorway)
} }
}) })
} }
func BenchmarkTimeFormatter(b *testing.B) { func BenchmarkTimeFormatter(b *testing.B) {
+37 -10
View File
@@ -37,32 +37,47 @@ type ReadSeekCloserProvider interface {
ReadSeekCloser() (ReadSeekCloser, error) ReadSeekCloser() (ReadSeekCloser, error)
} }
// ReadSeekerNoOpCloser implements ReadSeekCloser by doing nothing in Close. // readSeekerNopCloser implements ReadSeekCloser by doing nothing in Close.
// TODO(bep) rename this and similar to ReadSeekerNopCloser, naming used in stdlib, which kind of makes sense. type readSeekerNopCloser struct {
type ReadSeekerNoOpCloser struct {
ReadSeeker ReadSeeker
} }
// Close does nothing. // Close does nothing.
func (r ReadSeekerNoOpCloser) Close() error { func (r readSeekerNopCloser) Close() error {
return nil return nil
} }
// NewReadSeekerNoOpCloser creates a new ReadSeekerNoOpCloser with the given ReadSeeker. // NewReadSeekerNoOpCloser creates a new ReadSeekerNoOpCloser with the given ReadSeeker.
func NewReadSeekerNoOpCloser(r ReadSeeker) ReadSeekerNoOpCloser { func NewReadSeekerNoOpCloser(r ReadSeeker) ReadSeekCloser {
return ReadSeekerNoOpCloser{r} return readSeekerNopCloser{r}
} }
// NewReadSeekerNoOpCloserFromString uses strings.NewReader to create a new ReadSeekerNoOpCloser // NewReadSeekerNoOpCloserFromString uses strings.NewReader to create a new ReadSeekerNoOpCloser
// from the given string. // from the given string.
func NewReadSeekerNoOpCloserFromString(content string) ReadSeekerNoOpCloser { func NewReadSeekerNoOpCloserFromString(content string) ReadSeekCloser {
return ReadSeekerNoOpCloser{strings.NewReader(content)} return stringReadSeeker{s: content, readSeekerNopCloser: readSeekerNopCloser{strings.NewReader(content)}}
}
var _ StringReader = (*stringReadSeeker)(nil)
type stringReadSeeker struct {
s string
readSeekerNopCloser
}
func (s *stringReadSeeker) ReadString() string {
return s.s
}
// StringReader provides a way to read a string.
type StringReader interface {
ReadString() string
} }
// NewReadSeekerNoOpCloserFromString uses strings.NewReader to create a new ReadSeekerNoOpCloser // NewReadSeekerNoOpCloserFromString uses strings.NewReader to create a new ReadSeekerNoOpCloser
// from the given bytes slice. // from the given bytes slice.
func NewReadSeekerNoOpCloserFromBytes(content []byte) ReadSeekerNoOpCloser { func NewReadSeekerNoOpCloserFromBytes(content []byte) readSeekerNopCloser {
return ReadSeekerNoOpCloser{bytes.NewReader(content)} return readSeekerNopCloser{bytes.NewReader(content)}
} }
// NewReadSeekCloser creates a new ReadSeekCloser from the given ReadSeeker. // NewReadSeekCloser creates a new ReadSeekCloser from the given ReadSeeker.
@@ -77,3 +92,15 @@ func NewOpenReadSeekCloser(r ReadSeekCloser) OpenReadSeekCloser {
// OpenReadSeekCloser allows setting some other way (than reading from a filesystem) // OpenReadSeekCloser allows setting some other way (than reading from a filesystem)
// to open or create a ReadSeekCloser. // to open or create a ReadSeekCloser.
type OpenReadSeekCloser func() (ReadSeekCloser, error) type OpenReadSeekCloser func() (ReadSeekCloser, error)
// ReadString reads from the given reader and returns the content as a string.
func ReadString(r io.Reader) (string, error) {
if sr, ok := r.(StringReader); ok {
return sr.ReadString(), nil
}
b, err := io.ReadAll(r)
if err != nil {
return "", err
}
return string(b), nil
}
+1 -1
View File
@@ -19,5 +19,5 @@ var CurrentVersion = Version{
Major: 0, Major: 0,
Minor: 123, Minor: 123,
PatchLevel: 0, PatchLevel: 0,
Suffix: "-DEV", Suffix: "",
} }
+13 -2
View File
@@ -179,9 +179,9 @@ type Logger interface {
Debugln(v ...any) Debugln(v ...any)
Error() logg.LevelLogger Error() logg.LevelLogger
Errorf(format string, v ...any) Errorf(format string, v ...any)
Erroridf(id, format string, v ...any)
Errorln(v ...any) Errorln(v ...any)
Errors() string Errors() string
Errorsf(id, format string, v ...any)
Info() logg.LevelLogger Info() logg.LevelLogger
InfoCommand(command string) logg.LevelLogger InfoCommand(command string) logg.LevelLogger
Infof(format string, v ...any) Infof(format string, v ...any)
@@ -197,6 +197,7 @@ type Logger interface {
Warn() logg.LevelLogger Warn() logg.LevelLogger
WarnCommand(command string) logg.LevelLogger WarnCommand(command string) logg.LevelLogger
Warnf(format string, v ...any) Warnf(format string, v ...any)
Warnidf(id, format string, v ...any)
Warnln(v ...any) Warnln(v ...any)
Deprecatef(fail bool, format string, v ...any) Deprecatef(fail bool, format string, v ...any)
Trace(s logg.StringFunc) Trace(s logg.StringFunc)
@@ -321,10 +322,20 @@ func (l *logAdapter) Errors() string {
return l.errors.String() return l.errors.String()
} }
func (l *logAdapter) Errorsf(id, format string, v ...any) { func (l *logAdapter) Erroridf(id, format string, v ...any) {
format += l.idfInfoStatement("error", id, format)
l.errorl.WithField(FieldNameStatementID, id).Logf(format, v...) l.errorl.WithField(FieldNameStatementID, id).Logf(format, v...)
} }
func (l *logAdapter) Warnidf(id, format string, v ...any) {
format += l.idfInfoStatement("warning", id, format)
l.warnl.WithField(FieldNameStatementID, id).Logf(format, v...)
}
func (l *logAdapter) idfInfoStatement(what, id, format string) string {
return fmt.Sprintf("\nYou can suppress this %s by adding the following to your site configuration:\nignoreLogs = ['%s']", what, id)
}
func (l *logAdapter) Trace(s logg.StringFunc) { func (l *logAdapter) Trace(s logg.StringFunc) {
l.tracel.Log(s) l.tracel.Log(s)
} }
-1
View File
@@ -192,5 +192,4 @@ func TestLookupEqualFold(t *testing.T) {
v, found = LookupEqualFold(m2, "b") v, found = LookupEqualFold(m2, "b")
c.Assert(found, qt.IsTrue) c.Assert(found, qt.IsTrue)
c.Assert(v, qt.Equals, "bv") c.Assert(v, qt.Equals, "bv")
} }
-1
View File
@@ -154,7 +154,6 @@ func TestParamsSetAndMerge(t *testing.T) {
"a": "av", "a": "av",
"c": "cv", "c": "cv",
}) })
} }
func TestParamsIsZero(t *testing.T) { func TestParamsIsZero(t *testing.T) {
+5
View File
@@ -387,6 +387,11 @@ func ToSlashTrimLeading(s string) string {
return strings.TrimPrefix(filepath.ToSlash(s), "/") return strings.TrimPrefix(filepath.ToSlash(s), "/")
} }
// ToSlashTrimTrailing is just a filepath.ToSlash with an added / suffix trimmer.
func ToSlashTrimTrailing(s string) string {
return strings.TrimSuffix(filepath.ToSlash(s), "/")
}
// ToSlashPreserveLeading converts the path given to a forward slash separated path // ToSlashPreserveLeading converts the path given to a forward slash separated path
// and preserves the leading slash if present trimming any trailing slash. // and preserves the leading slash if present trimming any trailing slash.
func ToSlashPreserveLeading(s string) string { func ToSlashPreserveLeading(s string) string {
+82 -17
View File
@@ -18,9 +18,11 @@ import (
"path/filepath" "path/filepath"
"runtime" "runtime"
"strings" "strings"
"sync"
"github.com/gohugoio/hugo/common/types" "github.com/gohugoio/hugo/common/types"
"github.com/gohugoio/hugo/hugofs/files" "github.com/gohugoio/hugo/hugofs/files"
"github.com/gohugoio/hugo/identity"
) )
var defaultPathParser PathParser var defaultPathParser PathParser
@@ -29,6 +31,9 @@ var defaultPathParser PathParser
type PathParser struct { type PathParser struct {
// Maps the language code to its index in the languages/sites slice. // Maps the language code to its index in the languages/sites slice.
LanguageIndex map[string]int LanguageIndex map[string]int
// Reports whether the given language is disabled.
IsLangDisabled func(string) bool
} }
// Parse parses component c with path s into Path using the default path parser. // Parse parses component c with path s into Path using the default path parser.
@@ -47,19 +52,42 @@ func NormalizePathStringBasic(s string) string {
return s return s
} }
// ParseIdentity parses component c with path s into a StringIdentity.
func (pp *PathParser) ParseIdentity(c, s string) identity.StringIdentity {
s = NormalizePathStringBasic(s)
p := getPath()
p.component = c
defer putPath(p)
p, err := pp.doParse(c, s, p)
if err != nil {
panic(err)
}
return identity.StringIdentity(p.IdentifierBase())
}
// Parse parses component c with path s into Path using Hugo's content path rules. // Parse parses component c with path s into Path using Hugo's content path rules.
func (parser PathParser) Parse(c, s string) *Path { func (pp *PathParser) Parse(c, s string) *Path {
p, err := parser.parse(c, s) p, err := pp.parse(c, s)
if err != nil { if err != nil {
panic(err) panic(err)
} }
return p return p
} }
func (pp *PathParser) newPath(component string) *Path {
return &Path{
component: component,
posContainerLow: -1,
posContainerHigh: -1,
posSectionHigh: -1,
posIdentifierLanguage: -1,
}
}
func (pp *PathParser) parse(component, s string) (*Path, error) { func (pp *PathParser) parse(component, s string) (*Path, error) {
ss := NormalizePathStringBasic(s) ss := NormalizePathStringBasic(s)
p, err := pp.doParse(component, ss) p, err := pp.doParse(component, ss, pp.newPath(component))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -67,7 +95,7 @@ func (pp *PathParser) parse(component, s string) (*Path, error) {
if s != ss { if s != ss {
var err error var err error
// Preserve the original case for titles etc. // Preserve the original case for titles etc.
p.unnormalized, err = pp.doParse(component, s) p.unnormalized, err = pp.doParse(component, s, pp.newPath(component))
if err != nil { if err != nil {
return nil, err return nil, err
@@ -79,15 +107,7 @@ func (pp *PathParser) parse(component, s string) (*Path, error) {
return p, nil return p, nil
} }
func (pp *PathParser) doParse(component, s string) (*Path, error) { func (pp *PathParser) doParse(component, s string, p *Path) (*Path, error) {
p := &Path{
component: component,
posContainerLow: -1,
posContainerHigh: -1,
posSectionHigh: -1,
posIdentifierLanguage: -1,
}
hasLang := pp.LanguageIndex != nil hasLang := pp.LanguageIndex != nil
hasLang = hasLang && (component == files.ComponentFolderContent || component == files.ComponentFolderLayouts) hasLang = hasLang && (component == files.ComponentFolderContent || component == files.ComponentFolderLayouts)
@@ -134,7 +154,16 @@ func (pp *PathParser) doParse(component, s string) (*Path, error) {
s := p.s[id.Low:id.High] s := p.s[id.Low:id.High]
if hasLang { if hasLang {
if _, found := pp.LanguageIndex[s]; found { var disabled bool
_, langFound := pp.LanguageIndex[s]
if !langFound {
disabled = pp.IsLangDisabled != nil && pp.IsLangDisabled(s)
if disabled {
p.disabled = true
langFound = true
}
}
if langFound {
p.posIdentifierLanguage = 1 p.posIdentifierLanguage = 1
p.identifiers = append(p.identifiers, id) p.identifiers = append(p.identifiers, id)
} }
@@ -208,6 +237,7 @@ const (
) )
type Path struct { type Path struct {
// Note: Any additions to this struct should also be added to the pathPool.
s string s string
posContainerLow int posContainerLow int
@@ -220,12 +250,38 @@ type Path struct {
identifiers []types.LowHigh identifiers []types.LowHigh
posIdentifierLanguage int posIdentifierLanguage int
disabled bool
trimLeadingSlash bool trimLeadingSlash bool
unnormalized *Path unnormalized *Path
} }
var pathPool = &sync.Pool{
New: func() any {
return &Path{}
},
}
func getPath() *Path {
return pathPool.Get().(*Path)
}
func putPath(p *Path) {
p.s = ""
p.posContainerLow = -1
p.posContainerHigh = -1
p.posSectionHigh = -1
p.component = ""
p.bundleType = 0
p.identifiers = p.identifiers[:0]
p.posIdentifierLanguage = -1
p.disabled = false
p.trimLeadingSlash = false
p.unnormalized = nil
pathPool.Put(p)
}
// TrimLeadingSlash returns a copy of the Path with the leading slash removed. // TrimLeadingSlash returns a copy of the Path with the leading slash removed.
func (p Path) TrimLeadingSlash() *Path { func (p Path) TrimLeadingSlash() *Path {
p.trimLeadingSlash = true p.trimLeadingSlash = true
@@ -241,7 +297,7 @@ func (p *Path) norm(s string) string {
// IdentifierBase satifies identity.Identity. // IdentifierBase satifies identity.Identity.
func (p *Path) IdentifierBase() string { func (p *Path) IdentifierBase() string {
return p.Base()[1:] return p.Base()
} }
// Component returns the component for this path (e.g. "content"). // Component returns the component for this path (e.g. "content").
@@ -346,8 +402,8 @@ func (p *Path) Path() (d string) {
return p.norm(p.s) return p.norm(p.s)
} }
// Unmormalized returns the Path with the original case preserved. // Unnormalized returns the Path with the original case preserved.
func (p *Path) Unmormalized() *Path { func (p *Path) Unnormalized() *Path {
return p.unnormalized return p.unnormalized
} }
@@ -435,6 +491,10 @@ func (p *Path) Identifier(i int) string {
return p.identifierAsString(i) return p.identifierAsString(i)
} }
func (p *Path) Disabled() bool {
return p.disabled
}
func (p *Path) Identifiers() []string { func (p *Path) Identifiers() []string {
ids := make([]string, len(p.identifiers)) ids := make([]string, len(p.identifiers))
for i, id := range p.identifiers { for i, id := range p.identifiers {
@@ -463,6 +523,11 @@ func (p *Path) IsLeafBundle() bool {
return p.bundleType == PathTypeLeaf return p.bundleType == PathTypeLeaf
} }
func (p Path) ForBundleType(t PathType) *Path {
p.bundleType = t
return &p
}
func (p *Path) identifierAsString(i int) string { func (p *Path) identifierAsString(i int) string {
i = p.identifierIndex(i) i = p.identifierIndex(i)
if i == -1 { if i == -1 {
+7 -1
View File
@@ -93,7 +93,7 @@ func TestParse(t *testing.T) {
"Basic text file, mixed case and spaces, unnormalized", "Basic text file, mixed case and spaces, unnormalized",
"/a/Foo BAR.txt", "/a/Foo BAR.txt",
func(c *qt.C, p *Path) { func(c *qt.C, p *Path) {
pp := p.Unmormalized() pp := p.Unnormalized()
c.Assert(pp, qt.IsNotNil) c.Assert(pp, qt.IsNotNil)
c.Assert(pp.BaseNameNoIdentifier(), qt.Equals, "Foo BAR") c.Assert(pp.BaseNameNoIdentifier(), qt.Equals, "Foo BAR")
}, },
@@ -349,3 +349,9 @@ func TestHasExt(t *testing.T) {
c.Assert(HasExt("/a/b/c"), qt.IsFalse) c.Assert(HasExt("/a/b/c"), qt.IsFalse)
c.Assert(HasExt("/a/b.c/d"), qt.IsFalse) c.Assert(HasExt("/a/b.c/d"), qt.IsFalse)
} }
func BenchmarkParseIdentity(b *testing.B) {
for i := 0; i < b.N; i++ {
testParser.ParseIdentity(files.ComponentFolderAssets, "/a/b.css")
}
}
-1
View File
@@ -163,7 +163,6 @@ func Uglify(in string) string {
// If ParseRequestURI fails, the input is just converted to OS specific slashes and returned. // If ParseRequestURI fails, the input is just converted to OS specific slashes and returned.
func UrlToFilename(s string) (string, bool) { func UrlToFilename(s string) (string, bool) {
u, err := url.ParseRequestURI(s) u, err := url.ParseRequestURI(s)
if err != nil { if err != nil {
return filepath.FromSlash(s), false return filepath.FromSlash(s), false
} }
-4
View File
@@ -57,7 +57,6 @@ line 3`
c := qt.New(t) c := qt.New(t)
c.Assert(collected, qt.DeepEquals, []string{"line 1\n", "line 2\n", "\n", "line 3"}) c.Assert(collected, qt.DeepEquals, []string{"line 1\n", "line 2\n", "\n", "line 3"})
} }
func BenchmarkVisitLinesAfter(b *testing.B) { func BenchmarkVisitLinesAfter(b *testing.B) {
@@ -68,9 +67,6 @@ func BenchmarkVisitLinesAfter(b *testing.B) {
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
VisitLinesAfter(lines, func(s string) { VisitLinesAfter(lines, func(s string) {
}) })
} }
} }
-1
View File
@@ -80,7 +80,6 @@ func ToStringSlicePreserveStringE(v any) ([]string, error) {
default: default:
return nil, fmt.Errorf("failed to convert %T to a string slice", v) return nil, fmt.Errorf("failed to convert %T to a string slice", v)
} }
} }
// TypeToString converts v to a string if it's a valid string type. // TypeToString converts v to a string if it's a valid string type.
-1
View File
@@ -45,5 +45,4 @@ func TestToDuration(t *testing.T) {
c.Assert(ToDuration("200"), qt.Equals, 200*time.Millisecond) c.Assert(ToDuration("200"), qt.Equals, 200*time.Millisecond)
c.Assert(ToDuration("4m"), qt.Equals, 4*time.Minute) c.Assert(ToDuration("4m"), qt.Equals, 4*time.Minute)
c.Assert(ToDuration("asdfadf"), qt.Equals, time.Duration(0)) c.Assert(ToDuration("asdfadf"), qt.Equals, time.Duration(0))
} }
+5
View File
@@ -107,3 +107,8 @@ type LowHigh struct {
// This is only used for debugging purposes. // This is only used for debugging purposes.
var InvocationCounter atomic.Int64 var InvocationCounter atomic.Int64
// NewTrue returns a pointer to b.
func NewBool(b bool) *bool {
return &b
}
-1
View File
@@ -79,5 +79,4 @@ func BenchmarkStringSort(b *testing.B) {
}) })
} }
}) })
} }
+29 -14
View File
@@ -31,12 +31,13 @@ import (
"github.com/gohugoio/hugo/common/loggers" "github.com/gohugoio/hugo/common/loggers"
"github.com/gohugoio/hugo/common/maps" "github.com/gohugoio/hugo/common/maps"
"github.com/gohugoio/hugo/common/paths" "github.com/gohugoio/hugo/common/paths"
"github.com/gohugoio/hugo/common/types"
"github.com/gohugoio/hugo/common/urls" "github.com/gohugoio/hugo/common/urls"
"github.com/gohugoio/hugo/config" "github.com/gohugoio/hugo/config"
"github.com/gohugoio/hugo/config/privacy" "github.com/gohugoio/hugo/config/privacy"
"github.com/gohugoio/hugo/config/security" "github.com/gohugoio/hugo/config/security"
"github.com/gohugoio/hugo/config/services" "github.com/gohugoio/hugo/config/services"
"github.com/gohugoio/hugo/deploy" "github.com/gohugoio/hugo/deploy/deployconfig"
"github.com/gohugoio/hugo/helpers" "github.com/gohugoio/hugo/helpers"
"github.com/gohugoio/hugo/langs" "github.com/gohugoio/hugo/langs"
"github.com/gohugoio/hugo/markup/markup_config" "github.com/gohugoio/hugo/markup/markup_config"
@@ -64,6 +65,7 @@ type InternalConfig struct {
Verbose bool Verbose bool
Clock string Clock string
Watch bool Watch bool
FastRenderMode bool
LiveReloadPort int LiveReloadPort int
} }
@@ -139,8 +141,8 @@ type Config struct {
// <docsmeta>{"refs": ["config:languages:menus"] }</docsmeta> // <docsmeta>{"refs": ["config:languages:menus"] }</docsmeta>
Menus *config.ConfigNamespace[map[string]navigation.MenuConfig, navigation.Menus] `mapstructure:"-"` Menus *config.ConfigNamespace[map[string]navigation.MenuConfig, navigation.Menus] `mapstructure:"-"`
// The deployment configuration section contains for hugo deploy. // The deployment configuration section contains for hugo deployconfig.
Deployment deploy.DeployConfig `mapstructure:"-"` Deployment deployconfig.DeployConfig `mapstructure:"-"`
// Module configuration. // Module configuration.
Module modules.Config `mapstructure:"-"` Module modules.Config `mapstructure:"-"`
@@ -206,7 +208,7 @@ func (c Config) cloneForLang() *Config {
x.DisableKinds = copyStringSlice(x.DisableKinds) x.DisableKinds = copyStringSlice(x.DisableKinds)
x.DisableLanguages = copyStringSlice(x.DisableLanguages) x.DisableLanguages = copyStringSlice(x.DisableLanguages)
x.MainSections = copyStringSlice(x.MainSections) x.MainSections = copyStringSlice(x.MainSections)
x.IgnoreErrors = copyStringSlice(x.IgnoreErrors) x.IgnoreLogs = copyStringSlice(x.IgnoreLogs)
x.IgnoreFiles = copyStringSlice(x.IgnoreFiles) x.IgnoreFiles = copyStringSlice(x.IgnoreFiles)
x.Theme = copyStringSlice(x.Theme) x.Theme = copyStringSlice(x.Theme)
@@ -299,9 +301,9 @@ func (c *Config) CompileConfig(logger loggers.Logger) error {
} }
} }
ignoredErrors := make(map[string]bool) ignoredLogIDs := make(map[string]bool)
for _, err := range c.IgnoreErrors { for _, err := range c.IgnoreLogs {
ignoredErrors[strings.ToLower(err)] = true ignoredLogIDs[strings.ToLower(err)] = true
} }
baseURL, err := urls.NewBaseURLFromString(c.BaseURL) baseURL, err := urls.NewBaseURLFromString(c.BaseURL)
@@ -357,7 +359,7 @@ func (c *Config) CompileConfig(logger loggers.Logger) error {
BaseURLLiveReload: baseURL, BaseURLLiveReload: baseURL,
DisabledKinds: disabledKinds, DisabledKinds: disabledKinds,
DisabledLanguages: disabledLangs, DisabledLanguages: disabledLangs,
IgnoredErrors: ignoredErrors, IgnoredLogs: ignoredLogIDs,
KindOutputFormats: kindOutputFormats, KindOutputFormats: kindOutputFormats,
CreateTitle: helpers.GetTitleFunc(c.TitleCaseStyle), CreateTitle: helpers.GetTitleFunc(c.TitleCaseStyle),
IsUglyURLSection: isUglyURL, IsUglyURLSection: isUglyURL,
@@ -394,7 +396,7 @@ type ConfigCompiled struct {
KindOutputFormats map[string]output.Formats KindOutputFormats map[string]output.Formats
DisabledKinds map[string]bool DisabledKinds map[string]bool
DisabledLanguages map[string]bool DisabledLanguages map[string]bool
IgnoredErrors map[string]bool IgnoredLogs map[string]bool
CreateTitle func(s string) string CreateTitle func(s string) string
IsUglyURLSection func(section string) bool IsUglyURLSection func(section string) bool
IgnoreFile func(filename string) bool IgnoreFile func(filename string) bool
@@ -501,8 +503,8 @@ type RootConfig struct {
// Enable to disable the build lock file. // Enable to disable the build lock file.
NoBuildLock bool NoBuildLock bool
// A list of error IDs to ignore. // A list of log IDs to ignore.
IgnoreErrors []string IgnoreLogs []string
// A list of regexps that match paths to ignore. // A list of regexps that match paths to ignore.
// Deprecated: Use the settings on module imports. // Deprecated: Use the settings on module imports.
@@ -661,7 +663,7 @@ type Configs struct {
// All below is set in Init. // All below is set in Init.
Languages langs.Languages Languages langs.Languages
LanguagesDefaultFirst langs.Languages LanguagesDefaultFirst langs.Languages
ContentPathParser paths.PathParser ContentPathParser *paths.PathParser
configLangs []config.AllProvider configLangs []config.AllProvider
} }
@@ -732,7 +734,8 @@ func (c *Configs) Init() error {
c.Languages = languages c.Languages = languages
c.LanguagesDefaultFirst = languagesDefaultFirst c.LanguagesDefaultFirst = languagesDefaultFirst
c.ContentPathParser = paths.PathParser{LanguageIndex: languagesDefaultFirst.AsIndexSet()}
c.ContentPathParser = &paths.PathParser{LanguageIndex: languagesDefaultFirst.AsIndexSet(), IsLangDisabled: c.Base.IsLangDisabled}
c.configLangs = make([]config.AllProvider, len(c.Languages)) c.configLangs = make([]config.AllProvider, len(c.Languages))
for i, l := range c.LanguagesDefaultFirst { for i, l := range c.LanguagesDefaultFirst {
@@ -899,6 +902,18 @@ func fromLoadConfigResult(fs afero.Fs, logger loggers.Logger, res config.LoadCon
return nil, err return nil, err
} }
// Adjust Goldmark config defaults for multilingual, single-host sites.
if len(languagesConfig) > 1 && !isMultiHost && !clone.Markup.Goldmark.DuplicateResourceFiles {
if !clone.Markup.Goldmark.DuplicateResourceFiles {
if clone.Markup.Goldmark.RenderHooks.Link.EnableDefault == nil {
clone.Markup.Goldmark.RenderHooks.Link.EnableDefault = types.NewBool(true)
}
if clone.Markup.Goldmark.RenderHooks.Image.EnableDefault == nil {
clone.Markup.Goldmark.RenderHooks.Image.EnableDefault = types.NewBool(true)
}
}
}
langConfigMap[k] = clone langConfigMap[k] = clone
case maps.ParamsMergeStrategy: case maps.ParamsMergeStrategy:
default: default:
@@ -951,7 +966,7 @@ func decodeConfigFromParams(fs afero.Fs, logger loggers.Logger, bcfg config.Base
}) })
for _, v := range decoderSetups { for _, v := range decoderSetups {
p := decodeConfig{p: p, c: target, fs: fs, bcfg: bcfg} p := decodeConfig{p: p, c: target, fs: fs, logger: logger, bcfg: bcfg}
if err := v.decode(v, p); err != nil { if err := v.decode(v, p); err != nil {
return fmt.Errorf("failed to decode %q: %w", v.key, err) return fmt.Errorf("failed to decode %q: %w", v.key, err)
} }
+9 -7
View File
@@ -18,13 +18,14 @@ import (
"strings" "strings"
"github.com/gohugoio/hugo/cache/filecache" "github.com/gohugoio/hugo/cache/filecache"
"github.com/gohugoio/hugo/common/loggers"
"github.com/gohugoio/hugo/common/maps" "github.com/gohugoio/hugo/common/maps"
"github.com/gohugoio/hugo/common/types" "github.com/gohugoio/hugo/common/types"
"github.com/gohugoio/hugo/config" "github.com/gohugoio/hugo/config"
"github.com/gohugoio/hugo/config/privacy" "github.com/gohugoio/hugo/config/privacy"
"github.com/gohugoio/hugo/config/security" "github.com/gohugoio/hugo/config/security"
"github.com/gohugoio/hugo/config/services" "github.com/gohugoio/hugo/config/services"
"github.com/gohugoio/hugo/deploy" "github.com/gohugoio/hugo/deploy/deployconfig"
"github.com/gohugoio/hugo/langs" "github.com/gohugoio/hugo/langs"
"github.com/gohugoio/hugo/markup/markup_config" "github.com/gohugoio/hugo/markup/markup_config"
"github.com/gohugoio/hugo/media" "github.com/gohugoio/hugo/media"
@@ -42,10 +43,11 @@ import (
) )
type decodeConfig struct { type decodeConfig struct {
p config.Provider p config.Provider
c *Config c *Config
fs afero.Fs fs afero.Fs
bcfg config.BaseConfig logger loggers.Logger
bcfg config.BaseConfig
} }
type decodeWeight struct { type decodeWeight struct {
@@ -291,7 +293,7 @@ var allDecoderSetups = map[string]decodeWeight{
key: "cascade", key: "cascade",
decode: func(d decodeWeight, p decodeConfig) error { decode: func(d decodeWeight, p decodeConfig) error {
var err error var err error
p.c.Cascade, err = page.DecodeCascadeConfig(p.p.Get(d.key)) p.c.Cascade, err = page.DecodeCascadeConfig(p.logger, p.p.Get(d.key))
return err return err
}, },
}, },
@@ -331,7 +333,7 @@ var allDecoderSetups = map[string]decodeWeight{
key: "deployment", key: "deployment",
decode: func(d decodeWeight, p decodeConfig) error { decode: func(d decodeWeight, p decodeConfig) error {
var err error var err error
p.c.Deployment, err = deploy.DecodeConfig(p.p) p.c.Deployment, err = deployconfig.DecodeConfig(p.p)
return err return err
}, },
}, },
+15 -3
View File
@@ -19,6 +19,7 @@ import (
"github.com/gohugoio/hugo/common/paths" "github.com/gohugoio/hugo/common/paths"
"github.com/gohugoio/hugo/common/urls" "github.com/gohugoio/hugo/common/urls"
"github.com/gohugoio/hugo/config" "github.com/gohugoio/hugo/config"
"github.com/gohugoio/hugo/identity"
"github.com/gohugoio/hugo/langs" "github.com/gohugoio/hugo/langs"
) )
@@ -42,7 +43,7 @@ func (c ConfigLanguage) LanguagesDefaultFirst() langs.Languages {
return c.m.LanguagesDefaultFirst return c.m.LanguagesDefaultFirst
} }
func (c ConfigLanguage) PathParser() paths.PathParser { func (c ConfigLanguage) PathParser() *paths.PathParser {
return c.m.ContentPathParser return c.m.ContentPathParser
} }
@@ -73,6 +74,10 @@ func (c ConfigLanguage) IsMultihost() bool {
return c.m.IsMultihost return c.m.IsMultihost
} }
func (c ConfigLanguage) FastRenderMode() bool {
return c.config.Internal.FastRenderMode
}
func (c ConfigLanguage) IsMultiLingual() bool { func (c ConfigLanguage) IsMultiLingual() bool {
return len(c.m.Languages) > 1 return len(c.m.Languages) > 1
} }
@@ -89,8 +94,8 @@ func (c ConfigLanguage) IsLangDisabled(lang string) bool {
return c.config.C.DisabledLanguages[lang] return c.config.C.DisabledLanguages[lang]
} }
func (c ConfigLanguage) IgnoredErrors() map[string]bool { func (c ConfigLanguage) IgnoredLogs() map[string]bool {
return c.config.C.IgnoredErrors return c.config.C.IgnoredLogs
} }
func (c ConfigLanguage) NoBuildLock() bool { func (c ConfigLanguage) NoBuildLock() bool {
@@ -129,6 +134,13 @@ func (c ConfigLanguage) Watching() bool {
return c.m.Base.Internal.Watch return c.m.Base.Internal.Watch
} }
func (c ConfigLanguage) NewIdentityManager(name string) identity.Manager {
if !c.Watching() {
return identity.NopManager
}
return identity.NewManager(name)
}
// GetConfigSection is mostly used in tests. The switch statement isn't complete, but what's in use. // GetConfigSection is mostly used in tests. The switch statement isn't complete, but what's in use.
func (c ConfigLanguage) GetConfigSection(s string) any { func (c ConfigLanguage) GetConfigSection(s string) any {
switch s { switch s {
+1
View File
@@ -141,6 +141,7 @@ func (l configLoader) applyConfigAliases() error {
{Key: "indexes", Value: "taxonomies"}, {Key: "indexes", Value: "taxonomies"},
{Key: "logI18nWarnings", Value: "printI18nWarnings"}, {Key: "logI18nWarnings", Value: "printI18nWarnings"},
{Key: "logPathWarnings", Value: "printPathWarnings"}, {Key: "logPathWarnings", Value: "printPathWarnings"},
{Key: "ignoreErrors", Value: "ignoreLogs"},
} }
for _, alias := range aliases { for _, alias := range aliases {
+1 -1
View File
@@ -50,7 +50,7 @@ weight = 3
title = "Svenska" title = "Svenska"
weight = 4 weight = 4
` `
if err := os.WriteFile(configFilename, []byte(config), 0666); err != nil { if err := os.WriteFile(configFilename, []byte(config), 0o666); err != nil {
b.Fatal(err) b.Fatal(err)
} }
d := ConfigSourceDescriptor{ d := ConfigSourceDescriptor{
-1
View File
@@ -208,7 +208,6 @@ func LoadConfigFromDir(sourceFs afero.Fs, configDir, environment string) (Provid
} }
return cfg, dirnames, nil return cfg, dirnames, nil
} }
var keyAliases maps.KeyRenamer var keyAliases maps.KeyRenamer
+5 -2
View File
@@ -20,6 +20,7 @@ import (
"github.com/gohugoio/hugo/common/paths" "github.com/gohugoio/hugo/common/paths"
"github.com/gohugoio/hugo/common/types" "github.com/gohugoio/hugo/common/types"
"github.com/gohugoio/hugo/common/urls" "github.com/gohugoio/hugo/common/urls"
"github.com/gohugoio/hugo/identity"
"github.com/gohugoio/hugo/langs" "github.com/gohugoio/hugo/langs"
) )
@@ -31,7 +32,7 @@ type AllProvider interface {
LanguagePrefix() string LanguagePrefix() string
BaseURL() urls.BaseURL BaseURL() urls.BaseURL
BaseURLLiveReload() urls.BaseURL BaseURLLiveReload() urls.BaseURL
PathParser() paths.PathParser PathParser() *paths.PathParser
Environment() string Environment() string
IsMultihost() bool IsMultihost() bool
IsMultiLingual() bool IsMultiLingual() bool
@@ -57,6 +58,8 @@ type AllProvider interface {
BuildDrafts() bool BuildDrafts() bool
Running() bool Running() bool
Watching() bool Watching() bool
NewIdentityManager(name string) identity.Manager
FastRenderMode() bool
PrintUnusedTemplates() bool PrintUnusedTemplates() bool
EnableMissingTranslationPlaceholders() bool EnableMissingTranslationPlaceholders() bool
TemplateMetrics() bool TemplateMetrics() bool
@@ -67,7 +70,7 @@ type AllProvider interface {
NewContentEditor() string NewContentEditor() string
Timeout() time.Duration Timeout() time.Duration
StaticDirs() []string StaticDirs() []string
IgnoredErrors() map[string]bool IgnoredLogs() map[string]bool
WorkingDir() string WorkingDir() string
EnableEmoji() bool EnableEmoji() bool
} }
-1
View File
@@ -370,7 +370,6 @@ func (c *defaultConfigProvider) SetDefaultMergeStrategy() {
} }
return false return false
}) })
} }
func (c *defaultConfigProvider) getNestedKeyAndMap(key string, create bool) (string, maps.Params) { func (c *defaultConfigProvider) getNestedKeyAndMap(key string, create bool) (string, maps.Params) {
-1
View File
@@ -49,7 +49,6 @@ func GetMemoryLimit() uint64 {
if v := stringToGibabyte(mem); v > 0 { if v := stringToGibabyte(mem); v > 0 {
return v return v
} }
} }
// There is a FreeMemory function, but as the kernel in most situations // There is a FreeMemory function, but as the kernel in most situations
+1 -1
View File
@@ -42,7 +42,7 @@ var DefaultConfig = Config{
), ),
// These have been tested to work with Hugo's external programs // These have been tested to work with Hugo's external programs
// on Windows, Linux and MacOS. // on Windows, Linux and MacOS.
OsEnv: MustNewWhitelist(`(?i)^((HTTPS?|NO)_PROXY|PATH(EXT)?|APPDATA|TE?MP|TERM|GO\w+|(XDG_CONFIG_)?HOME|USERPROFILE|SSH_AUTH_SOCK|DISPLAY|LANG)$`), OsEnv: MustNewWhitelist(`(?i)^((HTTPS?|NO)_PROXY|PATH(EXT)?|APPDATA|TE?MP|TERM|GO\w+|(XDG_CONFIG_)?HOME|USERPROFILE|SSH_AUTH_SOCK|DISPLAY|LANG|SYSTEMDRIVE)$`),
}, },
Funcs: Funcs{ Funcs: Funcs{
Getenv: MustNewWhitelist("^HUGO_", "^CI$"), Getenv: MustNewWhitelist("^HUGO_", "^CI$"),
+1 -1
View File
@@ -135,7 +135,7 @@ func TestToTOML(t *testing.T) {
got := DefaultConfig.ToTOML() got := DefaultConfig.ToTOML()
c.Assert(got, qt.Equals, c.Assert(got, qt.Equals,
"[security]\n enableInlineShortcodes = false\n\n [security.exec]\n allow = ['^(dart-)?sass(-embedded)?$', '^go$', '^npx$', '^postcss$']\n osEnv = ['(?i)^((HTTPS?|NO)_PROXY|PATH(EXT)?|APPDATA|TE?MP|TERM|GO\\w+|(XDG_CONFIG_)?HOME|USERPROFILE|SSH_AUTH_SOCK|DISPLAY|LANG)$']\n\n [security.funcs]\n getenv = ['^HUGO_', '^CI$']\n\n [security.http]\n methods = ['(?i)GET|POST']\n urls = ['.*']", "[security]\n enableInlineShortcodes = false\n\n [security.exec]\n allow = ['^(dart-)?sass(-embedded)?$', '^go$', '^npx$', '^postcss$']\n osEnv = ['(?i)^((HTTPS?|NO)_PROXY|PATH(EXT)?|APPDATA|TE?MP|TERM|GO\\w+|(XDG_CONFIG_)?HOME|USERPROFILE|SSH_AUTH_SOCK|DISPLAY|LANG|SYSTEMDRIVE)$']\n\n [security.funcs]\n getenv = ['^HUGO_', '^CI$']\n\n [security.http]\n methods = ['(?i)GET|POST']\n urls = ['.*']",
) )
} }
-1
View File
@@ -43,5 +43,4 @@ func TestWhitelist(t *testing.T) {
c.Assert(w.Accept("bar"), qt.IsTrue) c.Assert(w.Accept("bar"), qt.IsTrue)
c.Assert(w.Accept("mbar"), qt.IsFalse) c.Assert(w.Accept("mbar"), qt.IsFalse)
}) })
} }
+30 -9
View File
@@ -21,32 +21,53 @@ import (
"net/url" "net/url"
"time" "time"
"github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go/service/cloudfront" "github.com/aws/aws-sdk-go-v2/service/cloudfront"
"github.com/aws/aws-sdk-go-v2/service/cloudfront/types"
"github.com/gohugoio/hugo/deploy/deployconfig"
gcaws "gocloud.dev/aws" gcaws "gocloud.dev/aws"
) )
// V2ConfigFromURLParams will fail for any unknown params, so we need to remove them.
// This is a mysterious API, but inspecting the code the known params are:
var v2ConfigValidParams = map[string]bool{
"endpoint": true,
"region": true,
"profile": true,
"awssdk": true,
}
// InvalidateCloudFront invalidates the CloudFront cache for distributionID. // InvalidateCloudFront invalidates the CloudFront cache for distributionID.
// Uses AWS credentials config from the bucket URL. // Uses AWS credentials config from the bucket URL.
func InvalidateCloudFront(ctx context.Context, target *Target) error { func InvalidateCloudFront(ctx context.Context, target *deployconfig.Target) error {
u, err := url.Parse(target.URL) u, err := url.Parse(target.URL)
if err != nil { if err != nil {
return err return err
} }
sess, _, err := gcaws.NewSessionFromURLParams(u.Query()) vals := u.Query()
// Remove any unknown params.
for k := range vals {
if !v2ConfigValidParams[k] {
vals.Del(k)
}
}
cfg, err := gcaws.V2ConfigFromURLParams(ctx, vals)
if err != nil { if err != nil {
return err return err
} }
cf := cloudfront.NewFromConfig(cfg)
req := &cloudfront.CreateInvalidationInput{ req := &cloudfront.CreateInvalidationInput{
DistributionId: aws.String(target.CloudFrontDistributionID), DistributionId: aws.String(target.CloudFrontDistributionID),
InvalidationBatch: &cloudfront.InvalidationBatch{ InvalidationBatch: &types.InvalidationBatch{
CallerReference: aws.String(time.Now().Format("20060102150405")), CallerReference: aws.String(time.Now().Format("20060102150405")),
Paths: &cloudfront.Paths{ Paths: &types.Paths{
Items: []*string{aws.String("/*")}, Items: []string{"/*"},
Quantity: aws.Int64(1), Quantity: aws.Int32(1),
}, },
}, },
} }
_, err = cloudfront.New(sess).CreateInvalidationWithContext(ctx, req) _, err = cf.CreateInvalidation(ctx, req)
return err return err
} }
+11 -10
View File
@@ -38,6 +38,7 @@ import (
"github.com/gobwas/glob" "github.com/gobwas/glob"
"github.com/gohugoio/hugo/common/loggers" "github.com/gohugoio/hugo/common/loggers"
"github.com/gohugoio/hugo/config" "github.com/gohugoio/hugo/config"
"github.com/gohugoio/hugo/deploy/deployconfig"
"github.com/gohugoio/hugo/media" "github.com/gohugoio/hugo/media"
"github.com/spf13/afero" "github.com/spf13/afero"
"golang.org/x/text/unicode/norm" "golang.org/x/text/unicode/norm"
@@ -57,10 +58,10 @@ type Deployer struct {
mediaTypes media.Types // Hugo's MediaType to guess ContentType mediaTypes media.Types // Hugo's MediaType to guess ContentType
quiet bool // true reduces STDOUT // TODO(bep) remove, this is a global feature. quiet bool // true reduces STDOUT // TODO(bep) remove, this is a global feature.
cfg DeployConfig cfg deployconfig.DeployConfig
logger loggers.Logger logger loggers.Logger
target *Target // the target to deploy to target *deployconfig.Target // the target to deploy to
// For tests... // For tests...
summary deploySummary // summary of latest Deploy results summary deploySummary // summary of latest Deploy results
@@ -74,7 +75,7 @@ const metaMD5Hash = "md5chksum" // the meta key to store md5hash in
// New constructs a new *Deployer. // New constructs a new *Deployer.
func New(cfg config.AllProvider, logger loggers.Logger, localFs afero.Fs) (*Deployer, error) { func New(cfg config.AllProvider, logger loggers.Logger, localFs afero.Fs) (*Deployer, error) {
dcfg := cfg.GetConfigSection(deploymentConfigKey).(DeployConfig) dcfg := cfg.GetConfigSection(deployconfig.DeploymentConfigKey).(deployconfig.DeployConfig)
targetName := dcfg.Target targetName := dcfg.Target
if len(dcfg.Targets) == 0 { if len(dcfg.Targets) == 0 {
@@ -83,7 +84,7 @@ func New(cfg config.AllProvider, logger loggers.Logger, localFs afero.Fs) (*Depl
mediaTypes := cfg.GetConfigSection("mediaTypes").(media.Types) mediaTypes := cfg.GetConfigSection("mediaTypes").(media.Types)
// Find the target to deploy to. // Find the target to deploy to.
var tgt *Target var tgt *deployconfig.Target
if targetName == "" { if targetName == "" {
// Default to the first target. // Default to the first target.
tgt = dcfg.Targets[0] tgt = dcfg.Targets[0]
@@ -133,7 +134,7 @@ func (d *Deployer) Deploy(ctx context.Context) error {
// Load local files from the source directory. // Load local files from the source directory.
var include, exclude glob.Glob var include, exclude glob.Glob
if d.target != nil { if d.target != nil {
include, exclude = d.target.includeGlob, d.target.excludeGlob include, exclude = d.target.IncludeGlob, d.target.ExcludeGlob
} }
local, err := d.walkLocal(d.localFs, d.cfg.Matchers, include, exclude, d.mediaTypes) local, err := d.walkLocal(d.localFs, d.cfg.Matchers, include, exclude, d.mediaTypes)
if err != nil { if err != nil {
@@ -178,7 +179,7 @@ func (d *Deployer) Deploy(ctx context.Context) error {
// Order the uploads. They are organized in groups; all uploads in a group // Order the uploads. They are organized in groups; all uploads in a group
// must be complete before moving on to the next group. // must be complete before moving on to the next group.
uploadGroups := applyOrdering(d.cfg.ordering, uploads) uploadGroups := applyOrdering(d.cfg.Ordering, uploads)
nParallel := d.cfg.Workers nParallel := d.cfg.Workers
var errs []error var errs []error
@@ -343,14 +344,14 @@ type localFile struct {
UploadSize int64 UploadSize int64
fs afero.Fs fs afero.Fs
matcher *Matcher matcher *deployconfig.Matcher
md5 []byte // cache md5 []byte // cache
gzipped bytes.Buffer // cached of gzipped contents if gzipping gzipped bytes.Buffer // cached of gzipped contents if gzipping
mediaTypes media.Types mediaTypes media.Types
} }
// newLocalFile initializes a *localFile. // newLocalFile initializes a *localFile.
func newLocalFile(fs afero.Fs, nativePath, slashpath string, m *Matcher, mt media.Types) (*localFile, error) { func newLocalFile(fs afero.Fs, nativePath, slashpath string, m *deployconfig.Matcher, mt media.Types) (*localFile, error) {
f, err := fs.Open(nativePath) f, err := fs.Open(nativePath)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -482,7 +483,7 @@ func knownHiddenDirectory(name string) bool {
// walkLocal walks the source directory and returns a flat list of files, // walkLocal walks the source directory and returns a flat list of files,
// using localFile.SlashPath as the map keys. // using localFile.SlashPath as the map keys.
func (d *Deployer) walkLocal(fs afero.Fs, matchers []*Matcher, include, exclude glob.Glob, mediaTypes media.Types) (map[string]*localFile, error) { func (d *Deployer) walkLocal(fs afero.Fs, matchers []*deployconfig.Matcher, include, exclude glob.Glob, mediaTypes media.Types) (map[string]*localFile, error) {
retval := map[string]*localFile{} retval := map[string]*localFile{}
err := afero.Walk(fs, "", func(path string, info os.FileInfo, err error) error { err := afero.Walk(fs, "", func(path string, info os.FileInfo, err error) error {
if err != nil { if err != nil {
@@ -521,7 +522,7 @@ func (d *Deployer) walkLocal(fs afero.Fs, matchers []*Matcher, include, exclude
} }
// Find the first matching matcher (if any). // Find the first matching matcher (if any).
var m *Matcher var m *deployconfig.Matcher
for _, cur := range matchers { for _, cur := range matchers {
if cur.Matches(slashpath) { if cur.Matches(slashpath) {
m = cur m = cur
+18 -17
View File
@@ -31,6 +31,7 @@ import (
"testing" "testing"
"github.com/gohugoio/hugo/common/loggers" "github.com/gohugoio/hugo/common/loggers"
"github.com/gohugoio/hugo/deploy/deployconfig"
"github.com/gohugoio/hugo/hugofs" "github.com/gohugoio/hugo/hugofs"
"github.com/gohugoio/hugo/media" "github.com/gohugoio/hugo/media"
"github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp"
@@ -110,7 +111,7 @@ func TestFindDiffs(t *testing.T) {
{ {
Description: "local == remote with route.Force true -> diffs", Description: "local == remote with route.Force true -> diffs",
Local: []*localFile{ Local: []*localFile{
{NativePath: "aaa", SlashPath: "aaa", UploadSize: 1, matcher: &Matcher{Force: true}, md5: hash1}, {NativePath: "aaa", SlashPath: "aaa", UploadSize: 1, matcher: &deployconfig.Matcher{Force: true}, md5: hash1},
makeLocal("bbb", 2, hash1), makeLocal("bbb", 2, hash1),
}, },
Remote: []*blob.ListObject{ Remote: []*blob.ListObject{
@@ -293,7 +294,7 @@ func TestLocalFile(t *testing.T) {
tests := []struct { tests := []struct {
Description string Description string
Path string Path string
Matcher *Matcher Matcher *deployconfig.Matcher
MediaTypesConfig map[string]any MediaTypesConfig map[string]any
WantContent []byte WantContent []byte
WantSize int64 WantSize int64
@@ -319,7 +320,7 @@ func TestLocalFile(t *testing.T) {
{ {
Description: "CacheControl from matcher", Description: "CacheControl from matcher",
Path: "foo.txt", Path: "foo.txt",
Matcher: &Matcher{CacheControl: "max-age=630720000"}, Matcher: &deployconfig.Matcher{CacheControl: "max-age=630720000"},
WantContent: contentBytes, WantContent: contentBytes,
WantSize: contentLen, WantSize: contentLen,
WantMD5: contentMD5[:], WantMD5: contentMD5[:],
@@ -328,7 +329,7 @@ func TestLocalFile(t *testing.T) {
{ {
Description: "ContentEncoding from matcher", Description: "ContentEncoding from matcher",
Path: "foo.txt", Path: "foo.txt",
Matcher: &Matcher{ContentEncoding: "foobar"}, Matcher: &deployconfig.Matcher{ContentEncoding: "foobar"},
WantContent: contentBytes, WantContent: contentBytes,
WantSize: contentLen, WantSize: contentLen,
WantMD5: contentMD5[:], WantMD5: contentMD5[:],
@@ -337,7 +338,7 @@ func TestLocalFile(t *testing.T) {
{ {
Description: "ContentType from matcher", Description: "ContentType from matcher",
Path: "foo.txt", Path: "foo.txt",
Matcher: &Matcher{ContentType: "foo/bar"}, Matcher: &deployconfig.Matcher{ContentType: "foo/bar"},
WantContent: contentBytes, WantContent: contentBytes,
WantSize: contentLen, WantSize: contentLen,
WantMD5: contentMD5[:], WantMD5: contentMD5[:],
@@ -346,7 +347,7 @@ func TestLocalFile(t *testing.T) {
{ {
Description: "gzipped content", Description: "gzipped content",
Path: "foo.txt", Path: "foo.txt",
Matcher: &Matcher{Gzip: true}, Matcher: &deployconfig.Matcher{Gzip: true},
WantContent: gzBytes, WantContent: gzBytes,
WantSize: gzLen, WantSize: gzLen,
WantMD5: gzMD5[:], WantMD5: gzMD5[:],
@@ -560,7 +561,7 @@ func TestEndToEndSync(t *testing.T) {
localFs: test.fs, localFs: test.fs,
bucket: test.bucket, bucket: test.bucket,
mediaTypes: media.DefaultTypes, mediaTypes: media.DefaultTypes,
cfg: DeployConfig{MaxDeletes: -1}, cfg: deployconfig.DeployConfig{MaxDeletes: -1},
} }
// Initial deployment should sync remote with local. // Initial deployment should sync remote with local.
@@ -643,7 +644,7 @@ func TestMaxDeletes(t *testing.T) {
localFs: test.fs, localFs: test.fs,
bucket: test.bucket, bucket: test.bucket,
mediaTypes: media.DefaultTypes, mediaTypes: media.DefaultTypes,
cfg: DeployConfig{MaxDeletes: -1}, cfg: deployconfig.DeployConfig{MaxDeletes: -1},
} }
// Sync remote with local. // Sync remote with local.
@@ -764,16 +765,16 @@ func TestIncludeExclude(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
tgt := &Target{ tgt := &deployconfig.Target{
Include: test.Include, Include: test.Include,
Exclude: test.Exclude, Exclude: test.Exclude,
} }
if err := tgt.parseIncludeExclude(); err != nil { if err := tgt.ParseIncludeExclude(); err != nil {
t.Error(err) t.Error(err)
} }
deployer := &Deployer{ deployer := &Deployer{
localFs: fsTest.fs, localFs: fsTest.fs,
cfg: DeployConfig{MaxDeletes: -1}, bucket: fsTest.bucket, cfg: deployconfig.DeployConfig{MaxDeletes: -1}, bucket: fsTest.bucket,
target: tgt, target: tgt,
mediaTypes: media.DefaultTypes, mediaTypes: media.DefaultTypes,
} }
@@ -830,7 +831,7 @@ func TestIncludeExcludeRemoteDelete(t *testing.T) {
} }
deployer := &Deployer{ deployer := &Deployer{
localFs: fsTest.fs, localFs: fsTest.fs,
cfg: DeployConfig{MaxDeletes: -1}, bucket: fsTest.bucket, cfg: deployconfig.DeployConfig{MaxDeletes: -1}, bucket: fsTest.bucket,
mediaTypes: media.DefaultTypes, mediaTypes: media.DefaultTypes,
} }
@@ -848,11 +849,11 @@ func TestIncludeExcludeRemoteDelete(t *testing.T) {
} }
// Second sync // Second sync
tgt := &Target{ tgt := &deployconfig.Target{
Include: test.Include, Include: test.Include,
Exclude: test.Exclude, Exclude: test.Exclude,
} }
if err := tgt.parseIncludeExclude(); err != nil { if err := tgt.ParseIncludeExclude(); err != nil {
t.Error(err) t.Error(err)
} }
deployer.target = tgt deployer.target = tgt
@@ -882,7 +883,7 @@ func TestCompression(t *testing.T) {
deployer := &Deployer{ deployer := &Deployer{
localFs: test.fs, localFs: test.fs,
bucket: test.bucket, bucket: test.bucket,
cfg: DeployConfig{MaxDeletes: -1, Matchers: []*Matcher{{Pattern: ".*", Gzip: true, re: regexp.MustCompile(".*")}}}, cfg: deployconfig.DeployConfig{MaxDeletes: -1, Matchers: []*deployconfig.Matcher{{Pattern: ".*", Gzip: true, Re: regexp.MustCompile(".*")}}},
mediaTypes: media.DefaultTypes, mediaTypes: media.DefaultTypes,
} }
@@ -937,7 +938,7 @@ func TestMatching(t *testing.T) {
deployer := &Deployer{ deployer := &Deployer{
localFs: test.fs, localFs: test.fs,
bucket: test.bucket, bucket: test.bucket,
cfg: DeployConfig{MaxDeletes: -1, Matchers: []*Matcher{{Pattern: "^subdir/aaa$", Force: true, re: regexp.MustCompile("^subdir/aaa$")}}}, cfg: deployconfig.DeployConfig{MaxDeletes: -1, Matchers: []*deployconfig.Matcher{{Pattern: "^subdir/aaa$", Force: true, Re: regexp.MustCompile("^subdir/aaa$")}}},
mediaTypes: media.DefaultTypes, mediaTypes: media.DefaultTypes,
} }
@@ -962,7 +963,7 @@ func TestMatching(t *testing.T) {
} }
// Repeat with a matcher that should now match 3 files. // Repeat with a matcher that should now match 3 files.
deployer.cfg.Matchers = []*Matcher{{Pattern: "aaa", Force: true, re: regexp.MustCompile("aaa")}} deployer.cfg.Matchers = []*deployconfig.Matcher{{Pattern: "aaa", Force: true, Re: regexp.MustCompile("aaa")}}
if err := deployer.Deploy(ctx); err != nil { if err := deployer.Deploy(ctx); err != nil {
t.Errorf("no-op deploy with triple force matcher: %v", err) t.Errorf("no-op deploy with triple force matcher: %v", err)
} }
@@ -1,4 +1,4 @@
// Copyright 2019 The Hugo Authors. All rights reserved. // Copyright 2024 The Hugo Authors. All rights reserved.
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
@@ -11,21 +11,20 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
package deploy package deployconfig
import ( import (
"errors"
"fmt" "fmt"
"regexp" "regexp"
"errors"
"github.com/gobwas/glob" "github.com/gobwas/glob"
"github.com/gohugoio/hugo/config" "github.com/gohugoio/hugo/config"
hglob "github.com/gohugoio/hugo/hugofs/glob" hglob "github.com/gohugoio/hugo/hugofs/glob"
"github.com/mitchellh/mapstructure" "github.com/mitchellh/mapstructure"
) )
const deploymentConfigKey = "deployment" const DeploymentConfigKey = "deployment"
// DeployConfig is the complete configuration for deployment. // DeployConfig is the complete configuration for deployment.
type DeployConfig struct { type DeployConfig struct {
@@ -49,7 +48,7 @@ type DeployConfig struct {
// Number of concurrent workers to use when uploading files. // Number of concurrent workers to use when uploading files.
Workers int Workers int
ordering []*regexp.Regexp // compiled Order Ordering []*regexp.Regexp `json:"-"` // compiled Order
} }
type Target struct { type Target struct {
@@ -68,20 +67,20 @@ type Target struct {
Exclude string Exclude string
// Parsed versions of Include/Exclude. // Parsed versions of Include/Exclude.
includeGlob glob.Glob IncludeGlob glob.Glob `json:"-"`
excludeGlob glob.Glob ExcludeGlob glob.Glob `json:"-"`
} }
func (tgt *Target) parseIncludeExclude() error { func (tgt *Target) ParseIncludeExclude() error {
var err error var err error
if tgt.Include != "" { if tgt.Include != "" {
tgt.includeGlob, err = hglob.GetGlob(tgt.Include) tgt.IncludeGlob, err = hglob.GetGlob(tgt.Include)
if err != nil { if err != nil {
return fmt.Errorf("invalid deployment.target.include %q: %v", tgt.Include, err) return fmt.Errorf("invalid deployment.target.include %q: %v", tgt.Include, err)
} }
} }
if tgt.Exclude != "" { if tgt.Exclude != "" {
tgt.excludeGlob, err = hglob.GetGlob(tgt.Exclude) tgt.ExcludeGlob, err = hglob.GetGlob(tgt.Exclude)
if err != nil { if err != nil {
return fmt.Errorf("invalid deployment.target.exclude %q: %v", tgt.Exclude, err) return fmt.Errorf("invalid deployment.target.exclude %q: %v", tgt.Exclude, err)
} }
@@ -116,12 +115,12 @@ type Matcher struct {
// other route-determined metadata (e.g., ContentType) has changed. // other route-determined metadata (e.g., ContentType) has changed.
Force bool Force bool
// re is Pattern compiled. // Re is Pattern compiled.
re *regexp.Regexp Re *regexp.Regexp `json:"-"`
} }
func (m *Matcher) Matches(path string) bool { func (m *Matcher) Matches(path string) bool {
return m.re.MatchString(path) return m.Re.MatchString(path)
} }
var DefaultConfig = DeployConfig{ var DefaultConfig = DeployConfig{
@@ -132,13 +131,12 @@ var DefaultConfig = DeployConfig{
// DecodeConfig creates a config from a given Hugo configuration. // DecodeConfig creates a config from a given Hugo configuration.
func DecodeConfig(cfg config.Provider) (DeployConfig, error) { func DecodeConfig(cfg config.Provider) (DeployConfig, error) {
dcfg := DefaultConfig dcfg := DefaultConfig
if !cfg.IsSet(deploymentConfigKey) { if !cfg.IsSet(DeploymentConfigKey) {
return dcfg, nil return dcfg, nil
} }
if err := mapstructure.WeakDecode(cfg.GetStringMap(deploymentConfigKey), &dcfg); err != nil { if err := mapstructure.WeakDecode(cfg.GetStringMap(DeploymentConfigKey), &dcfg); err != nil {
return dcfg, err return dcfg, err
} }
@@ -150,7 +148,7 @@ func DecodeConfig(cfg config.Provider) (DeployConfig, error) {
if *tgt == (Target{}) { if *tgt == (Target{}) {
return dcfg, errors.New("empty deployment target") return dcfg, errors.New("empty deployment target")
} }
if err := tgt.parseIncludeExclude(); err != nil { if err := tgt.ParseIncludeExclude(); err != nil {
return dcfg, err return dcfg, err
} }
} }
@@ -159,7 +157,7 @@ func DecodeConfig(cfg config.Provider) (DeployConfig, error) {
if *m == (Matcher{}) { if *m == (Matcher{}) {
return dcfg, errors.New("empty deployment matcher") return dcfg, errors.New("empty deployment matcher")
} }
m.re, err = regexp.Compile(m.Pattern) m.Re, err = regexp.Compile(m.Pattern)
if err != nil { if err != nil {
return dcfg, fmt.Errorf("invalid deployment.matchers.pattern: %v", err) return dcfg, fmt.Errorf("invalid deployment.matchers.pattern: %v", err)
} }
@@ -169,7 +167,7 @@ func DecodeConfig(cfg config.Provider) (DeployConfig, error) {
if err != nil { if err != nil {
return dcfg, fmt.Errorf("invalid deployment.orderings.pattern: %v", err) return dcfg, fmt.Errorf("invalid deployment.orderings.pattern: %v", err)
} }
dcfg.ordering = append(dcfg.ordering, re) dcfg.Ordering = append(dcfg.Ordering, re)
} }
return dcfg, nil return dcfg, nil
@@ -1,4 +1,4 @@
// Copyright 2019 The Hugo Authors. All rights reserved. // Copyright 2024 The Hugo Authors. All rights reserved.
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
//go:build !nodeploy //go:build !nodeploy
// +build !nodeploy // +build !nodeploy
package deploy package deployconfig
import ( import (
"fmt" "fmt"
@@ -91,7 +91,7 @@ force = true
c.Assert(len(dcfg.Order), qt.Equals, 2) c.Assert(len(dcfg.Order), qt.Equals, 2)
c.Assert(dcfg.Order[0], qt.Equals, "o1") c.Assert(dcfg.Order[0], qt.Equals, "o1")
c.Assert(dcfg.Order[1], qt.Equals, "o2") c.Assert(dcfg.Order[1], qt.Equals, "o2")
c.Assert(len(dcfg.ordering), qt.Equals, 2) c.Assert(len(dcfg.Ordering), qt.Equals, 2)
// Targets. // Targets.
c.Assert(len(dcfg.Targets), qt.Equals, 3) c.Assert(len(dcfg.Targets), qt.Equals, 3)
@@ -104,11 +104,11 @@ force = true
c.Assert(tgt.CloudFrontDistributionID, qt.Equals, fmt.Sprintf("cdn%d", i)) c.Assert(tgt.CloudFrontDistributionID, qt.Equals, fmt.Sprintf("cdn%d", i))
c.Assert(tgt.Include, qt.Equals, wantInclude[i]) c.Assert(tgt.Include, qt.Equals, wantInclude[i])
if wantInclude[i] != "" { if wantInclude[i] != "" {
c.Assert(tgt.includeGlob, qt.Not(qt.IsNil)) c.Assert(tgt.IncludeGlob, qt.Not(qt.IsNil))
} }
c.Assert(tgt.Exclude, qt.Equals, wantExclude[i]) c.Assert(tgt.Exclude, qt.Equals, wantExclude[i])
if wantExclude[i] != "" { if wantExclude[i] != "" {
c.Assert(tgt.excludeGlob, qt.Not(qt.IsNil)) c.Assert(tgt.ExcludeGlob, qt.Not(qt.IsNil))
} }
} }
@@ -117,7 +117,7 @@ force = true
for i := 0; i < 3; i++ { for i := 0; i < 3; i++ {
m := dcfg.Matchers[i] m := dcfg.Matchers[i]
c.Assert(m.Pattern, qt.Equals, fmt.Sprintf("^pattern%d$", i)) c.Assert(m.Pattern, qt.Equals, fmt.Sprintf("^pattern%d$", i))
c.Assert(m.re, qt.Not(qt.IsNil)) c.Assert(m.Re, qt.Not(qt.IsNil))
c.Assert(m.CacheControl, qt.Equals, fmt.Sprintf("cachecontrol%d", i)) c.Assert(m.CacheControl, qt.Equals, fmt.Sprintf("cachecontrol%d", i))
c.Assert(m.ContentEncoding, qt.Equals, fmt.Sprintf("contentencoding%d", i)) c.Assert(m.ContentEncoding, qt.Equals, fmt.Sprintf("contentencoding%d", i))
c.Assert(m.ContentType, qt.Equals, fmt.Sprintf("contenttype%d", i)) c.Assert(m.ContentType, qt.Equals, fmt.Sprintf("contenttype%d", i))
+1
View File
@@ -105,6 +105,7 @@
"doas", "doas",
"eopkg", "eopkg",
"gitee", "gitee",
"gohugoio",
"goldmark", "goldmark",
"KaTeX", "KaTeX",
"kubuntu", "kubuntu",
+2 -2
View File
@@ -18,9 +18,9 @@ jobs:
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Initialize CodeQL - name: Initialize CodeQL
uses: github/codeql-action/init@v2 uses: github/codeql-action/init@v3
with: with:
languages: "javascript" languages: "javascript"
- name: Perform CodeQL Analysis - name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2 uses: github/codeql-action/analyze@v3
+1 -1
View File
@@ -21,7 +21,7 @@ jobs:
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Lint Code Base - name: Lint Code Base
uses: super-linter/super-linter/slim@v5 uses: super-linter/super-linter/slim@v6
env: env:
DEFAULT_BRANCH: master DEFAULT_BRANCH: master
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+13 -49
View File
@@ -1,56 +1,20 @@
<a href="https://gohugo.io/"><img src="https://raw.githubusercontent.com/gohugoio/gohugoioTheme/master/static/images/hugo-logo-wide.svg?sanitize=true" alt="Hugo" width="565"></a>
A fast and flexible static site generator built with love by [bep], [spf13], and [friends] in [Go].
---
[![Netlify Status](https://api.netlify.com/api/v1/badges/e0dbbfc7-34f1-4393-a679-c16e80162705/deploy-status)](https://app.netlify.com/sites/gohugoio/deploys) [![Netlify Status](https://api.netlify.com/api/v1/badges/e0dbbfc7-34f1-4393-a679-c16e80162705/deploy-status)](https://app.netlify.com/sites/gohugoio/deploys)
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](https://gohugo.io/contribute/documentation/) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](https://gohugo.io/contribute/documentation/)
# Hugo Docs This is the repository for the [Hugo](https://github.com/gohugoio/hugo) documentation site.
Documentation site for [Hugo](https://github.com/gohugoio/hugo), the very fast and flexible static site generator built with love in Go. Please see the [contributing] section for guidelines, examples, and process.
## Contributing
We welcome contributions to Hugo of any kind including documentation, suggestions, bug reports, pull requests etc. Also check out our [contribution guide](https://gohugo.io/contribute/documentation/). We would love to hear from you.
Note that this repository contains solely the documentation for Hugo. For contributions that aren't documentation-related please refer to the [hugo](https://github.com/gohugoio/hugo) repository. [bep]: https://github.com/bep
[spf13]: https://github.com/spf13
*Pull requests shall **only** contain changes to the actual documentation. However, changes on the codebase of Hugo **and** the documentation shall be a single, atomic pull request in the [hugo](https://github.com/gohugoio/hugo) repository.* [friends]: https://github.com/gohugoio/hugo/graphs/contributors
[go]: https://go.dev/
Spelling fixes are most welcomed, and if you want to contribute longer sections to the documentation, it would be great if you had the following criteria in mind when writing: [contributing]: https://gohugo.io/contribute/documentation
* Short is good. People go to the library to read novels. If there is more than one way to _do a thing_ in Hugo, describe the current _best practice_ (avoid "… but you can also do …" and "… in older versions of Hugo you had to …".
* For example, try to find short snippets that teaches people about the concept. If the example is also useful as-is (copy and paste), then great. Don't list long and similar examples just so people can use them on their sites.
* Hugo has users from all over the world, so easy to understand and [simple English](https://simple.wikipedia.org/wiki/Basic_English) is good.
## Edit the theme
If you want to do docs-related theme changes, the simplest way is to have both `hugoDocs` and `gohugoioTheme` cloned as sibling directories, and then run:
```sh
HUGO_MODULE_WORKSPACE=hugo.work hugo server --ignoreVendorPaths "**"
```
## Branches
* The `master` branch is where the site is automatically built from, and is the place to put changes relevant to the current Hugo version.
* The `next` branch is where we store changes that are related to the next Hugo release. This can be previewed here: https://next--gohugoio.netlify.com/
## Build
To view the documentation site locally, you need to clone this repository:
```sh
git clone https://github.com/gohugoio/hugoDocs.git
```
Also note that the documentation version for a given version of Hugo can also be found in the `/docs` sub-folder of the [Hugo source repository](https://github.com/gohugoio/hugo).
Then to view the docs in your browser, run Hugo and open up the link:
```sh
▶ hugo server
Started building sites ...
.
.
Serving pages from memory
Web Server is available at http://localhost:1313/ (bind address 127.0.0.1)
Press Ctrl+C to stop
```
@@ -1,4 +1,4 @@
<!DOCTYPE html> <!doctype html>
<html <html
class="no-js" class="no-js"
lang="{{ with $.Site.LanguageCode }} lang="{{ with $.Site.LanguageCode }}
@@ -98,7 +98,8 @@
{{ partial "gtag.html" . }} {{ partial "gtag.html" . }}
{{ end }} {{ end }}
{{ if .Param "math" }} {{ $hasMath := .Param "math" }}
{{ if $hasMath }}
{{ partialCached "math.html" . }} {{ partialCached "math.html" . }}
{{ end }} {{ end }}
@@ -107,7 +108,7 @@
<body <body
class="ma0 sans-serif bg-primary-color-light{{ with getenv "HUGO_ENV" }} class="ma0 sans-serif bg-primary-color-light{{ with getenv "HUGO_ENV" }}
{{ . }} {{ . }}
{{ end }}"> {{ end }} {{ if $hasMath }}{{ print " dn" }}{{ end }}">
{{ partial "hooks/after-body-start.html" . }} {{ partial "hooks/after-body-start.html" . }}
{{ block "nav" . }}{{ partial "site-nav.html" . }}{{ end }} {{ block "nav" . }}{{ partial "site-nav.html" . }}{{ end }}
{{ block "header" . }}{{ end }} {{ block "header" . }}{{ end }}
@@ -1,32 +1,42 @@
{{ $author := .context.Params.author }} {{ $author := .context.Params.author }}
{{ if $author }} {{ if $author }}
<aside class="mw5 center bg-white br3 pa3 pa4-ns mv3 ba b--black-10 nested-links"> <aside class="mw5 center bg-white br3 pa3 pa4-ns mv3 ba b--black-10 nested-links">
{{ $urlPre := "https://api.github.com" }}
{{ $user_json := getJSON $urlPre "/users/" $author }} {{ $data := "" }}
{{ $url := urls.JoinPath "https://api.github.com/users" $author }}
{{ with resources.GetRemote $url }}
{{ with .Err }}
{{ errorf "%s" . }}
{{ else }}
{{ $data = . | transform.Unmarshal }}
{{ end }}
{{ else }}
{{ errorf "Unable to get remote resource %q" $url }}
{{ end }}
<div class="tc"> <div class="tc">
{{ with $data }}
{{ if $user_json.avatar_url }} {{ with .avatar_url }}
<a href="{{ $user_json.html_url }}" class="link hover-bg-light-gray pa1 br-100"> <a href="{{ . }}" class="link hover-bg-light-gray pa1 br-100">
<img src="{{ $user_json.avatar_url }}&size={{ .size }}" alt="" class="br-100 ba b--light-gray"> <img src="{{ . }}&size={{ $.size }}" alt="" class="br-100 ba b--light-gray">
</a>
{{ end }}
{{ if $user_json.name }}
<h3 class="f4">
<a href="{{ $user_json.html_url }}" class="link dim">
{{ $user_json.name }}
</a> </a>
</h3> {{ end }}
<hr class="mw3 bb bw1 b--black-10"> {{ with .name }}
{{ end }} <h3 class="f4">
<a href="{{ $data.html_url }}" class="link dim">
{{ . | htmlEscape }}
</a>
</h3>
<hr class="mw3 bb bw1 b--black-10">
{{ end }}
{{ with .bio }}
<p class="lh-copy measure center f6 black-70">
{{ . | htmlEscape }}
</p>
{{ end }}
{{ if $user_json.bio }}
<p class="lh-copy measure center f6 black-70">
{{ $user_json.bio }}
</p>
{{ end }} {{ end }}
</div> </div>
</aside> </aside>
@@ -1,21 +1,36 @@
{{ $author := .context.Params.author }} {{ $author := .context.Params.author }}
{{ if $author }} {{ if $author }}
<aside class="mw5 br3 mv3 nested-links"> <aside class="mw5 br3 mv3 nested-links">
{{ $urlPre := "https://api.github.com" }}
{{ $user_json := getJSON $urlPre "/users/" $author }}
{{ if $user_json.name }}
<h3 class="f4 dib">
{{ $user_json.name | htmlEscape }}
</h3>
{{ $data := "" }}
{{ $url := urls.JoinPath "https://api.github.com/users" $author }}
{{ with resources.GetRemote $url }}
{{ with .Err }}
{{ errorf "%s" . }}
{{ else }}
{{ $data = . | transform.Unmarshal }}
{{ end }} {{ end }}
{{ if $user_json.bio }} {{ else }}
{{ errorf "Unable to get remote resource %q" $url }}
{{ end }}
{{ with $data }}
{{ with .name }}
<h3 class="f4 dib">
{{ . | htmlEscape }}
</h3>
{{ end }}
{{ with .bio }}
<p class="lh-copy measure center mt0 f6 black-60"> <p class="lh-copy measure center mt0 f6 black-60">
{{ $user_json.bio | htmlEscape }} {{ . | htmlEscape }}
</p> </p>
{{ end }} {{ end }}
<a href="{{ $user_json.html_url }}" class="link dim v-mid dib"> {{ with .html_url }}
{{ partial "svg/github-squared.svg" (dict "fill" "gray" "width" "16" "height" "18") }} <a href="{{ . }}" class="link dim v-mid dib">
</a> {{ partial "svg/github-squared.svg" (dict "fill" "gray" "width" "16" "height" "18") }}
</a>
{{ end }}
{{ end }}
</aside> </aside>
{{ end }} {{ end }}
@@ -14,11 +14,11 @@
<a href="{{ .Permalink }}">{{ .Title }}</a> <a href="{{ .Permalink }}">{{ .Title }}</a>
</td> </td>
<td class="pv2 ph3"> <td class="pv2 ph3">
<a href="{{.Site.Params.ghrepo}}blob/master/content/{{.Lang }}/{{.File.Path}}"> <a href="{{ .Site.Params.ghrepo }}blob/master/content/{{ .Language.Lang }}/{{ .File.Path }}">
{{ with .GitInfo }}{{ .Subject }}{{ else }}Source{{ end }} {{ with .GitInfo }}{{ .Subject }}{{ else }}Source{{ end }}
</a> </a>
</td> </td>
</tr> </tr>
{{ end }} {{ end }}
</tbody> </tbody>
</table> </table>
@@ -2,8 +2,15 @@
<script> <script>
MathJax = { MathJax = {
tex: { tex: {
displayMath: [['\\[', '\\]'], ['$$', '$$']], // block inlineMath: [['$', '$'], ['\\(', '\\)']], // inline
inlineMath: [['\\(', '\\)']] // inline displayMath: [['$$', '$$'], ['\\[', '\\]']] // block
},
startup: {
pageReady: () => {
return MathJax.startup.defaultPageReady().then(() => {
document.body.classList.remove("dn");
});
}
} }
}; };
</script> </script>
@@ -1,3 +1,3 @@
<a href="{{.Site.Params.ghrepo}}edit/master/content/{{ .Lang }}/{{.File.Path}}" class=" <a href="{{.Site.Params.ghrepo }}edit/master/content/{{ .Language.Lang }}/{{ .File.Path }}" class="
f6 ph3 pv1 br2 dib tc ttu mv3 bg-primary-color white hover-bg-green link f6 ph3 pv1 br2 dib tc ttu mv3 bg-primary-color white hover-bg-green link
">Improve this page</a> ">Improve this page</a>
+1 -1
View File
@@ -1 +1 @@
# github.com/gohugoio/gohugoioTheme v0.0.0-20240126181647-31e47d550511 # github.com/gohugoio/gohugoioTheme v0.0.0-20240201183016-8e648a3b5342
+1 -1
View File
@@ -56,7 +56,7 @@ hugo [flags]
--printPathWarnings print warnings on duplicate target paths etc. --printPathWarnings print warnings on duplicate target paths etc.
--printUnusedTemplates print warnings on unused templates. --printUnusedTemplates print warnings on unused templates.
--quiet build in quiet mode --quiet build in quiet mode
--renderToMemory render to memory (only useful for benchmark testing) --renderToMemory render to memory (mostly useful when running the server)
-s, --source string filesystem path to read files relative from -s, --source string filesystem path to read files relative from
--templateMetrics display metrics about template executions --templateMetrics display metrics about template executions
--templateMetricsHints calculate some improvement hints when combined with --templateMetrics --templateMetricsHints calculate some improvement hints when combined with --templateMetrics
@@ -31,6 +31,7 @@ See each sub-command's help for details on how to use the generated script.
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern --ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--logLevel string log level (debug|info|warn|error) --logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode --quiet build in quiet mode
--renderToMemory render to memory (mostly useful when running the server)
-s, --source string filesystem path to read files relative from -s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory --themesDir string filesystem path to themes directory
-v, --verbose verbose output -v, --verbose verbose output
@@ -54,6 +54,7 @@ hugo completion bash
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern --ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--logLevel string log level (debug|info|warn|error) --logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode --quiet build in quiet mode
--renderToMemory render to memory (mostly useful when running the server)
-s, --source string filesystem path to read files relative from -s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory --themesDir string filesystem path to themes directory
-v, --verbose verbose output -v, --verbose verbose output
@@ -45,6 +45,7 @@ hugo completion fish [flags]
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern --ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--logLevel string log level (debug|info|warn|error) --logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode --quiet build in quiet mode
--renderToMemory render to memory (mostly useful when running the server)
-s, --source string filesystem path to read files relative from -s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory --themesDir string filesystem path to themes directory
-v, --verbose verbose output -v, --verbose verbose output
@@ -42,6 +42,7 @@ hugo completion powershell [flags]
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern --ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--logLevel string log level (debug|info|warn|error) --logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode --quiet build in quiet mode
--renderToMemory render to memory (mostly useful when running the server)
-s, --source string filesystem path to read files relative from -s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory --themesDir string filesystem path to themes directory
-v, --verbose verbose output -v, --verbose verbose output
@@ -56,6 +56,7 @@ hugo completion zsh [flags]
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern --ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--logLevel string log level (debug|info|warn|error) --logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode --quiet build in quiet mode
--renderToMemory render to memory (mostly useful when running the server)
-s, --source string filesystem path to read files relative from -s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory --themesDir string filesystem path to themes directory
-v, --verbose verbose output -v, --verbose verbose output
+1
View File
@@ -39,6 +39,7 @@ hugo config [command] [flags]
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern --ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--logLevel string log level (debug|info|warn|error) --logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode --quiet build in quiet mode
--renderToMemory render to memory (mostly useful when running the server)
-s, --source string filesystem path to read files relative from -s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory --themesDir string filesystem path to themes directory
-v, --verbose verbose output -v, --verbose verbose output
@@ -33,6 +33,7 @@ hugo config mounts [flags] [args]
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern --ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--logLevel string log level (debug|info|warn|error) --logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode --quiet build in quiet mode
--renderToMemory render to memory (mostly useful when running the server)
-s, --source string filesystem path to read files relative from -s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory --themesDir string filesystem path to themes directory
-v, --verbose verbose output -v, --verbose verbose output
+1
View File
@@ -33,6 +33,7 @@ See convert's subcommands toJSON, toTOML and toYAML for more information.
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern --ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--logLevel string log level (debug|info|warn|error) --logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode --quiet build in quiet mode
--renderToMemory render to memory (mostly useful when running the server)
-s, --source string filesystem path to read files relative from -s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory --themesDir string filesystem path to themes directory
-v, --verbose verbose output -v, --verbose verbose output
@@ -35,6 +35,7 @@ hugo convert toJSON [flags] [args]
--logLevel string log level (debug|info|warn|error) --logLevel string log level (debug|info|warn|error)
-o, --output string filesystem path to write files to -o, --output string filesystem path to write files to
--quiet build in quiet mode --quiet build in quiet mode
--renderToMemory render to memory (mostly useful when running the server)
-s, --source string filesystem path to read files relative from -s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory --themesDir string filesystem path to themes directory
--unsafe enable less safe operations, please backup first --unsafe enable less safe operations, please backup first
@@ -35,6 +35,7 @@ hugo convert toTOML [flags] [args]
--logLevel string log level (debug|info|warn|error) --logLevel string log level (debug|info|warn|error)
-o, --output string filesystem path to write files to -o, --output string filesystem path to write files to
--quiet build in quiet mode --quiet build in quiet mode
--renderToMemory render to memory (mostly useful when running the server)
-s, --source string filesystem path to read files relative from -s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory --themesDir string filesystem path to themes directory
--unsafe enable less safe operations, please backup first --unsafe enable less safe operations, please backup first
@@ -35,6 +35,7 @@ hugo convert toYAML [flags] [args]
--logLevel string log level (debug|info|warn|error) --logLevel string log level (debug|info|warn|error)
-o, --output string filesystem path to write files to -o, --output string filesystem path to write files to
--quiet build in quiet mode --quiet build in quiet mode
--renderToMemory render to memory (mostly useful when running the server)
-s, --source string filesystem path to read files relative from -s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory --themesDir string filesystem path to themes directory
--unsafe enable less safe operations, please backup first --unsafe enable less safe operations, please backup first
+1
View File
@@ -44,6 +44,7 @@ hugo deploy [flags] [args]
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern --ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--logLevel string log level (debug|info|warn|error) --logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode --quiet build in quiet mode
--renderToMemory render to memory (mostly useful when running the server)
-s, --source string filesystem path to read files relative from -s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory --themesDir string filesystem path to themes directory
-v, --verbose verbose output -v, --verbose verbose output
+1
View File
@@ -33,6 +33,7 @@ hugo env [flags] [args]
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern --ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--logLevel string log level (debug|info|warn|error) --logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode --quiet build in quiet mode
--renderToMemory render to memory (mostly useful when running the server)
-s, --source string filesystem path to read files relative from -s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory --themesDir string filesystem path to themes directory
-v, --verbose verbose output -v, --verbose verbose output
+1
View File
@@ -25,6 +25,7 @@ A collection of several useful generators.
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern --ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--logLevel string log level (debug|info|warn|error) --logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode --quiet build in quiet mode
--renderToMemory render to memory (mostly useful when running the server)
-s, --source string filesystem path to read files relative from -s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory --themesDir string filesystem path to themes directory
-v, --verbose verbose output -v, --verbose verbose output
@@ -38,6 +38,7 @@ hugo gen chromastyles [flags] [args]
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern --ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--logLevel string log level (debug|info|warn|error) --logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode --quiet build in quiet mode
--renderToMemory render to memory (mostly useful when running the server)
-s, --source string filesystem path to read files relative from -s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory --themesDir string filesystem path to themes directory
-v, --verbose verbose output -v, --verbose verbose output
+1
View File
@@ -39,6 +39,7 @@ hugo gen doc [flags] [args]
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern --ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--logLevel string log level (debug|info|warn|error) --logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode --quiet build in quiet mode
--renderToMemory render to memory (mostly useful when running the server)
-s, --source string filesystem path to read files relative from -s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory --themesDir string filesystem path to themes directory
-v, --verbose verbose output -v, --verbose verbose output
+1
View File
@@ -36,6 +36,7 @@ hugo gen man [flags] [args]
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern --ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--logLevel string log level (debug|info|warn|error) --logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode --quiet build in quiet mode
--renderToMemory render to memory (mostly useful when running the server)
-s, --source string filesystem path to read files relative from -s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory --themesDir string filesystem path to themes directory
-v, --verbose verbose output -v, --verbose verbose output
+1
View File
@@ -31,6 +31,7 @@ Import requires a subcommand, e.g. `hugo import jekyll jekyll_root_path target_p
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern --ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--logLevel string log level (debug|info|warn|error) --logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode --quiet build in quiet mode
--renderToMemory render to memory (mostly useful when running the server)
-s, --source string filesystem path to read files relative from -s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory --themesDir string filesystem path to themes directory
-v, --verbose verbose output -v, --verbose verbose output
@@ -36,6 +36,7 @@ hugo import jekyll [flags] [args]
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern --ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--logLevel string log level (debug|info|warn|error) --logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode --quiet build in quiet mode
--renderToMemory render to memory (mostly useful when running the server)
-s, --source string filesystem path to read files relative from -s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory --themesDir string filesystem path to themes directory
-v, --verbose verbose output -v, --verbose verbose output
+1
View File
@@ -31,6 +31,7 @@ List requires a subcommand, e.g. hugo list drafts
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern --ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--logLevel string log level (debug|info|warn|error) --logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode --quiet build in quiet mode
--renderToMemory render to memory (mostly useful when running the server)
-s, --source string filesystem path to read files relative from -s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory --themesDir string filesystem path to themes directory
-v, --verbose verbose output -v, --verbose verbose output
@@ -33,6 +33,7 @@ hugo list all [flags] [args]
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern --ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--logLevel string log level (debug|info|warn|error) --logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode --quiet build in quiet mode
--renderToMemory render to memory (mostly useful when running the server)
-s, --source string filesystem path to read files relative from -s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory --themesDir string filesystem path to themes directory
-v, --verbose verbose output -v, --verbose verbose output
@@ -33,6 +33,7 @@ hugo list drafts [flags] [args]
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern --ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--logLevel string log level (debug|info|warn|error) --logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode --quiet build in quiet mode
--renderToMemory render to memory (mostly useful when running the server)
-s, --source string filesystem path to read files relative from -s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory --themesDir string filesystem path to themes directory
-v, --verbose verbose output -v, --verbose verbose output
@@ -33,6 +33,7 @@ hugo list expired [flags] [args]
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern --ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--logLevel string log level (debug|info|warn|error) --logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode --quiet build in quiet mode
--renderToMemory render to memory (mostly useful when running the server)
-s, --source string filesystem path to read files relative from -s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory --themesDir string filesystem path to themes directory
-v, --verbose verbose output -v, --verbose verbose output
@@ -33,6 +33,7 @@ hugo list future [flags] [args]
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern --ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--logLevel string log level (debug|info|warn|error) --logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode --quiet build in quiet mode
--renderToMemory render to memory (mostly useful when running the server)
-s, --source string filesystem path to read files relative from -s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory --themesDir string filesystem path to themes directory
-v, --verbose verbose output -v, --verbose verbose output
+1
View File
@@ -40,6 +40,7 @@ See https://gohugo.io/hugo-modules/ for more information.
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern --ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--logLevel string log level (debug|info|warn|error) --logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode --quiet build in quiet mode
--renderToMemory render to memory (mostly useful when running the server)
-s, --source string filesystem path to read files relative from -s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory --themesDir string filesystem path to themes directory
-v, --verbose verbose output -v, --verbose verbose output
@@ -39,6 +39,7 @@ hugo mod clean [flags] [args]
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern --ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--logLevel string log level (debug|info|warn|error) --logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode --quiet build in quiet mode
--renderToMemory render to memory (mostly useful when running the server)
-s, --source string filesystem path to read files relative from -s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory --themesDir string filesystem path to themes directory
-v, --verbose verbose output -v, --verbose verbose output
+1
View File
@@ -64,6 +64,7 @@ hugo mod get [flags] [args]
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern --ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--logLevel string log level (debug|info|warn|error) --logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode --quiet build in quiet mode
--renderToMemory render to memory (mostly useful when running the server)
-s, --source string filesystem path to read files relative from -s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory --themesDir string filesystem path to themes directory
-v, --verbose verbose output -v, --verbose verbose output
@@ -40,6 +40,7 @@ hugo mod graph [flags] [args]
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern --ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--logLevel string log level (debug|info|warn|error) --logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode --quiet build in quiet mode
--renderToMemory render to memory (mostly useful when running the server)
-s, --source string filesystem path to read files relative from -s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory --themesDir string filesystem path to themes directory
-v, --verbose verbose output -v, --verbose verbose output
@@ -44,6 +44,7 @@ hugo mod init [flags] [args]
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern --ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--logLevel string log level (debug|info|warn|error) --logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode --quiet build in quiet mode
--renderToMemory render to memory (mostly useful when running the server)
-s, --source string filesystem path to read files relative from -s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory --themesDir string filesystem path to themes directory
-v, --verbose verbose output -v, --verbose verbose output
+1
View File
@@ -33,6 +33,7 @@ hugo mod npm [command] [flags]
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern --ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--logLevel string log level (debug|info|warn|error) --logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode --quiet build in quiet mode
--renderToMemory render to memory (mostly useful when running the server)
-s, --source string filesystem path to read files relative from -s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory --themesDir string filesystem path to themes directory
-v, --verbose verbose output -v, --verbose verbose output
@@ -47,6 +47,7 @@ hugo mod npm pack [flags] [args]
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern --ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--logLevel string log level (debug|info|warn|error) --logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode --quiet build in quiet mode
--renderToMemory render to memory (mostly useful when running the server)
-s, --source string filesystem path to read files relative from -s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory --themesDir string filesystem path to themes directory
-v, --verbose verbose output -v, --verbose verbose output
@@ -33,6 +33,7 @@ hugo mod tidy [flags] [args]
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern --ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--logLevel string log level (debug|info|warn|error) --logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode --quiet build in quiet mode
--renderToMemory render to memory (mostly useful when running the server)
-s, --source string filesystem path to read files relative from -s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory --themesDir string filesystem path to themes directory
-v, --verbose verbose output -v, --verbose verbose output

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