Compare commits

...

82 Commits

Author SHA1 Message Date
hugoreleaser cb4a097190 releaser: Prepare repository for 0.146.0-DEV
[ci skip]
2025-02-26 15:58:38 +00:00
hugoreleaser 666444f0a5 releaser: Bump versions for release of 0.145.0
[ci skip]
2025-02-26 15:41:25 +00:00
margau e5eecbd9bc github: Build docker image with both extended and withdeploy tags 2025-02-26 16:33:22 +01:00
coliff 4094a1e12c all: Typo fixes 2025-02-26 15:10:28 +01:00
Bjørn Erik Pedersen 6927e6f048 deps: Upgrade github.com/rogpeppe/go-internal v1.13.1 => v1.14.1
Closes #13449
2025-02-26 14:43:03 +01:00
Bjørn Erik Pedersen c498d0fe1e Use the page path and not the backing filename as the last resort in the default sort
This should:

1. Fix some (rare) tiebreaker issues when sorting pages from multiple content adapters.
2. Improve the sorting for pages without a backing file.
2025-02-26 13:06:26 +01:00
Bjørn Erik Pedersen 521911a576 all: Run modernize -fix ./... 2025-02-26 11:44:25 +01:00
dependabot[bot] b7ae24b9c2 build(deps): bump github.com/yuin/goldmark-emoji from 1.0.4 to 1.0.5
Bumps [github.com/yuin/goldmark-emoji](https://github.com/yuin/goldmark-emoji) from 1.0.4 to 1.0.5.
- [Release notes](https://github.com/yuin/goldmark-emoji/releases)
- [Commits](https://github.com/yuin/goldmark-emoji/compare/v1.0.4...v1.0.5)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-26 10:56:23 +01:00
Christian Oliff 2f4e666d7e tpl: HTTPS the instagram Shortcode JS
This JavaScript will always load over HTTPS so it's best to specify that. Protocol-less loaded resources are an anti-pattern (REF: https://www.paulirish.com/2010/the-protocol-relative-url/)
2025-02-26 09:27:31 +01:00
dependabot[bot] 1a4851f138 build(deps): bump github.com/google/go-cmp from 0.6.0 to 0.7.0
Bumps [github.com/google/go-cmp](https://github.com/google/go-cmp) from 0.6.0 to 0.7.0.
- [Release notes](https://github.com/google/go-cmp/releases)
- [Commits](https://github.com/google/go-cmp/compare/v0.6.0...v0.7.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-25 19:41:18 +01:00
dependabot[bot] d1f23309bf build(deps): bump github.com/tetratelabs/wazero from 1.8.2 to 1.9.0
Bumps [github.com/tetratelabs/wazero](https://github.com/tetratelabs/wazero) from 1.8.2 to 1.9.0.
- [Release notes](https://github.com/tetratelabs/wazero/releases)
- [Commits](https://github.com/tetratelabs/wazero/compare/v1.8.2...v1.9.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-25 19:40:01 +01:00
Bjørn Erik Pedersen 04f21b4d80 Add transform.PortableText
Using this in a content adapter could look like this:

```handlebars
{{ $projectID := "<myproject>" }}
{{ $useCached := true }}
{{ $api := "api" }}
{{ if $useCached }}
  {{/* See https://www.sanity.io/docs/api-cdn */}}
  {{ $api = "apicdn" }}
{{ end }}
{{ $url := printf "https://%s.%s.sanity.io/v2021-06-07/data/query/production"  $projectID $api }}

{{/* prettier-ignore-start */ -}}
{{ $q :=  `*[_type == 'post']{
  title, publishedAt, summary, slug, body[]{
    ...,
    _type == "image" => {
      ...,
      asset->{
        _id,
        path,
        url,
        altText,
        title,
        description,
        metadata {
          dimensions {
            aspectRatio,
            width,
            height
          }
        }
      }
    }
  },
  }`
}}
{{/* prettier-ignore-end */ -}}
{{ $body := dict "query" $q | jsonify }}
{{ $opts := dict "method" "post" "body" $body }}
{{ $t := debug.Timer "sanity.get" }}
{{ $r := resources.GetRemote $url $opts }}
{{ $t.Stop }}
{{ $m := $r | transform.Unmarshal }}
{{ $result := $m.result }}
{{ $t := debug.Timer "sanity.parse" }}
{{ range $result }}
  {{ if not .slug }}
    {{ continue }}
  {{ end }}
  {{ $markdown := transform.PortableText .body }}
  {{ $t.Stop }}
  {{ $content := dict
    "mediaType" "text/markdown"
    "value" $markdown
  }}
  {{ $params := dict
    "portabletext" (.body | jsonify (dict "indent" " "))
  }}
  {{ $page := dict
    "content" $content
    "kind" "page"
    "path" .slug.current
    "title" .title
    "date" (.publishedAt | time )
    "summary" .summary
    "params" $params
  }}
  {{ $.AddPage $page }}
{{ end }}
```
2025-02-25 19:35:47 +01:00
Martey Dodoo ab9e545760 readme: Fix relative links in Editions section
Make relative gohugo.io links used in Editions section of README
absolute so that they resolve successfully.
2025-02-25 18:26:05 +01:00
Bjørn Erik Pedersen 381c0da85d Fix some related content issues with content adapters
Fixes #13443
2025-02-25 14:14:56 +01:00
Bjørn Erik Pedersen 227e429267 Fix potential nilpointer in httpcache config 2025-02-24 18:42:50 +01:00
Joe Mooring d0ce942190 hugolib: Deprecate _build front matter key in favor of build
We effectively aliased "_build" to "build" in v0.123.0, and
removed "_build" from the documentation at the same time.
2025-02-24 10:13:53 +01:00
Joe Mooring 4fd7f3233f snap: Update Node.js to 22.x 2025-02-22 07:49:02 -08:00
Bjørn Erik Pedersen c3d435acfa Fix --printPathWarnings when site calls templates.Defer
This issue was introduced recently in eb7a5aabaa.

Fixes #13420
2025-02-19 12:59:40 +01:00
hugoreleaser 669216e204 releaser: Prepare repository for 0.145.0-DEV
[ci skip]
2025-02-18 12:29:51 +00:00
hugoreleaser a79d63a446 releaser: Bump versions for release of 0.144.1
[ci skip]
2025-02-18 12:14:07 +00:00
Bjørn Erik Pedersen 494e88abf6 markup/goldmark: Fix panic on empty Markdown header
Fixes #13416
2025-02-18 11:12:39 +01:00
hugoreleaser f1e799c2e1 releaser: Prepare repository for 0.145.0-DEV
[ci skip]
2025-02-17 16:36:56 +00:00
hugoreleaser b289b17c43 releaser: Bump versions for release of 0.144.0
[ci skip]
2025-02-17 16:22:31 +00:00
Bjørn Erik Pedersen 85c1727748 markup/goldmark: Fix panic on stray attribute nodes 2025-02-17 17:19:53 +01:00
Bjørn Erik Pedersen 641403f7de Fix Position for passthrough hooks
Fixes #13406
2025-02-17 12:23:49 +01:00
Bjørn Erik Pedersen 24cc25552f Fix auto generated header ids so they don't contain e.g. hyperlink destinations (note)
This makes the header ids match the newly added dt ids.

Also make sure newlines are preserved in hooks' `.PlainText`.

Fixes #13405
Fixes #13410
2025-02-17 12:23:49 +01:00
dependabot[bot] a2ca95629a build(deps): bump github.com/spf13/cobra from 1.8.1 to 1.9.1
Bumps [github.com/spf13/cobra](https://github.com/spf13/cobra) from 1.8.1 to 1.9.1.
- [Release notes](https://github.com/spf13/cobra/releases)
- [Commits](https://github.com/spf13/cobra/compare/v1.8.1...v1.9.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-17 12:08:14 +01:00
dependabot[bot] 367fe526e2 build(deps): bump github.com/sanity-io/litter from 1.5.7 to 1.5.8
Bumps [github.com/sanity-io/litter](https://github.com/sanity-io/litter) from 1.5.7 to 1.5.8.
- [Changelog](https://github.com/sanity-io/litter/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sanity-io/litter/compare/v1.5.7...v1.5.8)

---
updated-dependencies:
- dependency-name: github.com/sanity-io/litter
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-17 12:06:55 +01:00
Joe Mooring 5de3913ed4 config/allconfig: Deprecate :filename and :slugorfilename tokens 2025-02-17 12:06:32 +01:00
Bjørn Erik Pedersen 7b7a0f3624 resources/page: Revise the new contentbasename permalinks tokens
* Make it work for all pages, including those created from content adapters and not backed by a file.
* Allow the `slug` to win, so the new tokens are:

`:contentbasename`:

1. ContentBaseName

`:slugorcontentbasename`:

1. Slug
2. ContentBaseName

Note that a page will always have a `ContentBaseName`, so no need to fall back to e.g. the title.

Closes #11722
2025-02-17 09:41:49 +01:00
Henrique Dias cb7a4339b7 resources/page: Add :contentbasename and :contentbasenameorslug permalink tokens
See #11722
2025-02-17 09:41:49 +01:00
Bjørn Erik Pedersen 157d3703c3 Add autoID for definition terms
Fixes #13403
See #11566

Co-authored-by: Joe Mooring <joe@mooring.com>
2025-02-16 20:55:27 +01:00
dependabot[bot] 9c2f8ec61b build(deps): bump github.com/sanity-io/litter from 1.5.5 to 1.5.7
Bumps [github.com/sanity-io/litter](https://github.com/sanity-io/litter) from 1.5.5 to 1.5.7.
- [Changelog](https://github.com/sanity-io/litter/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sanity-io/litter/compare/v1.5.5...v1.5.7)

---
updated-dependencies:
- dependency-name: github.com/sanity-io/litter
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-14 14:25:11 +01:00
dependabot[bot] bd77944ba2 build(deps): bump github.com/gohugoio/hugo-goldmark-extensions/extras
Bumps [github.com/gohugoio/hugo-goldmark-extensions/extras](https://github.com/gohugoio/hugo-goldmark-extensions) from 0.2.0 to 0.3.0.
- [Release notes](https://github.com/gohugoio/hugo-goldmark-extensions/releases)
- [Commits](https://github.com/gohugoio/hugo-goldmark-extensions/compare/extras/v0.2.0...extras/v0.3.0)

---
updated-dependencies:
- dependency-name: github.com/gohugoio/hugo-goldmark-extensions/extras
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-14 14:24:04 +01:00
Peter Weston c1f4228d61 config: Fix server.redirects.fromRe being ignored unless server.redirects.from is also set 2025-02-14 10:21:19 +01:00
Joe Mooring 503dcf6252 internal/warpc: Enable KaTeX mhchem extension 2025-02-14 10:04:15 +01:00
Joe Mooring 5dd0ba00f7 Update README.md
- Include section about editions
- Bump minimum required Go version for building from source
- Include instructions for building the extended/deploy edition
- Update dependency list
2025-02-13 17:17:59 +01:00
dependabot[bot] 2e835d0841 build(deps): bump golang.org/x/tools from 0.29.0 to 0.30.0
Bumps [golang.org/x/tools](https://github.com/golang/tools) from 0.29.0 to 0.30.0.
- [Release notes](https://github.com/golang/tools/releases)
- [Commits](https://github.com/golang/tools/compare/v0.29.0...v0.30.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>
2025-02-13 15:01:51 +01:00
Bjørn Erik Pedersen 2c77719cd6 modules: Add GOAUTH to module config
Closes #13385
2025-02-13 15:01:28 +01:00
dependabot[bot] d89b9d891c build(deps): bump github.com/aws/aws-sdk-go-v2/service/cloudfront
Bumps [github.com/aws/aws-sdk-go-v2/service/cloudfront](https://github.com/aws/aws-sdk-go-v2) from 1.44.9 to 1.44.10.
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/main/changelog-template.json)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/service/macie2/v1.44.9...service/s3control/v1.44.10)

---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go-v2/service/cloudfront
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-13 13:48:54 +01:00
dependabot[bot] 8721a35202 build(deps): bump google.golang.org/api from 0.206.0 to 0.221.0
Bumps [google.golang.org/api](https://github.com/googleapis/google-api-go-client) from 0.206.0 to 0.221.0.
- [Release notes](https://github.com/googleapis/google-api-go-client/releases)
- [Changelog](https://github.com/googleapis/google-api-go-client/blob/main/CHANGES.md)
- [Commits](https://github.com/googleapis/google-api-go-client/compare/v0.206.0...v0.221.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-13 13:47:55 +01:00
Bjørn Erik Pedersen fd38aee694 Support menus as maps in content adapters
Fixes #13384
2025-02-13 13:29:24 +01:00
Bjørn Erik Pedersen d25f7ec172 js/esbuild: Add drop option
Fixes #13362
2025-02-13 13:26:46 +01:00
Bjørn Erik Pedersen 304a7e5e74 Merge commit 'a024bc7d76fcc5e49e8210f9b0896db9ef21861a' 2025-02-13 10:40:34 +01:00
Bjørn Erik Pedersen a024bc7d76 Squashed 'docs/' changes from 73a01565c..d1a251933
d1a251933 theme: Optimize for printing
d906488d5 theme: Add border to highlighted code blocks within list items
9630c38cb theme: Display short command on commands list
7f81dd997 content: Regen commands markup
a84008e99 content: Cleanup primary list page
0874b03e9 content: Publish QR code examples to the images/qr directory
ef1ce3498 Restore static/img
489a68458 content: Restore KeyCDN screen captures
7d6e6184b theme: Move search button in navbar to the right on smaller screens
b03b96082 theme: Misc style adjustments
ecad97821 theme: Misc fixes
cf5e07b0f content: Restore example data and images
c7265041f content: Reformat css.TailwindCSS setup steps
3226e668f theme: Make the search button more compact on mobile
1f6614ee8 content: Update css.TailwindCSS example
49a2e7d71 theme: Improve search output
7e6b81ffa misc: Create issue template
826740223 theme: Misc search improvements
75f32b2f6 theme:  Remove the search alert
fd3de4ac2 config: Enable link render hook warnings
769e387cd Adjust logic to mark current section for Algolia
ba73ce646 Adjust markup to make it easier to match in Algolia
5accec5f1 Misc adjustments
eb5842566 Some content adjustments
bdf97b7b4 Add new theme
b19d68ee5 Remove old theme
a04e96e55 Rewrite the css.TailwindCSS page
1c46f1864 Update deprecation notes
aedcb444c Fix typo
c3290b876 Changes related to release of v0.144.0
a0012fcce netlify: Hugo 0.143.1
9e4d73e87 Include sections in quick-reference page collection
4591058f5 Miscellaneous edits
612b8528f glossary: More edits
1f0c54e60 Fit typo
6f14084c1 Move glossary to quick reference section
2d94905be Improve branch bundle admonition
2ea56bef3 Fix typos found with codespell
71c5fe951 Close shortcode
e95d06592 Document the responseHeaders option for resources.GetRemote
da7c12aaa Deprecate gist shortcode
c2d3e2c25 netlify: Bump to 0.143.0
367d3a7ab Improve new-in shortcode
1a7413a16 Clean up shortcode documentation
d847892aa Improve glossary
6a7fd42ff Update pages describing Store methods and functions
fa7643d1b Revert "Improve link render hook performance"
fe4c86ec4 Reformat MathJax example
cea44922a Update MathJax example to use safe mode
0b6d0292c Update KaTeX example to use latest version
fd4508645 Improve link render hook performance
23aeb5bd0 Update purgecss example
f7ef83e56 Refer each Hugo Pipe page to the corresponding function
81b91ef4e Remove related pages from pages for deprecated functions and methods
53c7627d5 Remove body from deprecated functions and methods
d9cf034c8 Consolidate css.ToCSS information
b7ed108f9 Improve js.Build example and presentation of options
86a4a5088 Improve babel example and description of options
d1874c5f5 Consistently use "edition" when referring to standard, extended, etc.
92f03a350 Revise description of privacy settings
152a92d80 Update Last.md
82a2365bd Add print-only QR code example
d22cadc25 Update mathematics.md
b8160af03 Delete page self-reference in page/type.md
ce24fe4e0 Update param.md
51cb92180 Improve description of output format template selection
78bcf358e Update Tailwind CSS npm package version to 4.0
2ca9da4af Include winget command to uninstall

git-subtree-dir: docs
git-subtree-split: d1a2519330
2025-02-13 10:40:34 +01:00
dependabot[bot] c054e18827 build(deps): bump github.com/bep/imagemeta from 0.8.3 to 0.8.4
Bumps [github.com/bep/imagemeta](https://github.com/bep/imagemeta) from 0.8.3 to 0.8.4.
- [Release notes](https://github.com/bep/imagemeta/releases)
- [Commits](https://github.com/bep/imagemeta/compare/v0.8.3...v0.8.4)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-13 09:02:59 +01:00
Joe Mooring 34dcac53bf config: Remove unused code 2025-02-13 08:40:49 +01:00
Joe Mooring ee438606dd commands: Use punctuation consistently in short description 2025-02-13 08:40:26 +01:00
Bjørn Erik Pedersen fd8b0fbf8a Upgrade to Go 1.24
Fixes #13381
2025-02-12 22:01:25 +01:00
Bjørn Erik Pedersen 9b5f786df8 Deprecate kind, lang, and path from front matter
These were added to the page meta object when we implemented "pages from data", but were not meant to be used in front matter.

That is not supported, so we might as well add validation.

Fixes #12484
2025-02-10 21:22:43 +01:00
Bjørn Erik Pedersen e6feb9e0be commands: Move the CHMOD event filter up
To prevent ghost rebuilds (from VSCode and possibly others).

Fixes #13373
2025-02-10 17:02:06 +01:00
dependabot[bot] 5e4ffa0e89 build(deps): bump golang.org/x/image from 0.22.0 to 0.24.0
Bumps [golang.org/x/image](https://github.com/golang/image) from 0.22.0 to 0.24.0.
- [Commits](https://github.com/golang/image/compare/v0.22.0...v0.24.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>
2025-02-10 12:46:06 +01:00
dependabot[bot] 0cdcc2b584 build(deps): bump golang.org/x/mod from 0.22.0 to 0.23.0
Bumps [golang.org/x/mod](https://github.com/golang/mod) from 0.22.0 to 0.23.0.
- [Commits](https://github.com/golang/mod/compare/v0.22.0...v0.23.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>
2025-02-10 11:43:49 +01:00
dependabot[bot] a591c4406a build(deps): bump github.com/gohugoio/hashstructure from 0.3.0 to 0.5.0
Bumps [github.com/gohugoio/hashstructure](https://github.com/gohugoio/hashstructure) from 0.3.0 to 0.5.0.
- [Release notes](https://github.com/gohugoio/hashstructure/releases)
- [Commits](https://github.com/gohugoio/hashstructure/compare/v0.3.0...v0.5.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-10 11:43:11 +01:00
dependabot[bot] 2d86a0512c build(deps): bump github.com/bep/simplecobra from 0.4.0 to 0.5.0
Bumps [github.com/bep/simplecobra](https://github.com/bep/simplecobra) from 0.4.0 to 0.5.0.
- [Release notes](https://github.com/bep/simplecobra/releases)
- [Commits](https://github.com/bep/simplecobra/compare/v0.4.0...v0.5.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-09 23:31:45 +01:00
Dominik Süß f02da7fbce parser: Handle org-mode filetags as slice
This adds support for filetags by slicing them according to [the org mode tag
specification](https://orgmode.org/guide/Tags.html).

Can be used to create taxonomies based on org-mode tags
2025-02-09 22:40:28 +01:00
dependabot[bot] 22ee0918f3 build(deps): bump github.com/aws/aws-sdk-go-v2/service/cloudfront
Bumps [github.com/aws/aws-sdk-go-v2/service/cloudfront](https://github.com/aws/aws-sdk-go-v2) from 1.41.0 to 1.44.9.
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/main/changelog-template.json)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/service/s3/v1.41.0...service/macie2/v1.44.9)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-08 15:46:45 +01:00
dependabot[bot] b50ab04031 build(deps): bump github.com/aws/aws-sdk-go-v2 from 1.32.4 to 1.36.1
Bumps [github.com/aws/aws-sdk-go-v2](https://github.com/aws/aws-sdk-go-v2) from 1.32.4 to 1.36.1.
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/main/changelog-template.json)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/v1.32.4...v1.36.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-08 10:33:03 +01:00
dependabot[bot] b772f0e3d2 build(deps): bump github.com/getkin/kin-openapi from 0.123.0 to 0.129.0
Bumps [github.com/getkin/kin-openapi](https://github.com/getkin/kin-openapi) from 0.123.0 to 0.129.0.
- [Release notes](https://github.com/getkin/kin-openapi/releases)
- [Commits](https://github.com/getkin/kin-openapi/compare/v0.123.0...v0.129.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>
2025-02-08 10:32:42 +01:00
dependabot[bot] d58c0198d3 build(deps): bump github.com/spf13/pflag from 1.0.5 to 1.0.6
Bumps [github.com/spf13/pflag](https://github.com/spf13/pflag) from 1.0.5 to 1.0.6.
- [Release notes](https://github.com/spf13/pflag/releases)
- [Commits](https://github.com/spf13/pflag/compare/v1.0.5...v1.0.6)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-08 10:31:42 +01:00
Bjørn Erik Pedersen c2fb221209 Add ContentTypes to config
This is an empty struct for now, but we will most likely expand on that.

```
[contentTypes]
  [contentTypes.'text/markdown']
```

The above means that only Markdown will be considered a content type. E.g. HTML will be treated as plain text.

Fixes #12274
2025-02-08 10:31:15 +01:00
Oleksandr Redko 4245a4514d all: Remove deprecated build tags 2025-02-08 10:29:42 +01:00
Joe Mooring f0c1852978 helpers: Add Chroma styles to docs.yaml
Closes #13360
2025-02-08 00:30:05 +01:00
Joe Mooring a352e69b02 commands: Validate style argument passed to gen chromastyles
Closes #13357
2025-02-07 22:44:22 +01:00
Bjørn Erik Pedersen 1dd27be81a Update CONTRIBUTING.md 2025-02-07 22:25:19 +01:00
Bjørn Erik Pedersen eb7a5aabaa Move "print unused templates" after renderDeferred
Fixes #13355
2025-02-07 18:04:12 +01:00
Bjørn Erik Pedersen 029d1e0ced Add some more server options/improvements
New options:

* `FromHeaders`: Server header matching for redirects
* `FromRe`: Regexp with group support, i.e. it replaces $1, $2 in To with the group matches.

Note that if both `From` and `FromRe` is set, both must match.

Also

* Allow redirects to non HTML URLs as long as the Sec-Fetch-Mode is set to navigate on the request.
* Detect and stop redirect loops.

This was all done while testing out InertiaJS with Hugo. So, after this commit, this setup will support the main parts of the protocol that Inertia uses:

```toml
[server]
    [[server.headers]]
        for = '/**/inertia.json'
        [server.headers.values]
            Content-Type = 'text/html'
            X-Inertia    = 'true'
            Vary         = 'Accept'

    [[server.redirects]]
        force       = true
        from        = '/**/'
        fromRe      = "^/(.*)/$"
        fromHeaders = { "X-Inertia" = "true" }
        status      = 301
        to          = '/$1/inertia.json'
```

Unfortunately, a provider like Netlify does not support redirects matching by request headers. It should be possible with some edge function, but then again, I'm not sure that InertiaJS is a very good fit with the common Hugo use cases.

But this commit should be generally useful.
2025-02-05 18:14:15 +01:00
Bjørn Erik Pedersen e865d59844 Fix shortcode name in error message on self-closing shortcodes with no .Inner
Fixes #13344
2025-02-05 16:35:02 +01:00
hugoreleaser 377287a614 releaser: Prepare repository for 0.144.0-DEV
[ci skip]
2025-02-04 09:14:03 +00:00
hugoreleaser 0270364a34 releaser: Bump versions for release of 0.143.1
[ci skip]
2025-02-04 08:57:38 +00:00
Bjørn Erik Pedersen 760c13a7ac Fix RSS with baseURL with sub dir when render hooks is enabled
Fixes #13332
2025-02-03 19:00:12 +01:00
Oleksandr Redko 3bd73d262d mage: Simplify magefile 2025-02-03 18:34:16 +01:00
Joe Mooring 7104de83ce common/hugo: Adjust deprecation timing and message
Closes #13333
2025-02-03 18:32:30 +01:00
Bjørn Erik Pedersen 835579b338 Re-introduce the LRU-evicted identities in change set calculation
This is a follow up to db28695ff5 -- that commit dropped the cache items evicted in the LRU process. This was done as performance optimization for large Hugo sites.

That made much sense, but now there's a slight chance that we miss out on a change when rebuilding.

This commit fixes this by applying the same logic to the evicted items as if they were still in the cache. This should preserve the performance gains in db28695ff5 and close the hole for the possible false negatives.
2025-02-02 15:55:11 +01:00
hugoreleaser 05e067ced8 releaser: Prepare repository for 0.144.0-DEV
[ci skip]
2025-02-01 16:09:38 +00:00
hugoreleaser ee48d9692a releaser: Bump versions for release of 0.143.0
[ci skip]
2025-02-01 15:56:04 +00:00
Bjørn Erik Pedersen db28695ff5 Fix some server/watch rebuild issues
Two issues:

1. Fixe potential edit-loop in server/watch mode (see below)
2. Drain the cache eviction stack before we start calculating the change set. This should allow more fine grained rebuilds for bigger sites and/or in low memory situations.

The fix in 6c68142cc1 wasn't really fixing the complete problem.

In Hugo we have some steps that takes more time than others, one example being CSS building with TailwindCSS.

The symptom here is that sometimes when you:

1. Edit content or templates that does not trigger a CSS rebuild => Snappy rebuild.
2. Edit stylesheet or add a CSS class to template that triggers a CSS rebuild => relatively slow rebuild (expected)
3. Then back to content editing or template edits that should not trigger a CSS rebuild => relatively slow rebuild (not expected)

This commit fixes this by pulling the dynacache GC step up and merge it with the cache buster step.

Fixes #13316
2025-02-01 16:29:14 +01:00
Bjørn Erik Pedersen 778f0d9002 Don't re-render aliases on server rebuilds
This can lead to stale aliases when rebuilding, but that's a trade-off we need to take for snappier rebuilds on bigger sites.

Note that it should be possible to detect alias changes, but I'm not sure it's worth it.
2025-02-01 15:23:36 +01:00
Alex Shpak 13b208e2f7 tpl/tplimpl: Remove leading whitespaces produced by Youtube shortcode 2025-01-31 09:29:10 +01:00
Bjørn Erik Pedersen 329b2342f0 Fix "concurrent map iteration and map write" in pages from data
Fixes #13254
2025-01-30 19:57:09 +01:00
Joe Mooring 33b46d8a41 resources: Remove debug statement
Closes #13320
2025-01-30 11:32:57 +01:00
Bjørn Erik Pedersen 6c68142cc1 Fix TailwindCSS related server rebuild issue
Fixes #13316
2025-01-29 18:46:12 +01:00
1100 changed files with 8440 additions and 16460 deletions
+2 -2
View File
@@ -4,7 +4,7 @@ parameters:
defaults: &defaults
resource_class: large
docker:
- image: bepsays/ci-hugoreleaser:1.22301.20401
- image: bepsays/ci-hugoreleaser:1.22400.20000
environment: &buildenv
GOMODCACHE: /root/project/gomodcache
version: 2
@@ -58,7 +58,7 @@ jobs:
environment:
<<: [*buildenv]
docker:
- image: bepsays/ci-hugoreleaser-linux-arm64:1.22301.20401
- image: bepsays/ci-hugoreleaser-linux-arm64:1.22400.20000
steps:
- *restore-cache
- &attach-workspace
+1
View File
@@ -46,3 +46,4 @@ jobs:
platforms: linux/amd64,linux/arm64
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: HUGO_BUILD_TAGS=extended,withdeploy
+1 -1
View File
@@ -16,7 +16,7 @@ jobs:
test:
strategy:
matrix:
go-version: [1.22.x, 1.23.x]
go-version: [1.23.x, 1.24.x]
os: [ubuntu-latest, windows-latest] # macos disabled for now because of disk space issues.
runs-on: ${{ matrix.os }}
steps:
+2 -1
View File
@@ -1,4 +1,4 @@
>**Note:** We would apprecitate if you hold on with any big refactorings (like renaming deprecated Go packages), mainly because of potential for extra merge work for future coming in in the near future.
>**Note:** We would appreciate if you hold on with any big refactoring (like renaming deprecated Go packages), mainly because of potential for extra merge work for future coming in in the near future.
# Contributing to Hugo
@@ -93,6 +93,7 @@ Most title/subjects should have a lower-cased prefix with a colon and one whites
* If this commit touches many packages without a common functional topic, prefix with `all:` (e.g. `all: Reformat Go code`)
* If this is a documentation update, prefix with `docs:`.
* If nothing of the above applies, just leave the prefix out.
* Note that the above excludes nouns seen in other repositories, e.g. "chore:".
Also, if your commit references one or more GitHub issues, always end your commit message body with *See #1234* or *Fixes #1234*.
Replace *1234* with the GitHub issue ID. The last example will close the issue when the commit is merged into *master*.
+62 -31
View File
@@ -34,6 +34,7 @@ A fast and flexible static site generator built with love by [bep], [spf13], and
[![Go Report Card](https://goreportcard.com/badge/github.com/gohugoio/hugo)](https://goreportcard.com/report/github.com/gohugoio/hugo)
[Website] | [Installation] | [Documentation] | [Support] | [Contributing] | <a rel="me" href="https://fosstodon.org/@gohugoio">Mastodon</a>
## Overview
Hugo is a [static site generator] written in [Go], optimized for speed and designed for flexibility. With its advanced templating system and fast asset pipelines, Hugo renders a complete site in seconds, often less.
@@ -69,6 +70,23 @@ See the [features] section of the documentation for a comprehensive summary of H
<a href="https://www.jetbrains.com/go/?utm_source=OSS&utm_medium=referral&utm_campaign=hugo" target="_blank"><img src="https://raw.githubusercontent.com/gohugoio/gohugoioTheme/master/assets/images/sponsors/goland.svg" width="200" alt="The complete IDE crafted for professional Go developers."></a>
</p>
## Editions
Hugo is available in three editions: standard, extended, and extended/deploy. While the standard edition provides core functionality, the extended and extended/deploy editions offer advanced features.
Feature|extended edition|extended/deploy edition
:--|:-:|:-:
Encode to the WebP format when [processing images]. You can decode WebP images with any edition.|:heavy_check_mark:|:heavy_check_mark:
[Transpile Sass to CSS] using the embedded LibSass transpiler. You can use the [Dart Sass] transpiler with any edition.|:heavy_check_mark:|:heavy_check_mark:
Deploy your site directly to a Google Cloud Storage bucket, an AWS S3 bucket, or an Azure Storage container. See&nbsp;[details].|:x:|:heavy_check_mark:
[dart sass]: https://gohugo.io/functions/css/sass/#dart-sass
[processing images]: https://gohugo.io/content-management/image-processing/
[transpile sass to css]: https://gohugo.io/functions/css/sass/
[details]: https://gohugo.io/hosting-and-deployment/hugo-deploy/
Unless your specific deployment needs require the extended/deploy edition, we recommend the extended edition.
## Installation
Install Hugo from a [prebuilt binary], package manager, or package repository. Please see the installation instructions for your operating system:
@@ -80,15 +98,11 @@ Install Hugo from a [prebuilt binary], package manager, or package repository. P
## Build from source
Hugo is available in two editions: standard and extended. With the extended edition you can:
- Encode to the WebP format when processing images. You can decode WebP images with either edition.
- Transpile Sass to CSS using the embedded LibSass transpiler. The extended edition is not required to use the Dart Sass transpiler.
Prerequisites to build Hugo from source:
- Standard edition: Go 1.20 or later
- Extended edition: Go 1.20 or later, and GCC
- Standard edition: Go 1.23.0 or later
- Extended edition: Go 1.23.0 or later, and GCC
- Extended/deploy edition: Go 1.23.0 or later, and GCC
Build the standard edition:
@@ -102,6 +116,12 @@ Build the extended edition:
CGO_ENABLED=1 go install -tags extended github.com/gohugoio/hugo@latest
```
Build the extended/deploy edition:
```text
CGO_ENABLED=1 go install -tags extended,withdeploy github.com/gohugoio/hugo@latest
```
## Star History
[![Star History Chart](https://api.star-history.com/svg?repos=gohugoio/hugo&type=Timeline)](https://star-history.com/#gohugoio/hugo&Timeline)
@@ -149,7 +169,9 @@ Hugo stands on the shoulders of great open source libraries. Run `hugo env --log
```text
github.com/BurntSushi/locker="v0.0.0-20171006230638-a6e239ea1c69"
github.com/alecthomas/chroma/v2="v2.14.0"
github.com/PuerkitoBio/goquery="v1.10.1"
github.com/alecthomas/chroma/v2="v2.15.0"
github.com/andybalholm/cascadia="v1.3.3"
github.com/armon/go-radix="v1.0.1-0.20221118154546-54df44f2176c"
github.com/bep/clocks="v0.5.0"
github.com/bep/debounce="v1.2.0"
@@ -158,73 +180,78 @@ github.com/bep/goat="v0.5.0"
github.com/bep/godartsass/v2="v2.3.2"
github.com/bep/golibsass="v1.2.0"
github.com/bep/gowebp="v0.3.0"
github.com/bep/imagemeta="v0.8.3"
github.com/bep/imagemeta="v0.8.4"
github.com/bep/lazycache="v0.7.0"
github.com/bep/logg="v0.4.0"
github.com/bep/mclib="v1.20400.20402"
github.com/bep/overlayfs="v0.9.2"
github.com/bep/simplecobra="v0.4.0"
github.com/bep/simplecobra="v0.5.0"
github.com/bep/tmc="v0.5.1"
github.com/cespare/xxhash/v2="v2.3.0"
github.com/clbanning/mxj/v2="v2.7.0"
github.com/cli/safeexec="v1.0.1"
github.com/cpuguy83/go-md2man/v2="v2.0.4"
github.com/disintegration/gift="v1.2.1"
github.com/dlclark/regexp2="v1.11.0"
github.com/evanw/esbuild="v0.24.0"
github.com/dlclark/regexp2="v1.11.5"
github.com/dop251/goja="v0.0.0-20250125213203-5ef83b82af17"
github.com/evanw/esbuild="v0.24.2"
github.com/fatih/color="v1.18.0"
github.com/frankban/quicktest="v1.14.6"
github.com/fsnotify/fsnotify="v1.8.0"
github.com/getkin/kin-openapi="v0.123.0"
github.com/getkin/kin-openapi="v0.129.0"
github.com/ghodss/yaml="v1.0.0"
github.com/go-openapi/jsonpointer="v0.20.2"
github.com/go-openapi/swag="v0.22.8"
github.com/go-openapi/jsonpointer="v0.21.0"
github.com/go-openapi/swag="v0.23.0"
github.com/go-sourcemap/sourcemap="v2.1.4+incompatible"
github.com/gobuffalo/flect="v1.0.3"
github.com/gobwas/glob="v0.2.3"
github.com/gohugoio/go-i18n/v2="v2.1.3-0.20230805085216-e63c13218d0e"
github.com/gohugoio/hashstructure="v0.1.0"
github.com/gohugoio/hashstructure="v0.5.0"
github.com/gohugoio/httpcache="v0.7.0"
github.com/gohugoio/hugo-goldmark-extensions/extras="v0.2.0"
github.com/gohugoio/hugo-goldmark-extensions/passthrough="v0.3.0"
github.com/gohugoio/locales="v0.14.0"
github.com/gohugoio/localescompressed="v1.0.1"
github.com/golang/freetype="v0.0.0-20170609003504-e2365dfdc4a0"
github.com/google/go-cmp="v0.6.0"
github.com/google/pprof="v0.0.0-20250208200701-d0013a598941"
github.com/gorilla/websocket="v1.5.3"
github.com/hairyhenderson/go-codeowners="v0.7.0"
github.com/hashicorp/golang-lru/v2="v2.0.7"
github.com/invopop/yaml="v0.2.0"
github.com/jdkato/prose="v1.2.1"
github.com/josharian/intern="v1.0.0"
github.com/kr/pretty="v0.3.1"
github.com/kr/text="v0.2.0"
github.com/kyokomi/emoji/v2="v2.2.13"
github.com/lucasb-eyer/go-colorful="v1.2.0"
github.com/mailru/easyjson="v0.7.7"
github.com/makeworld-the-better-one/dither/v2="v2.4.0"
github.com/marekm4/color-extractor="v1.2.1"
github.com/mattn/go-colorable="v0.1.13"
github.com/mattn/go-isatty="v0.0.20"
github.com/mattn/go-runewidth="v0.0.9"
github.com/mazznoer/csscolorparser="v0.1.5"
github.com/mitchellh/mapstructure="v1.5.1-0.20231216201459-8508981c8b6c"
github.com/mohae/deepcopy="v0.0.0-20170929034955-c48cc78d4826"
github.com/muesli/smartcrop="v0.3.0"
github.com/niklasfasching/go-org="v1.7.0"
github.com/oasdiff/yaml3="v0.0.0-20241210130736-a94c01f36349"
github.com/oasdiff/yaml="v0.0.0-20241210131133-6b86fb107d80"
github.com/olekukonko/tablewriter="v0.0.5"
github.com/pbnjay/memory="v0.0.0-20210728143218-7b4eea64cf58"
github.com/pelletier/go-toml/v2="v2.2.3"
github.com/perimeterx/marshmallow="v1.1.5"
github.com/pkg/browser="v0.0.0-20240102092130-5ac0b6a4141c"
github.com/pkg/errors="v0.9.1"
github.com/rivo/uniseg="v0.4.7"
github.com/rogpeppe/go-internal="v1.13.1"
github.com/russross/blackfriday/v2="v2.1.0"
github.com/sass/dart-sass/compiler="1.81.0"
github.com/sass/dart-sass/implementation="1.81.0"
github.com/sass/dart-sass/protocol="3.1.0"
github.com/sass/libsass="3.6.6"
github.com/spf13/afero="v1.11.0"
github.com/spf13/cast="v1.7.1"
github.com/spf13/cobra="v1.8.1"
github.com/spf13/fsync="v0.10.1"
github.com/spf13/pflag="v1.0.5"
github.com/spf13/pflag="v1.0.6"
github.com/tdewolff/minify/v2="v2.20.37"
github.com/tdewolff/parse/v2="v2.7.15"
github.com/tetratelabs/wazero="v1.8.2"
@@ -232,18 +259,22 @@ github.com/webmproject/libwebp="v1.3.2"
github.com/yuin/goldmark-emoji="v1.0.4"
github.com/yuin/goldmark="v1.7.8"
go.uber.org/automaxprocs="v1.5.3"
golang.org/x/crypto="v0.31.0"
golang.org/x/exp="v0.0.0-20221031165847-c99f073a8326"
golang.org/x/image="v0.22.0"
golang.org/x/mod="v0.22.0"
golang.org/x/net="v0.33.0"
golang.org/x/sync="v0.10.0"
golang.org/x/sys="v0.28.0"
golang.org/x/text="v0.21.0"
golang.org/x/tools="v0.28.0"
google.golang.org/protobuf="v1.35.2"
golang.org/x/crypto="v0.33.0"
golang.org/x/exp="v0.0.0-20250210185358-939b2ce775ac"
golang.org/x/image="v0.24.0"
golang.org/x/mod="v0.23.0"
golang.org/x/net="v0.35.0"
golang.org/x/sync="v0.11.0"
golang.org/x/sys="v0.30.0"
golang.org/x/text="v0.22.0"
golang.org/x/tools="v0.30.0"
golang.org/x/xerrors="v0.0.0-20240903120638-7835f813f4da"
gonum.org/v1/plot="v0.15.0"
google.golang.org/protobuf="v1.36.5"
gopkg.in/yaml.v2="v2.4.0"
gopkg.in/yaml.v3="v3.0.1"
oss.terrastruct.com/d2="v0.6.9"
oss.terrastruct.com/util-go="v0.0.0-20241005222610-44c011a04896"
rsc.io/qr="v0.2.0"
software.sslmate.com/src/go-pkcs12="v0.2.0"
```
+11 -5
View File
@@ -176,11 +176,12 @@ func (c *Cache) ClearMatching(predicatePartition func(k string, p PartitionManag
}
// ClearOnRebuild prepares the cache for a new rebuild taking the given changeset into account.
func (c *Cache) ClearOnRebuild(changeset ...identity.Identity) {
// predicate is optional and will clear any entry for which it returns true.
func (c *Cache) ClearOnRebuild(predicate func(k, v any) bool, changeset ...identity.Identity) {
g := rungroup.Run[PartitionManager](context.Background(), rungroup.Config[PartitionManager]{
NumWorkers: len(c.partitions),
Handle: func(ctx context.Context, partition PartitionManager) error {
partition.clearOnRebuild(changeset...)
partition.clearOnRebuild(predicate, changeset...)
return nil
},
})
@@ -479,7 +480,12 @@ func (p *Partition[K, V]) clearMatching(predicate func(k, v any) bool) {
})
}
func (p *Partition[K, V]) clearOnRebuild(changeset ...identity.Identity) {
func (p *Partition[K, V]) clearOnRebuild(predicate func(k, v any) bool, changeset ...identity.Identity) {
if predicate == nil {
predicate = func(k, v any) bool {
return false
}
}
opts := p.getOptions()
if opts.ClearWhen == ClearNever {
return
@@ -525,7 +531,7 @@ func (p *Partition[K, V]) clearOnRebuild(changeset ...identity.Identity) {
// Second pass needs to be done in a separate loop to catch any
// elements marked as stale in the other partitions.
p.c.DeleteFunc(func(key K, v V) bool {
if shouldDelete(key, v) {
if predicate(key, v) || shouldDelete(key, v) {
p.trace.Log(
logg.StringFunc(
func() string {
@@ -601,7 +607,7 @@ type PartitionManager interface {
adjustMaxSize(addend int) int
getMaxSize() int
getOptions() OptionsPartition
clearOnRebuild(changeset ...identity.Identity)
clearOnRebuild(predicate func(k, v any) bool, changeset ...identity.Identity)
clearMatching(predicate func(k, v any) bool)
clearStale()
}
+6 -6
View File
@@ -147,13 +147,13 @@ func TestClear(t *testing.T) {
c.Assert(cache.Keys(predicateAll), qt.HasLen, 4)
cache.ClearOnRebuild()
cache.ClearOnRebuild(nil)
// Stale items are always cleared.
c.Assert(cache.Keys(predicateAll), qt.HasLen, 2)
cache = newTestCache(t)
cache.ClearOnRebuild(identity.StringIdentity("changed"))
cache.ClearOnRebuild(nil, identity.StringIdentity("changed"))
c.Assert(cache.Keys(nil), qt.HasLen, 1)
@@ -191,16 +191,16 @@ func TestPanicInCreate(t *testing.T) {
return err
}
for i := 0; i < 3; i++ {
for j := 0; j < 3; j++ {
for i := range 3 {
for range 3 {
c.Assert(willPanic(i), qt.PanicMatches, fmt.Sprintf("panic-%d", i))
c.Assert(willErr(i), qt.ErrorMatches, fmt.Sprintf("error-%d", i))
}
}
// Test the same keys again without the panic.
for i := 0; i < 3; i++ {
for j := 0; j < 3; j++ {
for i := range 3 {
for range 3 {
v, err := p1.GetOrCreate(fmt.Sprintf("panic-%d", i), func(key string) (testItem, error) {
return testItem{
name: key,
+3 -3
View File
@@ -59,7 +59,7 @@ dir = ":resourceDir/_gen"
caches, err := filecache.NewCaches(p)
c.Assert(err, qt.IsNil)
cache := caches[name]
for i := 0; i < 10; i++ {
for i := range 10 {
id := fmt.Sprintf("i%d", i)
cache.GetOrCreateBytes(id, func() ([]byte, error) {
return []byte("abc"), nil
@@ -74,7 +74,7 @@ dir = ":resourceDir/_gen"
c.Assert(err, qt.IsNil)
c.Assert(count, qt.Equals, 5, msg)
for i := 0; i < 10; i++ {
for i := range 10 {
id := fmt.Sprintf("i%d", i)
v := cache.GetString(id)
if i < 5 {
@@ -97,7 +97,7 @@ dir = ":resourceDir/_gen"
c.Assert(count, qt.Equals, 4)
// Now only the i5 should be left.
for i := 0; i < 10; i++ {
for i := range 10 {
id := fmt.Sprintf("i%d", i)
v := cache.GetString(id)
if i != 5 {
+3 -3
View File
@@ -105,7 +105,7 @@ dir = ":cacheDir/c"
}
for _, ca := range []*filecache.Cache{caches.ImageCache(), caches.AssetsCache(), caches.GetJSONCache(), caches.GetCSVCache()} {
for i := 0; i < 2; i++ {
for range 2 {
info, r, err := ca.GetOrCreate("a", rf("abc"))
c.Assert(err, qt.IsNil)
c.Assert(r, qt.Not(qt.IsNil))
@@ -193,11 +193,11 @@ dir = "/cache/c"
var wg sync.WaitGroup
for i := 0; i < 50; i++ {
for i := range 50 {
wg.Add(1)
go func(i int) {
defer wg.Done()
for j := 0; j < 20; j++ {
for range 20 {
ca := caches.Get(cacheName)
c.Assert(ca, qt.Not(qt.IsNil))
filename, data := filenameData(i)
+13 -2
View File
@@ -42,7 +42,7 @@ var DefaultConfig = Config{
// Config holds the configuration for the HTTP cache.
type Config struct {
// Configures the HTTP cache behaviour (RFC 9111).
// Configures the HTTP cache behavior (RFC 9111).
// When this is not enabled for a resource, Hugo will go straight to the file cache.
Cache Cache
@@ -52,7 +52,7 @@ type Config struct {
}
type Cache struct {
// Enable HTTP cache behaviour (RFC 9111) for these rsources.
// Enable HTTP cache behavior (RFC 9111) for these resources.
For GlobMatcher
}
@@ -122,6 +122,10 @@ type GlobMatcher struct {
Includes []string
}
func (gm GlobMatcher) IsZero() bool {
return len(gm.Includes) == 0 && len(gm.Excludes) == 0
}
type ConfigCompiled struct {
For predicate.P[string]
PollConfigs []PollConfigCompiled
@@ -155,6 +159,9 @@ func (p PollConfigCompiled) IsZero() bool {
}
func (gm *GlobMatcher) CompilePredicate() (func(string) bool, error) {
if gm.IsZero() {
panic("no includes or excludes")
}
var p predicate.P[string]
for _, include := range gm.Includes {
g, err := glob.Compile(include, '/')
@@ -203,5 +210,9 @@ func DecodeConfig(bcfg config.BaseConfig, m map[string]any) (Config, error) {
return c, err
}
if c.Cache.For.IsZero() {
c.Cache.For = DefaultConfig.Cache.For
}
return c, nil
}
+31
View File
@@ -22,6 +22,8 @@ import (
)
func TestConfigCustom(t *testing.T) {
t.Parallel()
files := `
-- hugo.toml --
[httpcache]
@@ -51,6 +53,8 @@ includes = ["**gohugo.io**"]
}
func TestConfigDefault(t *testing.T) {
t.Parallel()
files := `
-- hugo.toml --
`
@@ -62,3 +66,30 @@ func TestConfigDefault(t *testing.T) {
b.Assert(compiled.For("https://gohugo.io/foo.jpg"), qt.IsFalse)
b.Assert(compiled.PollConfigFor("https://gohugo.io/foo.jpg").Config.Disable, qt.IsTrue)
}
func TestConfigPollsOnly(t *testing.T) {
t.Parallel()
files := `
-- hugo.toml --
[httpcache]
[[httpcache.polls]]
low = "5s"
high = "32s"
[httpcache.polls.for]
includes = ["**gohugo.io**"]
`
b := hugolib.Test(t, files)
compiled := b.H.Configs.Base.C.HTTPCache
b.Assert(compiled.For("https://gohugo.io/posts.json"), qt.IsFalse)
b.Assert(compiled.For("https://gohugo.io/foo.jpg"), qt.IsFalse)
pc := compiled.PollConfigFor("https://gohugo.io/foo.jpg")
b.Assert(pc.Config.Low, qt.Equals, 5*time.Second)
b.Assert(pc.Config.High, qt.Equals, 32*time.Second)
b.Assert(compiled.PollConfigFor("https://example.com/foo.jpg").IsZero(), qt.IsTrue)
}
+8 -7
View File
@@ -26,6 +26,7 @@ import (
"path/filepath"
"reflect"
"regexp"
"slices"
"sort"
"strings"
"sync"
@@ -102,7 +103,7 @@ func (c *Inspector) MethodsFromTypes(include []reflect.Type, exclude []reflect.T
}
for _, t := range include {
for i := 0; i < t.NumMethod(); i++ {
for i := range t.NumMethod() {
m := t.Method(i)
if excludes[m.Name] || seen[m.Name] {
@@ -122,7 +123,7 @@ func (c *Inspector) MethodsFromTypes(include []reflect.Type, exclude []reflect.T
method := Method{Owner: t, OwnerName: ownerName, Name: m.Name}
for i := 0; i < numIn; i++ {
for i := range numIn {
in := m.Type.In(i)
name, pkg := nameAndPackage(in)
@@ -137,7 +138,7 @@ func (c *Inspector) MethodsFromTypes(include []reflect.Type, exclude []reflect.T
numOut := m.Type.NumOut()
if numOut > 0 {
for i := 0; i < numOut; i++ {
for i := range numOut {
out := m.Type.Out(i)
name, pkg := nameAndPackage(out)
@@ -304,7 +305,7 @@ func (m Method) inOutStr() string {
}
args := make([]string, len(m.In))
for i := 0; i < len(args); i++ {
for i := range args {
args[i] = fmt.Sprintf("arg%d", i)
}
return "(" + strings.Join(args, ", ") + ")"
@@ -316,7 +317,7 @@ func (m Method) inStr() string {
}
args := make([]string, len(m.In))
for i := 0; i < len(args); i++ {
for i := range args {
args[i] = fmt.Sprintf("arg%d %s", i, m.In[i])
}
return "(" + strings.Join(args, ", ") + ")"
@@ -339,7 +340,7 @@ func (m Method) outStrNamed() string {
}
outs := make([]string, len(m.Out))
for i := 0; i < len(outs); i++ {
for i := range outs {
outs[i] = fmt.Sprintf("o%d %s", i, m.Out[i])
}
@@ -435,7 +436,7 @@ func (m Methods) ToMarshalJSON(receiver, pkgPath string, excludes ...string) (st
// Exclude self
for i, pkgImp := range pkgImports {
if pkgImp == pkgPath {
pkgImports = append(pkgImports[:i], pkgImports[i+1:]...)
pkgImports = slices.Delete(pkgImports, i, i+1)
}
}
}
+5 -5
View File
@@ -101,8 +101,8 @@ type configKey struct {
// This is the root command.
type rootCommand struct {
Printf func(format string, v ...interface{})
Println func(a ...interface{})
Printf func(format string, v ...any)
Println func(a ...any)
StdOut io.Writer
StdErr io.Writer
@@ -431,12 +431,12 @@ func (r *rootCommand) PreRun(cd, runner *simplecobra.Commandeer) error {
// Used by mkcert (server).
log.SetOutput(r.StdOut)
r.Printf = func(format string, v ...interface{}) {
r.Printf = func(format string, v ...any) {
if !r.quiet {
fmt.Fprintf(r.StdOut, format, v...)
}
}
r.Println = func(a ...interface{}) {
r.Println = func(a ...any) {
if !r.quiet {
fmt.Fprintln(r.StdOut, a...)
}
@@ -448,7 +448,7 @@ func (r *rootCommand) PreRun(cd, runner *simplecobra.Commandeer) error {
return err
}
// Set up the global logger early to allow info deprecations during config load.
loggers.InitGlobalLogger(r.logger.Level(), false)
loggers.SetGlobalLogger(r.logger)
r.changesFromBuild = make(chan []identity.Identity, 10)
+1 -1
View File
@@ -90,7 +90,7 @@ func (c *configCommand) Run(ctx context.Context, cd *simplecobra.Commandeer, arg
os.Stdout.Write(buf.Bytes())
default:
// Decode the JSON to a map[string]interface{} and then unmarshal it again to the correct format.
var m map[string]interface{}
var m map[string]any
if err := json.Unmarshal(buf.Bytes(), &m); err != nil {
return err
}
-1
View File
@@ -12,7 +12,6 @@
// limitations under the License.
//go:build withdeploy
// +build withdeploy
package commands
-1
View File
@@ -12,7 +12,6 @@
// limitations under the License.
//go:build !withdeploy
// +build !withdeploy
// Copyright 2024 The Hugo Authors. All rights reserved.
//
+8 -3
View File
@@ -21,6 +21,7 @@ import (
"os"
"path"
"path/filepath"
"slices"
"strings"
"github.com/alecthomas/chroma/v2"
@@ -60,6 +61,10 @@ func newGenCommand() *genCommand {
See https://xyproto.github.io/splash/docs/all.html for a preview of the available styles`,
run: func(ctx context.Context, cd *simplecobra.Commandeer, r *rootCommand, args []string) error {
style = strings.ToLower(style)
if !slices.Contains(styles.Names(), style) {
return fmt.Errorf("invalid style: %s", style)
}
builder := styles.Get(style).Builder()
if highlightStyle != "" {
builder.Add(chroma.LineHighlight, highlightStyle)
@@ -144,7 +149,7 @@ url: %s
return &simpleCommand{
name: "doc",
short: "Generate Markdown documentation for the Hugo CLI.",
short: "Generate Markdown documentation for the Hugo CLI",
long: `Generate Markdown documentation for the Hugo CLI.
This command is, mostly, used to create up-to-date documentation
of Hugo's command-line interface for https://gohugo.io/.
@@ -196,7 +201,7 @@ url: %s
newDocsHelper := func() simplecobra.Commander {
return &simpleCommand{
name: "docshelper",
short: "Generate some data files for the Hugo docs.",
short: "Generate some data files for the Hugo docs",
run: func(ctx context.Context, cd *simplecobra.Commandeer, r *rootCommand, args []string) error {
r.Println("Generate docs data to", docsHelperTarget)
@@ -217,7 +222,7 @@ url: %s
}
// Decode the JSON to a map[string]interface{} and then unmarshal it again to the correct format.
var m map[string]interface{}
var m map[string]any
if err := json.Unmarshal(buf.Bytes(), &m); err != nil {
return err
}
+14 -16
View File
@@ -663,7 +663,20 @@ func (c *hugoBuilder) handleEvents(watcher *watcher.Batcher,
var n int
for _, ev := range evs {
keep := true
if ev.Has(fsnotify.Create) || ev.Has(fsnotify.Write) {
// Write and rename operations are often followed by CHMOD.
// There may be valid use cases for rebuilding the site on CHMOD,
// but that will require more complex logic than this simple conditional.
// On OS X this seems to be related to Spotlight, see:
// https://github.com/go-fsnotify/fsnotify/issues/15
// A workaround is to put your site(s) on the Spotlight exception list,
// but that may be a little mysterious for most end users.
// So, for now, we skip reload on CHMOD.
// We do have to check for WRITE though. On slower laptops a Chmod
// could be aggregated with other important events, and we still want
// to rebuild on those
if ev.Op == fsnotify.Chmod {
keep = false
} else if ev.Has(fsnotify.Create) || ev.Has(fsnotify.Write) {
if _, err := os.Stat(ev.Name); err != nil {
keep = false
}
@@ -805,21 +818,6 @@ func (c *hugoBuilder) handleEvents(watcher *watcher.Batcher,
continue
}
// Write and rename operations are often followed by CHMOD.
// There may be valid use cases for rebuilding the site on CHMOD,
// but that will require more complex logic than this simple conditional.
// On OS X this seems to be related to Spotlight, see:
// https://github.com/go-fsnotify/fsnotify/issues/15
// A workaround is to put your site(s) on the Spotlight exception list,
// but that may be a little mysterious for most end users.
// So, for now, we skip reload on CHMOD.
// We do have to check for WRITE though. On slower laptops a Chmod
// could be aggregated with other important events, and we still want
// to rebuild on those
if ev.Op&(fsnotify.Chmod|fsnotify.Write|fsnotify.Create) == fsnotify.Chmod {
continue
}
walkAdder := func(path string, f hugofs.FileMetaInfo) error {
if f.IsDir() {
c.r.logger.Println("adding created directory to watchlist", path)
+14 -14
View File
@@ -44,16 +44,16 @@ func newModCommands() *modCommands {
npmCommand := &simpleCommand{
name: "npm",
short: "Various npm helpers.",
short: "Various npm helpers",
long: `Various npm (Node package manager) helpers.`,
commands: []simplecobra.Commander{
&simpleCommand{
name: "pack",
short: "Experimental: Prepares and writes a composite package.json file for your project.",
short: "Experimental: Prepares and writes a composite package.json file for your project",
long: `Prepares and writes a composite package.json file for your project.
On first run it creates a "package.hugo.json" in the project root if not already there. This file will be used as a template file
with the base dependency set.
with the base dependency set.
This set will be merged with all "package.hugo.json" files found in the dependency tree, picking the version closest to the project.
@@ -80,12 +80,12 @@ so this may/will change in future versions of Hugo.
commands: []simplecobra.Commander{
&simpleCommand{
name: "init",
short: "Initialize this project as a Hugo Module.",
short: "Initialize this project as a Hugo Module",
long: `Initialize this project as a Hugo Module.
It will try to guess the module path, but you may help by passing it as an argument, e.g:
hugo mod init github.com/gohugoio/testshortcodes
Note that Hugo Modules supports multi-module projects, so you can initialize a Hugo Module
inside a subfolder on GitHub, as one example.
`,
@@ -111,7 +111,7 @@ so this may/will change in future versions of Hugo.
},
&simpleCommand{
name: "verify",
short: "Verify dependencies.",
short: "Verify dependencies",
long: `Verify checks that the dependencies of the current module, which are stored in a local downloaded source cache, have not been modified since being downloaded.`,
withc: func(cmd *cobra.Command, r *rootCommand) {
cmd.ValidArgsFunction = cobra.NoFileCompletions
@@ -129,7 +129,7 @@ so this may/will change in future versions of Hugo.
},
&simpleCommand{
name: "graph",
short: "Print a module dependency graph.",
short: "Print a module dependency graph",
long: `Print a module dependency graph with information about module status (disabled, vendored).
Note that for vendored modules, that is the version listed and not the one from go.mod.
`,
@@ -149,7 +149,7 @@ Note that for vendored modules, that is the version listed and not the one from
},
&simpleCommand{
name: "clean",
short: "Delete the Hugo Module cache for the current project.",
short: "Delete the Hugo Module cache for the current project",
long: `Delete the Hugo Module cache for the current project.`,
withc: func(cmd *cobra.Command, r *rootCommand) {
cmd.ValidArgsFunction = cobra.NoFileCompletions
@@ -175,7 +175,7 @@ Note that for vendored modules, that is the version listed and not the one from
},
&simpleCommand{
name: "tidy",
short: "Remove unused entries in go.mod and go.sum.",
short: "Remove unused entries in go.mod and go.sum",
withc: func(cmd *cobra.Command, r *rootCommand) {
cmd.ValidArgsFunction = cobra.NoFileCompletions
applyLocalFlagsBuildConfig(cmd, r)
@@ -190,7 +190,7 @@ Note that for vendored modules, that is the version listed and not the one from
},
&simpleCommand{
name: "vendor",
short: "Vendor all module dependencies into the _vendor directory.",
short: "Vendor all module dependencies into the _vendor directory",
long: `Vendor all module dependencies into the _vendor directory.
If a module is vendored, that is where Hugo will look for it's dependencies.
`,
@@ -209,16 +209,16 @@ Note that for vendored modules, that is the version listed and not the one from
&simpleCommand{
name: "get",
short: "Resolves dependencies in your current Hugo Project.",
short: "Resolves dependencies in your current Hugo project",
long: `
Resolves dependencies in your current Hugo Project.
Resolves dependencies in your current Hugo project.
Some examples:
Install the latest version possible for a given module:
hugo mod get github.com/gohugoio/testshortcodes
Install a specific version:
hugo mod get github.com/gohugoio/testshortcodes@v0.3.0
+1 -1
View File
@@ -32,7 +32,7 @@ func newReleaseCommand() simplecobra.Commander {
return &simpleCommand{
name: "release",
short: "Release a new version of Hugo.",
short: "Release a new version of Hugo",
run: func(ctx context.Context, cd *simplecobra.Commandeer, r *rootCommand, args []string) error {
rel, err := releaser.New(skipPush, try, step)
if err != nil {
+78 -56
View File
@@ -65,6 +65,7 @@ import (
"github.com/spf13/fsync"
"golang.org/x/sync/errgroup"
"golang.org/x/sync/semaphore"
"maps"
)
var (
@@ -84,6 +85,10 @@ const (
configChangeGoWork = "go work file"
)
const (
hugoHeaderRedirect = "X-Hugo-Redirect"
)
func newHugoBuilder(r *rootCommand, s *serverCommand, onConfigLoaded ...func(reloaded bool) error) *hugoBuilder {
var visitedURLs *types.EvictingQueue[string]
if s != nil && !s.disableFastRender {
@@ -115,7 +120,7 @@ func newServerCommand() *serverCommand {
commands: []simplecobra.Commander{
&simpleCommand{
name: "trust",
short: "Install the local CA in the system trust store.",
short: "Install the local CA in the system trust store",
run: func(ctx context.Context, cd *simplecobra.Commandeer, r *rootCommand, args []string) error {
action := "-install"
if uninstall {
@@ -191,9 +196,7 @@ func (f *fileChangeDetector) PrepareNew() {
}
f.prev = make(map[string]uint64)
for k, v := range f.current {
f.prev[k] = v
}
maps.Copy(f.prev, f.current)
f.current = make(map[string]uint64)
}
@@ -307,67 +310,65 @@ func (f *fileServer) createEndpoint(i int) (*http.ServeMux, net.Listener, string
w.Header().Set(header.Key, header.Value)
}
if redirect := serverConfig.MatchRedirect(requestURI); !redirect.IsZero() {
// fullName := filepath.Join(dir, filepath.FromSlash(path.Clean("/"+name)))
doRedirect := true
// This matches Netlify's behavior and is needed for SPA behavior.
// See https://docs.netlify.com/routing/redirects/rewrites-proxies/
if !redirect.Force {
path := filepath.Clean(strings.TrimPrefix(requestURI, baseURL.Path()))
if root != "" {
path = filepath.Join(root, path)
}
var fs afero.Fs
f.c.withConf(func(conf *commonConfig) {
fs = conf.fs.PublishDirServer
})
fi, err := fs.Stat(path)
if err == nil {
if fi.IsDir() {
// There will be overlapping directories, so we
// need to check for a file.
_, err = fs.Stat(filepath.Join(path, "index.html"))
doRedirect = err != nil
} else {
doRedirect = false
if canRedirect(requestURI, r) {
if redirect := serverConfig.MatchRedirect(requestURI, r.Header); !redirect.IsZero() {
doRedirect := true
// This matches Netlify's behavior and is needed for SPA behavior.
// See https://docs.netlify.com/routing/redirects/rewrites-proxies/
if !redirect.Force {
path := filepath.Clean(strings.TrimPrefix(requestURI, baseURL.Path()))
if root != "" {
path = filepath.Join(root, path)
}
}
}
var fs afero.Fs
f.c.withConf(func(conf *commonConfig) {
fs = conf.fs.PublishDirServer
})
fi, err := fs.Stat(path)
if doRedirect {
switch redirect.Status {
case 404:
w.WriteHeader(404)
file, err := fs.Open(strings.TrimPrefix(redirect.To, baseURL.Path()))
if err == nil {
defer file.Close()
io.Copy(w, file)
} else {
fmt.Fprintln(w, "<h1>Page Not Found</h1>")
if fi.IsDir() {
// There will be overlapping directories, so we
// need to check for a file.
_, err = fs.Stat(filepath.Join(path, "index.html"))
doRedirect = err != nil
} else {
doRedirect = false
}
}
return
case 200:
if r2 := f.rewriteRequest(r, strings.TrimPrefix(redirect.To, baseURL.Path())); r2 != nil {
requestURI = redirect.To
r = r2
}
default:
w.Header().Set("Content-Type", "")
http.Redirect(w, r, redirect.To, redirect.Status)
return
}
if doRedirect {
w.Header().Set(hugoHeaderRedirect, "true")
switch redirect.Status {
case 404:
w.WriteHeader(404)
file, err := fs.Open(strings.TrimPrefix(redirect.To, baseURL.Path()))
if err == nil {
defer file.Close()
io.Copy(w, file)
} else {
fmt.Fprintln(w, "<h1>Page Not Found</h1>")
}
return
case 200:
if r2 := f.rewriteRequest(r, strings.TrimPrefix(redirect.To, baseURL.Path())); r2 != nil {
requestURI = redirect.To
r = r2
}
default:
w.Header().Set("Content-Type", "")
http.Redirect(w, r, redirect.To, redirect.Status)
return
}
}
}
}
if f.c.fastRenderMode && f.c.errState.buildErr() == nil {
// Sec-Fetch-Mode should be sent by all recent browser versions, see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Sec-Fetch-Mode#navigate
// Fall back to the file extension if not set.
// The main take here is that we don't want to have CSS/JS files etc. partake in this logic.
if r.Header.Get("Sec-Fetch-Mode") == "navigate" || strings.HasSuffix(requestURI, "/") || strings.HasSuffix(requestURI, "html") || strings.HasSuffix(requestURI, "htm") {
if isNavigation(requestURI, r) {
if !f.c.visitedURLs.Contains(requestURI) {
// If not already on stack, re-render that single page.
if err := f.c.partialReRender(requestURI); err != nil {
@@ -757,7 +758,7 @@ func (c *serverCommand) createServerPorts(cd *simplecobra.Commandeer) error {
c.serverPorts = make([]serverPortListener, len(conf.configs.Languages))
}
currentServerPort := c.serverPort
for i := 0; i < len(c.serverPorts); i++ {
for i := range c.serverPorts {
l, err := net.Listen("tcp", net.JoinHostPort(c.serverInterface, strconv.Itoa(currentServerPort)))
if err == nil {
c.serverPorts[i] = serverPortListener{ln: l, p: currentServerPort}
@@ -1233,3 +1234,24 @@ func formatByteCount(b uint64) string {
return fmt.Sprintf("%.1f %cB",
float64(b)/float64(div), "kMGTPE"[exp])
}
func canRedirect(requestURIWithoutQuery string, r *http.Request) bool {
if r.Header.Get(hugoHeaderRedirect) != "" {
return false
}
return isNavigation(requestURIWithoutQuery, r)
}
// Sec-Fetch-Mode should be sent by all recent browser versions, see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Sec-Fetch-Mode#navigate
// Fall back to the file extension if not set.
// The main take here is that we don't want to have CSS/JS files etc. partake in this logic.
func isNavigation(requestURIWithoutQuery string, r *http.Request) bool {
return r.Header.Get("Sec-Fetch-Mode") == "navigate" || isPropablyHTMLRequest(requestURIWithoutQuery)
}
func isPropablyHTMLRequest(requestURIWithoutQuery string) bool {
if strings.HasSuffix(requestURIWithoutQuery, "/") || strings.HasSuffix(requestURIWithoutQuery, "html") || strings.HasSuffix(requestURIWithoutQuery, "htm") {
return true
}
return !strings.Contains(requestURIWithoutQuery, ".")
}
+2 -2
View File
@@ -117,7 +117,7 @@ func appendToInterfaceSliceFromValues(slice1, slice2 reflect.Value) ([]any, erro
tos = append(tos, nil)
continue
}
for i := 0; i < slice.Len(); i++ {
for i := range slice.Len() {
tos = append(tos, slice.Index(i).Interface())
}
}
@@ -128,7 +128,7 @@ func appendToInterfaceSliceFromValues(slice1, slice2 reflect.Value) ([]any, erro
func appendToInterfaceSlice(tov reflect.Value, from ...any) ([]any, error) {
var tos []any
for i := 0; i < tov.Len(); i++ {
for i := range tov.Len() {
tos = append(tos, tov.Index(i).Interface())
}
+3 -1
View File
@@ -13,6 +13,8 @@
package collections
import "slices"
import "sync"
// Stack is a simple LIFO stack that is safe for concurrent use.
@@ -73,7 +75,7 @@ func (s *Stack[T]) DrainMatching(predicate func(T) bool) []T {
for i := len(s.items) - 1; i >= 0; i-- {
if predicate(s.items[i]) {
items = append(items, s.items[i])
s.items = append(s.items[:i], s.items[i+1:]...)
s.items = slices.Delete(s.items, i, i+1)
}
}
return items
+4 -4
View File
@@ -37,12 +37,12 @@ func TestXxHashFromReaderPara(t *testing.T) {
c := qt.New(t)
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
for i := range 10 {
i := i
wg.Add(1)
go func() {
defer wg.Done()
for j := 0; j < 100; j++ {
for j := range 100 {
s := strings.Repeat("Hello ", i+j+1*42)
r := strings.NewReader(s)
got, size, err := XXHashFromReader(r)
@@ -144,8 +144,8 @@ func BenchmarkHashString(b *testing.B) {
}
func BenchmarkHashMap(b *testing.B) {
m := map[string]interface{}{}
for i := 0; i < 1000; i++ {
m := map[string]any{}
for i := range 1000 {
m[fmt.Sprintf("key%d", i)] = i
}
+2 -8
View File
@@ -152,10 +152,7 @@ func locateError(r io.Reader, le FileError, matches LineMatcherFn) *ErrorContext
}
if ectx.Position.LineNumber > 0 {
low := ectx.Position.LineNumber - 3
if low < 0 {
low = 0
}
low := max(ectx.Position.LineNumber-3, 0)
if ectx.Position.LineNumber > 2 {
ectx.LinesPos = 2
@@ -163,10 +160,7 @@ func locateError(r io.Reader, le FileError, matches LineMatcherFn) *ErrorContext
ectx.LinesPos = ectx.Position.LineNumber - 1
}
high := ectx.Position.LineNumber + 2
if high > len(lines) {
high = len(lines)
}
high := min(ectx.Position.LineNumber+2, len(lines))
ectx.Lines = lines[low:high]
+11 -1
View File
@@ -74,6 +74,16 @@ func IsTruthful(in any) bool {
}
}
// IsMap reports whether v is a map.
func IsMap(v any) bool {
return reflect.ValueOf(v).Kind() == reflect.Map
}
// IsSlice reports whether v is a slice.
func IsSlice(v any) bool {
return reflect.ValueOf(v).Kind() == reflect.Slice
}
var zeroType = reflect.TypeOf((*types.Zeroer)(nil)).Elem()
// IsTruthfulValue returns whether the given value has a meaningful truth value.
@@ -235,7 +245,7 @@ func ToSliceAny(v any) ([]any, bool) {
vvv := reflect.ValueOf(v)
if vvv.Kind() == reflect.Slice {
out := make([]any, vvv.Len())
for i := 0; i < vvv.Len(); i++ {
for i := range vvv.Len() {
out[i] = vvv.Index(i).Interface()
}
return out, true
+3 -12
View File
@@ -20,6 +20,7 @@ import (
"sync"
"github.com/gohugoio/hugo/compare"
"slices"
)
var _ compare.Eqer = StringEqualFold("")
@@ -50,12 +51,7 @@ func (s StringEqualFold) Eq(s2 any) bool {
// EqualAny returns whether a string is equal to any of the given strings.
func EqualAny(a string, b ...string) bool {
for _, s := range b {
if a == s {
return true
}
}
return false
return slices.Contains(b, a)
}
// regexpCache represents a cache of regexp objects protected by a mutex.
@@ -103,12 +99,7 @@ func GetOrCompileRegexp(pattern string) (re *regexp.Regexp, err error) {
// InSlice checks if a string is an element of a slice of strings
// and returns a boolean value.
func InSlice(arr []string, el string) bool {
for _, v := range arr {
if v == el {
return true
}
}
return false
return slices.Contains(arr, el)
}
// InSlicEqualFold checks if a string is an element of a slice of strings
+1 -1
View File
@@ -46,7 +46,7 @@ func TestHasBytesWriter(t *testing.T) {
return strings.Repeat("ab cfo", r.Intn(33))
}
for i := 0; i < 22; i++ {
for range 22 {
h, w := neww()
fmt.Fprint(w, rndStr()+"abc __foobar"+rndStr())
c.Assert(h.Patterns[0].Match, qt.Equals, true)
+11 -5
View File
@@ -414,11 +414,17 @@ func Deprecate(item, alternative string, version string) {
DeprecateLevel(item, alternative, version, level)
}
// DeprecateLevelMin informs about a deprecation starting at the given version, but with a minimum log level.
func DeprecateLevelMin(item, alternative string, version string, minLevel logg.Level) {
level := max(deprecationLogLevelFromVersion(version), minLevel)
DeprecateLevel(item, alternative, version, level)
}
// DeprecateLevel informs about a deprecation logging at the given level.
func DeprecateLevel(item, alternative, version string, level logg.Level) {
var msg string
if level == logg.LevelError {
msg = fmt.Sprintf("%s was deprecated in Hugo %s and will be removed in Hugo %s. %s", item, version, CurrentVersion.Next().ReleaseVersion(), alternative)
msg = fmt.Sprintf("%s was deprecated in Hugo %s and subsequently removed. %s", item, version, alternative)
} else {
msg = fmt.Sprintf("%s was deprecated in Hugo %s and will be removed in a future release. %s", item, version, alternative)
}
@@ -434,11 +440,11 @@ func deprecationLogLevelFromVersion(ver string) logg.Level {
to := CurrentVersion
minorDiff := to.Minor - from.Minor
switch {
case minorDiff >= 12:
// Start failing the build after about a year.
case minorDiff >= 15:
// Start failing the build after about 15 months.
return logg.LevelError
case minorDiff >= 6:
// Start printing warnings after about six months.
case minorDiff >= 3:
// Start printing warnings after about 3 months.
return logg.LevelWarn
default:
return logg.LevelInfo
+4 -4
View File
@@ -57,11 +57,11 @@ func TestDeprecationLogLevelFromVersion(t *testing.T) {
c.Assert(deprecationLogLevelFromVersion("0.55.0"), qt.Equals, logg.LevelError)
ver := CurrentVersion
c.Assert(deprecationLogLevelFromVersion(ver.String()), qt.Equals, logg.LevelInfo)
ver.Minor -= 1
c.Assert(deprecationLogLevelFromVersion(ver.String()), qt.Equals, logg.LevelInfo)
ver.Minor -= 6
ver.Minor -= 3
c.Assert(deprecationLogLevelFromVersion(ver.String()), qt.Equals, logg.LevelWarn)
ver.Minor -= 6
ver.Minor -= 4
c.Assert(deprecationLogLevelFromVersion(ver.String()), qt.Equals, logg.LevelWarn)
ver.Minor -= 13
c.Assert(deprecationLogLevelFromVersion(ver.String()), qt.Equals, logg.LevelError)
// Added just to find the threshold for where we can remove deprecated items.
-1
View File
@@ -12,7 +12,6 @@
// limitations under the License.
//go:build extended
// +build extended
package hugo
-1
View File
@@ -12,7 +12,6 @@
// limitations under the License.
//go:build !extended
// +build !extended
package hugo
-1
View File
@@ -12,7 +12,6 @@
// limitations under the License.
//go:build withdeploy
// +build withdeploy
package hugo
-1
View File
@@ -12,7 +12,6 @@
// limitations under the License.
//go:build !withdeploy
// +build !withdeploy
package hugo
+1 -1
View File
@@ -17,7 +17,7 @@ package hugo
// This should be the only one.
var CurrentVersion = Version{
Major: 0,
Minor: 143,
Minor: 146,
PatchLevel: 0,
Suffix: "-DEV",
}
+2 -2
View File
@@ -37,7 +37,7 @@ func TestLogDistinct(t *testing.T) {
l := loggers.New(opts)
for i := 0; i < 10; i++ {
for range 10 {
l.Errorln("error 1")
l.Errorln("error 2")
l.Warnln("warn 1")
@@ -137,7 +137,7 @@ func TestReset(t *testing.T) {
l := loggers.New(opts)
for i := 0; i < 3; i++ {
for range 3 {
l.Errorln("error 1")
l.Errorln("error 2")
l.Errorln("error 1")
+10 -2
View File
@@ -21,7 +21,15 @@ import (
"github.com/bep/logg"
)
func InitGlobalLogger(level logg.Level, panicOnWarnings bool) {
// SetGlobalLogger sets the global logger.
// This is used in a few places in Hugo, e.g. deprecated functions.
func SetGlobalLogger(logger Logger) {
logMu.Lock()
defer logMu.Unlock()
log = logger
}
func initGlobalLogger(level logg.Level, panicOnWarnings bool) {
logMu.Lock()
defer logMu.Unlock()
var logHookLast func(e *logg.Entry) error
@@ -50,5 +58,5 @@ func Log() Logger {
var log Logger
func init() {
InitGlobalLogger(logg.LevelWarn, false)
initGlobalLogger(logg.LevelWarn, false)
}
+4
View File
@@ -73,10 +73,14 @@ func TestPrepareParams(t *testing.T) {
for i, test := range tests {
t.Run(fmt.Sprint(i), func(t *testing.T) {
// PrepareParams modifies input.
prepareClone := PrepareParamsClone(test.input)
PrepareParams(test.input)
if !reflect.DeepEqual(test.expected, test.input) {
t.Errorf("[%d] Expected\n%#v, got\n%#v\n", i, test.expected, test.input)
}
if !reflect.DeepEqual(test.expected, prepareClone) {
t.Errorf("[%d] Expected\n%#v, got\n%#v\n", i, test.expected, prepareClone)
}
})
}
}
+2 -1
View File
@@ -15,6 +15,7 @@ package maps
import (
"github.com/gohugoio/hugo/common/hashing"
"slices"
)
// Ordered is a map that can be iterated in the order of insertion.
@@ -64,7 +65,7 @@ func (m *Ordered[K, T]) Delete(key K) {
delete(m.values, key)
for i, k := range m.keys {
if k == key {
m.keys = append(m.keys[:i], m.keys[i+1:]...)
m.keys = slices.Delete(m.keys, i, i+1)
break
}
}
+40 -1
View File
@@ -303,7 +303,7 @@ func toMergeStrategy(v any) ParamsMergeStrategy {
}
// PrepareParams
// * makes all the keys in the given map lower cased and will do so
// * makes all the keys in the given map lower cased and will do so recursively.
// * This will modify the map given.
// * Any nested map[interface{}]interface{}, map[string]interface{},map[string]string will be converted to Params.
// * Any _merge value will be converted to proper type and value.
@@ -343,3 +343,42 @@ func PrepareParams(m Params) {
}
}
}
// PrepareParamsClone is like PrepareParams, but it does not modify the input.
func PrepareParamsClone(m Params) Params {
m2 := make(Params)
for k, v := range m {
var retyped bool
lKey := strings.ToLower(k)
if lKey == MergeStrategyKey {
v = toMergeStrategy(v)
retyped = true
} else {
switch vv := v.(type) {
case map[any]any:
var p Params = cast.ToStringMap(v)
v = PrepareParamsClone(p)
retyped = true
case map[string]any:
var p Params = v.(map[string]any)
v = PrepareParamsClone(p)
retyped = true
case map[string]string:
p := make(Params)
for k, v := range vv {
p[k] = v
}
v = p
PrepareParams(p)
retyped = true
}
}
if retyped || k != lKey {
m2[lKey] = v
} else {
m2[k] = v
}
}
return m2
}
+1 -1
View File
@@ -140,7 +140,7 @@ func TestScratchInParallel(t *testing.T) {
for i := 1; i <= 10; i++ {
wg.Add(1)
go func(j int) {
for k := 0; k < 10; k++ {
for k := range 10 {
newVal := int64(k + j)
_, err := scratch.Add(key, newVal)
+3 -3
View File
@@ -42,7 +42,7 @@ func TestPara(t *testing.T) {
c.Run("Order", func(c *qt.C) {
n := 500
ints := make([]int, n)
for i := 0; i < n; i++ {
for i := range n {
ints[i] = i
}
@@ -51,7 +51,7 @@ func TestPara(t *testing.T) {
var result []int
var mu sync.Mutex
for i := 0; i < n; i++ {
for i := range n {
i := i
r.Run(func() error {
mu.Lock()
@@ -78,7 +78,7 @@ func TestPara(t *testing.T) {
var counter int64
for i := 0; i < n; i++ {
for range n {
r.Run(func() error {
atomic.AddInt64(&counter, 1)
time.Sleep(1 * time.Millisecond)
+2
View File
@@ -165,6 +165,7 @@ func TestParse(t *testing.T) {
c.Assert(p.Identifiers(), qt.DeepEquals, []string{"txt", "no"})
c.Assert(p.Base(), qt.Equals, "/a/b.a.b.txt")
c.Assert(p.BaseNoLeadingSlash(), qt.Equals, "a/b.a.b.txt")
c.Assert(p.Path(), qt.Equals, "/a/b.a.b.no.txt")
c.Assert(p.PathNoLang(), qt.Equals, "/a/b.a.b.txt")
c.Assert(p.Ext(), qt.Equals, "txt")
c.Assert(p.PathNoIdentifier(), qt.Equals, "/a/b.a.b")
@@ -220,6 +221,7 @@ func TestParse(t *testing.T) {
c.Assert(p.NameNoExt(), qt.Equals, "index.no")
c.Assert(p.NameNoIdentifier(), qt.Equals, "index")
c.Assert(p.NameNoLang(), qt.Equals, "index.md")
c.Assert(p.Path(), qt.Equals, "/a/b/index.no.md")
c.Assert(p.PathNoLang(), qt.Equals, "/a/b/index.md")
c.Assert(p.Section(), qt.Equals, "a")
},
+1 -1
View File
@@ -51,7 +51,7 @@ func Run[T any](ctx context.Context, cfg Config[T]) Group[T] {
// Buffered for performance.
ch := make(chan T, cfg.NumWorkers)
for i := 0; i < cfg.NumWorkers; i++ {
for range cfg.NumWorkers {
g.Go(func() error {
for {
select {
+1 -4
View File
@@ -103,10 +103,7 @@ func (r *RunEvery) Add(name string, f Func) {
f.IntervalHigh = 20 * time.Second
}
start := f.IntervalHigh / 3
if start < f.IntervalLow {
start = f.IntervalLow
}
start := max(f.IntervalHigh/3, f.IntervalLow)
f.interval = start
f.last = time.Now()
+1 -1
View File
@@ -69,7 +69,7 @@ func ToStringSlicePreserveStringE(v any) ([]string, error) {
switch vv.Kind() {
case reflect.Slice, reflect.Array:
result = make([]string, vv.Len())
for i := 0; i < vv.Len(); i++ {
for i := range vv.Len() {
s, err := cast.ToStringE(vv.Index(i).Interface())
if err != nil {
return nil, err
+2 -1
View File
@@ -15,6 +15,7 @@
package types
import (
"slices"
"sync"
)
@@ -45,7 +46,7 @@ func (q *EvictingQueue[T]) Add(v T) *EvictingQueue[T] {
if len(q.set) == q.size {
// Full
delete(q.set, q.vals[0])
q.vals = append(q.vals[:0], q.vals[1:]...)
q.vals = slices.Delete(q.vals, 0, 1)
}
q.set[v] = true
q.vals = append(q.vals, v)
+1 -1
View File
@@ -55,7 +55,7 @@ func TestEvictingStringQueueConcurrent(t *testing.T) {
queue := NewEvictingQueue[string](3)
for j := 0; j < 100; j++ {
for range 100 {
wg.Add(1)
go func() {
defer wg.Done()
+1 -1
View File
@@ -59,7 +59,7 @@ func (k KeyValues) String() string {
// KeyValues struct.
func NewKeyValuesStrings(key string, values ...string) KeyValues {
iv := make([]any, len(values))
for i := 0; i < len(values); i++ {
for i := range values {
iv[i] = values[i]
}
return KeyValues{Key: key, Values: iv}
+14 -4
View File
@@ -82,7 +82,7 @@ func init() {
}
configLanguageKeys = make(map[string]bool)
addKeys := func(v reflect.Value) {
for i := 0; i < v.NumField(); i++ {
for i := range v.NumField() {
name := strings.ToLower(v.Type().Field(i).Name)
if skip[name] {
continue
@@ -128,6 +128,9 @@ type Config struct {
// <docsmeta>{"identifiers": ["markup"] }</docsmeta>
Markup markup_config.Config `mapstructure:"-"`
// ContentTypes are the media types that's considered content in Hugo.
ContentTypes *config.ConfigNamespace[map[string]media.ContentTypeConfig, media.ContentTypes] `mapstructure:"-"`
// The mediatypes configuration section maps the MIME type (a string) to a configuration object for that type.
// <docsmeta>{"identifiers": ["mediatypes"], "refs": ["types:media:type"] }</docsmeta>
MediaTypes *config.ConfigNamespace[map[string]media.MediaTypeConfig, media.Types] `mapstructure:"-"`
@@ -424,6 +427,15 @@ func (c *Config) CompileConfig(logger loggers.Logger) error {
c.Services.X.DisableInlineCSS = c.Services.Twitter.DisableInlineCSS
}
// Legacy permalink tokens
vs := fmt.Sprintf("%v", c.Permalinks)
if strings.Contains(vs, ":filename") {
hugo.Deprecate("the \":filename\" permalink token", "Use \":contentbasename\" instead.", "0.144.0")
}
if strings.Contains(vs, ":slugorfilename") {
hugo.Deprecate("the \":slugorfilename\" permalink token", "Use \":slugorcontentbasename\" instead.", "0.144.0")
}
c.C = &ConfigCompiled{
Timeout: timeout,
BaseURL: baseURL,
@@ -433,7 +445,6 @@ func (c *Config) CompileConfig(logger loggers.Logger) error {
IgnoredLogs: ignoredLogIDs,
KindOutputFormats: kindOutputFormats,
DefaultOutputFormat: defaultOutputFormat,
ContentTypes: media.DefaultContentTypes.FromTypes(c.MediaTypes.Config),
CreateTitle: helpers.GetTitleFunc(c.TitleCaseStyle),
IsUglyURLSection: isUglyURL,
IgnoreFile: ignoreFile,
@@ -471,7 +482,6 @@ type ConfigCompiled struct {
ServerInterface string
KindOutputFormats map[string]output.Formats
DefaultOutputFormat output.Format
ContentTypes media.ContentTypes
DisabledKinds map[string]bool
DisabledLanguages map[string]bool
IgnoredLogs map[string]bool
@@ -839,7 +849,7 @@ func (c *Configs) Init() error {
c.Languages = languages
c.LanguagesDefaultFirst = languagesDefaultFirst
c.ContentPathParser = &paths.PathParser{LanguageIndex: languagesDefaultFirst.AsIndexSet(), IsLangDisabled: c.Base.IsLangDisabled, IsContentExt: c.Base.C.ContentTypes.IsContentSuffix}
c.ContentPathParser = &paths.PathParser{LanguageIndex: languagesDefaultFirst.AsIndexSet(), IsLangDisabled: c.Base.IsLangDisabled, IsContentExt: c.Base.ContentTypes.Config.IsContentSuffix}
c.configLangs = make([]config.AllProvider, len(c.Languages))
for i, l := range c.LanguagesDefaultFirst {
+20 -1
View File
@@ -7,6 +7,7 @@ import (
qt "github.com/frankban/quicktest"
"github.com/gohugoio/hugo/config/allconfig"
"github.com/gohugoio/hugo/hugolib"
"github.com/gohugoio/hugo/media"
)
func TestDirsMount(t *testing.T) {
@@ -97,7 +98,7 @@ suffixes = ["html", "xhtml"]
b := hugolib.Test(t, files)
conf := b.H.Configs.Base
contentTypes := conf.C.ContentTypes
contentTypes := conf.ContentTypes.Config
b.Assert(contentTypes.HTML.Suffixes(), qt.DeepEquals, []string{"html", "xhtml"})
b.Assert(contentTypes.Markdown.Suffixes(), qt.DeepEquals, []string{"md", "mdown", "markdown"})
@@ -215,3 +216,21 @@ weight = 3
b := hugolib.Test(t, files)
b.Assert(b.H.Configs.LanguageConfigSlice[0].Title, qt.Equals, `TITLE_DE`)
}
func TestContentTypesDefault(t *testing.T) {
files := `
-- hugo.toml --
baseURL = "https://example.com"
`
b := hugolib.Test(t, files)
ct := b.H.Configs.Base.ContentTypes
c := ct.Config
s := ct.SourceStructure.(map[string]media.ContentTypeConfig)
b.Assert(c.IsContentFile("foo.md"), qt.Equals, true)
b.Assert(len(s), qt.Equals, 6)
}
+9
View File
@@ -163,6 +163,15 @@ var allDecoderSetups = map[string]decodeWeight{
return err
},
},
"contenttypes": {
key: "contenttypes",
weight: 100, // This needs to be decoded after media types.
decode: func(d decodeWeight, p decodeConfig) error {
var err error
p.c.ContentTypes, err = media.DecodeContentTypes(p.p.GetStringMap(d.key), p.c.MediaTypes.Config)
return err
},
},
"mediatypes": {
key: "mediatypes",
decode: func(d decodeWeight, p decodeConfig) error {
+1 -1
View File
@@ -145,7 +145,7 @@ func (c ConfigLanguage) NewIdentityManager(name string, opts ...identity.Manager
}
func (c ConfigLanguage) ContentTypes() config.ContentTypesProvider {
return c.config.C.ContentTypes
return c.config.ContentTypes.Config
}
// GetConfigSection is mostly used in tests. The switch statement isn't complete, but what's in use.
+2 -2
View File
@@ -91,7 +91,7 @@ func LoadConfig(d ConfigSourceDescriptor) (*Configs, error) {
return nil, fmt.Errorf("failed to init config: %w", err)
}
loggers.InitGlobalLogger(d.Logger.Level(), configs.Base.PanicOnWarning)
loggers.SetGlobalLogger(d.Logger)
return configs, nil
}
@@ -305,7 +305,7 @@ func (l configLoader) applyOsEnvOverrides(environ []string) error {
_, ok := allDecoderSetups[key]
if ok {
// A map.
if v, err := metadecoders.Default.UnmarshalStringTo(env.Value, map[string]interface{}{}); err == nil {
if v, err := metadecoders.Default.UnmarshalStringTo(env.Value, map[string]any{}); err == nil {
val = v
}
}
+96 -24
View File
@@ -15,6 +15,7 @@ package config
import (
"fmt"
"net/http"
"regexp"
"sort"
"strings"
@@ -27,6 +28,7 @@ import (
"github.com/gohugoio/hugo/common/herrors"
"github.com/mitchellh/mapstructure"
"github.com/spf13/cast"
"slices"
)
type BaseConfig struct {
@@ -127,7 +129,7 @@ func (w BuildStats) Enabled() bool {
}
func (b BuildConfig) clone() BuildConfig {
b.CacheBusters = append([]CacheBuster{}, b.CacheBusters...)
b.CacheBusters = slices.Clone(b.CacheBusters)
return b
}
@@ -226,7 +228,22 @@ type Server struct {
Redirects []Redirect
compiledHeaders []glob.Glob
compiledRedirects []glob.Glob
compiledRedirects []redirect
}
type redirect struct {
from glob.Glob
fromRe *regexp.Regexp
headers map[string]glob.Glob
}
func (r redirect) matchHeader(header http.Header) bool {
for k, v := range r.headers {
if !v.Match(header.Get(k)) {
return false
}
}
return true
}
func (s *Server) CompileConfig(logger loggers.Logger) error {
@@ -234,10 +251,41 @@ func (s *Server) CompileConfig(logger loggers.Logger) error {
return nil
}
for _, h := range s.Headers {
s.compiledHeaders = append(s.compiledHeaders, glob.MustCompile(h.For))
g, err := glob.Compile(h.For)
if err != nil {
return fmt.Errorf("failed to compile Headers glob %q: %w", h.For, err)
}
s.compiledHeaders = append(s.compiledHeaders, g)
}
for _, r := range s.Redirects {
s.compiledRedirects = append(s.compiledRedirects, glob.MustCompile(r.From))
if r.From == "" && r.FromRe == "" {
return fmt.Errorf("redirects must have either From or FromRe set")
}
rd := redirect{
headers: make(map[string]glob.Glob),
}
if r.From != "" {
g, err := glob.Compile(r.From)
if err != nil {
return fmt.Errorf("failed to compile Redirect glob %q: %w", r.From, err)
}
rd.from = g
}
if r.FromRe != "" {
re, err := regexp.Compile(r.FromRe)
if err != nil {
return fmt.Errorf("failed to compile Redirect regexp %q: %w", r.FromRe, err)
}
rd.fromRe = re
}
for k, v := range r.FromHeaders {
g, err := glob.Compile(v)
if err != nil {
return fmt.Errorf("failed to compile Redirect header glob %q: %w", v, err)
}
rd.headers[k] = g
}
s.compiledRedirects = append(s.compiledRedirects, rd)
}
return nil
@@ -266,22 +314,42 @@ func (s *Server) MatchHeaders(pattern string) []types.KeyValueStr {
return matches
}
func (s *Server) MatchRedirect(pattern string) Redirect {
func (s *Server) MatchRedirect(pattern string, header http.Header) Redirect {
if s.compiledRedirects == nil {
return Redirect{}
}
pattern = strings.TrimSuffix(pattern, "index.html")
for i, g := range s.compiledRedirects {
for i, r := range s.compiledRedirects {
redir := s.Redirects[i]
// No redirect to self.
if redir.To == pattern {
return Redirect{}
var found bool
if r.from != nil {
if r.from.Match(pattern) {
found = header == nil || r.matchHeader(header)
// We need to do regexp group replacements if needed.
}
}
if g.Match(pattern) {
if r.fromRe != nil {
m := r.fromRe.FindStringSubmatch(pattern)
if m != nil {
if !found {
found = header == nil || r.matchHeader(header)
}
if found {
// Replace $1, $2 etc. in To.
for i, g := range m[1:] {
redir.To = strings.ReplaceAll(redir.To, fmt.Sprintf("$%d", i+1), g)
}
}
}
}
if found {
return redir
}
}
@@ -295,8 +363,22 @@ type Headers struct {
}
type Redirect struct {
// From is the Glob pattern to match.
// One of From or FromRe must be set.
From string
To string
// FromRe is the regexp to match.
// This regexp can contain group matches (e.g. $1) that can be used in the To field.
// One of From or FromRe must be set.
FromRe string
// To is the target URL.
To string
// Headers to match for the redirect.
// This maps the HTTP header name to a Glob pattern with values to match.
// If the map is empty, the redirect will always be triggered.
FromHeaders map[string]string
// HTTP status code to use for the redirect.
// A status code of 200 will trigger a URL rewrite.
@@ -369,7 +451,7 @@ func (c *CacheBuster) CompileConfig(logger loggers.Logger) error {
}
func (r Redirect) IsZero() bool {
return r.From == ""
return r.From == "" && r.FromRe == ""
}
const (
@@ -383,17 +465,7 @@ func DecodeServer(cfg Provider) (Server, error) {
_ = mapstructure.WeakDecode(cfg.GetStringMap("server"), s)
for i, redir := range s.Redirects {
// Get it in line with the Hugo server for OK responses.
// We currently treat the 404 as a special case, they are always "ugly", so keep them as is.
if redir.Status != 404 {
redir.To = strings.TrimSuffix(redir.To, "index.html")
if !strings.HasPrefix(redir.To, "https") && !strings.HasSuffix(redir.To, "/") {
// There are some tricky infinite loop situations when dealing
// when the target does not have a trailing slash.
// This can certainly be handled better, but not time for that now.
return Server{}, fmt.Errorf("unsupported redirect to value %q in server config; currently this must be either a remote destination or a local folder, e.g. \"/blog/\" or \"/blog/index.html\"", redir.To)
}
}
redir.To = strings.TrimSuffix(redir.To, "index.html")
s.Redirects[i] = redir
}
@@ -401,7 +473,7 @@ func DecodeServer(cfg Provider) (Server, error) {
// Set up a default redirect for 404s.
s.Redirects = []Redirect{
{
From: "**",
From: "/**",
To: "/404.html",
Status: 404,
},
+42 -36
View File
@@ -71,7 +71,28 @@ X-Content-Type-Options = "nosniff"
[[server.redirects]]
from = "/foo/**"
to = "/foo/index.html"
to = "/baz/index.html"
status = 200
[[server.redirects]]
from = "/loop/**"
to = "/loop/foo/"
status = 200
[[server.redirects]]
from = "/b/**"
fromRe = "/b/(.*)/"
to = "/baz/$1/"
status = 200
[[server.redirects]]
fromRe = "/c/(.*)/"
to = "/boo/$1/"
status = 200
[[server.redirects]]
fromRe = "/d/(.*)/"
to = "/boo/$1/"
status = 200
[[server.redirects]]
@@ -79,11 +100,6 @@ from = "/google/**"
to = "https://google.com/"
status = 301
[[server.redirects]]
from = "/**"
to = "/default/index.html"
status = 301
`, "toml")
@@ -100,45 +116,35 @@ status = 301
{Key: "X-XSS-Protection", Value: "1; mode=block"},
})
c.Assert(s.MatchRedirect("/foo/bar/baz"), qt.DeepEquals, Redirect{
c.Assert(s.MatchRedirect("/foo/bar/baz", nil), qt.DeepEquals, Redirect{
From: "/foo/**",
To: "/foo/",
To: "/baz/",
Status: 200,
})
c.Assert(s.MatchRedirect("/someother"), qt.DeepEquals, Redirect{
From: "/**",
To: "/default/",
Status: 301,
c.Assert(s.MatchRedirect("/foo/bar/", nil), qt.DeepEquals, Redirect{
From: "/foo/**",
To: "/baz/",
Status: 200,
})
c.Assert(s.MatchRedirect("/google/foo"), qt.DeepEquals, Redirect{
c.Assert(s.MatchRedirect("/b/c/", nil), qt.DeepEquals, Redirect{
From: "/b/**",
FromRe: "/b/(.*)/",
To: "/baz/c/",
Status: 200,
})
c.Assert(s.MatchRedirect("/c/d/", nil).To, qt.Equals, "/boo/d/")
c.Assert(s.MatchRedirect("/c/d/e/", nil).To, qt.Equals, "/boo/d/e/")
c.Assert(s.MatchRedirect("/someother", nil), qt.DeepEquals, Redirect{})
c.Assert(s.MatchRedirect("/google/foo", nil), qt.DeepEquals, Redirect{
From: "/google/**",
To: "https://google.com/",
Status: 301,
})
// No redirect loop, please.
c.Assert(s.MatchRedirect("/default/index.html"), qt.DeepEquals, Redirect{})
c.Assert(s.MatchRedirect("/default/"), qt.DeepEquals, Redirect{})
for _, errorCase := range []string{
`[[server.redirects]]
from = "/**"
to = "/file"
status = 301`,
`[[server.redirects]]
from = "/**"
to = "/foo/file.html"
status = 301`,
} {
cfg, err := FromConfigString(errorCase, "toml")
c.Assert(err, qt.IsNil)
_, err = DecodeServer(cfg)
c.Assert(err, qt.Not(qt.IsNil))
}
}
func TestBuildConfigCacheBusters(t *testing.T) {
@@ -160,7 +166,7 @@ func TestBuildConfigCacheBusters(t *testing.T) {
func TestBuildConfigCacheBusterstTailwindSetup(t *testing.T) {
c := qt.New(t)
cfg := New()
cfg.Set("build", map[string]interface{}{
cfg.Set("build", map[string]any{
"cacheBusters": []map[string]string{
{
"source": "assets/watching/hugo_stats\\.json",
+1 -38
View File
@@ -15,7 +15,6 @@ package config
import (
"fmt"
"sort"
"strings"
"sync"
@@ -26,42 +25,6 @@ import (
"github.com/gohugoio/hugo/common/maps"
)
var (
// ConfigRootKeysSet contains all of the config map root keys.
ConfigRootKeysSet = map[string]bool{
"build": true,
"caches": true,
"cascade": true,
"frontmatter": true,
"languages": true,
"imaging": true,
"markup": true,
"mediatypes": true,
"menus": true,
"minify": true,
"module": true,
"outputformats": true,
"params": true,
"permalinks": true,
"related": true,
"sitemap": true,
"privacy": true,
"security": true,
"taxonomies": true,
}
// ConfigRootKeys is a sorted version of ConfigRootKeysSet.
ConfigRootKeys []string
)
func init() {
for k := range ConfigRootKeysSet {
ConfigRootKeys = append(ConfigRootKeys, k)
}
sort.Strings(ConfigRootKeys)
}
// New creates a Provider backed by an empty maps.Params.
func New() Provider {
return &defaultConfigProvider{
@@ -382,7 +345,7 @@ func (c *defaultConfigProvider) getNestedKeyAndMap(key string, create bool) (str
c.keyCache.Store(key, parts)
}
current := c.root
for i := 0; i < len(parts)-1; i++ {
for i := range len(parts) - 1 {
next, found := current[parts[i]]
if !found {
if create {
+1 -1
View File
@@ -332,7 +332,7 @@ func TestDefaultConfigProvider(t *testing.T) {
return nil
}
for i := 0; i < 20; i++ {
for i := range 20 {
i := i
r.Run(func() error {
const v = 42
+2 -2
View File
@@ -29,7 +29,7 @@ func TestNamespace(t *testing.T) {
// ns, err := config.DecodeNamespace[map[string]DocsMediaTypeConfig](in, defaultMediaTypesConfig, buildConfig)
ns, err := DecodeNamespace[[]*tstNsExt](
map[string]interface{}{"foo": "bar"},
map[string]any{"foo": "bar"},
func(v any) (*tstNsExt, any, error) {
t := &tstNsExt{}
m, err := maps.ToStringMapE(v)
@@ -42,7 +42,7 @@ func TestNamespace(t *testing.T) {
c.Assert(err, qt.IsNil)
c.Assert(ns, qt.Not(qt.IsNil))
c.Assert(ns.SourceStructure, qt.DeepEquals, map[string]interface{}{"foo": "bar"})
c.Assert(ns.SourceStructure, qt.DeepEquals, map[string]any{"foo": "bar"})
c.Assert(ns.SourceHash, qt.Equals, "1420f6c7782f7459")
c.Assert(ns.Config, qt.DeepEquals, &tstNsExt{Foo: "bar"})
c.Assert(ns.Signature(), qt.DeepEquals, []*tstNsExt(nil))
+2 -6
View File
@@ -36,10 +36,6 @@ respectDoNotTrack = true
[privacy.instagram]
disable = true
simple = true
[privacy.twitter]
disable = true
enableDNT = true
simple = true
[privacy.x]
disable = true
enableDNT = true
@@ -63,8 +59,8 @@ simple = true
got := []bool{
pc.Disqus.Disable, pc.GoogleAnalytics.Disable,
pc.GoogleAnalytics.RespectDoNotTrack, pc.Instagram.Disable,
pc.Instagram.Simple, pc.Twitter.Disable, pc.Twitter.EnableDNT,
pc.Twitter.Simple, pc.Vimeo.Disable, pc.Vimeo.EnableDNT, pc.Vimeo.Simple,
pc.Instagram.Simple,
pc.Vimeo.Disable, pc.Vimeo.EnableDNT, pc.Vimeo.Simple,
pc.YouTube.PrivacyEnhanced, pc.YouTube.Disable, pc.X.Disable, pc.X.EnableDNT,
pc.X.Simple,
}
+1 -1
View File
@@ -73,7 +73,7 @@ func NewWhitelist(patterns ...string) (Whitelist, error) {
var patternsr []*regexp.Regexp
for i := 0; i < len(patterns); i++ {
for i := range patterns {
p := strings.TrimSpace(patterns[i])
if p == "" {
continue
+1 -1
View File
@@ -129,7 +129,7 @@ site RegularPages: {{ len site.RegularPages }}
`
c.Assert(afero.WriteFile(mm, filepath.Join(archetypeDir, "index.md"), []byte(fmt.Sprintf(contentFile, "index.md")), 0o755), qt.IsNil)
c.Assert(afero.WriteFile(mm, filepath.Join(archetypeDir, "index.md"), fmt.Appendf(nil, contentFile, "index.md"), 0o755), qt.IsNil)
c.Assert(afero.WriteFile(mm, filepath.Join(defaultArchetypeDir, "index.md"), []byte("default archetype index.md"), 0o755), qt.IsNil)
c.Assert(initFs(mm), qt.IsNil)
-1
View File
@@ -12,7 +12,6 @@
// limitations under the License.
//go:build withdeploy
// +build withdeploy
package deploy
-1
View File
@@ -12,7 +12,6 @@
// limitations under the License.
//go:build withdeploy
// +build withdeploy
package deploy
-1
View File
@@ -12,7 +12,6 @@
// limitations under the License.
//go:build !solaris && withdeploy
// +build !solaris,withdeploy
package deploy
-1
View File
@@ -12,7 +12,6 @@
// limitations under the License.
//go:build withdeploy
// +build withdeploy
package deploy
-1
View File
@@ -12,7 +12,6 @@
// limitations under the License.
//go:build withdeploy
// +build withdeploy
package deployconfig
-1
View File
@@ -12,7 +12,6 @@
// limitations under the License.
//go:build withdeploy
// +build withdeploy
package deploy
+13
View File
@@ -0,0 +1,13 @@
# Config file for codespell.
# https://github.com/codespell-project/codespell#using-a-config-file
[codespell]
# Comma separated list of dirs to be skipped.
skip = _vendor,.cspell.json,chroma.css,chroma_dark.css
# Comma separated list of words to be ignored. Words must be lowercased.
ignore-words-list = abl,edn,te,ue,trys,januar,womens,crossreferences
# Check file names as well.
check-filenames = true
+5
View File
@@ -68,6 +68,7 @@
"# ----------------------------------------------------------------------",
"# cspell: ignore hugo terminology",
"# ----------------------------------------------------------------------",
"alignx",
"attrlink",
"canonify",
"codeowners",
@@ -85,6 +86,7 @@
"stringifier",
"struct",
"toclevels",
"unmarshal",
"unpublishdate",
"zgotmplz",
"# ----------------------------------------------------------------------",
@@ -158,6 +160,8 @@
"# cspell: ignore miscellaneous",
"# ----------------------------------------------------------------------",
"achristie",
"ccpa",
"crpa",
"ddmaurier",
"dring",
"fleqn",
@@ -171,6 +175,7 @@
"rsmith",
"tdewolff",
"tjones",
"vcard",
"wcag",
"xfeff"
]
+1
View File
@@ -0,0 +1 @@
blank_issues_enabled: false
+6
View File
@@ -0,0 +1,6 @@
---
name: Default
about: This is the default issue template.
labels:
- NeedsTriage
---
+5
View File
@@ -20,3 +20,8 @@ jobs:
incremental_files_only: true
inline: warning
strict: false
- uses: codespell-project/actions-codespell@v2
with:
check_filenames: true
check_hidden: true
# by default, codespell uses configuration from the .codespellrc
+9 -6
View File
@@ -1,10 +1,13 @@
.DS_Store
.hugo_build.lock
/.idea
/.vscode
/public
/dist
node_modules
/public
hugo_stats.json
node_modules/
nohup.out
.DS_Store
trace.out
.hugo_build.lock
resources/_gen/images/
package-lock.json
public/
resources/
trace.out
+2 -200
View File
@@ -1,201 +1,3 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
See [content/LICENSE.md](content/LICENSE.md) for the license of the content of this repository.
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.
The theme (layouts, CSS, JavaScript etc.) of this repository has no open source license. It is custom made for the Hugo sites and is not meant for reuse.
+9
View File
@@ -16,3 +16,12 @@ Please see the [contributing] section for guidelines, examples, and process.
[friends]: https://github.com/gohugoio/hugo/graphs/contributors
[go]: https://go.dev/
[contributing]: https://gohugo.io/contribute/documentation
# Install
```bash
npm i
hugo server
```
**Note:** We're working on removing the need to run `npm i` for local development. Stay tuned.
File diff suppressed because one or more lines are too long
@@ -1,21 +0,0 @@
.animated {
animation-duration: .5s;
animation-fill-mode: forwards;
animation-timing-function: ease-in-out;
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.fadeIn {
animation-name: fadeIn;
}
.animated-delay-1 {
animation-delay: 0.5s;
}
@@ -1,25 +0,0 @@
/* These styles enhance the home page carousel, located here: themes/gohugoioTheme/layouts/partials/home-page-sections/showcase.html */
.overflow-x-scroll{
-webkit-overflow-scrolling: touch;
}
.row {
transition: 450ms transform;
font-size: 0;
}
.tile {
transition: 450ms all;
}
.details {
background: -webkit-gradient(linear, left bottom, left top, from(rgba(0,0,0,0.9)), to(rgba(0,0,0,0)));
background: linear-gradient(to top, rgba(0,0,0,0.9) 0%, rgba(0,0,0,0) 100%);
transition: 450ms opacity;
}
.tile:hover .details {
opacity: 1;
}
.row:hover .tile {
opacity: 0.3;
}
.row:hover .tile:hover {
opacity: 1;
}
@@ -1,89 +0,0 @@
.chroma .lntable pre {
padding: 0;
margin: 0;
border: 0;
}
.chroma .lntable pre code {
padding: 0;
margin: 0;
}
code {
padding: 2px 3px;
margin: 0;
font-size: 93.75%;
background-color: rgba(27,31,35,0.05);
border-radius: 3px;
}
pre code {
display: block;
padding: 1.5em 1.5em;
font-size: .875rem;
line-height: 2;
overflow-x: auto;
}
pre {
background-color: #fff;
color: #333;
white-space: pre;
hyphens: none;
position: relative;
border-width: 1px;
border-color: #ccc;
border-style: solid;
}
/* The Pygments highlighter comes with its own styles. */
.highlight pre {
background-color: inherit;
color: inherit;
padding: 0.5em;
font-size: .875rem;
}
/*We are adding the copy button content here so we can change it with javascript. See the "Clipboard scripts"*/
.copy:after {
content: "Copy"
}
.copied:after {
content: "Copied"
}
@media (--breakpoint-large) {
.full-width
{
/*width: 100vw;
position: relative;
left: 50%;
right: 50%;
margin-left: -50vw;
margin-right: -50vw;*/
/*width: 60vw;*/
/*position: relative;
left: 50%;
right: 50%;*/
/*margin-left: -30vw;*/
margin-right: -30vw;
max-width: 100vw;
}
}
.code-block .line-numbers-rows {
background: #2f3a46;
border: none;
bottom: -50px;
color: #98a4b3;
left: -178px;
padding: 50px 0;
top: -50px;
width: 138px
}
.code-block .line-numbers-rows>span:before {
color: inherit;
padding-right: 30px
}
@@ -1,38 +0,0 @@
.primary-color {color: var(--primary-color)}
.bg-primary-color {background-color: var(--primary-color)}
.hover-bg-primary-color:hover {background-color: var(--primary-color)}
.primary-color-dark {color: var(--primary-color-dark)}
.bg-primary-color-dark {background-color: var(--primary-color-dark)}
.hover-bg-primary-color-dark:hover {background-color: var(--primary-color-dark)}
.primary-color-light {color: var(--primary-color-light)}
.bg-primary-color-light {background-color: var(--primary-color-light)}
.hover-bg-primary-color-light:hover {background-color: var(--primary-color-light)}
.accent-color {color: var(--accent-color)}
.bg-accent-color {background-color: var(--accent-color)}
.hover-bg-accent-color:hover {background-color: var(--accent-color)}
.accent-color-light {color: var(--accent-color-light)}
.hover-accent-color-light:hover {color: var(--accent-color-light)}
.bg-accent-color-light {background-color: var(--accent-color-light)}
.hover-bg-accent-color-light:hover {background-color: var(--accent-color-light)}
.accent-color-dark {color: var(--accent-color-dark)}
.bg-accent-color-dark {background-color: var(--accent-color-dark)}
.hover-bg-accent-color-dark:hover {background-color: var(--accent-color-dark)}
.text-color-primary {color: var(--text-color-primary)}
.text-on-primary-color {color: var(--text-on-primary-color)}
.text-color-secondary {color: var(--text-color-secondary)}
.text-color-disabled {color: var(--text-color-disabled)}
.divider-color {color: var(--divider-color)}
.warn-color {color: var(--warn-color)}
.nested-links a {
color: var(--primary-color);
text-decoration: none;
}
@@ -1,11 +0,0 @@
.column-count-2 {column-count: 1}
.column-gap-1 {column-gap: 0}
.break-inside-avoid {break-inside: auto}
@media (--breakpoint-large) {
.column-count-3-l {column-count: 3}
.column-count-2-l {column-count: 2}
.column-gap-1-l {column-gap: 1}
.break-inside-avoid-l {break-inside: avoid}
}
@@ -1,28 +0,0 @@
.prose table {
width: 100%;
margin-bottom: 3em;
border-collapse: collapse;
border-spacing: 0;
font-size: 1em;
border: 1px solid var(--light-gray);
& th {
background-color: var(--primary-color);
border-bottom: 1px solid var(--primary-color);
color: white;
font-weight: 400;
text-align: left;
padding: .375em .5em;
}
& td, & tc {
padding: .75em .5em;
text-align: left;
border-right: 1px solid var(--light-gray);
}
}
.prose table tr:nth-child(even) {
background-color: var(--light-gray);
}
@@ -1,53 +0,0 @@
.prose ul, .prose ol {
margin-bottom: 2em;
}
.prose ul li, .prose ol li {
margin-bottom: .5em;
}
.prose li:hover {
background-color: var(--light-gray)
}
.prose ::selection {
background: var(--primary-color); /* WebKit/Blink Browsers */
color: white;
}
.prose-glossary h3 {
margin-top: 0;
font-size: 1.125rem;
}
.prose-glossary h3:first-of-type {
margin-top: 3em;
}
.prose-glossary h3 ~ p {
margin: 0.5em 0 2em 0;
}
body {
line-height: 1.45;
}
p {margin-bottom: 1.3em;}
h1, h2, h3, h4 {
margin: 1.414em 0 0.5em;
line-height: 1.2;
}
h1 {
margin-top: 0;
font-size: 2.441em;
}
h2 {font-size: 1.953em;}
h3 {font-size: 1.563em;}
h4 {font-size: 1.25em;}
small, .font_small {font-size: 0.8em;}
@@ -1,9 +0,0 @@
dl dt {
font-weight: bold;
font-size: 1.125rem;
}
dd {
margin: .5em 0 2em 0;
padding: 0;
}
@@ -1,54 +0,0 @@
.note,
.warning {
border-left-width: 4px;
border-left-style: solid;
position: relative;
border-color: var(--primary-color);
display: block;
}
.note #exclamation-icon,
.warning #exclamation-icon {
fill: var(--primary-color);
position: absolute;
top: 35%;
left: -12px;
/*background-color: white;*/
}
.admonition-content {
display: block;
margin: 0px;
padding: .125em 1em;
/*margin-left: 1em;*/
margin-top: 2em;
margin-bottom: 2em;
overflow-x: auto;
/*font-size: .9375em;*/
background-color: var(--black-05);
}
.hide-child-menu .child-menu {
display: none;
}
.hide-child-menu:hover .child-menu,
.hide-child-menu:focus .child-menu,
.hide-child-menu:active .child-menu {
display: block;
}
/*documentation-copy headings exaggerate spacing and size to chunk content */
.documentation-copy h2 {
margin-top: 3em;
&.minor {
font-size: inherit;
margin-top: inherit;
border-bottom: none;
}
}
@@ -1,10 +0,0 @@
.f2-fluid {
font-size: 2.25rem;
}
@media (--breakpoint-large) {
.f2-fluid {
font-size: 1.25rem;
font-size: calc(0.875rem + 0.5 * ((100vw - 20rem) / 60));
}
}
@@ -1,74 +0,0 @@
/* From https://www.cssfontstack.com */
code, .code, pre code, .highlight pre {
font-family: 'inconsolata',Menlo,Monaco,'Courier New',monospace;
}
.sans-serif {
font-family: 'Muli', Avenir, 'Helvetica Neue', Helvetica, Roboto, Noto, 'Segoe UI', Arial, sans-serif;
}
.serif {
font-family: Palatino,"Palatino Linotype","Palatino LT STD","Book Antiqua",Georgia,serif;
}
/* Monospaced Typefaces (for code) */
.courier {
font-family: 'Courier Next',
courier,
monospace;
}
/* Sans-Serif Typefaces */
.helvetica {
font-family: 'helvetica neue', helvetica,
sans-serif;
}
.avenir {
font-family: 'avenir next', avenir,
sans-serif;
}
/* Serif Typefaces */
.athelas {
font-family: athelas,
georgia,
serif;
}
.georgia {
font-family: georgia,
serif;
}
.times {
font-family: times,
serif;
}
.bodoni {
font-family: "Bodoni MT",
serif;
}
.calisto {
font-family: "Calisto MT",
serif;
}
.garamond {
font-family: garamond,
serif;
}
.baskerville {
font-family: baskerville,
serif;
}
@@ -1,15 +0,0 @@
.header-link:after {
position: relative;
left: 0.5em;
opacity: 0;
font-size: 0.8em;
-moz-transition: opacity 0.2s ease-in-out 0.1s;
-ms-transition: opacity 0.2s ease-in-out 0.1s;
}
h2:hover .header-link,
h3:hover .header-link,
h4:hover .header-link,
h5:hover .header-link,
h6:hover .header-link {
opacity: 1;
}
@@ -1,52 +0,0 @@
/* pagination.html: https://github.com/gohugoio/hugo/blob/master/tpl/tplimpl/template_embedded.go#L117 */
.pagination {
margin: 3rem 0;
}
.pagination li {
display: inline-block;
margin-right: .375rem;
font-size: .875rem;
margin-bottom: 2.5em;
}
.pagination li a {
padding: .5rem .625rem;
background-color: white;
color: #333;
border: 1px solid #ddd;
border-radius: 3px;
text-decoration: none;
}
.pagination li.disabled {
display: none;
}
.pagination li.active a:link,
.pagination li.active a:active,
.pagination li.active a:visited {
background-color: #ddd;
}
/* Hides non-meaningful TOC items*/
#TableOfContents ul li ul li ul li{
display: none;
}
#TableOfContents ul li {
color: black;
display: block;
margin-bottom: .375em;
line-height: 1.375;
}
#TableOfContents ul li a{
width: 100%;
padding: .25em .375em;
margin-left: -.375em;
}
#TableOfContents ul li a:hover {
background-color: #999;
color: white;
}
@@ -1,7 +0,0 @@
.no-js .needs-js {
opacity: 0
}
.js .needs-js {
opacity: 1;
transition: opacity .15s ease-in;
}
@@ -1,7 +0,0 @@
@media print {
#page-footer,
body > footer,
body > nav {
display: none;
}
}
@@ -1,11 +0,0 @@
#right-sidebar {
scrollbar-width: none; /* hide scrollbar: Firefox */
-ms-overflow-style: none; /* hide scrollbar: Internet Explorer 10+ */
height: calc(100vh - 9rem);
overflow-y: auto;
}
#right-sidebar::-webkit-scrollbar { /* hide scrollbar: WebKit */
width: 0;
height: 0;
}
@@ -1,25 +0,0 @@
/*
Make h6 elements behave like dt elements. Initially implemented to support
linkable glossary entries.
Yes, it's a hack. That's why it's in the shame file.
*/
h6 {
margin-top: 0;
margin-bottom: 0;
font-size: 1.125rem;
}
h6:first-of-type {
margin-top: 3em;
}
h6 ~ p {
margin: 0.5em 0 2em 0;
}
/* QR codes */
img.qrcode {
width: initial;
}
@@ -1,52 +0,0 @@
.facebook,
.twitter,
.instagram,
.youtube {
fill: #bababa;
}
.facebook:hover {
fill: #3b5998;
}
.twitter {
fill: #55acee;
}
.twitter:hover {
fill: #bababa;
}
.instagram:hover {
fill: #e95950;
}
.youtube:hover {
fill: #bb0000;
}
.mstdn {
display: inline-block;
background-color: #282c37;
color: #d9e1e8;
text-decoration: none;
padding: 4px 10px 4px 30px;
border-radius: 4px;
font-size: 16px;
background-image: url("data:image/svg+xml;charset=utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2261.076954mm%22%20height%3D%2265.47831mm%22%20viewBox%3D%220%200%20216.4144%20232.00976%22%3E%3Cpath%20d%3D%22M211.80734%20139.0875c-3.18125%2016.36625-28.4925%2034.2775-57.5625%2037.74875-15.15875%201.80875-30.08375%203.47125-45.99875%202.74125-26.0275-1.1925-46.565-6.2125-46.565-6.2125%200%202.53375.15625%204.94625.46875%207.2025%203.38375%2025.68625%2025.47%2027.225%2046.39125%2027.9425%2021.11625.7225%2039.91875-5.20625%2039.91875-5.20625l.8675%2019.09s-14.77%207.93125-41.08125%209.39c-14.50875.7975-32.52375-.365-53.50625-5.91875C9.23234%20213.82%201.40609%20165.31125.20859%20116.09125c-.365-14.61375-.14-28.39375-.14-39.91875%200-50.33%2032.97625-65.0825%2032.97625-65.0825C49.67234%203.45375%2078.20359.2425%20107.86484%200h.72875c29.66125.2425%2058.21125%203.45375%2074.8375%2011.09%200%200%2032.975%2014.7525%2032.975%2065.0825%200%200%20.41375%2037.13375-4.59875%2062.915%22%20fill%3D%22%233088d4%22%2F%3E%3Cpath%20d%3D%22M177.50984%2080.077v60.94125h-24.14375v-59.15c0-12.46875-5.24625-18.7975-15.74-18.7975-11.6025%200-17.4175%207.5075-17.4175%2022.3525v32.37625H96.20734V85.42325c0-14.845-5.81625-22.3525-17.41875-22.3525-10.49375%200-15.74%206.32875-15.74%2018.7975v59.15H38.90484V80.077c0-12.455%203.17125-22.3525%209.54125-29.675%206.56875-7.3225%2015.17125-11.07625%2025.85-11.07625%2012.355%200%2021.71125%204.74875%2027.8975%2014.2475l6.01375%2010.08125%206.015-10.08125c6.185-9.49875%2015.54125-14.2475%2027.8975-14.2475%2010.6775%200%2019.28%203.75375%2025.85%2011.07625%206.36875%207.3225%209.54%2017.22%209.54%2029.675%22%20fill%3D%22%23fff%22%2F%3E%3C%2Fsvg%3E");
background-size: 16px;
background-repeat: no-repeat;
background-position: top 50% left 8px;
transition: all 0.5s;
}
.mstdn:hover {
background-color: #484c56;
}
.mstdn > span {
color: #9baec8;
font-size: 12px;
padding-left: 3px;
}
.mstdn > span:before {
content: "@";
}
@@ -1,15 +0,0 @@
@media (min-width: 75em) {
[data-scrolldir="down"] .sticky {
position: fixed;
top:100px;
right:0;
}
[data-scrolldir="up"] .sticky {
position: fixed;
top:100px;
right:0;
}
}
@@ -1 +0,0 @@
.fill-current { fill: currentColor; }
@@ -1,34 +0,0 @@
.tab-button{
margin-bottom:1px;
position: relative;
z-index: 1;
color:#333;
border-color:#ccc;
outline: none;
background-color:white;
}
.tab-pane code{
background:#f1f2f2;
border-radius:0;
}
.tab-pane .chroma{
background:none;
padding:0;
}
.tab-button.active{
border-bottom-color:#f1f2f2;
background-color: #f1f2f2;
}
.tab-content .tab-pane{
display: none;
}
.tab-content .tab-pane.active{
display: block;
}
/* Treatment of copy buttons inside a tab module */
.tab-content .copy, .tab-content .copied{
display: none;
}
.tab-content .tab-pane.active + .copy, .tab-content .tab-pane.active + .copied{
display: block;
}
@@ -1,94 +0,0 @@
/*! TACHYONS v4.7.0 | http://tachyons.io */
/*
* NOTE: The Tachyons folder is for backup/reference only. This file references the module
* ________ ______
* ___ __/_____ _________ /______ ______________________
* __ / _ __ `/ ___/_ __ \_ / / / __ \_ __ \_ ___/
* _ / / /_/ // /__ _ / / / /_/ // /_/ / / / /(__ )
* /_/ \__,_/ \___/ /_/ /_/_\__, / \____//_/ /_//____/
* /____/
*
* TABLE OF CONTENTS
*
* 1. External Library Includes
* - Normalize.css | http://normalize.css.github.io
* 2. Tachyons Modules
* 3. Variables
* - Media Queries
* - Colors
* 4. Debugging
* - Debug all
* - Debug children
*
*/
/* External Library Includes */
@import 'tachyons/src/_normalize';
/* Modules */
@import 'tachyons/src/_box-sizing';
/*@import 'tachyons/src/_aspect-ratios';*/
@import 'tachyons/src/_images';
@import 'tachyons/src/_background-size';
@import 'tachyons/src/_background-position';
/*@import 'tachyons/src/_outlines';*/
@import 'tachyons/src/_borders';
@import 'tachyons/src/_border-colors';
@import 'tachyons/src/_border-radius';
@import 'tachyons/src/_border-style';
@import 'tachyons/src/_border-widths';
@import 'tachyons/src/_box-shadow';
/*@import 'tachyons/src/_code';*/
@import 'tachyons/src/_coordinates';
@import 'tachyons/src/_clears';
@import 'tachyons/src/_display';
@import 'tachyons/src/_flexbox';
@import 'tachyons/src/_floats';
/*@import 'tachyons/src/_font-family';*/
@import 'tachyons/src/_font-style';
@import 'tachyons/src/_font-weight';
@import 'tachyons/src/_forms';
@import 'tachyons/src/_heights';
@import 'tachyons/src/_letter-spacing';
@import 'tachyons/src/_line-height';
@import 'tachyons/src/_links';
@import 'tachyons/src/_lists';
@import 'tachyons/src/_max-widths';
@import 'tachyons/src/_widths';
@import 'tachyons/src/_overflow';
@import 'tachyons/src/_position';
@import 'tachyons/src/_opacity';
/*@import 'tachyons/src/_rotations';*/
@import 'tachyons/src/_skins';
@import 'tachyons/src/_skins-pseudo';
@import 'tachyons/src/_spacing';
@import 'tachyons/src/_negative-margins';
@import 'tachyons/src/_tables';
@import 'tachyons/src/_text-decoration';
@import 'tachyons/src/_text-align';
@import 'tachyons/src/_text-transform';
@import 'tachyons/src/_type-scale';
@import 'tachyons/src/_typography';
@import 'tachyons/src/_utilities';
@import 'tachyons/src/_visibility';
@import 'tachyons/src/_white-space';
@import 'tachyons/src/_vertical-align';
@import 'tachyons/src/_hovers';
@import 'tachyons/src/_z-index';
@import 'tachyons/src/_nested';
/*@import 'tachyons/src/_styles';*/
/* Variables */
/* Importing here will allow you to override any variables in the modules */
@import 'tachyons/src/_colors';
@import 'tachyons/src/_media-queries';
/* Debugging */
/*@import 'tachyons/src/_debug-children';
@import 'tachyons/src/_debug-grid';*/
/* Uncomment out the line below to help debug layout issues */
/* @import 'tachyons/src/_debug'; */
@@ -1,16 +0,0 @@
:root {
--primary-color: #0594CB;
--primary-color-dark: #0A1922;
--primary-color-light: #f9f9f9;
--accent-color: #EBB951;
--accent-color-light: #FF4088;
--accent-color-dark: #33ba91;
--text-color-primary: #373737;
--text-on-primary-color: #fff;
--text-color-secondary: #ccc;
--text-color-disabled: #F7f7f7;
--divider-color: #f6f6f6;
--warn-color: red;
--blue: var(--primary-color);
}

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