Compare commits

...

57 commits

Author SHA1 Message Date
David Jones
dd6e2c8724
deploy: walkLocal worker pool for performance
Some checks are pending
Test / test (1.23.x, ubuntu-latest) (push) Waiting to run
Test / test (1.23.x, windows-latest) (push) Waiting to run
Test / test (1.24.x, ubuntu-latest) (push) Waiting to run
Test / test (1.24.x, windows-latest) (push) Waiting to run
2025-06-29 16:41:56 +02:00
hugoreleaser
762417617c releaser: Prepare repository for 0.148.0-DEV
[ci skip]
2025-06-23 08:38:21 +00:00
hugoreleaser
29bdbde19c releaser: Bump versions for release of 0.147.9
[ci skip]
2025-06-23 08:22:20 +00:00
Bjørn Erik Pedersen
6a4a3ab8f8 Remove WARN with false negatives
Fixes #13806
2025-06-22 16:55:43 +02:00
Bjørn Erik Pedersen
36f6f987a9 resources/page: Make sure a map is always initialized
Fixes #13810
2025-06-21 14:38:06 +02:00
Joe Mooring
18a9ca7d7a tpl/tplimpl: Copy embedded HTML table render hook to each output format
Closes #13351
2025-06-21 14:37:47 +02:00
Joe Mooring
b6c8dfa9dc
tpl/tplimpl: Change resources.GetRemote errors to suppressible warnings
Closes #13803
2025-06-17 07:35:14 -07:00
dependabot[bot]
621ea42f3c build(deps): bump google.golang.org/api from 0.221.0 to 0.237.0
Bumps [google.golang.org/api](https://github.com/googleapis/google-api-go-client) from 0.221.0 to 0.237.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.221.0...v0.237.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-13 13:53:25 +02:00
Bjørn Erik Pedersen
4ef5720141
hugolib: Remove test for deprecated future 2025-06-13 12:17:06 +02:00
dependabot[bot]
34e83789f7 build(deps): bump github.com/aws/aws-sdk-go-v2 from 1.36.1 to 1.36.4
Bumps [github.com/aws/aws-sdk-go-v2](https://github.com/aws/aws-sdk-go-v2) from 1.36.1 to 1.36.4.
- [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.36.1...v1.36.4)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-13 11:25:11 +02:00
dependabot[bot]
4d3ebe4d21 build(deps): bump golang.org/x/image from 0.27.0 to 0.28.0
Bumps [golang.org/x/image](https://github.com/golang/image) from 0.27.0 to 0.28.0.
- [Commits](https://github.com/golang/image/compare/v0.27.0...v0.28.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-12 14:17:16 +02:00
Joe Mooring
b5c0383bda deps: Upgrade github.com/spf13/cast v1.8.0 => v1.9.2 2025-06-12 10:07:09 +02:00
Joe Mooring
4217fee4b0 common/terminal: Enable color output on windows
Closes #8209
2025-06-09 11:44:13 +02:00
hugoreleaser
fad57964aa releaser: Prepare repository for 0.148.0-DEV
[ci skip]
2025-06-07 13:13:56 +00:00
hugoreleaser
10da2bd765 releaser: Bump versions for release of 0.147.8
[ci skip]
2025-06-07 12:59:52 +00:00
Joe Mooring
01241d5dc9 hugolib: Emit ignorable warning when home page is a leaf bundle
Closes #13538
2025-06-07 13:02:28 +02:00
Bjørn Erik Pedersen
8e61f1fe12
dockerfile: Update Alpine
Closes #13783
2025-06-06 08:16:30 +02:00
Bjørn Erik Pedersen
f37412a575
dockerfile: Update Go version
FIxes #13780
2025-06-04 16:52:17 +02:00
dependabot[bot]
21a4a9acd7 build(deps): bump github.com/evanw/esbuild from 0.25.3 to 0.25.5
Bumps [github.com/evanw/esbuild](https://github.com/evanw/esbuild) from 0.25.3 to 0.25.5.
- [Release notes](https://github.com/evanw/esbuild/releases)
- [Changelog](https://github.com/evanw/esbuild/blob/main/CHANGELOG.md)
- [Commits](https://github.com/evanw/esbuild/compare/v0.25.3...v0.25.5)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-03 11:27:57 +02:00
dependabot[bot]
7a4a4790e5 build(deps): bump github.com/niklasfasching/go-org from 1.7.0 to 1.8.0
Bumps [github.com/niklasfasching/go-org](https://github.com/niklasfasching/go-org) from 1.7.0 to 1.8.0.
- [Commits](https://github.com/niklasfasching/go-org/compare/v1.7.0...v1.8.0)

---
updated-dependencies:
- dependency-name: github.com/niklasfasching/go-org
  dependency-version: 1.8.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-03 11:26:51 +02:00
dependabot[bot]
54065b7ef8 build(deps): bump golang.org/x/net from 0.39.0 to 0.40.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.39.0 to 0.40.0.
- [Commits](https://github.com/golang/net/compare/v0.39.0...v0.40.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-03 09:01:37 +02:00
dependabot[bot]
e333836f49 build(deps): bump github.com/yuin/goldmark from 1.7.11 to 1.7.12
Bumps [github.com/yuin/goldmark](https://github.com/yuin/goldmark) from 1.7.11 to 1.7.12.
- [Release notes](https://github.com/yuin/goldmark/releases)
- [Commits](https://github.com/yuin/goldmark/compare/v1.7.11...v1.7.12)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-02 18:18:44 +02:00
dependabot[bot]
cc7bfeea32 build(deps): bump github.com/tdewolff/minify/v2 from 2.23.5 to 2.23.8
Bumps [github.com/tdewolff/minify/v2](https://github.com/tdewolff/minify) from 2.23.5 to 2.23.8.
- [Release notes](https://github.com/tdewolff/minify/releases)
- [Commits](https://github.com/tdewolff/minify/compare/v2.23.5...v2.23.8)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-02 18:18:24 +02:00
Bjørn Erik Pedersen
32eb1a8ad4 all: Replace _build with build in tests
_build is deprecated and now shows up as warning.
2025-06-02 16:35:37 +02:00
hugoreleaser
32af02cd3e releaser: Prepare repository for 0.148.0-DEV
[ci skip]
2025-05-31 12:55:24 +00:00
hugoreleaser
189453612e releaser: Bump versions for release of 0.147.7
[ci skip]
2025-05-31 12:41:12 +00:00
Bjørn Erik Pedersen
5273a884d4 Fix language handling in shortcode templates
Fixes #13767
2025-05-31 13:57:00 +02:00
Bjørn Erik Pedersen
6334948515
Handle KaTeX warnings (#13760)
Co-authored-by: Joe Mooring <joe.mooring@veriphor.com>

Fixes #13735
2025-05-30 20:57:54 +02:00
dependabot[bot]
75259636c8 build(deps): bump golang.org/x/image from 0.26.0 to 0.27.0
Bumps [golang.org/x/image](https://github.com/golang/image) from 0.26.0 to 0.27.0.
- [Commits](https://github.com/golang/image/compare/v0.26.0...v0.27.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-30 15:13:21 +02:00
dependabot[bot]
0df9f3510f build(deps): bump golang.org/x/text from 0.24.0 to 0.25.0
Bumps [golang.org/x/text](https://github.com/golang/text) from 0.24.0 to 0.25.0.
- [Release notes](https://github.com/golang/text/releases)
- [Commits](https://github.com/golang/text/compare/v0.24.0...v0.25.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-30 12:50:09 +02:00
dependabot[bot]
302e6a726b build(deps): bump github.com/spf13/cast from 1.7.1 to 1.8.0
Bumps [github.com/spf13/cast](https://github.com/spf13/cast) from 1.7.1 to 1.8.0.
- [Release notes](https://github.com/spf13/cast/releases)
- [Commits](https://github.com/spf13/cast/compare/v1.7.1...v1.8.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-30 08:34:09 +02:00
dependabot[bot]
202fe0d45c build(deps): bump github.com/alecthomas/chroma/v2 from 2.17.2 to 2.18.0
Bumps [github.com/alecthomas/chroma/v2](https://github.com/alecthomas/chroma) from 2.17.2 to 2.18.0.
- [Release notes](https://github.com/alecthomas/chroma/releases)
- [Changelog](https://github.com/alecthomas/chroma/blob/master/.goreleaser.yml)
- [Commits](https://github.com/alecthomas/chroma/compare/v2.17.2...v2.18.0)

---
updated-dependencies:
- dependency-name: github.com/alecthomas/chroma/v2
  dependency-version: 2.18.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-29 22:12:58 +02:00
Joe Mooring
843ffeb48d resources/page: Respect disablePathToLower for permalink tokens
Fixes #13755
2025-05-29 22:10:03 +02:00
Ruslan Semagin
bff5d19121 common/collections: Increase test coverage 2025-05-29 09:17:13 +02:00
Ruslan Semagin
da370d30de parser/pageparser: Add coverage for all IsX methods of Item
Added tests for all boolean methods on Item, increasing overall code coverage.
2025-05-28 21:53:17 +02:00
Bjørn Erik Pedersen
6bd328c584 resources: Remove unused interface 2025-05-28 19:32:28 +02:00
Bjørn Erik Pedersen
766a2e7868 Make sure that unreferenced but changed bundle resources gets republished
Fixes #13748
2025-05-28 19:32:28 +02:00
Bjørn Erik Pedersen
13e1617557 deps: Upgrade github.com/olekukonko/tablewriter v0.0.5 => v1.0.7 2025-05-28 18:07:14 +02:00
hugoreleaser
463e440c7a releaser: Prepare repository for 0.148.0-DEV
[ci skip]
2025-05-27 11:31:53 +00:00
hugoreleaser
0a5fd8ebb8 releaser: Bump versions for release of 0.147.6
[ci skip]
2025-05-27 11:17:16 +00:00
Andreas Deininger
e57dcd3795 Improve warning message on superfluous prefix when using function 'partials.Include' 2025-05-27 12:16:26 +02:00
Bjørn Erik Pedersen
eaf5ace30d Fix recent regression with cascading of params to content adapters
Fixes #13743
2025-05-26 21:26:19 +02:00
Bjørn Erik Pedersen
9ad26b69ad Fix it so e.g. de in layouts/_shortcodes/de.html is not interpreted as a language code
Fixes #13740
2025-05-26 20:26:56 +02:00
Bjørn Erik Pedersen
f47193669d commands: Make sure the browser gets refreshed on changes when --disableFastRender is set
Fixes #13727
2025-05-23 19:46:16 +02:00
Joe Mooring
013c8cfb25 tpl/transform: Expose the KaTeX strict option
Closes #13729
2025-05-23 19:21:38 +02:00
hugoreleaser
e25db38467 releaser: Prepare repository for 0.148.0-DEV
[ci skip]
2025-05-22 11:51:47 +00:00
hugoreleaser
7766fc6241 releaser: Bump versions for release of 0.147.5
[ci skip]
2025-05-22 11:37:19 +00:00
Bjørn Erik Pedersen
4a48facef4
Merge branch 'release-0.147.4' 2025-05-22 13:19:34 +02:00
Bjørn Erik Pedersen
0c7b1a3f26 Fix live reload when editing inline partials
Fixes #13723
2025-05-22 13:15:41 +02:00
dependabot[bot]
970b887ba1 build(deps): bump github.com/tdewolff/minify/v2 from 2.20.37 to 2.23.5
Bumps [github.com/tdewolff/minify/v2](https://github.com/tdewolff/minify) from 2.20.37 to 2.23.5.
- [Release notes](https://github.com/tdewolff/minify/releases)
- [Commits](https://github.com/tdewolff/minify/compare/v2.20.37...v2.23.5)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-20 14:49:06 +02:00
hugoreleaser
b9b95e5aec releaser: Prepare repository for 0.148.0-DEV
[ci skip]
2025-05-20 10:55:43 +00:00
hugoreleaser
84c8426f32 releaser: Bump versions for release of 0.147.4
[ci skip]
2025-05-20 10:41:19 +00:00
Bjørn Erik Pedersen
a03a245f0c Fix it so css.TailwindCSS inlineImports options isn't always enabled
To avoid breaking existing setup and to make a better default option, the option is now `disableInlineImports` (default false).
Fixes #13719
2025-05-19 19:36:48 +02:00
Bjørn Erik Pedersen
5a81a3a4cf tpl: Add a test case
I'm not able to reproduce this, but leaving it in.

Closes #13699
2025-05-18 12:48:24 +02:00
Bjørn Erik Pedersen
61317821e4 tpl: Narrow down the usage of plain text shortcodes when rendering HTML
After this commit, if you want to resolve `layouts/_shortcodes/myshortcode.txt` when rendering HTML content, you need to use the `{{%` shortcode delimiter:

```
{{% myshortcode %}}
```

This should be what people would do anyway, but we have also as part of this improved the error message to inform about what needs to be done.

Note that this is not relevant for partials.

Fixes #13698
2025-05-18 12:48:24 +02:00
Bjørn Erik Pedersen
6142bc701c tpl: Fix theme overrides when theme has old layout setup (e.g. _default)
Fixes #13715
2025-05-18 12:48:24 +02:00
hugoreleaser
e6574cf7a7 releaser: Prepare repository for 0.148.0-DEV
[ci skip]
2025-05-12 12:40:04 +00:00
73 changed files with 1726 additions and 576 deletions

View file

@ -2,8 +2,8 @@
# Twitter: https://twitter.com/gohugoio # Twitter: https://twitter.com/gohugoio
# Website: https://gohugo.io/ # Website: https://gohugo.io/
ARG GO_VERSION="1.23.2" ARG GO_VERSION="1.24"
ARG ALPINE_VERSION="3.20" ARG ALPINE_VERSION="3.22"
ARG DART_SASS_VERSION="1.79.3" ARG DART_SASS_VERSION="1.79.3"
FROM --platform=$BUILDPLATFORM tonistiigi/xx:1.5.0 AS xx FROM --platform=$BUILDPLATFORM tonistiigi/xx:1.5.0 AS xx

View file

@ -972,6 +972,9 @@ func (c *hugoBuilder) handleEvents(watcher *watcher.Batcher,
lrl.Logf("force refresh") lrl.Logf("force refresh")
livereload.ForceRefresh() livereload.ForceRefresh()
} }
} else {
lrl.Logf("force refresh")
livereload.ForceRefresh()
} }
if len(cssChanges) > 0 { if len(cssChanges) > 0 {

View file

@ -15,6 +15,7 @@ package collections
import ( import (
"html/template" "html/template"
"reflect"
"testing" "testing"
qt "github.com/frankban/quicktest" qt "github.com/frankban/quicktest"
@ -77,6 +78,7 @@ func TestAppend(t *testing.T) {
{[]string{"a", "b"}, []any{nil}, []any{"a", "b", nil}}, {[]string{"a", "b"}, []any{nil}, []any{"a", "b", nil}},
{[]string{"a", "b"}, []any{nil, "d", nil}, []any{"a", "b", nil, "d", nil}}, {[]string{"a", "b"}, []any{nil, "d", nil}, []any{"a", "b", nil, "d", nil}},
{[]any{"a", nil, "c"}, []any{"d", nil, "f"}, []any{"a", nil, "c", "d", nil, "f"}}, {[]any{"a", nil, "c"}, []any{"d", nil, "f"}, []any{"a", nil, "c", "d", nil, "f"}},
{[]string{"a", "b"}, []any{}, []string{"a", "b"}},
} { } {
result, err := Append(test.start, test.addend...) result, err := Append(test.start, test.addend...)
@ -146,3 +148,66 @@ func TestAppendShouldMakeACopyOfTheInputSlice(t *testing.T) {
c.Assert(result, qt.DeepEquals, []string{"a", "b", "c"}) c.Assert(result, qt.DeepEquals, []string{"a", "b", "c"})
c.Assert(slice, qt.DeepEquals, []string{"d", "b"}) c.Assert(slice, qt.DeepEquals, []string{"d", "b"})
} }
func TestIndirect(t *testing.T) {
t.Parallel()
c := qt.New(t)
type testStruct struct {
Field string
}
var (
nilPtr *testStruct
nilIface interface{} = nil
nonNilIface interface{} = &testStruct{Field: "hello"}
)
tests := []struct {
name string
input any
wantKind reflect.Kind
wantNil bool
}{
{
name: "nil pointer",
input: nilPtr,
wantKind: reflect.Ptr,
wantNil: true,
},
{
name: "nil interface",
input: nilIface,
wantKind: reflect.Invalid,
wantNil: false,
},
{
name: "non-nil pointer to struct",
input: &testStruct{Field: "abc"},
wantKind: reflect.Struct,
wantNil: false,
},
{
name: "non-nil interface holding pointer",
input: nonNilIface,
wantKind: reflect.Struct,
wantNil: false,
},
{
name: "plain value",
input: testStruct{Field: "xyz"},
wantKind: reflect.Struct,
wantNil: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
v := reflect.ValueOf(tt.input)
got, isNil := indirect(v)
c.Assert(got.Kind(), qt.Equals, tt.wantKind)
c.Assert(isNil, qt.Equals, tt.wantNil)
})
}
}

View file

@ -136,3 +136,37 @@ func TestSortedStringSlice(t *testing.T) {
c.Assert(s.Count("z"), qt.Equals, 0) c.Assert(s.Count("z"), qt.Equals, 0)
c.Assert(s.Count("a"), qt.Equals, 1) c.Assert(s.Count("a"), qt.Equals, 1)
} }
func TestStringSliceToInterfaceSlice(t *testing.T) {
t.Parallel()
c := qt.New(t)
tests := []struct {
name string
in []string
want []any
}{
{
name: "empty slice",
in: []string{},
want: []any{},
},
{
name: "single element",
in: []string{"hello"},
want: []any{"hello"},
},
{
name: "multiple elements",
in: []string{"a", "b", "c"},
want: []any{"a", "b", "c"},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := StringSliceToInterfaceSlice(tt.in)
c.Assert(got, qt.DeepEquals, tt.want)
})
}
}

View file

@ -0,0 +1,77 @@
package collections
import (
"testing"
qt "github.com/frankban/quicktest"
)
func TestNewStack(t *testing.T) {
t.Parallel()
c := qt.New(t)
s := NewStack[int]()
c.Assert(s, qt.IsNotNil)
}
func TestStackBasic(t *testing.T) {
t.Parallel()
c := qt.New(t)
s := NewStack[int]()
c.Assert(s.Len(), qt.Equals, 0)
s.Push(1)
s.Push(2)
s.Push(3)
c.Assert(s.Len(), qt.Equals, 3)
top, ok := s.Peek()
c.Assert(ok, qt.Equals, true)
c.Assert(top, qt.Equals, 3)
popped, ok := s.Pop()
c.Assert(ok, qt.Equals, true)
c.Assert(popped, qt.Equals, 3)
c.Assert(s.Len(), qt.Equals, 2)
_, _ = s.Pop()
_, _ = s.Pop()
_, ok = s.Pop()
c.Assert(ok, qt.Equals, false)
}
func TestStackDrain(t *testing.T) {
t.Parallel()
c := qt.New(t)
s := NewStack[string]()
s.Push("a")
s.Push("b")
got := s.Drain()
c.Assert(got, qt.DeepEquals, []string{"a", "b"})
c.Assert(s.Len(), qt.Equals, 0)
}
func TestStackDrainMatching(t *testing.T) {
t.Parallel()
c := qt.New(t)
s := NewStack[int]()
s.Push(1)
s.Push(2)
s.Push(3)
s.Push(4)
got := s.DrainMatching(func(v int) bool { return v%2 == 0 })
c.Assert(got, qt.DeepEquals, []int{4, 2})
c.Assert(s.Drain(), qt.DeepEquals, []int{1, 3})
}

View file

@ -24,6 +24,7 @@ const (
WarnRenderShortcodesInHTML = "warning-rendershortcodes-in-html" WarnRenderShortcodesInHTML = "warning-rendershortcodes-in-html"
WarnGoldmarkRawHTML = "warning-goldmark-raw-html" WarnGoldmarkRawHTML = "warning-goldmark-raw-html"
WarnPartialSuperfluousPrefix = "warning-partial-superfluous-prefix" WarnPartialSuperfluousPrefix = "warning-partial-superfluous-prefix"
WarnHomePageIsLeafBundle = "warning-home-page-is-leaf-bundle"
) )
// Field/method names with special meaning. // Field/method names with special meaning.

View file

@ -17,7 +17,7 @@ package hugo
// This should be the only one. // This should be the only one.
var CurrentVersion = Version{ var CurrentVersion = Version{
Major: 0, Major: 0,
Minor: 147, Minor: 148,
PatchLevel: 3, PatchLevel: 0,
Suffix: "", Suffix: "-DEV",
} }

View file

@ -120,15 +120,20 @@ func (pp *PathParser) parse(component, s string) (*Path, error) {
return p, nil return p, nil
} }
func (pp *PathParser) parseIdentifier(component, s string, p *Path, i, lastDot int) { func (pp *PathParser) parseIdentifier(component, s string, p *Path, i, lastDot, numDots int, isLast bool) {
if p.posContainerHigh != -1 { if p.posContainerHigh != -1 {
return return
} }
mayHaveLang := p.posIdentifierLanguage == -1 && pp.LanguageIndex != nil mayHaveLang := numDots > 1 && p.posIdentifierLanguage == -1 && pp.LanguageIndex != nil
mayHaveLang = mayHaveLang && (component == files.ComponentFolderContent || component == files.ComponentFolderLayouts) mayHaveLang = mayHaveLang && (component == files.ComponentFolderContent || component == files.ComponentFolderLayouts)
mayHaveOutputFormat := component == files.ComponentFolderLayouts mayHaveOutputFormat := component == files.ComponentFolderLayouts
mayHaveKind := p.posIdentifierKind == -1 && mayHaveOutputFormat mayHaveKind := p.posIdentifierKind == -1 && mayHaveOutputFormat
mayHaveLayout := component == files.ComponentFolderLayouts var mayHaveLayout bool
if p.pathType == TypeShortcode {
mayHaveLayout = !isLast && component == files.ComponentFolderLayouts
} else {
mayHaveLayout = component == files.ComponentFolderLayouts
}
var found bool var found bool
var high int var high int
@ -167,7 +172,6 @@ func (pp *PathParser) parseIdentifier(component, s string, p *Path, i, lastDot i
if langFound { if langFound {
p.identifiersKnown = append(p.identifiersKnown, id) p.identifiersKnown = append(p.identifiersKnown, id)
p.posIdentifierLanguage = len(p.identifiersKnown) - 1 p.posIdentifierLanguage = len(p.identifiersKnown) - 1
} }
} }
@ -234,19 +238,24 @@ func (pp *PathParser) doParse(component, s string, p *Path) (*Path, error) {
p.s = s p.s = s
slashCount := 0 slashCount := 0
lastDot := 0 lastDot := 0
lastSlashIdx := strings.LastIndex(s, "/")
numDots := strings.Count(s[lastSlashIdx+1:], ".")
if strings.Contains(s, "/_shortcodes/") {
p.pathType = TypeShortcode
}
for i := len(s) - 1; i >= 0; i-- { for i := len(s) - 1; i >= 0; i-- {
c := s[i] c := s[i]
switch c { switch c {
case '.': case '.':
pp.parseIdentifier(component, s, p, i, lastDot) pp.parseIdentifier(component, s, p, i, lastDot, numDots, false)
lastDot = i lastDot = i
case '/': case '/':
slashCount++ slashCount++
if p.posContainerHigh == -1 { if p.posContainerHigh == -1 {
if lastDot > 0 { if lastDot > 0 {
pp.parseIdentifier(component, s, p, i, lastDot) pp.parseIdentifier(component, s, p, i, lastDot, numDots, true)
} }
p.posContainerHigh = i + 1 p.posContainerHigh = i + 1
} else if p.posContainerLow == -1 { } else if p.posContainerLow == -1 {
@ -282,10 +291,9 @@ func (pp *PathParser) doParse(component, s string, p *Path) (*Path, error) {
p.pathType = TypeContentData p.pathType = TypeContentData
} }
} }
} }
if component == files.ComponentFolderLayouts { if p.pathType < TypeMarkup && component == files.ComponentFolderLayouts {
if p.posIdentifierBaseof != -1 { if p.posIdentifierBaseof != -1 {
p.pathType = TypeBaseof p.pathType = TypeBaseof
} else { } else {
@ -301,12 +309,10 @@ func (pp *PathParser) doParse(component, s string, p *Path) (*Path, error) {
} }
if p.pathType == TypeShortcode && p.posIdentifierLayout != -1 { if p.pathType == TypeShortcode && p.posIdentifierLayout != -1 {
// myshortcode or myshortcode.html, no layout. id := p.identifiersKnown[p.posIdentifierLayout]
if len(p.identifiersKnown) <= 2 { if id.Low == p.posContainerHigh {
// First identifier is shortcode name.
p.posIdentifierLayout = -1 p.posIdentifierLayout = -1
} else {
// First is always the name.
p.posIdentifierLayout--
} }
} }

View file

@ -434,12 +434,12 @@ func TestParseLayouts(t *testing.T) {
}, },
{ {
"Layout multiple", "Layout multiple",
"/maylayout.list.section.no.html", "/mylayout.list.section.no.html",
func(c *qt.C, p *Path) { func(c *qt.C, p *Path) {
c.Assert(p.Layout(), qt.Equals, "maylayout") c.Assert(p.Layout(), qt.Equals, "mylayout")
c.Assert(p.Identifiers(), qt.DeepEquals, []string{"html", "no", "section", "list", "maylayout"}) c.Assert(p.Identifiers(), qt.DeepEquals, []string{"html", "no", "section", "list", "mylayout"})
c.Assert(p.IdentifiersUnknown(), qt.DeepEquals, []string{}) c.Assert(p.IdentifiersUnknown(), qt.DeepEquals, []string{})
c.Assert(p.Base(), qt.Equals, "/maylayout.html") c.Assert(p.Base(), qt.Equals, "/mylayout.html")
c.Assert(p.Lang(), qt.Equals, "no") c.Assert(p.Lang(), qt.Equals, "no")
}, },
}, },
@ -487,7 +487,8 @@ func TestParseLayouts(t *testing.T) {
func(c *qt.C, p *Path) { func(c *qt.C, p *Path) {
c.Assert(p.Base(), qt.Equals, "/_shortcodes/myshortcode.html") c.Assert(p.Base(), qt.Equals, "/_shortcodes/myshortcode.html")
c.Assert(p.Type(), qt.Equals, TypeShortcode) c.Assert(p.Type(), qt.Equals, TypeShortcode)
c.Assert(p.Identifiers(), qt.DeepEquals, []string{"html", "list", "myshortcode"}) c.Assert(p.Identifiers(), qt.DeepEquals, []string{"html", "list"})
c.Assert(p.Layout(), qt.Equals, "list")
c.Assert(p.PathNoIdentifier(), qt.Equals, "/_shortcodes/myshortcode") c.Assert(p.PathNoIdentifier(), qt.Equals, "/_shortcodes/myshortcode")
c.Assert(p.PathBeforeLangAndOutputFormatAndExt(), qt.Equals, "/_shortcodes/myshortcode.list") c.Assert(p.PathBeforeLangAndOutputFormatAndExt(), qt.Equals, "/_shortcodes/myshortcode.list")
c.Assert(p.Lang(), qt.Equals, "") c.Assert(p.Lang(), qt.Equals, "")
@ -563,11 +564,30 @@ func TestParseLayouts(t *testing.T) {
c.Assert(p.Type(), qt.Equals, TypePartial) c.Assert(p.Type(), qt.Equals, TypePartial)
}, },
}, },
{
"Shortcode lang in root",
"/_shortcodes/no.html",
func(c *qt.C, p *Path) {
c.Assert(p.Type(), qt.Equals, TypeShortcode)
c.Assert(p.Lang(), qt.Equals, "")
c.Assert(p.NameNoIdentifier(), qt.Equals, "no")
},
},
{
"Shortcode lang layout",
"/_shortcodes/myshortcode.no.html",
func(c *qt.C, p *Path) {
c.Assert(p.Type(), qt.Equals, TypeShortcode)
c.Assert(p.Lang(), qt.Equals, "no")
c.Assert(p.Layout(), qt.Equals, "")
c.Assert(p.NameNoIdentifier(), qt.Equals, "myshortcode")
},
},
} }
for _, test := range tests { for _, test := range tests {
c.Run(test.name, func(c *qt.C) { c.Run(test.name, func(c *qt.C) {
if test.name != "Baseof" { if test.name != "Shortcode lang layout" {
// return // return
} }
test.assert(c, testParser.Parse(files.ComponentFolderLayouts, test.path)) test.assert(c, testParser.Parse(files.ComponentFolderLayouts, test.path))

View file

@ -17,7 +17,6 @@ package terminal
import ( import (
"fmt" "fmt"
"os" "os"
"runtime"
"strings" "strings"
isatty "github.com/mattn/go-isatty" isatty "github.com/mattn/go-isatty"
@ -41,10 +40,6 @@ func PrintANSIColors(f *os.File) bool {
// IsTerminal return true if the file descriptor is terminal and the TERM // IsTerminal return true if the file descriptor is terminal and the TERM
// environment variable isn't a dumb one. // environment variable isn't a dumb one.
func IsTerminal(f *os.File) bool { func IsTerminal(f *os.File) bool {
if runtime.GOOS == "windows" {
return false
}
fd := f.Fd() fd := f.Fd()
return os.Getenv("TERM") != "dumb" && (isatty.IsTerminal(fd) || isatty.IsCygwinTerminal(fd)) return os.Getenv("TERM") != "dumb" && (isatty.IsTerminal(fd) || isatty.IsCygwinTerminal(fd))
} }

View file

@ -146,7 +146,7 @@ type Config struct {
// The cascade configuration section contains the top level front matter cascade configuration options, // The cascade configuration section contains the top level front matter cascade configuration options,
// a slice of page matcher and params to apply to those pages. // a slice of page matcher and params to apply to those pages.
Cascade *config.ConfigNamespace[[]page.PageMatcherParamsConfig, *maps.Ordered[page.PageMatcher, maps.Params]] `mapstructure:"-"` Cascade *config.ConfigNamespace[[]page.PageMatcherParamsConfig, *maps.Ordered[page.PageMatcher, page.PageMatcherParamsConfig]] `mapstructure:"-"`
// The segments defines segments for the site. Used for partial/segmented builds. // The segments defines segments for the site. Used for partial/segmented builds.
Segments *config.ConfigNamespace[map[string]segments.SegmentConfig, segments.Segments] `mapstructure:"-"` Segments *config.ConfigNamespace[map[string]segments.SegmentConfig, segments.Segments] `mapstructure:"-"`
@ -776,7 +776,7 @@ type Configs struct {
} }
func (c *Configs) Validate(logger loggers.Logger) error { func (c *Configs) Validate(logger loggers.Logger) error {
c.Base.Cascade.Config.Range(func(p page.PageMatcher, params maps.Params) bool { c.Base.Cascade.Config.Range(func(p page.PageMatcher, cfg page.PageMatcherParamsConfig) bool {
page.CheckCascadePattern(logger, p) page.CheckCascadePattern(logger, p)
return true return true
}) })

View file

@ -36,6 +36,7 @@ import (
"github.com/dustin/go-humanize" "github.com/dustin/go-humanize"
"github.com/gobwas/glob" "github.com/gobwas/glob"
"github.com/gohugoio/hugo/common/loggers" "github.com/gohugoio/hugo/common/loggers"
"github.com/gohugoio/hugo/common/para"
"github.com/gohugoio/hugo/config" "github.com/gohugoio/hugo/config"
"github.com/gohugoio/hugo/deploy/deployconfig" "github.com/gohugoio/hugo/deploy/deployconfig"
"github.com/gohugoio/hugo/media" "github.com/gohugoio/hugo/media"
@ -487,7 +488,12 @@ func knownHiddenDirectory(name string) bool {
// walkLocal walks the source directory and returns a flat list of files, // walkLocal walks the source directory and returns a flat list of files,
// using localFile.SlashPath as the map keys. // using localFile.SlashPath as the map keys.
func (d *Deployer) walkLocal(fs afero.Fs, matchers []*deployconfig.Matcher, include, exclude glob.Glob, mediaTypes media.Types, mappath func(string) string) (map[string]*localFile, error) { func (d *Deployer) walkLocal(fs afero.Fs, matchers []*deployconfig.Matcher, include, exclude glob.Glob, mediaTypes media.Types, mappath func(string) string) (map[string]*localFile, error) {
retval := map[string]*localFile{} retval := make(map[string]*localFile)
var mu sync.Mutex
workers := para.New(d.cfg.Workers)
g, _ := workers.Start(context.Background())
err := afero.Walk(fs, "", func(path string, info os.FileInfo, err error) error { err := afero.Walk(fs, "", func(path string, info os.FileInfo, err error) error {
if err != nil { if err != nil {
return err return err
@ -508,6 +514,8 @@ func (d *Deployer) walkLocal(fs afero.Fs, matchers []*deployconfig.Matcher, incl
return nil return nil
} }
// Process each file in a worker
g.Run(func() error {
// When a file system is HFS+, its filepath is in NFD form. // When a file system is HFS+, its filepath is in NFD form.
if runtime.GOOS == "darwin" { if runtime.GOOS == "darwin" {
path = norm.NFC.String(path) path = norm.NFC.String(path)
@ -541,12 +549,19 @@ func (d *Deployer) walkLocal(fs afero.Fs, matchers []*deployconfig.Matcher, incl
if err != nil { if err != nil {
return err return err
} }
mu.Lock()
retval[lf.SlashPath] = lf retval[lf.SlashPath] = lf
mu.Unlock()
return nil
})
return nil return nil
}) })
if err != nil { if err != nil {
return nil, err return nil, err
} }
if err := g.Wait(); err != nil {
return nil, err
}
return retval, nil return retval, nil
} }

View file

@ -623,7 +623,7 @@ func TestEndToEndSync(t *testing.T) {
localFs: test.fs, localFs: test.fs,
bucket: test.bucket, bucket: test.bucket,
mediaTypes: media.DefaultTypes, mediaTypes: media.DefaultTypes,
cfg: deployconfig.DeployConfig{MaxDeletes: -1}, cfg: deployconfig.DeployConfig{Workers: 2, MaxDeletes: -1},
} }
// Initial deployment should sync remote with local. // Initial deployment should sync remote with local.
@ -706,7 +706,7 @@ func TestMaxDeletes(t *testing.T) {
localFs: test.fs, localFs: test.fs,
bucket: test.bucket, bucket: test.bucket,
mediaTypes: media.DefaultTypes, mediaTypes: media.DefaultTypes,
cfg: deployconfig.DeployConfig{MaxDeletes: -1}, cfg: deployconfig.DeployConfig{Workers: 2, MaxDeletes: -1},
} }
// Sync remote with local. // Sync remote with local.
@ -836,7 +836,7 @@ func TestIncludeExclude(t *testing.T) {
} }
deployer := &Deployer{ deployer := &Deployer{
localFs: fsTest.fs, localFs: fsTest.fs,
cfg: deployconfig.DeployConfig{MaxDeletes: -1}, bucket: fsTest.bucket, cfg: deployconfig.DeployConfig{Workers: 2, MaxDeletes: -1}, bucket: fsTest.bucket,
target: tgt, target: tgt,
mediaTypes: media.DefaultTypes, mediaTypes: media.DefaultTypes,
} }
@ -893,7 +893,7 @@ func TestIncludeExcludeRemoteDelete(t *testing.T) {
} }
deployer := &Deployer{ deployer := &Deployer{
localFs: fsTest.fs, localFs: fsTest.fs,
cfg: deployconfig.DeployConfig{MaxDeletes: -1}, bucket: fsTest.bucket, cfg: deployconfig.DeployConfig{Workers: 2, MaxDeletes: -1}, bucket: fsTest.bucket,
mediaTypes: media.DefaultTypes, mediaTypes: media.DefaultTypes,
} }
@ -945,7 +945,7 @@ func TestCompression(t *testing.T) {
deployer := &Deployer{ deployer := &Deployer{
localFs: test.fs, localFs: test.fs,
bucket: test.bucket, bucket: test.bucket,
cfg: deployconfig.DeployConfig{MaxDeletes: -1, Matchers: []*deployconfig.Matcher{{Pattern: ".*", Gzip: true, Re: regexp.MustCompile(".*")}}}, cfg: deployconfig.DeployConfig{Workers: 2, MaxDeletes: -1, Matchers: []*deployconfig.Matcher{{Pattern: ".*", Gzip: true, Re: regexp.MustCompile(".*")}}},
mediaTypes: media.DefaultTypes, mediaTypes: media.DefaultTypes,
} }
@ -1000,7 +1000,7 @@ func TestMatching(t *testing.T) {
deployer := &Deployer{ deployer := &Deployer{
localFs: test.fs, localFs: test.fs,
bucket: test.bucket, bucket: test.bucket,
cfg: deployconfig.DeployConfig{MaxDeletes: -1, Matchers: []*deployconfig.Matcher{{Pattern: "^subdir/aaa$", Force: true, Re: regexp.MustCompile("^subdir/aaa$")}}}, cfg: deployconfig.DeployConfig{Workers: 2, MaxDeletes: -1, Matchers: []*deployconfig.Matcher{{Pattern: "^subdir/aaa$", Force: true, Re: regexp.MustCompile("^subdir/aaa$")}}},
mediaTypes: media.DefaultTypes, mediaTypes: media.DefaultTypes,
} }
@ -1097,5 +1097,6 @@ func verifyRemote(ctx context.Context, bucket *blob.Bucket, local []*fileData) (
func newDeployer() *Deployer { func newDeployer() *Deployer {
return &Deployer{ return &Deployer{
logger: loggers.NewDefault(), logger: loggers.NewDefault(),
cfg: deployconfig.DeployConfig{Workers: 2},
} }
} }

96
go.mod
View file

@ -2,9 +2,9 @@ module github.com/gohugoio/hugo
require ( require (
github.com/BurntSushi/locker v0.0.0-20171006230638-a6e239ea1c69 github.com/BurntSushi/locker v0.0.0-20171006230638-a6e239ea1c69
github.com/alecthomas/chroma/v2 v2.17.2 github.com/alecthomas/chroma/v2 v2.18.0
github.com/armon/go-radix v1.0.1-0.20221118154546-54df44f2176c github.com/armon/go-radix v1.0.1-0.20221118154546-54df44f2176c
github.com/aws/aws-sdk-go-v2 v1.36.1 github.com/aws/aws-sdk-go-v2 v1.36.4
github.com/aws/aws-sdk-go-v2/service/cloudfront v1.44.10 github.com/aws/aws-sdk-go-v2/service/cloudfront v1.44.10
github.com/bep/clocks v0.5.0 github.com/bep/clocks v0.5.0
github.com/bep/debounce v1.2.0 github.com/bep/debounce v1.2.0
@ -26,7 +26,7 @@ require (
github.com/clbanning/mxj/v2 v2.7.0 github.com/clbanning/mxj/v2 v2.7.0
github.com/disintegration/gift v1.2.1 github.com/disintegration/gift v1.2.1
github.com/dustin/go-humanize v1.0.1 github.com/dustin/go-humanize v1.0.1
github.com/evanw/esbuild v0.25.3 github.com/evanw/esbuild v0.25.5
github.com/fatih/color v1.18.0 github.com/fatih/color v1.18.0
github.com/fortytw2/leaktest v1.3.0 github.com/fortytw2/leaktest v1.3.0
github.com/frankban/quicktest v1.14.6 github.com/frankban/quicktest v1.14.6
@ -54,44 +54,46 @@ require (
github.com/mattn/go-isatty v0.0.20 github.com/mattn/go-isatty v0.0.20
github.com/mitchellh/mapstructure v1.5.1-0.20231216201459-8508981c8b6c github.com/mitchellh/mapstructure v1.5.1-0.20231216201459-8508981c8b6c
github.com/muesli/smartcrop v0.3.0 github.com/muesli/smartcrop v0.3.0
github.com/niklasfasching/go-org v1.7.0 github.com/niklasfasching/go-org v1.8.0
github.com/olekukonko/tablewriter v0.0.5 github.com/olekukonko/tablewriter v1.0.7
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58
github.com/pelletier/go-toml/v2 v2.2.4 github.com/pelletier/go-toml/v2 v2.2.4
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c
github.com/rogpeppe/go-internal v1.14.1 github.com/rogpeppe/go-internal v1.14.1
github.com/sanity-io/litter v1.5.8 github.com/sanity-io/litter v1.5.8
github.com/spf13/afero v1.14.0 github.com/spf13/afero v1.14.0
github.com/spf13/cast v1.7.1 github.com/spf13/cast v1.9.2
github.com/spf13/cobra v1.9.1 github.com/spf13/cobra v1.9.1
github.com/spf13/fsync v0.10.1 github.com/spf13/fsync v0.10.1
github.com/spf13/pflag v1.0.6 github.com/spf13/pflag v1.0.6
github.com/tdewolff/minify/v2 v2.20.37 github.com/tdewolff/minify/v2 v2.23.8
github.com/tdewolff/parse/v2 v2.7.15 github.com/tdewolff/parse/v2 v2.8.1
github.com/tetratelabs/wazero v1.9.0 github.com/tetratelabs/wazero v1.9.0
github.com/yuin/goldmark v1.7.11 github.com/yuin/goldmark v1.7.12
github.com/yuin/goldmark-emoji v1.0.6 github.com/yuin/goldmark-emoji v1.0.6
go.uber.org/automaxprocs v1.5.3 go.uber.org/automaxprocs v1.5.3
gocloud.dev v0.40.0 gocloud.dev v0.40.0
golang.org/x/exp v0.0.0-20221031165847-c99f073a8326 golang.org/x/exp v0.0.0-20221031165847-c99f073a8326
golang.org/x/image v0.26.0 golang.org/x/image v0.28.0
golang.org/x/mod v0.24.0 golang.org/x/mod v0.25.0
golang.org/x/net v0.39.0 golang.org/x/net v0.41.0
golang.org/x/sync v0.13.0 golang.org/x/sync v0.15.0
golang.org/x/text v0.24.0 golang.org/x/text v0.26.0
golang.org/x/tools v0.32.0 golang.org/x/tools v0.33.0
google.golang.org/api v0.221.0 google.golang.org/api v0.237.0
gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v2 v2.4.0
rsc.io/qr v0.2.0 rsc.io/qr v0.2.0
) )
require ( require (
cloud.google.com/go v0.116.0 // indirect cel.dev/expr v0.23.0 // indirect
cloud.google.com/go/auth v0.14.1 // indirect cloud.google.com/go v0.120.0 // indirect
cloud.google.com/go/auth/oauth2adapt v0.2.7 // indirect cloud.google.com/go/auth v0.16.2 // indirect
cloud.google.com/go/compute/metadata v0.6.0 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
cloud.google.com/go/iam v1.2.2 // indirect cloud.google.com/go/compute/metadata v0.7.0 // indirect
cloud.google.com/go/storage v1.43.0 // indirect cloud.google.com/go/iam v1.5.2 // indirect
cloud.google.com/go/monitoring v1.24.2 // indirect
cloud.google.com/go/storage v1.50.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect
@ -99,6 +101,9 @@ require (
github.com/Azure/go-autorest v14.2.0+incompatible // indirect github.com/Azure/go-autorest v14.2.0+incompatible // indirect
github.com/Azure/go-autorest/autorest/to v0.4.0 // indirect github.com/Azure/go-autorest/autorest/to v0.4.0 // indirect
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 // indirect github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.50.0 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.50.0 // indirect
github.com/aws/aws-sdk-go v1.55.5 // indirect github.com/aws/aws-sdk-go v1.55.5 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.3 // indirect github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.3 // indirect
github.com/aws/aws-sdk-go-v2/config v1.27.27 // indirect github.com/aws/aws-sdk-go-v2/config v1.27.27 // indirect
@ -118,9 +123,13 @@ require (
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.30.3 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.30.3 // indirect
github.com/aws/smithy-go v1.22.2 // indirect github.com/aws/smithy-go v1.22.2 // indirect
github.com/cncf/xds/go v0.0.0-20250326154945-ae57f3c0d45f // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect
github.com/dlclark/regexp2 v1.11.5 // indirect github.com/dlclark/regexp2 v1.11.5 // indirect
github.com/envoyproxy/go-control-plane/envoy v1.32.4 // indirect
github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/go-jose/go-jose/v4 v4.0.5 // indirect
github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect
@ -130,8 +139,8 @@ require (
github.com/google/s2a-go v0.1.9 // indirect github.com/google/s2a-go v0.1.9 // indirect
github.com/google/uuid v1.6.0 // indirect github.com/google/uuid v1.6.0 // indirect
github.com/google/wire v0.6.0 // indirect github.com/google/wire v0.6.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect
github.com/googleapis/gax-go/v2 v2.14.1 // indirect github.com/googleapis/gax-go/v2 v2.14.2 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect
@ -141,31 +150,40 @@ require (
github.com/kylelemons/godebug v1.1.0 // indirect github.com/kylelemons/godebug v1.1.0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-runewidth v0.0.9 // indirect github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect
github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect
github.com/olekukonko/errors v0.0.0-20250405072817-4e6d85265da6 // indirect
github.com/olekukonko/ll v0.0.8 // indirect
github.com/perimeterx/marshmallow v1.1.5 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/spiffe/go-spiffe/v2 v2.5.0 // indirect
github.com/zeebo/errs v1.4.0 // indirect
go.opencensus.io v0.24.0 // indirect go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.58.0 // indirect go.opentelemetry.io/contrib/detectors/gcp v1.35.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 // indirect
go.opentelemetry.io/otel v1.34.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect
go.opentelemetry.io/otel/metric v1.34.0 // indirect go.opentelemetry.io/otel v1.36.0 // indirect
go.opentelemetry.io/otel/trace v1.34.0 // indirect go.opentelemetry.io/otel/metric v1.36.0 // indirect
golang.org/x/crypto v0.37.0 // indirect go.opentelemetry.io/otel/sdk v1.36.0 // indirect
golang.org/x/oauth2 v0.26.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.36.0 // indirect
golang.org/x/sys v0.32.0 // indirect go.opentelemetry.io/otel/trace v1.36.0 // indirect
golang.org/x/time v0.10.0 // indirect golang.org/x/crypto v0.39.0 // indirect
golang.org/x/oauth2 v0.30.0 // indirect
golang.org/x/sys v0.33.0 // indirect
golang.org/x/time v0.12.0 // indirect
golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9 // indirect golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9 // indirect
google.golang.org/genproto v0.0.0-20241104194629-dd2ea8efbc28 // indirect google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250505200425-f936aa4a68b2 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250207221924-e9438ea467c6 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect
google.golang.org/grpc v1.70.0 // indirect google.golang.org/grpc v1.73.0 // indirect
google.golang.org/protobuf v1.36.5 // indirect google.golang.org/protobuf v1.36.6 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
howett.net/plist v1.0.0 // indirect howett.net/plist v1.0.0 // indirect
software.sslmate.com/src/go-pkcs12 v0.2.0 // indirect software.sslmate.com/src/go-pkcs12 v0.2.0 // indirect

217
go.sum
View file

@ -1,3 +1,5 @@
cel.dev/expr v0.23.0 h1:wUb94w6OYQS4uXraxo9U+wUAs9jT47Xvl4iPgAwM2ss=
cel.dev/expr v0.23.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw=
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
@ -17,26 +19,30 @@ cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHOb
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY=
cloud.google.com/go v0.116.0 h1:B3fRrSDkLRt5qSHWe40ERJvhvnQwdZiHu0bJOpldweE= cloud.google.com/go v0.120.0 h1:wc6bgG9DHyKqF5/vQvX1CiZrtHnxJjBlKUyF9nP6meA=
cloud.google.com/go v0.116.0/go.mod h1:cEPSRWPzZEswwdr9BxE6ChEn01dWlTaF05LiC2Xs70U= cloud.google.com/go v0.120.0/go.mod h1:/beW32s8/pGRuj4IILWQNd4uuebeT4dkOhKmkfit64Q=
cloud.google.com/go/auth v0.14.1 h1:AwoJbzUdxA/whv1qj3TLKwh3XX5sikny2fc40wUl+h0= cloud.google.com/go/auth v0.16.2 h1:QvBAGFPLrDeoiNjyfVunhQ10HKNYuOwZ5noee0M5df4=
cloud.google.com/go/auth v0.14.1/go.mod h1:4JHUxlGXisL0AW8kXPtUF6ztuOksyfUQNFjfsOCXkPM= cloud.google.com/go/auth v0.16.2/go.mod h1:sRBas2Y1fB1vZTdurouM0AzuYQBMZinrUYL8EufhtEA=
cloud.google.com/go/auth/oauth2adapt v0.2.7 h1:/Lc7xODdqcEw8IrZ9SvwnlLX6j9FHQM74z6cBk9Rw6M= cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc=
cloud.google.com/go/auth/oauth2adapt v0.2.7/go.mod h1:NTbTTzfvPl1Y3V1nPpOgl2w6d/FjO7NNUQaWSox6ZMc= cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I= cloud.google.com/go/compute/metadata v0.7.0 h1:PBWF+iiAerVNe8UCHxdOt6eHLVc3ydFeOCw78U8ytSU=
cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg= cloud.google.com/go/compute/metadata v0.7.0/go.mod h1:j5MvL9PprKL39t166CoB1uVHfQMs4tFQZZcKwksXUjo=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
cloud.google.com/go/iam v1.2.2 h1:ozUSofHUGf/F4tCNy/mu9tHLTaxZFLOUiKzjcgWHGIA= cloud.google.com/go/iam v1.5.2 h1:qgFRAGEmd8z6dJ/qyEchAuL9jpswyODjA2lS+w234g8=
cloud.google.com/go/iam v1.2.2/go.mod h1:0Ys8ccaZHdI1dEUilwzqng/6ps2YB6vRsjIe00/+6JY= cloud.google.com/go/iam v1.5.2/go.mod h1:SE1vg0N81zQqLzQEwxL2WI6yhetBdbNQuTvIKCSkUHE=
cloud.google.com/go/longrunning v0.6.2 h1:xjDfh1pQcWPEvnfjZmwjKQEcHnpz6lHjfy7Fo0MK+hc= cloud.google.com/go/logging v1.13.0 h1:7j0HgAp0B94o1YRDqiqm26w4q1rDMH7XNRU34lJXHYc=
cloud.google.com/go/longrunning v0.6.2/go.mod h1:k/vIs83RN4bE3YCswdXC5PFfWVILjm3hpEUlSko4PiI= cloud.google.com/go/logging v1.13.0/go.mod h1:36CoKh6KA/M0PbhPKMq6/qety2DCAErbhXT62TuXALA=
cloud.google.com/go/longrunning v0.6.7 h1:IGtfDWHhQCgCjwQjV9iiLnUta9LBCo8R9QmAFsS/PrE=
cloud.google.com/go/longrunning v0.6.7/go.mod h1:EAFV3IZAKmM56TyiE6VAP3VoTzhZzySwI/YI1s/nRsY=
cloud.google.com/go/monitoring v1.24.2 h1:5OTsoJ1dXYIiMiuL+sYscLc9BumrL3CarVLL7dd7lHM=
cloud.google.com/go/monitoring v1.24.2/go.mod h1:x7yzPWcgDRnPEv3sI+jJGBkwl5qINf+6qY4eq0I9B4U=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
@ -47,8 +53,10 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
cloud.google.com/go/storage v1.43.0 h1:CcxnSohZwizt4LCzQHWvBf1/kvtHUn7gk9QERXPyXFs= cloud.google.com/go/storage v1.50.0 h1:3TbVkzTooBvnZsk7WaAQfOsNrdoM8QHusXA1cpk6QJs=
cloud.google.com/go/storage v1.43.0/go.mod h1:ajvxEa7WmZS1PxvKRq4bq0tFT3vMd502JwstCcYv0Q0= cloud.google.com/go/storage v1.50.0/go.mod h1:l7XeiD//vx5lfqE3RavfmU9yvk5Pp0Zhcv482poyafY=
cloud.google.com/go/trace v1.11.6 h1:2O2zjPzqPYAHrn3OKl029qlqG6W8ZdYaOWRyr8NgMT4=
cloud.google.com/go/trace v1.11.6/go.mod h1:GA855OeDEBiBMzcckLPE2kDunIpC72N+Pq8WFieFjnI=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0 h1:nyQWyZvwGTvunIMxi1Y9uXkcyr+I7TeNrr/foo4Kpk8= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0 h1:nyQWyZvwGTvunIMxi1Y9uXkcyr+I7TeNrr/foo4Kpk8=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0/go.mod h1:l38EPgmsp71HHLq9j7De57JcKOWPyhrsW1Awm1JS6K0= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0/go.mod h1:l38EPgmsp71HHLq9j7De57JcKOWPyhrsW1Awm1JS6K0=
@ -71,18 +79,26 @@ github.com/BurntSushi/locker v0.0.0-20171006230638-a6e239ea1c69/go.mod h1:L1AbZd
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0 h1:ErKg/3iS1AKcTkf3yixlZ54f9U1rljCkQyEXWUnIUxc=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0/go.mod h1:yAZHSGnqScoU556rBOVkwLze6WP5N+U11RHuWaGVxwY=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.50.0 h1:5IT7xOdq17MtcdtL/vtl6mGfzhaq4m4vpollPRmlsBQ=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.50.0/go.mod h1:ZV4VOm0/eHR06JLrXWe09068dHpr3TRpY9Uo7T+anuA=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.50.0 h1:nNMpRpnkWDAaqcpxMJvxa/Ud98gjbYwayJY4/9bdjiU=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.50.0/go.mod h1:SZiPHWGOOk3bl8tkevxkoiwPgsIl6CwrWcbwjfHZpdM=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.50.0 h1:ig/FpDD2JofP/NExKQUbn7uOSZzJAQqogfqluZK4ed4=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.50.0/go.mod h1:otE2jQekW/PqXk1Awf5lmfokJx4uwuqcj1ab5SpGeW0=
github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0=
github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
github.com/alecthomas/chroma/v2 v2.17.2 h1:Rm81SCZ2mPoH+Q8ZCc/9YvzPUN/E7HgPiPJD8SLV6GI= github.com/alecthomas/chroma/v2 v2.18.0 h1:6h53Q4hW83SuF+jcsp7CVhLsMozzvQvO8HBbKQW+gn4=
github.com/alecthomas/chroma/v2 v2.17.2/go.mod h1:RVX6AvYm4VfYe/zsk7mjHueLDZor3aWCNE14TFlepBk= github.com/alecthomas/chroma/v2 v2.18.0/go.mod h1:RVX6AvYm4VfYe/zsk7mjHueLDZor3aWCNE14TFlepBk=
github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc= github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc=
github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
github.com/armon/go-radix v1.0.1-0.20221118154546-54df44f2176c h1:651/eoCRnQ7YtSjAnSzRucrJz+3iGEFt+ysraELS81M= github.com/armon/go-radix v1.0.1-0.20221118154546-54df44f2176c h1:651/eoCRnQ7YtSjAnSzRucrJz+3iGEFt+ysraELS81M=
github.com/armon/go-radix v1.0.1-0.20221118154546-54df44f2176c/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.1-0.20221118154546-54df44f2176c/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/aws/aws-sdk-go v1.55.5 h1:KKUZBfBoyqy5d3swXyiC7Q76ic40rYcbqH7qjh59kzU= github.com/aws/aws-sdk-go v1.55.5 h1:KKUZBfBoyqy5d3swXyiC7Q76ic40rYcbqH7qjh59kzU=
github.com/aws/aws-sdk-go v1.55.5/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= github.com/aws/aws-sdk-go v1.55.5/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU=
github.com/aws/aws-sdk-go-v2 v1.36.1 h1:iTDl5U6oAhkNPba0e1t1hrwAo02ZMqbrGq4k5JBWM5E= github.com/aws/aws-sdk-go-v2 v1.36.4 h1:GySzjhVvx0ERP6eyfAbAuAXLtAda5TEy19E5q5W8I9E=
github.com/aws/aws-sdk-go-v2 v1.36.1/go.mod h1:5PMILGVKiW32oDzjj6RU52yrNrDPUHcbZQYr1sM7qmM= github.com/aws/aws-sdk-go-v2 v1.36.4/go.mod h1:LLXuLpgzEbD766Z5ECcRmi8AzSwfZItDtmABVkRLGzg=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.3 h1:tW1/Rkad38LA15X4UQtjXZXNKsCgkshC3EbmcUmghTg= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.3 h1:tW1/Rkad38LA15X4UQtjXZXNKsCgkshC3EbmcUmghTg=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.3/go.mod h1:UbnqO+zjqk3uIt9yCACHJ9IVNhyhOCnYk8yA19SAWrM= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.3/go.mod h1:UbnqO+zjqk3uIt9yCACHJ9IVNhyhOCnYk8yA19SAWrM=
github.com/aws/aws-sdk-go-v2/config v1.27.27 h1:HdqgGt1OAP0HkEDDShEl0oSYa9ZZBSOmKpdpsDMdO90= github.com/aws/aws-sdk-go-v2/config v1.27.27 h1:HdqgGt1OAP0HkEDDShEl0oSYa9ZZBSOmKpdpsDMdO90=
@ -167,6 +183,8 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/xds/go v0.0.0-20250326154945-ae57f3c0d45f h1:C5bqEmzEPLsHm9Mv73lSE9e9bKV23aB1vxOsmZrkl3k=
github.com/cncf/xds/go v0.0.0-20250326154945-ae57f3c0d45f/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
github.com/cpuguy83/go-md2man/v2 v2.0.6 h1:XJtiaUW6dEEqVuZiMTn1ldk455QWwEIsMIJlo5vtkx0= github.com/cpuguy83/go-md2man/v2 v2.0.6 h1:XJtiaUW6dEEqVuZiMTn1ldk455QWwEIsMIJlo5vtkx0=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
@ -185,9 +203,17 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.13.4 h1:zEqyPVyku6IvWCFwux4x9RxkLOMUL+1vC9xUFv5l2/M=
github.com/envoyproxy/go-control-plane v0.13.4/go.mod h1:kDfuBlDVsSj2MjrLEtRWtHlsWIFcGyB2RMO44Dc5GZA=
github.com/envoyproxy/go-control-plane/envoy v1.32.4 h1:jb83lalDRZSpPWW2Z7Mck/8kXZ5CQAFYVjQcdVIr83A=
github.com/envoyproxy/go-control-plane/envoy v1.32.4/go.mod h1:Gzjc5k8JcJswLjAx1Zm+wSYE20UrLtt7JZMWiWQXQEw=
github.com/envoyproxy/go-control-plane/ratelimit v0.1.0 h1:/G9QYbddjL25KvtKTv3an9lx6VBE2cnb8wp1vEGNYGI=
github.com/envoyproxy/go-control-plane/ratelimit v0.1.0/go.mod h1:Wk+tMFAFbCXaJPzVVHnPgRKdUdwW/KdbRt94AzgRee4=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/evanw/esbuild v0.25.3 h1:4JKyUsm/nHDhpxis4IyWXAi8GiyTwG1WdEp6OhGVE8U= github.com/envoyproxy/protoc-gen-validate v1.2.1 h1:DEo3O99U8j4hBFwbJfrz9VtgcDfUKS7KJ7spH3d86P8=
github.com/evanw/esbuild v0.25.3/go.mod h1:D2vIQZqV/vIf/VRHtViaUtViZmG7o+kKmlBfVQuRi48= github.com/envoyproxy/protoc-gen-validate v1.2.1/go.mod h1:d/C80l/jxXLdfEIhX1W2TmLfsJ31lvEjwamM4DxlWXU=
github.com/evanw/esbuild v0.25.5 h1:E+JpeY5S/1LFmnX1vtuZqUKT7qDVcfXdhzMhM3uIKFs=
github.com/evanw/esbuild v0.25.5/go.mod h1:D2vIQZqV/vIf/VRHtViaUtViZmG7o+kKmlBfVQuRi48=
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
@ -208,6 +234,8 @@ github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeME
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-jose/go-jose/v4 v4.0.5 h1:M6T8+mKZl/+fNNuFHvGIzDz7BTLQPIounk/b9dw3AaE=
github.com/go-jose/go-jose/v4 v4.0.5/go.mod h1:s3P1lRrkT8igV8D9OjyL4WRyHvjB6a4JSllnOrmmBOA=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
@ -317,12 +345,12 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/wire v0.6.0 h1:HBkoIh4BdSxoyo9PveV8giw7ZsaBOvzWKfcg/6MrVwI= github.com/google/wire v0.6.0 h1:HBkoIh4BdSxoyo9PveV8giw7ZsaBOvzWKfcg/6MrVwI=
github.com/google/wire v0.6.0/go.mod h1:F4QhpQ9EDIdJ1Mbop/NZBRB+5yrR6qg3BnctaoUk6NA= github.com/google/wire v0.6.0/go.mod h1:F4QhpQ9EDIdJ1Mbop/NZBRB+5yrR6qg3BnctaoUk6NA=
github.com/googleapis/enterprise-certificate-proxy v0.3.4 h1:XYIDZApgAnrN1c855gTgghdIA6Stxb52D5RnLI1SLyw= github.com/googleapis/enterprise-certificate-proxy v0.3.6 h1:GW/XbdyBFQ8Qe+YAmFU9uHLo7OnF5tL52HFAgMmyrf4=
github.com/googleapis/enterprise-certificate-proxy v0.3.4/go.mod h1:YKe7cfqYXjKGpGvmSg28/fFvhNzinZQm8DGnaburhGA= github.com/googleapis/enterprise-certificate-proxy v0.3.6/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/googleapis/gax-go/v2 v2.14.1 h1:hb0FFeiPaQskmvakKu5EbCbpntQn48jyHuvrkurSS/Q= github.com/googleapis/gax-go/v2 v2.14.2 h1:eBLnkZ9635krYIPD+ag1USrOAI0Nr0QYF3+/3GqO0k0=
github.com/googleapis/gax-go/v2 v2.14.1/go.mod h1:Hb/NubMaVM88SrNkvl8X/o8XWwDJEPqouaLeN2IUxoA= github.com/googleapis/gax-go/v2 v2.14.2/go.mod h1:ON64QhlJkhVtSqp4v1uaK92VyZ2gmvDQsweuyLV+8+w=
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
@ -376,8 +404,8 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mitchellh/mapstructure v1.5.1-0.20231216201459-8508981c8b6c h1:cqn374mizHuIWj+OSJCajGr/phAmuMug9qIX3l9CflE= github.com/mitchellh/mapstructure v1.5.1-0.20231216201459-8508981c8b6c h1:cqn374mizHuIWj+OSJCajGr/phAmuMug9qIX3l9CflE=
github.com/mitchellh/mapstructure v1.5.1-0.20231216201459-8508981c8b6c/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.1-0.20231216201459-8508981c8b6c/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
@ -388,14 +416,18 @@ github.com/muesli/smartcrop v0.3.0/go.mod h1:i2fCI/UorTfgEpPPLWiFBv4pye+YAG78Rwc
github.com/neurosnap/sentences v1.0.6/go.mod h1:pg1IapvYpWCJJm/Etxeh0+gtMf1rI1STY9S7eUCPbDc= github.com/neurosnap/sentences v1.0.6/go.mod h1:pg1IapvYpWCJJm/Etxeh0+gtMf1rI1STY9S7eUCPbDc=
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ= github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
github.com/niklasfasching/go-org v1.7.0 h1:vyMdcMWWTe/XmANk19F4k8XGBYg0GQ/gJGMimOjGMek= github.com/niklasfasching/go-org v1.8.0 h1:WyGLaajLLp8JbQzkmapZ1y0MOzKuKV47HkZRloi+HGY=
github.com/niklasfasching/go-org v1.7.0/go.mod h1:WuVm4d45oePiE0eX25GqTDQIt/qPW1T9DGkRscqLW5o= github.com/niklasfasching/go-org v1.8.0/go.mod h1:e2A9zJs7cdONrEGs3gvxCcaAEpwwPNPG7csDpXckMNg=
github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY= github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY=
github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037/go.mod h1:2bpvgLBZEtENV5scfDFEtB/5+1M4hkQhDQrccEJ/qGw= github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037/go.mod h1:2bpvgLBZEtENV5scfDFEtB/5+1M4hkQhDQrccEJ/qGw=
github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletIKwUIt4x3t8n2SxavmoclizMb8c= github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletIKwUIt4x3t8n2SxavmoclizMb8c=
github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90/go.mod h1:y5+oSEHCPT/DGrS++Wc/479ERge0zTFxaF8PbGKcg2o= github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90/go.mod h1:y5+oSEHCPT/DGrS++Wc/479ERge0zTFxaF8PbGKcg2o=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/errors v0.0.0-20250405072817-4e6d85265da6 h1:r3FaAI0NZK3hSmtTDrBVREhKULp8oUeqLT5Eyl2mSPo=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/olekukonko/errors v0.0.0-20250405072817-4e6d85265da6/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=
github.com/olekukonko/ll v0.0.8 h1:sbGZ1Fx4QxJXEqL/6IG8GEFnYojUSQ45dJVwN2FH2fc=
github.com/olekukonko/ll v0.0.8/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g=
github.com/olekukonko/tablewriter v1.0.7 h1:HCC2e3MM+2g72M81ZcJU11uciw6z/p82aEnm4/ySDGw=
github.com/olekukonko/tablewriter v1.0.7/go.mod h1:H428M+HzoUXC6JU2Abj9IT9ooRmdq9CxuDmKMtrOCMs=
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0=
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y=
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
@ -408,12 +440,16 @@ github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsK
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo=
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8=
github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
@ -428,14 +464,16 @@ github.com/shogo82148/go-shuffle v0.0.0-20180218125048-27e6095f230d/go.mod h1:2h
github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y=
github.com/spf13/afero v1.14.0 h1:9tH6MapGnn/j0eb0yIXiLjERO8RB6xIVZRDCX7PtqWA= github.com/spf13/afero v1.14.0 h1:9tH6MapGnn/j0eb0yIXiLjERO8RB6xIVZRDCX7PtqWA=
github.com/spf13/afero v1.14.0/go.mod h1:acJQ8t0ohCGuMN3O+Pv0V0hgMxNYDlvdk+VTfyZmbYo= github.com/spf13/afero v1.14.0/go.mod h1:acJQ8t0ohCGuMN3O+Pv0V0hgMxNYDlvdk+VTfyZmbYo=
github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y= github.com/spf13/cast v1.9.2 h1:SsGfm7M8QOFtEzumm7UZrZdLLquNdzFYfIbEXntcFbE=
github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/cast v1.9.2/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo=
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
github.com/spf13/fsync v0.10.1 h1:JRnB7G72b+gIBaBcpn5ibJSd7ww1iEahXSX2B8G6dSE= github.com/spf13/fsync v0.10.1 h1:JRnB7G72b+gIBaBcpn5ibJSd7ww1iEahXSX2B8G6dSE=
github.com/spf13/fsync v0.10.1/go.mod h1:y+B41vYq5i6Boa3Z+BVoPbDeOvxVkNU5OBXhoT8i4TQ= github.com/spf13/fsync v0.10.1/go.mod h1:y+B41vYq5i6Boa3Z+BVoPbDeOvxVkNU5OBXhoT8i4TQ=
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spiffe/go-spiffe/v2 v2.5.0 h1:N2I01KCUkv1FAjZXJMwh95KK1ZIQLYbPfhaxw8WS0hE=
github.com/spiffe/go-spiffe/v2 v2.5.0/go.mod h1:P+NxobPc6wXhVtINNtFjNWGBTreew1GBUCwT2wPmb7g=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
@ -449,13 +487,12 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tdewolff/minify/v2 v2.20.37 h1:Q97cx4STXCh1dlWDlNHZniE8BJ2EBL0+2b0n92BJQhw= github.com/tdewolff/minify/v2 v2.23.8 h1:tvjHzRer46kwOfpdCBCWsDblCw3QtnLJRd61pTVkyZ8=
github.com/tdewolff/minify/v2 v2.20.37/go.mod h1:L1VYef/jwKw6Wwyk5A+T0mBjjn3mMPgmjjA688RNsxU= github.com/tdewolff/minify/v2 v2.23.8/go.mod h1:VW3ISUd3gDOZuQ/jwZr4sCzsuX+Qvsx87FDMjk6Rvno=
github.com/tdewolff/parse/v2 v2.7.15 h1:hysDXtdGZIRF5UZXwpfn3ZWRbm+ru4l53/ajBRGpCTw= github.com/tdewolff/parse/v2 v2.8.1 h1:J5GSHru6o3jF1uLlEKVXkDxxcVx6yzOlIVIotK4w2po=
github.com/tdewolff/parse/v2 v2.7.15/go.mod h1:3FbJWZp3XT9OWVN3Hmfp0p/a08v4h8J9W1aghka0soA= github.com/tdewolff/parse/v2 v2.8.1/go.mod h1:Hwlni2tiVNKyzR1o6nUs4FOF07URA+JLBLd6dlIXYqo=
github.com/tdewolff/test v1.0.11-0.20231101010635-f1265d231d52/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE= github.com/tdewolff/test v1.0.11 h1:FdLbwQVHxqG16SlkGveC0JVyrJN62COWTRyUFzfbtBE=
github.com/tdewolff/test v1.0.11-0.20240106005702-7de5f7df4739 h1:IkjBCtQOOjIn03u/dMQK9g+Iw9ewps4mCl1nB8Sscbo= github.com/tdewolff/test v1.0.11/go.mod h1:XPuWBzvdUzhCuxWO1ojpXsyzsA5bFoS3tO/Q3kFuTG8=
github.com/tdewolff/test v1.0.11-0.20240106005702-7de5f7df4739/go.mod h1:XPuWBzvdUzhCuxWO1ojpXsyzsA5bFoS3tO/Q3kFuTG8=
github.com/tetratelabs/wazero v1.9.0 h1:IcZ56OuxrtaEz8UYNRHBrUa9bYeX9oVY93KspZZBf/I= github.com/tetratelabs/wazero v1.9.0 h1:IcZ56OuxrtaEz8UYNRHBrUa9bYeX9oVY93KspZZBf/I=
github.com/tetratelabs/wazero v1.9.0/go.mod h1:TSbcXCfFP0L2FGkRPxHphadXPjo1T6W+CseNNY7EkjM= github.com/tetratelabs/wazero v1.9.0/go.mod h1:TSbcXCfFP0L2FGkRPxHphadXPjo1T6W+CseNNY7EkjM=
github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0= github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0=
@ -466,10 +503,12 @@ github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yuin/goldmark v1.7.11 h1:ZCxLyDMtz0nT2HFfsYG8WZ47Trip2+JyLysKcMYE5bo= github.com/yuin/goldmark v1.7.12 h1:YwGP/rrea2/CnCtUHgjuolG/PnMxdQtPMO5PvaE2/nY=
github.com/yuin/goldmark v1.7.11/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg= github.com/yuin/goldmark v1.7.12/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg=
github.com/yuin/goldmark-emoji v1.0.6 h1:QWfF2FYaXwL74tfGOW5izeiZepUDroDJfWubQI9HTHs= github.com/yuin/goldmark-emoji v1.0.6 h1:QWfF2FYaXwL74tfGOW5izeiZepUDroDJfWubQI9HTHs=
github.com/yuin/goldmark-emoji v1.0.6/go.mod h1:ukxJDKFpdFb5x0a5HqbdlcKtebh086iJpI31LTKmWuA= github.com/yuin/goldmark-emoji v1.0.6/go.mod h1:ukxJDKFpdFb5x0a5HqbdlcKtebh086iJpI31LTKmWuA=
github.com/zeebo/errs v1.4.0 h1:XNdoD/RRMKP7HD0UhJnIzUy74ISdGGxURlYG8HSWSfM=
github.com/zeebo/errs v1.4.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
@ -480,20 +519,24 @@ go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.58.0 h1:PS8wXpbyaDJQ2VDHHncMe9Vct0Zn1fEjpsjrLxGJoSc= go.opentelemetry.io/contrib/detectors/gcp v1.35.0 h1:bGvFt68+KTiAKFlacHW6AhA56GF2rS0bdD3aJYEnmzA=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.58.0/go.mod h1:HDBUsEjOuRC0EzKZ1bSaRGZWUBAzo+MhAcUUORSr4D0= go.opentelemetry.io/contrib/detectors/gcp v1.35.0/go.mod h1:qGWP8/+ILwMRIUf9uIVLloR1uo5ZYAslM4O6OqUi1DA=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 h1:yd02MEjBdJkG3uabWP9apV+OuWRIXGDuJEUJbOHmCFU= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 h1:q4XOmH/0opmeuJtPsbFNivyl7bCt7yRBbeEm2sC/XtQ=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0/go.mod h1:umTcuxiv1n/s/S6/c2AT/g2CQ7u5C59sHDNmfSwgz7Q= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0/go.mod h1:snMWehoOh2wsEwnvvwtDyFCxVeDAODenXHtn5vzrKjo=
go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus=
go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q=
go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ= go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg=
go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE= go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E=
go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A= go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.29.0 h1:WDdP9acbMYjbKIyJUhTvtzj601sVJOqgWdUxSdR/Ysc=
go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU= go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.29.0/go.mod h1:BLbf7zbNIONBLPwvFnwNHGj4zge8uTCM/UPIVW1Mq2I=
go.opentelemetry.io/otel/sdk/metric v1.32.0 h1:rZvFnvmvawYb0alrYkjraqJq0Z4ZUJAiyYCU9snn1CU= go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE=
go.opentelemetry.io/otel/sdk/metric v1.32.0/go.mod h1:PWeZlq0zt9YkYAp3gjKZ0eicRYvOh1Gd+X99x6GHpCQ= go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs=
go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k= go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs=
go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE= go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY=
go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis=
go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4=
go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w=
go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA=
go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8= go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8=
go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0= go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0=
gocloud.dev v0.40.0 h1:f8LgP+4WDqOG/RXoUcyLpeIAGOcAbZrZbDQCUee10ng= gocloud.dev v0.40.0 h1:f8LgP+4WDqOG/RXoUcyLpeIAGOcAbZrZbDQCUee10ng=
@ -509,8 +552,8 @@ golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5y
golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE= golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc= golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@ -526,8 +569,8 @@ golang.org/x/exp v0.0.0-20221031165847-c99f073a8326/go.mod h1:CxIveKay+FTh1D0yPZ
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.26.0 h1:4XjIFEZWQmCZi6Wv8BoxsDhRU3RVnLX04dToTDAEPlY= golang.org/x/image v0.28.0 h1:gdem5JW1OLS4FbkWgLO+7ZeFzYtL3xClb97GaUzYMFE=
golang.org/x/image v0.26.0/go.mod h1:lcxbMFAovzpnJxzXS3nyL83K27tmqtKzIJpctK8YO5c= golang.org/x/image v0.28.0/go.mod h1:GUJYXtnGKEUgggyzh+Vxt+AviiCcyiwpsl8iQ8MvwGY=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@ -554,8 +597,8 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU= golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w=
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -595,8 +638,8 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY= golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E= golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@ -606,8 +649,8 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.26.0 h1:afQXWNNaeC4nvZ0Ed9XvCCzXM6UHJG7iCg0W4fPqSBE= golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
golang.org/x/oauth2 v0.26.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -623,8 +666,8 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610= golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -672,8 +715,8 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
@ -692,13 +735,13 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0= golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU= golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.10.0 h1:3usCWA8tQn0L8+hFJQNgzpWbd89begxN66o1Ojdn5L4= golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
golang.org/x/time v0.10.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
@ -751,8 +794,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=
golang.org/x/tools v0.32.0 h1:Q7N1vhpkQv7ybVzLFtTjvQya2ewbwNDZzUgfXGqtMWU= golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc=
golang.org/x/tools v0.32.0/go.mod h1:ZxrU41P/wAbZD8EDa6dDCa6XfpkhJ7HFMjHJXfBDu8s= golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@ -778,8 +821,8 @@ google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz513
google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
google.golang.org/api v0.221.0 h1:qzaJfLhDsbMeFee8zBRdt/Nc+xmOuafD/dbdgGfutOU= google.golang.org/api v0.237.0 h1:MP7XVsGZesOsx3Q8WVa4sUdbrsTvDSOERd3Vh4xj/wc=
google.golang.org/api v0.221.0/go.mod h1:7sOU2+TL4TxUTdbi0gWgAIg7tH5qBXxoyhtL+9x3biQ= google.golang.org/api v0.237.0/go.mod h1:cOVEm2TpdAGHL2z+UwyS+kmlGr3bVWQQ6sYEqkKje50=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
@ -823,12 +866,12 @@ google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6D
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20241104194629-dd2ea8efbc28 h1:KJjNNclfpIkVqrZlTWcgOOaVQ00LdBnoEaRfkUx760s= google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2 h1:1tXaIXCracvtsRxSBsYDiSBN0cuJvM7QYW+MrpIRY78=
google.golang.org/genproto v0.0.0-20241104194629-dd2ea8efbc28/go.mod h1:mt9/MofW7AWQ+Gy179ChOnvmJatV8YHUmrcedo9CIFI= google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2/go.mod h1:49MsLSx0oWMOZqcpB3uL8ZOkAh1+TndpJ8ONoCBWiZk=
google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576 h1:CkkIfIt50+lT6NHAVoRYEyAvQGFM7xEwXUUywFvEb3Q= google.golang.org/genproto/googleapis/api v0.0.0-20250505200425-f936aa4a68b2 h1:vPV0tzlsK6EzEDHNNH5sa7Hs9bd7iXR7B1tSiPepkV0=
google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576/go.mod h1:1R3kvZ1dtP3+4p4d3G8uJ8rFk/fWlScl38vanWACI08= google.golang.org/genproto/googleapis/api v0.0.0-20250505200425-f936aa4a68b2/go.mod h1:pKLAc5OolXC3ViWGI62vvC0n10CpwAtRcTNCFwTKBEw=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250207221924-e9438ea467c6 h1:2duwAxN2+k0xLNpjnHTXoMUgnv6VPSp5fiqTuwSxjmI= google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 h1:fc6jSaCT0vBduLYZHYrBBNY4dsWuvgyff9noRNDdBeE=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250207221924-e9438ea467c6/go.mod h1:8BS3B93F/U1juMFq9+EDk+qOT5CO1R9IzXxG3PTqiRk= google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
@ -845,8 +888,8 @@ google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ= google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok=
google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw= google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@ -857,8 +900,8 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=

View file

@ -19,6 +19,8 @@ import (
"sync/atomic" "sync/atomic"
"github.com/olekukonko/tablewriter" "github.com/olekukonko/tablewriter"
"github.com/olekukonko/tablewriter/renderer"
"github.com/olekukonko/tablewriter/tw"
) )
// ProcessingStats represents statistics about a site build. // ProcessingStats represents statistics about a site build.
@ -66,23 +68,6 @@ func (s *ProcessingStats) Add(counter *uint64, amount int) {
atomic.AddUint64(counter, uint64(amount)) atomic.AddUint64(counter, uint64(amount))
} }
// Table writes a table-formatted representation of the stats in a
// ProcessingStats instance to w.
func (s *ProcessingStats) Table(w io.Writer) {
titleVals := s.toVals()
data := make([][]string, len(titleVals))
for i, tv := range titleVals {
data[i] = []string{tv.name, strconv.Itoa(int(tv.val))}
}
table := tablewriter.NewWriter(w)
table.AppendBulk(data)
table.SetHeader([]string{"", s.Name})
table.SetBorder(false)
table.Render()
}
// ProcessingStatsTable writes a table-formatted representation of stats to w. // ProcessingStatsTable writes a table-formatted representation of stats to w.
func ProcessingStatsTable(w io.Writer, stats ...*ProcessingStats) { func ProcessingStatsTable(w io.Writer, stats ...*ProcessingStats) {
names := make([]string, len(stats)+1) names := make([]string, len(stats)+1)
@ -106,13 +91,26 @@ func ProcessingStatsTable(w io.Writer, stats ...*ProcessingStats) {
data[j] = append(data[j], strconv.Itoa(int(tv.val))) data[j] = append(data[j], strconv.Itoa(int(tv.val)))
} }
} }
} }
table := tablewriter.NewWriter(w) table := tablewriter.NewTable(
w,
tablewriter.WithRenderer(renderer.NewBlueprint(tw.Rendition{
Borders: tw.BorderNone,
Symbols: tw.NewSymbols(tw.StyleLight),
Settings: tw.Settings{
Separators: tw.Separators{BetweenRows: tw.Off},
Lines: tw.Lines{ShowFooterLine: tw.On},
},
})),
tablewriter.WithConfig(
tablewriter.Config{
MaxWidth: 70,
Row: tw.CellConfig{Alignment: tw.CellAlignment{Global: tw.AlignRight, PerColumn: []tw.Align{tw.AlignLeft}}},
}),
)
table.AppendBulk(data) table.Bulk(data)
table.SetHeader(names) table.Header(names)
table.SetBorder(false)
table.Render() table.Render()
} }

View file

@ -892,7 +892,7 @@ disableKinds = ['home','rss','sitemap','taxonomy','term']
--- ---
title: s title: s
cascade: cascade:
_build: build:
render: never render: never
--- ---
-- content/s/p1.md -- -- content/s/p1.md --
@ -917,3 +917,51 @@ title: p2
b.AssertFileExists("public/sx/index.html", true) // failing b.AssertFileExists("public/sx/index.html", true) // failing
b.AssertFileExists("public/sx/p2/index.html", true) // failing b.AssertFileExists("public/sx/p2/index.html", true) // failing
} }
func TestCascadeGotmplIssue13743(t *testing.T) {
t.Parallel()
files := `
-- hugo.toml --
disableKinds = ['home','rss','section','sitemap','taxonomy','term']
[cascade.params]
foo = 'bar'
[cascade.target]
path = '/p1'
-- content/_content.gotmpl --
{{ .AddPage (dict "title" "p1" "path" "p1") }}
-- layouts/all.html --
{{ .Title }}|{{ .Params.foo }}
`
b := Test(t, files)
b.AssertFileContent("public/p1/index.html", "p1|bar") // actual content is "p1|"
}
func TestCascadeWarnOverrideIssue13806(t *testing.T) {
t.Parallel()
files := `
-- hugo.toml --
disableKinds = ['home','rss','section','sitemap','taxonomy','term']
[[cascade]]
[cascade.params]
searchable = true
[cascade.target]
kind = 'page'
-- content/something.md --
---
title: Something
params:
searchable: false
---
-- layouts/all.html --
All.
`
b := Test(t, files, TestOptWarn())
b.AssertLogContains("! WARN")
}

View file

@ -1406,7 +1406,7 @@ home = ["html"]
"home": {"html"}, "home": {"html"},
"page": {"html"}, "page": {"html"},
"rss": {"rss"}, "rss": {"rss"},
"section": nil, "section": {},
"taxonomy": {"html", "rss"}, "taxonomy": {"html", "rss"},
"term": {"html", "rss"}, "term": {"html", "rss"},
}) })

View file

@ -21,7 +21,6 @@ import (
"sort" "sort"
"strconv" "strconv"
"strings" "strings"
"sync"
"sync/atomic" "sync/atomic"
"time" "time"
@ -1310,7 +1309,6 @@ func (h *HugoSites) resolveAndResetDependententPageOutputs(ctx context.Context,
} }
po.renderState = 0 po.renderState = 0
po.p.resourcesPublishInit = &sync.Once{}
if r == identity.FinderFoundOneOfMany || po.f.Name == output.HTTPStatus404HTMLFormat.Name { if r == identity.FinderFoundOneOfMany || po.f.Name == output.HTTPStatus404HTMLFormat.Name {
// Will force a re-render even in fast render mode. // Will force a re-render even in fast render mode.
po.renderOnce = false po.renderOnce = false
@ -1412,7 +1410,7 @@ func (sa *sitePagesAssembler) applyAggregates() error {
} }
// Handle cascades first to get any default dates set. // Handle cascades first to get any default dates set.
var cascade *maps.Ordered[page.PageMatcher, maps.Params] var cascade *maps.Ordered[page.PageMatcher, page.PageMatcherParamsConfig]
if keyPage == "" { if keyPage == "" {
// Home page gets it's cascade from the site config. // Home page gets it's cascade from the site config.
cascade = sa.conf.Cascade.Config cascade = sa.conf.Cascade.Config
@ -1424,7 +1422,7 @@ func (sa *sitePagesAssembler) applyAggregates() error {
} else { } else {
_, data := pw.WalkContext.Data().LongestPrefix(paths.Dir(keyPage)) _, data := pw.WalkContext.Data().LongestPrefix(paths.Dir(keyPage))
if data != nil { if data != nil {
cascade = data.(*maps.Ordered[page.PageMatcher, maps.Params]) cascade = data.(*maps.Ordered[page.PageMatcher, page.PageMatcherParamsConfig])
} }
} }
@ -1506,11 +1504,11 @@ func (sa *sitePagesAssembler) applyAggregates() error {
pageResource := rs.r.(*pageState) pageResource := rs.r.(*pageState)
relPath := pageResource.m.pathInfo.BaseRel(pageBundle.m.pathInfo) relPath := pageResource.m.pathInfo.BaseRel(pageBundle.m.pathInfo)
pageResource.m.resourcePath = relPath pageResource.m.resourcePath = relPath
var cascade *maps.Ordered[page.PageMatcher, maps.Params] var cascade *maps.Ordered[page.PageMatcher, page.PageMatcherParamsConfig]
// Apply cascade (if set) to the page. // Apply cascade (if set) to the page.
_, data := pw.WalkContext.Data().LongestPrefix(resourceKey) _, data := pw.WalkContext.Data().LongestPrefix(resourceKey)
if data != nil { if data != nil {
cascade = data.(*maps.Ordered[page.PageMatcher, maps.Params]) cascade = data.(*maps.Ordered[page.PageMatcher, page.PageMatcherParamsConfig])
} }
if err := pageResource.setMetaPost(cascade); err != nil { if err := pageResource.setMetaPost(cascade); err != nil {
return false, err return false, err
@ -1574,10 +1572,10 @@ func (sa *sitePagesAssembler) applyAggregatesToTaxonomiesAndTerms() error {
const eventName = "dates" const eventName = "dates"
if p.Kind() == kinds.KindTerm { if p.Kind() == kinds.KindTerm {
var cascade *maps.Ordered[page.PageMatcher, maps.Params] var cascade *maps.Ordered[page.PageMatcher, page.PageMatcherParamsConfig]
_, data := pw.WalkContext.Data().LongestPrefix(s) _, data := pw.WalkContext.Data().LongestPrefix(s)
if data != nil { if data != nil {
cascade = data.(*maps.Ordered[page.PageMatcher, maps.Params]) cascade = data.(*maps.Ordered[page.PageMatcher, page.PageMatcherParamsConfig])
} }
if err := p.setMetaPost(cascade); err != nil { if err := p.setMetaPost(cascade); err != nil {
return false, err return false, err

View file

@ -44,14 +44,14 @@ tags: ["mytag"]
`, "sect/no-list.md", ` `, "sect/no-list.md", `
--- ---
title: No List title: No List
_build: build:
list: false list: false
--- ---
`, "sect/no-render.md", ` `, "sect/no-render.md", `
--- ---
title: No List title: No List
_build: build:
render: false render: false
--- ---
`, `,
@ -59,14 +59,14 @@ _build:
--- ---
title: No Render Link title: No Render Link
aliases: ["/link-alias"] aliases: ["/link-alias"]
_build: build:
render: link render: link
--- ---
`, `,
"sect/no-publishresources/index.md", ` "sect/no-publishresources/index.md", `
--- ---
title: No Publish Resources title: No Publish Resources
_build: build:
publishResources: false publishResources: false
--- ---
@ -81,7 +81,7 @@ headless: true
--- ---
title: Headless Local Lists title: Headless Local Lists
cascade: cascade:
_build: build:
render: false render: false
list: local list: local
publishResources: false publishResources: false
@ -365,7 +365,7 @@ Data1: {{ $data1.RelPermalink }}
`) `)
b.WithContent("section/bundle-false/index.md", `---\ntitle: BundleFalse b.WithContent("section/bundle-false/index.md", `---\ntitle: BundleFalse
_build: build:
publishResources: false publishResources: false
---`, ---`,
"section/bundle-false/data1.json", "Some data1", "section/bundle-false/data1.json", "Some data1",
@ -388,7 +388,7 @@ func TestNoRenderAndNoPublishResources(t *testing.T) {
noRenderPage := ` noRenderPage := `
--- ---
title: %s title: %s
_build: build:
render: false render: false
publishResources: false publishResources: false
--- ---

View file

@ -263,7 +263,7 @@ func (s *IntegrationTestBuilder) AssertLogContains(els ...string) {
} }
} }
// AssertLogNotContains asserts that the last build log does matches the given regular expressions. // AssertLogMatches asserts that the last build log matches the given regular expressions.
// The regular expressions can be negated with a "! " prefix. // The regular expressions can be negated with a "! " prefix.
func (s *IntegrationTestBuilder) AssertLogMatches(expression string) { func (s *IntegrationTestBuilder) AssertLogMatches(expression string) {
s.Helper() s.Helper()

View file

@ -19,7 +19,6 @@ import (
"path/filepath" "path/filepath"
"strconv" "strconv"
"strings" "strings"
"sync"
"sync/atomic" "sync/atomic"
"github.com/gohugoio/hugo/hugofs" "github.com/gohugoio/hugo/hugofs"
@ -29,6 +28,7 @@ import (
"github.com/gohugoio/hugo/media" "github.com/gohugoio/hugo/media"
"github.com/gohugoio/hugo/output" "github.com/gohugoio/hugo/output"
"github.com/gohugoio/hugo/related" "github.com/gohugoio/hugo/related"
"github.com/gohugoio/hugo/resources"
"github.com/gohugoio/hugo/tpl/tplimpl" "github.com/gohugoio/hugo/tpl/tplimpl"
"github.com/spf13/afero" "github.com/spf13/afero"
@ -111,7 +111,6 @@ type pageState struct {
resource.Staler resource.Staler
dependencyManager identity.Manager dependencyManager identity.Manager
resourcesPublishInit *sync.Once
} }
func (p *pageState) incrPageOutputTemplateVariation() { func (p *pageState) incrPageOutputTemplateVariation() {
@ -522,26 +521,23 @@ func (p *pageState) initPage() error {
} }
func (p *pageState) renderResources() error { func (p *pageState) renderResources() error {
var initErr error
p.resourcesPublishInit.Do(func() {
for _, r := range p.Resources() { for _, r := range p.Resources() {
if _, ok := r.(page.Page); ok { if _, ok := r.(page.Page); ok {
if p.s.h.buildCounter.Load() == 0 {
// Pages gets rendered with the owning page but we count them here. // Pages gets rendered with the owning page but we count them here.
p.s.PathSpec.ProcessingStats.Incr(&p.s.PathSpec.ProcessingStats.Pages) p.s.PathSpec.ProcessingStats.Incr(&p.s.PathSpec.ProcessingStats.Pages)
}
continue continue
} }
if _, isWrapper := r.(resource.ResourceWrapper); isWrapper { if resources.IsPublished(r) {
// Skip resources that are wrapped.
// These gets published on its own.
continue continue
} }
src, ok := r.(resource.Source) src, ok := r.(resource.Source)
if !ok { if !ok {
initErr = fmt.Errorf("resource %T does not support resource.Source", r) return fmt.Errorf("resource %T does not support resource.Source", r)
return
} }
if err := src.Publish(); err != nil { if err := src.Publish(); err != nil {
@ -552,9 +548,8 @@ func (p *pageState) renderResources() error {
p.s.PathSpec.ProcessingStats.Incr(&p.s.PathSpec.ProcessingStats.Files) p.s.PathSpec.ProcessingStats.Incr(&p.s.PathSpec.ProcessingStats.Files)
} }
} }
})
return initErr return nil
} }
func (p *pageState) AlternativeOutputFormats() page.OutputFormats { func (p *pageState) AlternativeOutputFormats() page.OutputFormats {

View file

@ -29,7 +29,6 @@ import (
"github.com/gohugoio/hugo/source" "github.com/gohugoio/hugo/source"
"github.com/gohugoio/hugo/common/constants"
"github.com/gohugoio/hugo/common/hashing" "github.com/gohugoio/hugo/common/hashing"
"github.com/gohugoio/hugo/common/hugo" "github.com/gohugoio/hugo/common/hugo"
"github.com/gohugoio/hugo/common/loggers" "github.com/gohugoio/hugo/common/loggers"
@ -84,7 +83,7 @@ type pageMetaParams struct {
// These are only set in watch mode. // These are only set in watch mode.
datesOriginal pagemeta.Dates datesOriginal pagemeta.Dates
paramsOriginal map[string]any // contains the original params as defined in the front matter. paramsOriginal map[string]any // contains the original params as defined in the front matter.
cascadeOriginal *maps.Ordered[page.PageMatcher, maps.Params] // contains the original cascade as defined in the front matter. cascadeOriginal *maps.Ordered[page.PageMatcher, page.PageMatcherParamsConfig] // contains the original cascade as defined in the front matter.
} }
func (m *pageMetaParams) init(preserveOriginal bool) { func (m *pageMetaParams) init(preserveOriginal bool) {
@ -291,7 +290,7 @@ func (p *pageMeta) setMetaPre(pi *contentParseInfo, logger loggers.Logger, conf
return nil return nil
} }
func (ps *pageState) setMetaPost(cascade *maps.Ordered[page.PageMatcher, maps.Params]) error { func (ps *pageState) setMetaPost(cascade *maps.Ordered[page.PageMatcher, page.PageMatcherParamsConfig]) error {
ps.m.setMetaPostCount++ ps.m.setMetaPostCount++
var cascadeHashPre uint64 var cascadeHashPre uint64
if ps.m.setMetaPostCount > 1 { if ps.m.setMetaPostCount > 1 {
@ -303,15 +302,20 @@ func (ps *pageState) setMetaPost(cascade *maps.Ordered[page.PageMatcher, maps.Pa
// Apply cascades first so they can be overridden later. // Apply cascades first so they can be overridden later.
if cascade != nil { if cascade != nil {
if ps.m.pageConfig.CascadeCompiled != nil { if ps.m.pageConfig.CascadeCompiled != nil {
cascade.Range(func(k page.PageMatcher, v maps.Params) bool { cascade.Range(func(k page.PageMatcher, v page.PageMatcherParamsConfig) bool {
vv, found := ps.m.pageConfig.CascadeCompiled.Get(k) vv, found := ps.m.pageConfig.CascadeCompiled.Get(k)
if !found { if !found {
ps.m.pageConfig.CascadeCompiled.Set(k, v) ps.m.pageConfig.CascadeCompiled.Set(k, v)
} else { } else {
// Merge // Merge
for ck, cv := range v { for ck, cv := range v.Params {
if _, found := vv[ck]; !found { if _, found := vv.Params[ck]; !found {
vv[ck] = cv vv.Params[ck] = cv
}
}
for ck, cv := range v.Fields {
if _, found := vv.Fields[ck]; !found {
vv.Fields[ck] = cv
} }
} }
} }
@ -341,11 +345,17 @@ func (ps *pageState) setMetaPost(cascade *maps.Ordered[page.PageMatcher, maps.Pa
// Cascade is also applied to itself. // Cascade is also applied to itself.
var err error var err error
cascade.Range(func(k page.PageMatcher, v maps.Params) bool { cascade.Range(func(k page.PageMatcher, v page.PageMatcherParamsConfig) bool {
if !k.Matches(ps) { if !k.Matches(ps) {
return true return true
} }
for kk, vv := range v { for kk, vv := range v.Params {
if _, found := ps.m.pageConfig.Params[kk]; !found {
ps.m.pageConfig.Params[kk] = vv
}
}
for kk, vv := range v.Fields {
if ps.m.pageConfig.IsFromContentAdapter { if ps.m.pageConfig.IsFromContentAdapter {
if _, found := ps.m.pageConfig.ContentAdapterData[kk]; !found { if _, found := ps.m.pageConfig.ContentAdapterData[kk]; !found {
ps.m.pageConfig.ContentAdapterData[kk] = vv ps.m.pageConfig.ContentAdapterData[kk] = vv
@ -636,9 +646,6 @@ params:
} }
for k, v := range userParams { for k, v := range userParams {
if _, found := params[k]; found {
p.s.Log.Warnidf(constants.WarnFrontMatterParamsOverrides, "Hugo front matter key %q is overridden in params section.", k)
}
params[strings.ToLower(k)] = v params[strings.ToLower(k)] = v
} }

View file

@ -16,12 +16,12 @@ package hugolib
import ( import (
"fmt" "fmt"
"strings" "strings"
"sync"
"sync/atomic" "sync/atomic"
"github.com/gohugoio/hugo/hugofs/files" "github.com/gohugoio/hugo/hugofs/files"
"github.com/gohugoio/hugo/resources" "github.com/gohugoio/hugo/resources"
"github.com/gohugoio/hugo/common/constants"
"github.com/gohugoio/hugo/common/maps" "github.com/gohugoio/hugo/common/maps"
"github.com/gohugoio/hugo/common/paths" "github.com/gohugoio/hugo/common/paths"
@ -40,6 +40,14 @@ func (h *HugoSites) newPage(m *pageMeta) (*pageState, *paths.Path, error) {
// Make sure that any partially created page part is marked as stale. // Make sure that any partially created page part is marked as stale.
m.MarkStale() m.MarkStale()
} }
if p != nil && pth != nil && p.IsHome() && pth.IsLeafBundle() {
msg := "Using %s in your content's root directory is usually incorrect for your home page. "
msg += "You should use %s instead. If you don't rename this file, your home page will be "
msg += "treated as a leaf bundle, meaning it won't be able to have any child pages or sections."
h.Log.Warnidf(constants.WarnHomePageIsLeafBundle, msg, pth.PathNoLeadingSlash(), strings.ReplaceAll(pth.PathNoLeadingSlash(), "index", "_index"))
}
return p, pth, err return p, pth, err
} }
@ -190,7 +198,6 @@ func (h *HugoSites) doNewPage(m *pageMeta) (*pageState, *paths.Path, error) {
pid: pid, pid: pid,
pageOutput: nopPageOutput, pageOutput: nopPageOutput,
pageOutputTemplateVariationsState: &atomic.Uint32{}, pageOutputTemplateVariationsState: &atomic.Uint32{},
resourcesPublishInit: &sync.Once{},
Staler: m, Staler: m,
dependencyManager: m.s.Conf.NewIdentityManager(m.Path()), dependencyManager: m.s.Conf.NewIdentityManager(m.Path()),
pageCommon: &pageCommon{ pageCommon: &pageCommon{

View file

@ -1968,3 +1968,35 @@ Title: {{ .Title }}
"deprecated: path in front matter was deprecated", "deprecated: path in front matter was deprecated",
) )
} }
// Issue 13538
func TestHomePageIsLeafBundle(t *testing.T) {
t.Parallel()
files := `
-- hugo.toml --
defaultContentLanguage = 'de'
defaultContentLanguageInSubdir = true
[languages.de]
weight = 1
[languages.en]
weight = 2
-- layouts/all.html --
{{ .Title }}
-- content/index.de.md --
---
title: home de
---
-- content/index.en.org --
---
title: home en
---
`
b := Test(t, files, TestOptWarn())
b.AssertFileContent("public/de/index.html", "home de")
b.AssertFileContent("public/en/index.html", "home en")
b.AssertLogContains("Using index.de.md in your content's root directory is usually incorrect for your home page. You should use _index.de.md instead.")
b.AssertLogContains("Using index.en.org in your content's root directory is usually incorrect for your home page. You should use _index.en.org instead.")
}

View file

@ -57,7 +57,7 @@ Summary: {{ .Summary }}|
) )
} }
func TestFrontMatterParamsKindPath(t *testing.T) { func TestFrontMatterParamsPath(t *testing.T) {
t.Parallel() t.Parallel()
files := ` files := `
@ -72,10 +72,9 @@ date: 2019-08-07
path: "/a/b/c" path: "/a/b/c"
slug: "s1" slug: "s1"
--- ---
-- content/mysection.md -- -- content/mysection/_index.md --
--- ---
title: "My Section" title: "My Section"
kind: "section"
date: 2022-08-07 date: 2022-08-07
path: "/a/b" path: "/a/b"
--- ---
@ -95,66 +94,6 @@ a/b pages: {{ range $ab.RegularPages }}{{ .Path }}|{{ .RelPermalink }}|{{ end }}
) )
} }
func TestFrontMatterParamsLang(t *testing.T) {
t.Parallel()
files := `
-- hugo.toml --
baseURL = "https://example.org/"
disableKinds = ["taxonomy", "term"]
defaultContentLanguage = "en"
defaultContentLanguageInSubdir = true
[languages]
[languages.en]
weight = 1
[languages.nn]
weight = 2
-- content/p1.md --
---
title: "P1 nn"
lang: "nn"
---
-- content/p2.md --
---
title: "P2"
---
-- layouts/index.html --
RegularPages: {{ range site.RegularPages }}{{ .Path }}|{{ .RelPermalink }}|{{ .Title }}|{{ end }}$
`
b := Test(t, files)
b.AssertFileContent("public/en/index.html",
"RegularPages: /p2|/en/p2/|P2|$",
)
b.AssertFileContent("public/nn/index.html",
"RegularPages: /p1|/nn/p1/|P1 nn|$",
)
}
func TestFrontMatterTitleOverrideWarn(t *testing.T) {
t.Parallel()
files := `
-- hugo.toml --
baseURL = "https://example.org/"
disableKinds = ["taxonomy", "term"]
-- content/p1.md --
---
title: "My title"
params:
title: "My title from params"
---
`
b := Test(t, files, TestOptWarn())
b.AssertLogContains("ARN Hugo front matter key \"title\" is overridden in params section", "You can suppress this warning")
}
func TestFrontMatterParamsLangNoCascade(t *testing.T) { func TestFrontMatterParamsLangNoCascade(t *testing.T) {
t.Parallel() t.Parallel()

View file

@ -1766,6 +1766,60 @@ MyTemplate: {{ partial "MyTemplate.html" . }}|
b.AssertFileContent("public/index.html", "MyTemplate: MyTemplate Edited") b.AssertFileContent("public/index.html", "MyTemplate: MyTemplate Edited")
} }
func TestRebuildEditInlinePartial13723(t *testing.T) {
t.Parallel()
files := `
-- hugo.toml --
baseURL = "https://example.com"
disableLiveReload = true
title = "Foo"
-- layouts/baseof.html --
{{ block "main" . }}Main.{{ end }}
{{ partial "myinlinepartialinbaseof.html" . }}|
{{- define "_partials/myinlinepartialinbaseof.html" }}
My inline partial in baseof.
{{ end }}
-- layouts/_partials/mypartial.html --
Mypartial.
{{ partial "myinlinepartial.html" . }}|
{{- define "_partials/myinlinepartial.html" }}
Mypartial Inline.|{{ .Title }}|
{{ end }}
-- layouts/_partials/myotherpartial.html --
Myotherpartial.
{{ partial "myotherinlinepartial.html" . }}|
{{- define "_partials/myotherinlinepartial.html" }}
Myotherpartial Inline.|{{ .Title }}|
{{ return "myotherinlinepartial" }}
{{ end }}
-- layouts/all.html --
{{ define "main" }}
{{ partial "mypartial.html" . }}|
{{ partial "myotherpartial.html" . }}|
{{ partial "myinlinepartialinall.html" . }}|
{{ end }}
{{- define "_partials/myinlinepartialinall.html" }}
My inline partial in all.
{{ end }}
`
b := TestRunning(t, files)
b.AssertFileContent("public/index.html", "Mypartial.", "Mypartial Inline.|Foo")
// Edit inline partial in partial.
b.EditFileReplaceAll("layouts/_partials/mypartial.html", "Mypartial Inline.", "Mypartial Inline Edited.").Build()
b.AssertFileContent("public/index.html", "Mypartial Inline Edited.|Foo")
// Edit inline partial in baseof.
b.EditFileReplaceAll("layouts/baseof.html", "My inline partial in baseof.", "My inline partial in baseof Edited.").Build()
b.AssertFileContent("public/index.html", "My inline partial in baseof Edited.")
// Edit inline partial in all.
b.EditFileReplaceAll("layouts/all.html", "My inline partial in all.", "My inline partial in all Edited.").Build()
b.AssertFileContent("public/index.html", "My inline partial in all Edited.")
}
func TestRebuildEditAsciidocContentFile(t *testing.T) { func TestRebuildEditAsciidocContentFile(t *testing.T) {
if !asciidocext.Supports() { if !asciidocext.Supports() {
t.Skip("skip asciidoc") t.Skip("skip asciidoc")
@ -1892,3 +1946,23 @@ tags: ["tag1"]
// But that is a harder problem to tackle. // But that is a harder problem to tackle.
b.AssertFileContent("public/tags/index.html", "All. Tag1|Tag2|") b.AssertFileContent("public/tags/index.html", "All. Tag1|Tag2|")
} }
func TestRebuildEditNonReferencedResourceIssue13748(t *testing.T) {
t.Parallel()
files := `
-- hugo.toml --
baseURL = "https://example.com"
disableLiveReload = true
-- content/mybundle/index.md --
-- content/mybundle/resource.txt --
This is a resource file.
-- layouts/all.html --
All.
`
b := TestRunning(t, files)
b.AssertFileContent("public/mybundle/resource.txt", "This is a resource file.")
b.EditFileReplaceAll("content/mybundle/resource.txt", "This is a resource file.", "This is an edited resource file.").Build()
b.AssertFileContent("public/mybundle/resource.txt", "This is an edited resource file.")
}

View file

@ -398,6 +398,10 @@ func doRenderShortcode(
return true return true
} }
base, layoutDescriptor := po.GetInternalTemplateBasePathAndDescriptor() base, layoutDescriptor := po.GetInternalTemplateBasePathAndDescriptor()
// With shortcodes/mymarkdown.md (only), this allows {{% mymarkdown %}} when rendering HTML,
// but will not resolve any template when doing {{< mymarkdown >}}.
layoutDescriptor.AlwaysAllowPlainText = sc.doMarkup
q := tplimpl.TemplateQuery{ q := tplimpl.TemplateQuery{
Path: base, Path: base,
Name: sc.name, Name: sc.name,
@ -405,10 +409,9 @@ func doRenderShortcode(
Desc: layoutDescriptor, Desc: layoutDescriptor,
Consider: include, Consider: include,
} }
v := s.TemplateStore.LookupShortcode(q) v, err := s.TemplateStore.LookupShortcode(q)
if v == nil { if v == nil {
s.Log.Errorf("Unable to locate template for shortcode %q in page %q", sc.name, p.File().Path()) return zeroShortcode, err
return zeroShortcode, nil
} }
tmpl = v tmpl = v
hasVariants = hasVariants || len(ofCount) > 1 hasVariants = hasVariants || len(ofCount) > 1

View file

@ -918,7 +918,7 @@ func TestShortcodeMarkdownOutputFormat(t *testing.T) {
--- ---
title: "p1" title: "p1"
--- ---
{{< foo >}} {{% foo %}}
# The below would have failed using the HTML template parser. # The below would have failed using the HTML template parser.
-- layouts/shortcodes/foo.md -- -- layouts/shortcodes/foo.md --
§§§ §§§
@ -930,9 +930,7 @@ title: "p1"
b := Test(t, files) b := Test(t, files)
b.AssertFileContent("public/p1/index.html", ` b.AssertFileContent("public/p1/index.html", "<code>&lt;x")
<x
`)
} }
func TestShortcodePreserveIndentation(t *testing.T) { func TestShortcodePreserveIndentation(t *testing.T) {

View file

@ -204,6 +204,7 @@ func NewHugoSites(cfg deps.DepsCfg) (*HugoSites, error) {
// Katex is relatively slow. // Katex is relatively slow.
PoolSize: 8, PoolSize: 8,
Infof: logger.InfoCommand("wasm").Logf, Infof: logger.InfoCommand("wasm").Logf,
Warnf: logger.WarnCommand("wasm").Logf,
}, },
), ),
} }

View file

@ -16,7 +16,6 @@ package hugolib
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"io"
"testing" "testing"
"github.com/gohugoio/hugo/helpers" "github.com/gohugoio/hugo/helpers"
@ -89,14 +88,11 @@ aliases: [/Ali%d]
h.Sites[1].PathSpec.ProcessingStats, h.Sites[1].PathSpec.ProcessingStats,
} }
stats[0].Table(io.Discard)
stats[1].Table(io.Discard)
var buff bytes.Buffer var buff bytes.Buffer
helpers.ProcessingStatsTable(&buff, stats...) helpers.ProcessingStatsTable(&buff, stats...)
c.Assert(buff.String(), qt.Contains, "Pages | 21 | 7") c.Assert(buff.String(), qt.Contains, "Pages │ 21 │ 7")
} }
func TestSiteLastmod(t *testing.T) { func TestSiteLastmod(t *testing.T) {

View file

@ -615,7 +615,7 @@ var weightedPage5 = `+++
weight = "5" weight = "5"
title = "Five" title = "Five"
[_build] [build]
render = "never" render = "never"
+++ +++
Front Matter with Ordered Pages 5` Front Matter with Ordered Pages 5`

View file

@ -1,7 +1,14 @@
# Release env. # Release env.
# These will be replaced by script before release. # These will be replaced by script before release.
HUGORELEASER_TAG=v0.147.2 HUGORELEASER_TAG=v0.147.9
HUGORELEASER_COMMITISH=c7feb15d10b29a94d7fb57c31e8bcb2e92718fb7 HUGORELEASER_COMMITISH=29bdbde19c288d190e889294a862103c6efb70bf

View file

@ -4,6 +4,15 @@ export function readInput(handle) {
let currentLine = []; let currentLine = [];
const buffer = new Uint8Array(buffSize); const buffer = new Uint8Array(buffSize);
// These are not implemented by QuickJS.
console.warn = (value) => {
console.log(value);
};
console.error = (value) => {
throw new Error(value);
};
// Read all the available bytes // Read all the available bytes
while (true) { while (true) {
// Stdin file descriptor // Stdin file descriptor

View file

@ -1,2 +1,2 @@
(()=>{function l(r){let e=[],a=new Uint8Array(1024);for(;;){let n=0;try{n=Javy.IO.readSync(0,a)}catch(o){if(o.message.includes("os error 29"))break;throw new Error("Error reading from stdin")}if(n<0)throw new Error("Error reading from stdin");if(n===0)break;if(e=[...e,...a.subarray(0,n)],!e.includes(10))continue;let t=0;for(let o=0;t<e.length;t++)if(e[t]===10){let w=e.splice(o,t+1),f=new Uint8Array(w),c;try{c=JSON.parse(new TextDecoder().decode(f))}catch(d){throw new Error(`Error parsing JSON '${new TextDecoder().decode(f)}' from stdin: ${d.message}`)}try{r(c)}catch(d){let u=c.header;u.err=d.message,i({header:u})}o=t+1}e=e.slice(t)}}function i(r){let s=new TextEncoder().encode(JSON.stringify(r)+` (()=>{function w(r){let e=[],c=new Uint8Array(1024);for(console.warn=n=>{console.log(n)},console.error=n=>{throw new Error(n)};;){let o=0;try{o=Javy.IO.readSync(0,c)}catch(a){if(a.message.includes("os error 29"))break;throw new Error("Error reading from stdin")}if(o<0)throw new Error("Error reading from stdin");if(o===0)break;if(e=[...e,...c.subarray(0,o)],!e.includes(10))continue;let t=0;for(let a=0;t<e.length;t++)if(e[t]===10){let h=e.splice(a,t+1),l=new Uint8Array(h),d;try{d=JSON.parse(new TextDecoder().decode(l))}catch(s){throw new Error(`Error parsing JSON '${new TextDecoder().decode(l)}' from stdin: ${s.message}`)}try{r(d)}catch(s){let u=d.header;u.err=s.message,i({header:u})}a=t+1}e=e.slice(t)}}function i(r){let f=new TextEncoder().encode(JSON.stringify(r)+`
`),e=new Uint8Array(s);Javy.IO.writeSync(1,e)}var h=function(r){i({header:r.header,data:{greeting:"Hello "+r.data.name+"!"}})};console.log("Greet module loaded");l(h);})(); `),e=new Uint8Array(f);Javy.IO.writeSync(1,e)}var g=function(r){i({header:r.header,data:{greeting:"Hello "+r.data.name+"!"}})};console.log("Greet module loaded");w(g);})();

File diff suppressed because one or more lines are too long

View file

@ -7,6 +7,16 @@ const render = function (input) {
const expression = data.expression; const expression = data.expression;
const options = data.options; const options = data.options;
const header = input.header; const header = input.header;
header.warnings = [];
if (options.strict == 'warn') {
// By default, KaTeX will write to console.warn, that's a little hard to handle.
options.strict = (errorCode, errorMsg) => {
header.warnings.push(
`katex: LaTeX-incompatible input and strict mode is set to 'warn': ${errorMsg} [${errorCode}]`,
);
};
}
// Any error thrown here will be caught by the common.js readInput function. // Any error thrown here will be caught by the common.js readInput function.
const output = katex.renderToString(expression, options); const output = katex.renderToString(expression, options);
writeOutput({ header: header, data: { output: output } }); writeOutput({ header: header, data: { output: output } });

View file

@ -53,6 +53,22 @@ type KatexOptions struct {
// If true, KaTeX will throw a ParseError when it encounters an unsupported command. // If true, KaTeX will throw a ParseError when it encounters an unsupported command.
ThrowOnError bool `json:"throwOnError"` ThrowOnError bool `json:"throwOnError"`
// Controls how KaTeX handles LaTeX features that offer convenience but
// aren't officially supported, one of error (default), ignore, or warn.
//
// - error: Throws an error when convenient, unsupported LaTeX features
// are encountered.
// - ignore: Allows convenient, unsupported LaTeX features without any
// feedback.
// - warn: Emits a warning when convenient, unsupported LaTeX features are
// encountered.
//
// The "newLineInDisplayMode" error code, which flags the use of \\
// or \newline in display mode outside an array or tabular environment, is
// intentionally designed not to throw an error, despite this behavior
// being questionable.
Strict string `json:"strict"`
} }
type KatexOutput struct { type KatexOutput struct {

View file

@ -51,6 +51,9 @@ type Header struct {
// Set in the response if there was an error. // Set in the response if there was an error.
Err string `json:"err"` Err string `json:"err"`
// Warnings is a list of warnings that may be returned in the response.
Warnings []string `json:"warnings,omitempty"`
} }
type Message[T any] struct { type Message[T any] struct {
@ -155,6 +158,7 @@ func (p *dispatcherPool[Q, R]) Execute(ctx context.Context, q Message[Q]) (Messa
} }
resp, err := call.response, p.Err() resp, err := call.response, p.Err()
if err == nil && resp.Header.Err != "" { if err == nil && resp.Header.Err != "" {
err = errors.New(resp.Header.Err) err = errors.New(resp.Header.Err)
} }
@ -270,6 +274,8 @@ type Options struct {
Infof func(format string, v ...any) Infof func(format string, v ...any)
Warnf func(format string, v ...any)
// E.g. quickjs wasm. May be omitted if not needed. // E.g. quickjs wasm. May be omitted if not needed.
Runtime Binary Runtime Binary
@ -325,6 +331,7 @@ type dispatcherPool[Q, R any] struct {
counter atomic.Uint32 counter atomic.Uint32
dispatchers []*dispatcher[Q, R] dispatchers []*dispatcher[Q, R]
close func() error close func() error
opts Options
errc chan error errc chan error
donec chan struct{} donec chan struct{}
@ -355,6 +362,11 @@ func newDispatcher[Q, R any](opts Options) (*dispatcherPool[Q, R], error) {
// noop // noop
} }
} }
if opts.Warnf == nil {
opts.Warnf = func(format string, v ...any) {
// noop
}
}
if opts.Memory <= 0 { if opts.Memory <= 0 {
// 32 MiB // 32 MiB
@ -466,6 +478,7 @@ func newDispatcher[Q, R any](opts Options) (*dispatcherPool[Q, R], error) {
dp := &dispatcherPool[Q, R]{ dp := &dispatcherPool[Q, R]{
dispatchers: make([]*dispatcher[Q, R], len(inOuts)), dispatchers: make([]*dispatcher[Q, R], len(inOuts)),
opts: opts,
errc: make(chan error, 10), errc: make(chan error, 10),
donec: make(chan struct{}), donec: make(chan struct{}),

Binary file not shown.

Binary file not shown.

View file

@ -104,7 +104,7 @@ func (i Item) ValTyped(source []byte) any {
} }
func (i Item) IsText() bool { func (i Item) IsText() bool {
return i.Type == tText || i.Type == tIndentation return i.Type == tText || i.IsIndentation()
} }
func (i Item) IsIndentation() bool { func (i Item) IsIndentation() bool {
@ -152,7 +152,7 @@ func (i Item) IsFrontMatter() bool {
} }
func (i Item) IsDone() bool { func (i Item) IsDone() bool {
return i.Type == tError || i.Type == tEOF return i.IsError() || i.IsEOF()
} }
func (i Item) IsEOF() bool { func (i Item) IsEOF() bool {
@ -166,19 +166,20 @@ func (i Item) IsError() bool {
func (i Item) ToString(source []byte) string { func (i Item) ToString(source []byte) string {
val := i.Val(source) val := i.Val(source)
switch { switch {
case i.Type == tEOF: case i.IsEOF():
return "EOF" return "EOF"
case i.Type == tError: case i.IsError():
return string(val) return string(val)
case i.Type == tIndentation: case i.IsIndentation():
return fmt.Sprintf("%s:[%s]", i.Type, util.VisualizeSpaces(val)) return fmt.Sprintf("%s:[%s]", i.Type, util.VisualizeSpaces(val))
case i.Type > tKeywordMarker: case i.Type > tKeywordMarker:
return fmt.Sprintf("<%s>", val) return fmt.Sprintf("<%s>", val)
case len(val) > 50: case len(val) > 50:
return fmt.Sprintf("%v:%.20q...", i.Type, val) return fmt.Sprintf("%v:%.20q...", i.Type, val)
} default:
return fmt.Sprintf("%v:[%s]", i.Type, val) return fmt.Sprintf("%v:[%s]", i.Type, val)
} }
}
type ItemType int type ItemType int

View file

@ -47,3 +47,217 @@ func TestItemValTyped(t *testing.T) {
source = []byte("xtrue") source = []byte("xtrue")
c.Assert(Item{low: 0, high: len(source)}.ValTyped(source), qt.Equals, "xtrue") c.Assert(Item{low: 0, high: len(source)}.ValTyped(source), qt.Equals, "xtrue")
} }
func TestItemBoolMethods(t *testing.T) {
c := qt.New(t)
source := []byte(" shortcode ")
tests := []struct {
name string
item Item
source []byte
want bool
call func(Item, []byte) bool
}{
{
name: "IsText true",
item: Item{Type: tText},
call: func(i Item, _ []byte) bool { return i.IsText() },
want: true,
},
{
name: "IsIndentation false",
item: Item{Type: tText},
call: func(i Item, _ []byte) bool { return i.IsIndentation() },
want: false,
},
{
name: "IsShortcodeName",
item: Item{Type: tScName},
call: func(i Item, _ []byte) bool { return i.IsShortcodeName() },
want: true,
},
{
name: "IsNonWhitespace true",
item: Item{
Type: tText,
low: 2,
high: 11,
},
source: source,
call: func(i Item, src []byte) bool { return i.IsNonWhitespace(src) },
want: true,
},
{
name: "IsShortcodeParam false",
item: Item{Type: tScParamVal},
call: func(i Item, _ []byte) bool { return i.IsShortcodeParam() },
want: false,
},
{
name: "IsInlineShortcodeName",
item: Item{Type: tScNameInline},
call: func(i Item, _ []byte) bool { return i.IsInlineShortcodeName() },
want: true,
},
{
name: "IsLeftShortcodeDelim tLeftDelimScWithMarkup",
item: Item{Type: tLeftDelimScWithMarkup},
call: func(i Item, _ []byte) bool { return i.IsLeftShortcodeDelim() },
want: true,
},
{
name: "IsLeftShortcodeDelim tLeftDelimScNoMarkup",
item: Item{Type: tLeftDelimScNoMarkup},
call: func(i Item, _ []byte) bool { return i.IsLeftShortcodeDelim() },
want: true,
},
{
name: "IsRightShortcodeDelim tRightDelimScWithMarkup",
item: Item{Type: tRightDelimScWithMarkup},
call: func(i Item, _ []byte) bool { return i.IsRightShortcodeDelim() },
want: true,
},
{
name: "IsRightShortcodeDelim tRightDelimScNoMarkup",
item: Item{Type: tRightDelimScNoMarkup},
call: func(i Item, _ []byte) bool { return i.IsRightShortcodeDelim() },
want: true,
},
{
name: "IsShortcodeClose",
item: Item{Type: tScClose},
call: func(i Item, _ []byte) bool { return i.IsShortcodeClose() },
want: true,
},
{
name: "IsShortcodeParamVal",
item: Item{Type: tScParamVal},
call: func(i Item, _ []byte) bool { return i.IsShortcodeParamVal() },
want: true,
},
{
name: "IsShortcodeMarkupDelimiter tLeftDelimScWithMarkup",
item: Item{Type: tLeftDelimScWithMarkup},
call: func(i Item, _ []byte) bool { return i.IsShortcodeMarkupDelimiter() },
want: true,
},
{
name: "IsShortcodeMarkupDelimiter tRightDelimScWithMarkup",
item: Item{Type: tRightDelimScWithMarkup},
call: func(i Item, _ []byte) bool { return i.IsShortcodeMarkupDelimiter() },
want: true,
},
{
name: "IsFrontMatter TypeFrontMatterYAML",
item: Item{Type: TypeFrontMatterYAML},
call: func(i Item, _ []byte) bool { return i.IsFrontMatter() },
want: true,
},
{
name: "IsFrontMatter TypeFrontMatterTOML",
item: Item{Type: TypeFrontMatterTOML},
call: func(i Item, _ []byte) bool { return i.IsFrontMatter() },
want: true,
},
{
name: "IsFrontMatter TypeFrontMatterJSON",
item: Item{Type: TypeFrontMatterJSON},
call: func(i Item, _ []byte) bool { return i.IsFrontMatter() },
want: true,
},
{
name: "IsFrontMatter TypeFrontMatterORG",
item: Item{Type: TypeFrontMatterORG},
call: func(i Item, _ []byte) bool { return i.IsFrontMatter() },
want: true,
},
{
name: "IsDone tError",
item: Item{Type: tError},
call: func(i Item, _ []byte) bool { return i.IsDone() },
want: true,
},
{
name: "IsDone tEOF",
item: Item{Type: tEOF},
call: func(i Item, _ []byte) bool { return i.IsDone() },
want: true,
},
{
name: "IsEOF",
item: Item{Type: tEOF},
call: func(i Item, _ []byte) bool { return i.IsEOF() },
want: true,
},
{
name: "IsError",
item: Item{Type: tError},
call: func(i Item, _ []byte) bool { return i.IsError() },
want: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := tt.call(tt.item, tt.source)
c.Assert(got, qt.Equals, tt.want)
})
}
}
func TestItem_ToString(t *testing.T) {
c := qt.New(t)
source := []byte("src")
long := make([]byte, 100)
for i := range long {
long[i] = byte(i)
}
tests := []struct {
name string
item Item
source []byte
want string
call func(Item, []byte) string
}{
{
name: "EOF",
item: Item{Type: tEOF},
call: func(i Item, _ []byte) string { return i.ToString(source) },
want: "EOF",
},
{
name: "Error",
item: Item{Type: tError},
call: func(i Item, _ []byte) string { return i.ToString(source) },
want: "",
},
{
name: "Indentation",
item: Item{Type: tIndentation},
call: func(i Item, _ []byte) string { return i.ToString(source) },
want: "tIndentation:[]",
},
{
name: "Long",
item: Item{Type: tKeywordMarker + 1, low: 0, high: 100},
call: func(i Item, _ []byte) string { return i.ToString(long) },
want: "<" + string(long) + ">",
},
{
name: "Empty",
item: Item{Type: tKeywordMarker + 1},
call: func(i Item, _ []byte) string { return i.ToString([]byte("")) },
want: "<>",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := tt.call(tt.item, tt.source)
c.Assert(got, qt.Equals, tt.want)
})
}
}

View file

@ -105,9 +105,9 @@ func CheckCascadePattern(logger loggers.Logger, m PageMatcher) {
} }
} }
func DecodeCascadeConfig(logger loggers.Logger, handleLegacyFormat bool, in any) (*config.ConfigNamespace[[]PageMatcherParamsConfig, *maps.Ordered[PageMatcher, maps.Params]], error) { func DecodeCascadeConfig(logger loggers.Logger, handleLegacyFormat bool, in any) (*config.ConfigNamespace[[]PageMatcherParamsConfig, *maps.Ordered[PageMatcher, PageMatcherParamsConfig]], error) {
buildConfig := func(in any) (*maps.Ordered[PageMatcher, maps.Params], any, error) { buildConfig := func(in any) (*maps.Ordered[PageMatcher, PageMatcherParamsConfig], any, error) {
cascade := maps.NewOrdered[PageMatcher, maps.Params]() cascade := maps.NewOrdered[PageMatcher, PageMatcherParamsConfig]()
if in == nil { if in == nil {
return cascade, []map[string]any{}, nil return cascade, []map[string]any{}, nil
} }
@ -124,11 +124,7 @@ func DecodeCascadeConfig(logger loggers.Logger, handleLegacyFormat bool, in any)
c PageMatcherParamsConfig c PageMatcherParamsConfig
err error err error
) )
if handleLegacyFormat {
c, err = mapToPageMatcherParamsConfigLegacy(m)
} else {
c, err = mapToPageMatcherParamsConfig(m) c, err = mapToPageMatcherParamsConfig(m)
}
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
@ -147,23 +143,28 @@ func DecodeCascadeConfig(logger loggers.Logger, handleLegacyFormat bool, in any)
if found { if found {
// Merge // Merge
for k, v := range cfg.Params { for k, v := range cfg.Params {
if _, found := c[k]; !found { if _, found := c.Params[k]; !found {
c[k] = v c.Params[k] = v
}
}
for k, v := range cfg.Fields {
if _, found := c.Fields[k]; !found {
c.Fields[k] = v
} }
} }
} else { } else {
cascade.Set(m, cfg.Params) cascade.Set(m, cfg)
} }
} }
return cascade, cfgs, nil return cascade, cfgs, nil
} }
return config.DecodeNamespace[[]PageMatcherParamsConfig, *maps.Ordered[PageMatcher, maps.Params]](in, buildConfig) return config.DecodeNamespace[[]PageMatcherParamsConfig, *maps.Ordered[PageMatcher, PageMatcherParamsConfig]](in, buildConfig)
} }
// DecodeCascade decodes in which could be either a map or a slice of maps. // DecodeCascade decodes in which could be either a map or a slice of maps.
func DecodeCascade(logger loggers.Logger, handleLegacyFormat bool, in any) (*maps.Ordered[PageMatcher, maps.Params], error) { func DecodeCascade(logger loggers.Logger, handleLegacyFormat bool, in any) (*maps.Ordered[PageMatcher, PageMatcherParamsConfig], error) {
conf, err := DecodeCascadeConfig(logger, handleLegacyFormat, in) conf, err := DecodeCascadeConfig(logger, handleLegacyFormat, in)
if err != nil { if err != nil {
return nil, err return nil, err
@ -173,6 +174,9 @@ func DecodeCascade(logger loggers.Logger, handleLegacyFormat bool, in any) (*map
func mapToPageMatcherParamsConfig(m map[string]any) (PageMatcherParamsConfig, error) { func mapToPageMatcherParamsConfig(m map[string]any) (PageMatcherParamsConfig, error) {
var pcfg PageMatcherParamsConfig var pcfg PageMatcherParamsConfig
if pcfg.Fields == nil {
pcfg.Fields = make(maps.Params)
}
for k, v := range m { for k, v := range m {
switch strings.ToLower(k) { switch strings.ToLower(k) {
case "_target", "target": case "_target", "target":
@ -181,47 +185,19 @@ func mapToPageMatcherParamsConfig(m map[string]any) (PageMatcherParamsConfig, er
return pcfg, err return pcfg, err
} }
pcfg.Target = target pcfg.Target = target
default: case "params":
if pcfg.Params == nil { if pcfg.Params == nil {
pcfg.Params = make(maps.Params) pcfg.Params = make(maps.Params)
} }
pcfg.Params[k] = v
}
}
return pcfg, pcfg.init()
}
func mapToPageMatcherParamsConfigLegacy(m map[string]any) (PageMatcherParamsConfig, error) {
var pcfg PageMatcherParamsConfig
for k, v := range m {
switch strings.ToLower(k) {
case "params":
// We simplified the structure of the cascade config in Hugo 0.111.0.
// There is a small chance that someone has used the old structure with the params keyword,
// those values will now be moved to the top level.
// This should be very unlikely as it would lead to constructs like .Params.params.foo,
// and most people see params as an Hugo internal keyword.
params := maps.ToStringMap(v) params := maps.ToStringMap(v)
if pcfg.Params == nil {
pcfg.Params = params
} else {
for k, v := range params { for k, v := range params {
if _, found := pcfg.Params[k]; !found { if _, found := pcfg.Params[k]; !found {
pcfg.Params[k] = v pcfg.Params[k] = v
} }
} }
}
case "_target", "target":
var target PageMatcher
if err := decodePageMatcher(v, &target); err != nil {
return pcfg, err
}
pcfg.Target = target
default: default:
if pcfg.Params == nil {
pcfg.Params = make(maps.Params) pcfg.Fields[k] = v
}
pcfg.Params[k] = v
} }
} }
return pcfg, pcfg.init() return pcfg, pcfg.init()
@ -250,10 +226,14 @@ func decodePageMatcher(m any, v *PageMatcher) error {
type PageMatcherParamsConfig struct { type PageMatcherParamsConfig struct {
// Apply Params to all Pages matching Target. // Apply Params to all Pages matching Target.
Params maps.Params Params maps.Params
// Fields holds all fields but Params.
Fields maps.Params
// Target is the PageMatcher that this config applies to.
Target PageMatcher Target PageMatcher
} }
func (p *PageMatcherParamsConfig) init() error { func (p *PageMatcherParamsConfig) init() error {
maps.PrepareParams(p.Params) maps.PrepareParams(p.Params)
maps.PrepareParams(p.Fields)
return nil return nil
} }

View file

@ -84,23 +84,22 @@ func TestPageMatcher(t *testing.T) {
c.Run("mapToPageMatcherParamsConfig", func(c *qt.C) { c.Run("mapToPageMatcherParamsConfig", func(c *qt.C) {
fn := func(m map[string]any) PageMatcherParamsConfig { fn := func(m map[string]any) PageMatcherParamsConfig {
v, err := mapToPageMatcherParamsConfigLegacy(m) v, err := mapToPageMatcherParamsConfig(m)
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
return v return v
} }
// Legacy.
c.Assert(fn(map[string]any{"_target": map[string]any{"kind": "page"}, "foo": "bar"}), qt.DeepEquals, PageMatcherParamsConfig{ c.Assert(fn(map[string]any{"_target": map[string]any{"kind": "page"}, "foo": "bar"}), qt.DeepEquals, PageMatcherParamsConfig{
Params: maps.Params{ Fields: maps.Params{
"foo": "bar", "foo": "bar",
}, },
Target: PageMatcher{Path: "", Kind: "page", Lang: "", Environment: ""}, Target: PageMatcher{Path: "", Kind: "page", Lang: "", Environment: ""},
}) })
// Current format.
c.Assert(fn(map[string]any{"target": map[string]any{"kind": "page"}, "params": map[string]any{"foo": "bar"}}), qt.DeepEquals, PageMatcherParamsConfig{ c.Assert(fn(map[string]any{"target": map[string]any{"kind": "page"}, "params": map[string]any{"foo": "bar"}}), qt.DeepEquals, PageMatcherParamsConfig{
Params: maps.Params{ Params: maps.Params{
"foo": "bar", "foo": "bar",
}, },
Fields: maps.Params{},
Target: PageMatcher{Path: "", Kind: "page", Lang: "", Environment: ""}, Target: PageMatcher{Path: "", Kind: "page", Lang: "", Environment: ""},
}) })
}) })
@ -134,13 +133,14 @@ func TestDecodeCascadeConfig(t *testing.T) {
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
c.Assert(got, qt.IsNotNil) c.Assert(got, qt.IsNotNil)
c.Assert(got.Config.Keys(), qt.DeepEquals, []PageMatcher{{Kind: "page", Environment: "production"}, {Kind: "page"}}) c.Assert(got.Config.Keys(), qt.DeepEquals, []PageMatcher{{Kind: "page", Environment: "production"}, {Kind: "page"}})
c.Assert(got.Config.Values(), qt.DeepEquals, []maps.Params{{"a": string("av")}, {"b": string("bv")}})
c.Assert(got.SourceStructure, qt.DeepEquals, []PageMatcherParamsConfig{ c.Assert(got.SourceStructure, qt.DeepEquals, []PageMatcherParamsConfig{
{ {
Params: maps.Params{"a": string("av")}, Params: maps.Params{"a": string("av")},
Fields: maps.Params{},
Target: PageMatcher{Kind: "page", Environment: "production"}, Target: PageMatcher{Kind: "page", Environment: "production"},
}, },
{Params: maps.Params{"b": string("bv")}, Target: PageMatcher{Kind: "page"}}, {Params: maps.Params{"b": string("bv")}, Fields: maps.Params{}, Target: PageMatcher{Kind: "page"}},
}) })
got, err = DecodeCascadeConfig(loggers.NewDefault(), true, nil) got, err = DecodeCascadeConfig(loggers.NewDefault(), true, nil)

View file

@ -125,7 +125,7 @@ type PageConfig struct {
ContentAdapterData map[string]any `mapstructure:"-" json:"-"` ContentAdapterData map[string]any `mapstructure:"-" json:"-"`
// Compiled values. // Compiled values.
CascadeCompiled *maps.Ordered[page.PageMatcher, maps.Params] `mapstructure:"-" json:"-"` CascadeCompiled *maps.Ordered[page.PageMatcher, page.PageMatcherParamsConfig] `mapstructure:"-" json:"-"`
ContentMediaType media.Type `mapstructure:"-" json:"-"` ContentMediaType media.Type `mapstructure:"-" json:"-"`
ConfiguredOutputFormats output.Formats `mapstructure:"-" json:"-"` ConfiguredOutputFormats output.Formats `mapstructure:"-" json:"-"`
IsFromContentAdapter bool `mapstructure:"-" json:"-"` IsFromContentAdapter bool `mapstructure:"-" json:"-"`

View file

@ -31,7 +31,7 @@ func TestDecodeBuildConfig(t *testing.T) {
c := qt.New(t) c := qt.New(t)
configTempl := ` configTempl := `
[_build] [build]
render = %s render = %s
list = %s list = %s
publishResources = true` publishResources = true`
@ -82,7 +82,7 @@ publishResources = true`
} { } {
cfg, err := config.FromConfigString(fmt.Sprintf(configTempl, test.args...), "toml") cfg, err := config.FromConfigString(fmt.Sprintf(configTempl, test.args...), "toml")
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
bcfg, err := DecodeBuildConfig(cfg.Get("_build")) bcfg, err := DecodeBuildConfig(cfg.Get("build"))
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
eq := qt.CmpEquals(hqt.DeepAllowUnexported(BuildConfig{})) eq := qt.CmpEquals(hqt.DeepAllowUnexported(BuildConfig{}))

View file

@ -311,7 +311,7 @@ func (l PermalinkExpander) pageToPermalinkSections(p Page, _ string) (string, er
// pageToPermalinkContentBaseName returns the URL-safe form of the content base name. // pageToPermalinkContentBaseName returns the URL-safe form of the content base name.
func (l PermalinkExpander) pageToPermalinkContentBaseName(p Page, _ string) (string, error) { func (l PermalinkExpander) pageToPermalinkContentBaseName(p Page, _ string) (string, error) {
return l.urlize(p.PathInfo().BaseNameNoIdentifier()), nil return l.urlize(p.PathInfo().Unnormalized().BaseNameNoIdentifier()), nil
} }
// pageToPermalinkSlugOrContentBaseName returns the URL-safe form of the slug, content base name. // pageToPermalinkSlugOrContentBaseName returns the URL-safe form of the slug, content base name.

View file

@ -14,6 +14,7 @@
package page_test package page_test
import ( import (
"strings"
"testing" "testing"
"github.com/bep/logg" "github.com/bep/logg"
@ -343,3 +344,29 @@ slug: "c2slug"
b.AssertFileContent("public/myc/c1/index.html", "C1|/myc/c1/|term|") b.AssertFileContent("public/myc/c1/index.html", "C1|/myc/c1/|term|")
b.AssertFileContent("public/myc/c2slug/index.html", "C2|/myc/c2slug/|term|") b.AssertFileContent("public/myc/c2slug/index.html", "C2|/myc/c2slug/|term|")
} }
func TestIssue13755(t *testing.T) {
t.Parallel()
files := `
-- hugo.toml --
disableKinds = ['home','rss','section','sitemap','taxonomy','term']
disablePathToLower = false
[permalinks.page]
s1 = "/:contentbasename"
-- content/s1/aBc.md --
---
title: aBc
---
-- layouts/all.html --
{{ .Title }}
`
b := hugolib.Test(t, files)
b.AssertFileExists("public/abc/index.html", true)
files = strings.ReplaceAll(files, "disablePathToLower = false", "disablePathToLower = true")
b = hugolib.Test(t, files)
b.AssertFileExists("public/aBc/index.html", true)
}

View file

@ -24,6 +24,7 @@ import (
"sync/atomic" "sync/atomic"
"github.com/gohugoio/hugo/identity" "github.com/gohugoio/hugo/identity"
"github.com/gohugoio/hugo/lazy"
"github.com/gohugoio/hugo/resources/internal" "github.com/gohugoio/hugo/resources/internal"
"github.com/gohugoio/hugo/common/hashing" "github.com/gohugoio/hugo/common/hashing"
@ -54,6 +55,7 @@ var (
_ identity.DependencyManagerProvider = (*genericResource)(nil) _ identity.DependencyManagerProvider = (*genericResource)(nil)
_ identity.Identity = (*genericResource)(nil) _ identity.Identity = (*genericResource)(nil)
_ fileInfo = (*genericResource)(nil) _ fileInfo = (*genericResource)(nil)
_ isPublishedProvider = (*genericResource)(nil)
) )
type ResourceSourceDescriptor struct { type ResourceSourceDescriptor struct {
@ -242,6 +244,7 @@ type baseResourceInternal interface {
fileInfo fileInfo
mediaTypeAssigner mediaTypeAssigner
targetPather targetPather
isPublishedProvider
ReadSeekCloser() (hugio.ReadSeekCloser, error) ReadSeekCloser() (hugio.ReadSeekCloser, error)
@ -355,7 +358,7 @@ func GetTestInfoForResource(r resource.Resource) GenericResourceTestInfo {
// genericResource represents a generic linkable resource. // genericResource represents a generic linkable resource.
type genericResource struct { type genericResource struct {
publishInit *sync.Once publishInit *lazy.OnceMore
key string key string
keyInit *sync.Once keyInit *sync.Once
@ -536,6 +539,10 @@ func (l *genericResource) Publish() error {
return err return err
} }
func (l *genericResource) isPublished() bool {
return l.publishInit.Done()
}
func (l *genericResource) RelPermalink() string { func (l *genericResource) RelPermalink() string {
return l.spec.PathSpec.GetBasePath(false) + paths.PathEscape(l.paths.TargetLink()) return l.spec.PathSpec.GetBasePath(false) + paths.PathEscape(l.paths.TargetLink())
} }
@ -629,7 +636,7 @@ func (rc *genericResource) cloneWithUpdates(u *transformationUpdate) (baseResour
} }
func (l genericResource) clone() *genericResource { func (l genericResource) clone() *genericResource {
l.publishInit = &sync.Once{} l.publishInit = &lazy.OnceMore{}
l.keyInit = &sync.Once{} l.keyInit = &sync.Once{}
return &l return &l
} }
@ -643,6 +650,10 @@ type targetPather interface {
TargetPath() string TargetPath() string
} }
type isPublishedProvider interface {
isPublished() bool
}
type resourceHash struct { type resourceHash struct {
value uint64 value uint64
size int64 size int64
@ -702,6 +713,11 @@ func InternalResourceSourcePathBestEffort(r resource.Resource) string {
return InternalResourceTargetPath(r) return InternalResourceTargetPath(r)
} }
// isPublished returns true if the resource is published.
func IsPublished(r resource.Resource) bool {
return r.(isPublishedProvider).isPublished()
}
type targetPathProvider interface { type targetPathProvider interface {
// targetPath is the relative path to this resource. // targetPath is the relative path to this resource.
// In most cases this will be the same as the RelPermalink(), // In most cases this will be the same as the RelPermalink(),

View file

@ -81,11 +81,6 @@ type ResourceWithoutMeta interface {
ResourceDataProvider ResourceDataProvider
} }
type ResourceWrapper interface {
UnwrappedResource() Resource
WrapResource(Resource) ResourceWrapper
}
type ResourceTypeProvider interface { type ResourceTypeProvider interface {
// ResourceType is the resource type. For most file types, this is the main // ResourceType is the resource type. For most file types, this is the main
// part of the MIME type, e.g. "image", "application", "text" etc. // part of the MIME type, e.g. "image", "application", "text" etc.

View file

@ -20,6 +20,7 @@ import (
"github.com/gohugoio/hugo/config" "github.com/gohugoio/hugo/config"
"github.com/gohugoio/hugo/config/allconfig" "github.com/gohugoio/hugo/config/allconfig"
"github.com/gohugoio/hugo/lazy"
"github.com/gohugoio/hugo/output" "github.com/gohugoio/hugo/output"
"github.com/gohugoio/hugo/resources/internal" "github.com/gohugoio/hugo/resources/internal"
"github.com/gohugoio/hugo/resources/jsconfig" "github.com/gohugoio/hugo/resources/jsconfig"
@ -189,7 +190,7 @@ func (r *Spec) NewResource(rd ResourceSourceDescriptor) (resource.Resource, erro
gr := &genericResource{ gr := &genericResource{
Staler: &AtomicStaler{}, Staler: &AtomicStaler{},
h: &resourceHash{}, h: &resourceHash{},
publishInit: &sync.Once{}, publishInit: &lazy.OnceMore{},
keyInit: &sync.Once{}, keyInit: &sync.Once{},
includeHashInKey: isImage, includeHashInKey: isImage,
paths: rp, paths: rp,

View file

@ -69,7 +69,6 @@ func (c *PostCSSClient) Process(res resources.ResourceTransformer, options map[s
} }
type InlineImports struct { type InlineImports struct {
// Service `mapstructure:",squash"`
// Enable inlining of @import statements. // Enable inlining of @import statements.
// Does so recursively, but currently once only per file; // Does so recursively, but currently once only per file;
// that is, it's not possible to import the same file in // that is, it's not possible to import the same file in
@ -78,6 +77,11 @@ type InlineImports struct {
// so you can have @import anywhere in the file. // so you can have @import anywhere in the file.
InlineImports bool InlineImports bool
// See issue https://github.com/gohugoio/hugo/issues/13719
// Disable inlining of @import statements
// This is currenty only used for css.TailwindCSS.
DisableInlineImports bool
// When InlineImports is enabled, we fail the build if an import cannot be resolved. // When InlineImports is enabled, we fail the build if an import cannot be resolved.
// You can enable this to allow the build to continue and leave the import statement in place. // You can enable this to allow the build to continue and leave the import statement in place.
// Note that the inline importer does not process url location or imports with media queries, // Note that the inline importer does not process url location or imports with media queries,

View file

@ -129,10 +129,12 @@ func (t *tailwindcssTransformation) Transform(ctx *resources.ResourceTransformat
t.rs.Assets.Fs, t.rs.Logger, ctx.DependencyManager, t.rs.Assets.Fs, t.rs.Logger, ctx.DependencyManager,
) )
if !options.InlineImports.DisableInlineImports {
src, err = imp.resolve() src, err = imp.resolve()
if err != nil { if err != nil {
return err return err
} }
}
go func() { go func() {
defer stdin.Close() defer stdin.Close()
@ -146,7 +148,11 @@ func (t *tailwindcssTransformation) Transform(ctx *resources.ResourceTransformat
Cause: err, Cause: err,
} }
} }
return imp.toFileError(errBuf.String()) s := errBuf.String()
if options.InlineImports.DisableInlineImports && strings.Contains(s, "Can't resolve") {
s += "You may want to set the 'disableInlineImports' option to false to inline imports, see https://gohugo.io/functions/css/tailwindcss/#disableinlineimports"
}
return imp.toFileError(s)
} }
return nil return nil

View file

@ -17,6 +17,7 @@ import (
"testing" "testing"
"github.com/bep/logg" "github.com/bep/logg"
qt "github.com/frankban/quicktest"
"github.com/gohugoio/hugo/htesting" "github.com/gohugoio/hugo/htesting"
"github.com/gohugoio/hugo/hugolib" "github.com/gohugoio/hugo/hugolib"
) )
@ -70,3 +71,66 @@ CSS: {{ $css.Content | safeCSS }}|
b.AssertFileContent("public/index.html", "/*! tailwindcss v4.") b.AssertFileContent("public/index.html", "/*! tailwindcss v4.")
} }
func TestTailwindCSSNoInlineImportsIssue13719(t *testing.T) {
t.Parallel()
files := `
-- hugo.toml --
disableKinds = ['page','rss','section','sitemap','taxonomy','term']
theme = 'my-theme'
[[module.mounts]]
source = 'assets'
target = 'assets'
[[module.mounts]]
source = 'other'
target = 'assets/css'
-- assets/css/main.css --
@import "tailwindcss";
@import "colors/red.css";
@import "colors/blue.css";
@import "colors/purple.css";
-- assets/css/colors/red.css --
@import "green.css";
.red {color: red;}
-- assets/css/colors/green.css --
.green {color: green;}
-- themes/my-theme/assets/css/colors/blue.css --
.blue {color: blue;}
-- other/colors/purple.css --
.purple {color: purple;}
-- layouts/home.html --
{{ with (templates.Defer (dict "key" "global")) }}
{{ with resources.Get "css/main.css" }}
{{ $opts := dict "disableInlineImports" true }}
{{ with . | css.TailwindCSS $opts }}
<link rel="stylesheet" href="{{ .RelPermalink }}">
{{ end }}
{{ end }}
{{ end }}
-- package.json --
{
"devDependencies": {
"@tailwindcss/cli": "^4.1.7",
"tailwindcss": "^4.1.7"
}
}
`
b, err := hugolib.NewIntegrationTestBuilder(
hugolib.IntegrationTestConfig{
T: t,
TxtarString: files,
NeedsOsFS: true,
NeedsNpmInstall: true,
LogLevel: logg.LevelInfo,
}).BuildE()
b.Assert(err, qt.IsNotNil)
b.Assert(err.Error(), qt.Contains, "Can't resolve 'colors/red.css'")
b.Assert(err.Error(), qt.Contains, "You may want to set the 'disableInlineImports' option to false")
}

View file

@ -61,6 +61,7 @@ var (
_ identity.DependencyManagerProvider = (*resourceAdapter)(nil) _ identity.DependencyManagerProvider = (*resourceAdapter)(nil)
_ identity.IdentityGroupProvider = (*resourceAdapter)(nil) _ identity.IdentityGroupProvider = (*resourceAdapter)(nil)
_ resource.NameNormalizedProvider = (*resourceAdapter)(nil) _ resource.NameNormalizedProvider = (*resourceAdapter)(nil)
_ isPublishedProvider = (*resourceAdapter)(nil)
) )
// These are transformations that need special support in Hugo that may not // These are transformations that need special support in Hugo that may not
@ -325,6 +326,11 @@ func (r *resourceAdapter) Publish() error {
return r.target.Publish() return r.target.Publish()
} }
func (r *resourceAdapter) isPublished() bool {
r.init(false, false)
return r.target.isPublished()
}
func (r *resourceAdapter) ReadSeekCloser() (hugio.ReadSeekCloser, error) { func (r *resourceAdapter) ReadSeekCloser() (hugio.ReadSeekCloser, error) {
r.init(false, false) r.init(false, false)
return r.target.ReadSeekCloser() return r.target.ReadSeekCloser()

View file

@ -15,6 +15,7 @@ package template
import ( import (
"fmt" "fmt"
"iter"
"github.com/gohugoio/hugo/common/types" "github.com/gohugoio/hugo/common/types"
template "github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate" template "github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate"
@ -38,6 +39,19 @@ func (t *Template) Prepare() (*template.Template, error) {
return t.text, nil return t.text, nil
} }
func (t *Template) All() iter.Seq[*Template] {
return func(yield func(t *Template) bool) {
ns := t.nameSpace
ns.mu.Lock()
defer ns.mu.Unlock()
for _, v := range ns.set {
if !yield(v) {
return
}
}
}
}
// See https://github.com/golang/go/issues/5884 // See https://github.com/golang/go/issues/5884
func StripTags(html string) string { func StripTags(html string) string {
return stripTags(html) return stripTags(html)

View file

@ -17,6 +17,7 @@ import (
"context" "context"
"fmt" "fmt"
"io" "io"
"iter"
"reflect" "reflect"
"github.com/gohugoio/hugo/common/herrors" "github.com/gohugoio/hugo/common/herrors"
@ -433,3 +434,18 @@ func (s *state) evalCall(dot, fun reflect.Value, isBuiltin bool, node parse.Node
func isTrue(val reflect.Value) (truth, ok bool) { func isTrue(val reflect.Value) (truth, ok bool) {
return hreflect.IsTruthfulValue(val), true return hreflect.IsTruthfulValue(val), true
} }
func (t *Template) All() iter.Seq[*Template] {
return func(yield func(t *Template) bool) {
if t.common == nil {
return
}
t.muTmpl.RLock()
defer t.muTmpl.RUnlock()
for _, v := range t.tmpl {
if !yield(v) {
return
}
}
}
}

View file

@ -258,7 +258,7 @@ func TestMod(t *testing.T) {
{int32(3), int32(2), int64(1)}, {int32(3), int32(2), int64(1)},
{int64(3), int64(2), int64(1)}, {int64(3), int64(2), int64(1)},
{"3", "2", int64(1)}, {"3", "2", int64(1)},
{"3.1", "2", false}, {"3.1", "2", int64(1)},
{"aaa", "0", false}, {"aaa", "0", false},
{"3", "aaa", false}, {"3", "aaa", false},
} { } {
@ -304,7 +304,7 @@ func TestModBool(t *testing.T) {
{int64(3), int64(2), false}, {int64(3), int64(2), false},
{"3", "3", true}, {"3", "3", true},
{"3", "2", false}, {"3", "2", false},
{"3.1", "2", nil}, {"3.1", "2", false},
{"aaa", "0", nil}, {"aaa", "0", nil},
{"3", "aaa", nil}, {"3", "aaa", nil},
} { } {

View file

@ -133,7 +133,7 @@ func (ns *Namespace) lookup(name string) (*tplimpl.TemplInfo, error) {
if strings.HasPrefix(name, "partials/") { if strings.HasPrefix(name, "partials/") {
// This is most likely not what the user intended. // This is most likely not what the user intended.
// This worked before Hugo 0.146.0. // This worked before Hugo 0.146.0.
ns.deps.Log.Warnidf(constants.WarnPartialSuperfluousPrefix, "Partial name %q starting with 'partials/' (as in {{ partial \"%s\"}}) is most likely not what you want. Before 0.146.0 we did a double lookup in this situation.", name, name) ns.deps.Log.Warnidf(constants.WarnPartialSuperfluousPrefix, "Doubtful use of partial function in {{ partial \"%s\"}}), this is most likely not what you want. Consider removing superfluous prefix \"partials/\" from template name given as first function argument.", name)
} }
v := ns.deps.TemplateStore.LookupPartial(name) v := ns.deps.TemplateStore.LookupPartial(name)
if v == nil { if v == nil {

View file

@ -20,7 +20,7 @@
{{- $request := printf "https://publish.twitter.com/oembed?%s" $query -}} {{- $request := printf "https://publish.twitter.com/oembed?%s" $query -}}
{{- with try (resources.GetRemote $request) -}} {{- with try (resources.GetRemote $request) -}}
{{- with .Err -}} {{- with .Err -}}
{{- errorf "%s" . -}} {{- warnidf "shortcode-twitter-getremote" "The %q shortcode was unable to retrieve the remote data: %s. See %s" $.ctx.Name . $.ctx.Position -}}
{{- else with .Value -}} {{- else with .Value -}}
{{- (. | transform.Unmarshal).html | safeHTML -}} {{- (. | transform.Unmarshal).html | safeHTML -}}
{{- else -}} {{- else -}}

View file

@ -16,7 +16,7 @@
{{- $request := printf "https://publish.twitter.com/oembed?%s" $query -}} {{- $request := printf "https://publish.twitter.com/oembed?%s" $query -}}
{{- with try (resources.GetRemote $request) -}} {{- with try (resources.GetRemote $request) -}}
{{- with .Err -}} {{- with .Err -}}
{{- errorf "%s" . -}} {{- warnidf "shortcode-twitter-simple-getremote" "The %q shortcode was unable to retrieve the remote data: %s. See %s" $.ctx.Name . $.ctx.Position -}}
{{- else with .Value -}} {{- else with .Value -}}
{{- if not site.Config.Services.Twitter.DisableInlineCSS }} {{- if not site.Config.Services.Twitter.DisableInlineCSS }}
{{- template "__h_simple_twitter_css" (dict "ctx" $.ctx) }} {{- template "__h_simple_twitter_css" (dict "ctx" $.ctx) }}

View file

@ -25,7 +25,7 @@
{{- $request := printf "https://vimeo.com/api/oembed.json?%s" $query -}} {{- $request := printf "https://vimeo.com/api/oembed.json?%s" $query -}}
{{- with try (resources.GetRemote $request) -}} {{- with try (resources.GetRemote $request) -}}
{{- with .Err -}} {{- with .Err -}}
{{- errorf "%s" . -}} {{- warnidf "shortcode-vimeo-simple" "The %q shortcode was unable to retrieve the remote data: %s. See %s" $.ctx.Name . $.ctx.Position -}}
{{- else with .Value -}} {{- else with .Value -}}
{{- with . | transform.Unmarshal -}} {{- with . | transform.Unmarshal -}}
{{- $class := printf "%s %s" "s_video_simple" "__h_video" -}} {{- $class := printf "%s %s" "s_video_simple" "__h_video" -}}

View file

@ -19,7 +19,7 @@
{{- $request := printf "https://publish.x.com/oembed?%s" $query -}} {{- $request := printf "https://publish.x.com/oembed?%s" $query -}}
{{- with try (resources.GetRemote $request) -}} {{- with try (resources.GetRemote $request) -}}
{{- with .Err -}} {{- with .Err -}}
{{- errorf "%s" . -}} {{- warnidf "shortcode-x-getremote" "The %q shortcode was unable to retrieve the remote data: %s. See %s" $.ctx.Name . $.ctx.Position -}}
{{- else with .Value -}} {{- else with .Value -}}
{{- (. | transform.Unmarshal).html | safeHTML -}} {{- (. | transform.Unmarshal).html | safeHTML -}}
{{- else -}} {{- else -}}

View file

@ -15,7 +15,7 @@
{{- $request := printf "https://publish.x.com/oembed?%s" $query -}} {{- $request := printf "https://publish.x.com/oembed?%s" $query -}}
{{- with try (resources.GetRemote $request) -}} {{- with try (resources.GetRemote $request) -}}
{{- with .Err -}} {{- with .Err -}}
{{- errorf "%s" . -}} {{- warnidf "shortcode-x-simple-getremote" "The %q shortcode was unable to retrieve the remote data: %s. See %s" $.ctx.Name . $.ctx.Position -}}
{{- else with .Value -}} {{- else with .Value -}}
{{- if not site.Config.Services.X.DisableInlineCSS }} {{- if not site.Config.Services.X.DisableInlineCSS }}
{{- template "__h_simple_x_css" (dict "ctx" $.ctx) }} {{- template "__h_simple_x_css" (dict "ctx" $.ctx) }}

View file

@ -17,6 +17,7 @@ import (
"strings" "strings"
"testing" "testing"
qt "github.com/frankban/quicktest"
"github.com/gohugoio/hugo/htesting/hqt" "github.com/gohugoio/hugo/htesting/hqt"
"github.com/gohugoio/hugo/hugolib" "github.com/gohugoio/hugo/hugolib"
) )
@ -696,3 +697,100 @@ title: p2
b.AssertFileContent("public/p1/index.html", "78eb19b5c6f3768f") b.AssertFileContent("public/p1/index.html", "78eb19b5c6f3768f")
b.AssertFileContent("public/p2/index.html", "a6db910a9cf54bc1") b.AssertFileContent("public/p2/index.html", "a6db910a9cf54bc1")
} }
func TestShortcodePlainTextVsHTMLTemplateIssue13698(t *testing.T) {
t.Parallel()
filesTemplate := `
-- hugo.toml --
markup.goldmark.renderer.unsafe = true
-- layouts/all.html --
Content: {{ .Content }}|
-- layouts/_shortcodes/mymarkdown.md --
<div>Foo bar</div>
-- content/p1.md --
---
title: p1
---
## A shortcode
SHORTCODE
`
files := strings.ReplaceAll(filesTemplate, "SHORTCODE", "{{% mymarkdown %}}")
b := hugolib.Test(t, files)
b.AssertFileContent("public/p1/index.html", "<div>Foo bar</div>")
files = strings.ReplaceAll(filesTemplate, "SHORTCODE", "{{< mymarkdown >}}")
var err error
b, err = hugolib.TestE(t, files)
b.Assert(err, qt.IsNotNil)
b.Assert(err.Error(), qt.Contains, `no compatible template found for shortcode "mymarkdown" in [/_shortcodes/mymarkdown.md]; note that to use plain text template shortcodes in HTML you need to use the shortcode {{% delimiter`)
}
func TestShortcodeOnlyLanguageInBaseIssue13699And13740(t *testing.T) {
t.Parallel()
files := `
-- hugo.toml --
baseURL = 'https://example.org/'
disableLanguages = ['de']
[languages]
[languages.en]
weight = 1
[languages.de]
weight = 2
-- layouts/_shortcodes/de.html --
de.html
-- layouts/all.html --
{{ .Content }}
-- content/_index.md --
---
title: home
---
{{< de >}}
`
b := hugolib.Test(t, files)
b.AssertFileContent("public/index.html", "de.html")
}
func TestShortcodeLanguage13767(t *testing.T) {
t.Parallel()
files := `
-- hugo.toml --
defaultContentLanguage = 'pl'
defaultContentLanguageInSubdir = true
[languages.pl]
weight = 1
[languages.en]
weight = 2
-- content/_index.md --
---
title: dom
---
{{< myshortcode >}}
-- content/_index.en.md --
---
title: home
---
{{< myshortcode >}}
-- layouts/_shortcodes/myshortcode.html --
myshortcode.html
-- layouts/_shortcodes/myshortcode.en.html --
myshortcode.en.html
-- layouts/all.html --
{{ .Content }}
`
b := hugolib.Test(t, files)
b.AssertFileContent("public/pl/index.html", "myshortcode.html")
b.AssertFileContent("public/en/index.html", "myshortcode.en.html")
}

View file

@ -37,6 +37,7 @@ type TemplateDescriptor struct {
// Misc. // Misc.
LayoutFromUserMustMatch bool // If set, we only look for the exact layout. LayoutFromUserMustMatch bool // If set, we only look for the exact layout.
IsPlainText bool // Whether this is a plain text template. IsPlainText bool // Whether this is a plain text template.
AlwaysAllowPlainText bool // Whether to e.g. allow plain text templates to be rendered in HTML.
} }
func (d *TemplateDescriptor) normalizeFromFile() { func (d *TemplateDescriptor) normalizeFromFile() {
@ -64,7 +65,7 @@ func (s descriptorHandler) compareDescriptors(category Category, isEmbedded bool
return weightNoMatch return weightNoMatch
} }
w := this.doCompare(category, isEmbedded, s.opts.DefaultContentLanguage, other) w := this.doCompare(category, s.opts.DefaultContentLanguage, other)
if w.w1 <= 0 { if w.w1 <= 0 {
if category == CategoryMarkup && (this.Variant1 == other.Variant1) && (this.Variant2 == other.Variant2 || this.Variant2 != "" && other.Variant2 == "") { if category == CategoryMarkup && (this.Variant1 == other.Variant1) && (this.Variant2 == other.Variant2 || this.Variant2 != "" && other.Variant2 == "") {
@ -74,7 +75,12 @@ func (s descriptorHandler) compareDescriptors(category Category, isEmbedded bool
} }
w.w1 = 1 w.w1 = 1
return w }
if category == CategoryShortcode {
if (this.IsPlainText == other.IsPlainText || !other.IsPlainText) || this.AlwaysAllowPlainText {
w.w1 = 1
}
} }
} }
@ -82,13 +88,16 @@ func (s descriptorHandler) compareDescriptors(category Category, isEmbedded bool
} }
//lint:ignore ST1006 this vs other makes it easier to reason about. //lint:ignore ST1006 this vs other makes it easier to reason about.
func (this TemplateDescriptor) doCompare(category Category, isEmbedded bool, defaultContentLanguage string, other TemplateDescriptor) weight { func (this TemplateDescriptor) doCompare(category Category, defaultContentLanguage string, other TemplateDescriptor) weight {
w := weightNoMatch w := weightNoMatch
if !this.AlwaysAllowPlainText {
// HTML in plain text is OK, but not the other way around. // HTML in plain text is OK, but not the other way around.
if other.IsPlainText && !this.IsPlainText { if other.IsPlainText && !this.IsPlainText {
return w return w
} }
}
if other.Kind != "" && other.Kind != this.Kind { if other.Kind != "" && other.Kind != this.Kind {
return w return w
} }

View file

@ -2,6 +2,7 @@ package tplimpl
import ( import (
"io" "io"
"iter"
"regexp" "regexp"
"strconv" "strconv"
"strings" "strings"
@ -44,16 +45,15 @@ var embeddedTemplatesAliases = map[string][]string{
"_shortcodes/twitter.html": {"_shortcodes/tweet.html"}, "_shortcodes/twitter.html": {"_shortcodes/tweet.html"},
} }
func (s *TemplateStore) parseTemplate(ti *TemplInfo) error { func (s *TemplateStore) parseTemplate(ti *TemplInfo, replace bool) error {
err := s.tns.doParseTemplate(ti) err := s.tns.doParseTemplate(ti, replace)
if err != nil { if err != nil {
return s.addFileContext(ti, "parse of template failed", err) return s.addFileContext(ti, "parse of template failed", err)
} }
return err return err
} }
func (t *templateNamespace) doParseTemplate(ti *TemplInfo) error { func (t *templateNamespace) doParseTemplate(ti *TemplInfo, replace bool) error {
if !ti.noBaseOf || ti.category == CategoryBaseof { if !ti.noBaseOf || ti.category == CategoryBaseof {
// Delay parsing until we have the base template. // Delay parsing until we have the base template.
return nil return nil
@ -68,7 +68,7 @@ func (t *templateNamespace) doParseTemplate(ti *TemplInfo) error {
if ti.D.IsPlainText { if ti.D.IsPlainText {
prototype := t.parseText prototype := t.parseText
if prototype.Lookup(name) != nil { if !replace && prototype.Lookup(name) != nil {
name += "-" + strconv.FormatUint(t.nameCounter.Add(1), 10) name += "-" + strconv.FormatUint(t.nameCounter.Add(1), 10)
} }
templ, err = prototype.New(name).Parse(ti.content) templ, err = prototype.New(name).Parse(ti.content)
@ -77,7 +77,7 @@ func (t *templateNamespace) doParseTemplate(ti *TemplInfo) error {
} }
} else { } else {
prototype := t.parseHTML prototype := t.parseHTML
if prototype.Lookup(name) != nil { if !replace && prototype.Lookup(name) != nil {
name += "-" + strconv.FormatUint(t.nameCounter.Add(1), 10) name += "-" + strconv.FormatUint(t.nameCounter.Add(1), 10)
} }
templ, err = prototype.New(name).Parse(ti.content) templ, err = prototype.New(name).Parse(ti.content)
@ -181,19 +181,24 @@ func (t *templateNamespace) applyBaseTemplate(overlay *TemplInfo, base keyTempla
return nil return nil
} }
func (t *templateNamespace) templatesIn(in tpl.Template) []tpl.Template { func (t *templateNamespace) templatesIn(in tpl.Template) iter.Seq[tpl.Template] {
var templs []tpl.Template return func(yield func(t tpl.Template) bool) {
if textt, ok := in.(*texttemplate.Template); ok { switch in := in.(type) {
for _, t := range textt.Templates() { case *htmltemplate.Template:
templs = append(templs, t) for t := range in.All() {
if !yield(t) {
return
}
}
case *texttemplate.Template:
for t := range in.All() {
if !yield(t) {
return
} }
} }
if htmlt, ok := in.(*htmltemplate.Template); ok {
for _, t := range htmlt.Templates() {
templs = append(templs, t)
} }
} }
return templs
} }
/* /*
@ -337,8 +342,6 @@ func (t *templateNamespace) createPrototypes(init bool) error {
t.prototypeHTML = htmltemplate.Must(t.parseHTML.Clone()) t.prototypeHTML = htmltemplate.Must(t.parseHTML.Clone())
t.prototypeText = texttemplate.Must(t.parseText.Clone()) t.prototypeText = texttemplate.Must(t.parseText.Clone())
} }
// t.execHTML = htmltemplate.Must(t.parseHTML.Clone())
// t.execText = texttemplate.Must(t.parseText.Clone())
return nil return nil
} }
@ -350,3 +353,14 @@ func newTemplateNamespace(funcs map[string]any) *templateNamespace {
standaloneText: texttemplate.New("").Funcs(funcs), standaloneText: texttemplate.New("").Funcs(funcs),
} }
} }
func isText(t tpl.Template) bool {
switch t.(type) {
case *texttemplate.Template:
return true
case *htmltemplate.Template:
return false
default:
panic("unknown template type")
}
}

View file

@ -19,6 +19,7 @@ import (
"bytes" "bytes"
"context" "context"
"embed" "embed"
"errors"
"fmt" "fmt"
"io" "io"
"io/fs" "io/fs"
@ -124,6 +125,7 @@ func NewStore(opts StoreOptions, siteOpts SiteOptions) (*TemplateStore, error) {
templatesByPath: maps.NewCache[string, *TemplInfo](), templatesByPath: maps.NewCache[string, *TemplInfo](),
shortcodesByName: maps.NewCache[string, *TemplInfo](), shortcodesByName: maps.NewCache[string, *TemplInfo](),
cacheLookupPartials: maps.NewCache[string, *TemplInfo](), cacheLookupPartials: maps.NewCache[string, *TemplInfo](),
templatesSnapshotSet: maps.NewCache[*parse.Tree, struct{}](),
// Note that the funcs passed below is just for name validation. // Note that the funcs passed below is just for name validation.
tns: newTemplateNamespace(siteOpts.TemplateFuncs), tns: newTemplateNamespace(siteOpts.TemplateFuncs),
@ -142,10 +144,10 @@ func NewStore(opts StoreOptions, siteOpts SiteOptions) (*TemplateStore, error) {
if err := s.insertEmbedded(); err != nil { if err := s.insertEmbedded(); err != nil {
return nil, err return nil, err
} }
if err := s.parseTemplates(); err != nil { if err := s.parseTemplates(false); err != nil {
return nil, err return nil, err
} }
if err := s.extractInlinePartials(); err != nil { if err := s.extractInlinePartials(false); err != nil {
return nil, err return nil, err
} }
if err := s.transformTemplates(); err != nil { if err := s.transformTemplates(); err != nil {
@ -427,6 +429,7 @@ type TemplateStore struct {
treeShortcodes *doctree.SimpleTree[map[string]map[TemplateDescriptor]*TemplInfo] treeShortcodes *doctree.SimpleTree[map[string]map[TemplateDescriptor]*TemplInfo]
templatesByPath *maps.Cache[string, *TemplInfo] templatesByPath *maps.Cache[string, *TemplInfo]
shortcodesByName *maps.Cache[string, *TemplInfo] shortcodesByName *maps.Cache[string, *TemplInfo]
templatesSnapshotSet *maps.Cache[*parse.Tree, struct{}]
dh descriptorHandler dh descriptorHandler
@ -608,7 +611,7 @@ func (s *TemplateStore) LookupShortcodeByName(name string) *TemplInfo {
return ti return ti
} }
func (s *TemplateStore) LookupShortcode(q TemplateQuery) *TemplInfo { func (s *TemplateStore) LookupShortcode(q TemplateQuery) (*TemplInfo, error) {
q.init() q.init()
k1 := s.key(q.Path) k1 := s.key(q.Path)
@ -630,13 +633,15 @@ func (s *TemplateStore) LookupShortcode(q TemplateQuery) *TemplInfo {
} }
for k, vv := range v { for k, vv := range v {
best.candidates = append(best.candidates, vv)
if !q.Consider(vv) { if !q.Consider(vv) {
continue continue
} }
weight := s.dh.compareDescriptors(q.Category, vv.subCategory == SubCategoryEmbedded, q.Desc, k) weight := s.dh.compareDescriptors(q.Category, vv.subCategory == SubCategoryEmbedded, q.Desc, k)
weight.distance = distance weight.distance = distance
if best.isBetter(weight, vv) { isBetter := best.isBetter(weight, vv)
if isBetter {
best.updateValues(weight, k2, k, vv) best.updateValues(weight, k2, k, vv)
} }
} }
@ -644,8 +649,21 @@ func (s *TemplateStore) LookupShortcode(q TemplateQuery) *TemplInfo {
return false, nil return false, nil
}) })
// Any match will do. if best.w.w1 <= 0 {
return best.templ var err error
if s := best.candidatesAsStringSlice(); s != nil {
msg := fmt.Sprintf("no compatible template found for shortcode %q in %s", q.Name, s)
if !q.Desc.IsPlainText {
msg += "; note that to use plain text template shortcodes in HTML you need to use the shortcode {{% delimiter"
}
err = errors.New(msg)
} else {
err = fmt.Errorf("no template found for shortcode %q", q.Name)
}
return nil, err
}
return best.templ, nil
} }
// PrintDebug is for testing/debugging only. // PrintDebug is for testing/debugging only.
@ -693,12 +711,16 @@ func (s *TemplateStore) RefreshFiles(include func(fi hugofs.FileMetaInfo) bool)
if err := s.insertTemplates(include, true); err != nil { if err := s.insertTemplates(include, true); err != nil {
return err return err
} }
if err := s.parseTemplates(); err != nil { if err := s.createTemplatesSnapshot(); err != nil {
return err return err
} }
if err := s.extractInlinePartials(); err != nil { if err := s.parseTemplates(true); err != nil {
return err return err
} }
if err := s.extractInlinePartials(true); err != nil {
return err
}
if err := s.transformTemplates(); err != nil { if err := s.transformTemplates(); err != nil {
return err return err
} }
@ -924,19 +946,21 @@ func (s *TemplateStore) extractIdentifiers(line string) []string {
return identifiers return identifiers
} }
func (s *TemplateStore) extractInlinePartials() error { func (s *TemplateStore) extractInlinePartials(rebuild bool) error {
isPartialName := func(s string) bool { isPartialName := func(s string) bool {
return strings.HasPrefix(s, "partials/") || strings.HasPrefix(s, "_partials/") return strings.HasPrefix(s, "partials/") || strings.HasPrefix(s, "_partials/")
} }
p := s.tns
// We may find both inline and external partials in the current template namespaces, // We may find both inline and external partials in the current template namespaces,
// so only add the ones we have not seen before. // so only add the ones we have not seen before.
addIfNotSeen := func(isText bool, templs ...tpl.Template) error { for templ := range s.allRawTemplates() {
for _, templ := range templs {
if templ.Name() == "" || !isPartialName(templ.Name()) { if templ.Name() == "" || !isPartialName(templ.Name()) {
continue continue
} }
if rebuild && s.templatesSnapshotSet.Contains(getParseTree(templ)) {
// This partial was not created during this build.
continue
}
name := templ.Name() name := templ.Name()
if !paths.HasExt(name) { if !paths.HasExt(name) {
// Assume HTML. This in line with how the lookup works. // Assume HTML. This in line with how the lookup works.
@ -946,7 +970,7 @@ func (s *TemplateStore) extractInlinePartials() error {
name = "_" + name name = "_" + name
} }
pi := s.opts.PathParser.Parse(files.ComponentFolderLayouts, name) pi := s.opts.PathParser.Parse(files.ComponentFolderLayouts, name)
ti, err := s.insertTemplate(pi, nil, false, s.treeMain) ti, err := s.insertTemplate(pi, nil, SubCategoryInline, false, s.treeMain)
if err != nil { if err != nil {
return err return err
} }
@ -955,30 +979,46 @@ func (s *TemplateStore) extractInlinePartials() error {
ti.Template = templ ti.Template = templ
ti.noBaseOf = true ti.noBaseOf = true
ti.subCategory = SubCategoryInline ti.subCategory = SubCategoryInline
ti.D.IsPlainText = isText ti.D.IsPlainText = isText(templ)
}
} }
}
return nil return nil
} }
addIfNotSeen(false, p.templatesIn(p.parseHTML)...)
addIfNotSeen(true, p.templatesIn(p.parseText)...)
for _, t := range p.baseofHtmlClones { func (s *TemplateStore) allRawTemplates() iter.Seq[tpl.Template] {
if err := addIfNotSeen(false, p.templatesIn(t)...); err != nil { p := s.tns
return err return func(yield func(tpl.Template) bool) {
for t := range p.templatesIn(p.parseHTML) {
if !yield(t) {
return
}
}
for t := range p.templatesIn(p.parseText) {
if !yield(t) {
return
}
}
for _, tt := range p.baseofHtmlClones {
for t := range p.templatesIn(tt) {
if !yield(t) {
return
}
}
}
for _, tt := range p.baseofTextClones {
for t := range p.templatesIn(tt) {
if !yield(t) {
return
} }
} }
for _, t := range p.baseofTextClones {
if err := addIfNotSeen(true, p.templatesIn(t)...); err != nil {
return err
} }
} }
return nil
} }
func (s *TemplateStore) insertEmbedded() error { func (s *TemplateStore) insertEmbedded() error {
return fs.WalkDir(embeddedTemplatesFs, ".", func(path string, d fs.DirEntry, err error) error { return fs.WalkDir(embeddedTemplatesFs, ".", func(tpath string, d fs.DirEntry, err error) error {
if err != nil { if err != nil {
return err return err
} }
@ -986,7 +1026,7 @@ func (s *TemplateStore) insertEmbedded() error {
return nil return nil
} }
templb, err := embeddedTemplatesFs.ReadFile(path) templb, err := embeddedTemplatesFs.ReadFile(tpath)
if err != nil { if err != nil {
return err return err
} }
@ -994,7 +1034,7 @@ func (s *TemplateStore) insertEmbedded() error {
// Get the newlines on Windows in line with how we had it back when we used Go Generate // Get the newlines on Windows in line with how we had it back when we used Go Generate
// to write the templates to Go files. // to write the templates to Go files.
templ := string(bytes.ReplaceAll(templb, []byte("\r\n"), []byte("\n"))) templ := string(bytes.ReplaceAll(templb, []byte("\r\n"), []byte("\n")))
name := strings.TrimPrefix(filepath.ToSlash(path), "embedded/templates/") name := strings.TrimPrefix(filepath.ToSlash(tpath), "embedded/templates/")
insertOne := func(name, content string) error { insertOne := func(name, content string) error {
pi := s.opts.PathParser.Parse(files.ComponentFolderLayouts, name) pi := s.opts.PathParser.Parse(files.ComponentFolderLayouts, name)
@ -1008,7 +1048,7 @@ func (s *TemplateStore) insertEmbedded() error {
return err return err
} }
} else { } else {
ti, err = s.insertTemplate(pi, nil, false, s.treeMain) ti, err = s.insertTemplate(pi, nil, SubCategoryEmbedded, false, s.treeMain)
if err != nil { if err != nil {
return err return err
} }
@ -1024,6 +1064,19 @@ func (s *TemplateStore) insertEmbedded() error {
return nil return nil
} }
// Copy the embedded HTML table render hook to each output format.
// See https://github.com/gohugoio/hugo/issues/13351.
if name == path.Join(containerMarkup, "render-table.html") {
for _, of := range s.opts.OutputFormats {
path := paths.TrimExt(name) + "." + of.Name + of.MediaType.FirstSuffix.FullSuffix
if err := insertOne(path, templ); err != nil {
return err
}
}
return nil
}
if err := insertOne(name, templ); err != nil { if err := insertOne(name, templ); err != nil {
return err return err
} }
@ -1089,7 +1142,7 @@ func (s *TemplateStore) insertShortcode(pi *paths.Path, fi hugofs.FileMetaInfo,
return ti, nil return ti, nil
} }
func (s *TemplateStore) insertTemplate(pi *paths.Path, fi hugofs.FileMetaInfo, replace bool, tree doctree.Tree[map[nodeKey]*TemplInfo]) (*TemplInfo, error) { func (s *TemplateStore) insertTemplate(pi *paths.Path, fi hugofs.FileMetaInfo, subCategory SubCategory, replace bool, tree doctree.Tree[map[nodeKey]*TemplInfo]) (*TemplInfo, error) {
key, _, category, d, err := s.toKeyCategoryAndDescriptor(pi) key, _, category, d, err := s.toKeyCategoryAndDescriptor(pi)
// See #13577. Warn for now. // See #13577. Warn for now.
if err != nil { if err != nil {
@ -1103,7 +1156,7 @@ func (s *TemplateStore) insertTemplate(pi *paths.Path, fi hugofs.FileMetaInfo, r
return nil, nil return nil, nil
} }
return s.insertTemplate2(pi, fi, key, category, d, replace, false, tree) return s.insertTemplate2(pi, fi, key, category, subCategory, d, replace, false, tree)
} }
func (s *TemplateStore) insertTemplate2( func (s *TemplateStore) insertTemplate2(
@ -1111,6 +1164,7 @@ func (s *TemplateStore) insertTemplate2(
fi hugofs.FileMetaInfo, fi hugofs.FileMetaInfo,
key string, key string,
category Category, category Category,
subCategory SubCategory,
d TemplateDescriptor, d TemplateDescriptor,
replace, isLegacyMapped bool, replace, isLegacyMapped bool,
tree doctree.Tree[map[nodeKey]*TemplInfo], tree doctree.Tree[map[nodeKey]*TemplInfo],
@ -1133,14 +1187,28 @@ func (s *TemplateStore) insertTemplate2(
tree.Insert(key, m) tree.Insert(key, m)
} }
if !replace { nkExisting, existingFound := m[nk]
if v, found := m[nk]; found { if !replace && existingFound && fi != nil && nkExisting.Fi != nil {
if len(pi.Identifiers()) >= len(v.PathInfo.Identifiers()) { // See issue #13715.
// We do the merge on the file system level, but from Hugo v0.146.0 we have a situation where
// the project may well have a different layouts layout compared to the theme(s) it uses.
// We could possibly have fixed that on a lower (file system) level, but since this is just
// a temporary situation (until all projects are updated),
// do a replace here if the file comes from higher up in the module chain.
replace = fi.Meta().ModuleOrdinal < nkExisting.Fi.Meta().ModuleOrdinal
}
if !replace && existingFound {
// Always replace inline partials to allow for reloading.
replace = subCategory == SubCategoryInline && nkExisting.subCategory == SubCategoryInline
}
if !replace && existingFound {
if len(pi.Identifiers()) >= len(nkExisting.PathInfo.Identifiers()) {
// e.g. /pages/home.foo.html and /pages/home.html where foo may be a valid language name in another site. // e.g. /pages/home.foo.html and /pages/home.html where foo may be a valid language name in another site.
return nil, nil return nil, nil
} }
} }
}
ti := &TemplInfo{ ti := &TemplInfo{
PathInfo: pi, PathInfo: pi,
@ -1165,7 +1233,7 @@ func (s *TemplateStore) insertTemplate2(
return ti, nil return ti, nil
} }
func (s *TemplateStore) insertTemplates(include func(fi hugofs.FileMetaInfo) bool, replace bool) error { func (s *TemplateStore) insertTemplates(include func(fi hugofs.FileMetaInfo) bool, partialRebuild bool) error {
if include == nil { if include == nil {
include = func(fi hugofs.FileMetaInfo) bool { include = func(fi hugofs.FileMetaInfo) bool {
return true return true
@ -1347,7 +1415,7 @@ func (s *TemplateStore) insertTemplates(include func(fi hugofs.FileMetaInfo) boo
} }
if replace && pi.NameNoIdentifier() == baseNameBaseof { if partialRebuild && pi.NameNoIdentifier() == baseNameBaseof {
// A baseof file has changed. // A baseof file has changed.
resetBaseVariants = true resetBaseVariants = true
} }
@ -1355,12 +1423,12 @@ func (s *TemplateStore) insertTemplates(include func(fi hugofs.FileMetaInfo) boo
var ti *TemplInfo var ti *TemplInfo
var err error var err error
if pi.Type() == paths.TypeShortcode { if pi.Type() == paths.TypeShortcode {
ti, err = s.insertShortcode(pi, fi, replace, s.treeShortcodes) ti, err = s.insertShortcode(pi, fi, partialRebuild, s.treeShortcodes)
if err != nil || ti == nil { if err != nil || ti == nil {
return err return err
} }
} else { } else {
ti, err = s.insertTemplate(pi, fi, replace, s.treeMain) ti, err = s.insertTemplate(pi, fi, SubCategoryMain, partialRebuild, s.treeMain)
if err != nil || ti == nil { if err != nil || ti == nil {
return err return err
} }
@ -1394,7 +1462,7 @@ func (s *TemplateStore) insertTemplates(include func(fi hugofs.FileMetaInfo) boo
desc.IsPlainText = outputFormat.IsPlainText desc.IsPlainText = outputFormat.IsPlainText
desc.MediaType = mediaType.Type desc.MediaType = mediaType.Type
ti, err := s.insertTemplate2(pi, fi, targetPath, category, desc, true, true, s.treeMain) ti, err := s.insertTemplate2(pi, fi, targetPath, category, SubCategoryMain, desc, true, true, s.treeMain)
if err != nil { if err != nil {
return err return err
} }
@ -1405,6 +1473,7 @@ func (s *TemplateStore) insertTemplates(include func(fi hugofs.FileMetaInfo) boo
if err := s.tns.readTemplateInto(ti); err != nil { if err := s.tns.readTemplateInto(ti); err != nil {
return err return err
} }
} }
if resetBaseVariants { if resetBaseVariants {
@ -1431,7 +1500,15 @@ func (s *TemplateStore) key(dir string) string {
return paths.TrimTrailing(dir) return paths.TrimTrailing(dir)
} }
func (s *TemplateStore) parseTemplates() error { func (s *TemplateStore) createTemplatesSnapshot() error {
s.templatesSnapshotSet.Reset()
for t := range s.allRawTemplates() {
s.templatesSnapshotSet.Set(getParseTree(t), struct{}{})
}
return nil
}
func (s *TemplateStore) parseTemplates(replace bool) error {
if err := func() error { if err := func() error {
// Read and parse all templates. // Read and parse all templates.
for _, v := range s.treeMain.All() { for _, v := range s.treeMain.All() {
@ -1439,7 +1516,7 @@ func (s *TemplateStore) parseTemplates() error {
if vv.state == processingStateTransformed { if vv.state == processingStateTransformed {
continue continue
} }
if err := s.parseTemplate(vv); err != nil { if err := s.parseTemplate(vv, replace); err != nil {
return err return err
} }
} }
@ -1459,7 +1536,7 @@ func (s *TemplateStore) parseTemplates() error {
// The regular expression used to detect if a template needs a base template has some // The regular expression used to detect if a template needs a base template has some
// rare false positives. Assume we don't need one. // rare false positives. Assume we don't need one.
vv.noBaseOf = true vv.noBaseOf = true
if err := s.parseTemplate(vv); err != nil { if err := s.parseTemplate(vv, replace); err != nil {
return err return err
} }
continue continue
@ -1488,7 +1565,7 @@ func (s *TemplateStore) parseTemplates() error {
if vvv.state == processingStateTransformed { if vvv.state == processingStateTransformed {
continue continue
} }
if err := s.parseTemplate(vvv); err != nil { if err := s.parseTemplate(vvv, replace); err != nil {
return err return err
} }
} }
@ -1812,6 +1889,7 @@ type bestMatch struct {
desc TemplateDescriptor desc TemplateDescriptor
w weight w weight
key string key string
candidates []*TemplInfo
// settings. // settings.
defaultOutputformat string defaultOutputformat string
@ -1822,6 +1900,18 @@ func (best *bestMatch) reset() {
best.w = weight{} best.w = weight{}
best.desc = TemplateDescriptor{} best.desc = TemplateDescriptor{}
best.key = "" best.key = ""
best.candidates = nil
}
func (best *bestMatch) candidatesAsStringSlice() []string {
if len(best.candidates) == 0 {
return nil
}
candidates := make([]string, len(best.candidates))
for i, v := range best.candidates {
candidates[i] = v.PathInfo.Path()
}
return candidates
} }
func (best *bestMatch) isBetter(w weight, ti *TemplInfo) bool { func (best *bestMatch) isBetter(w weight, ti *TemplInfo) bool {
@ -1831,7 +1921,6 @@ func (best *bestMatch) isBetter(w weight, ti *TemplInfo) bool {
} }
if w.w1 <= 0 { if w.w1 <= 0 {
if best.w.w1 <= 0 { if best.w.w1 <= 0 {
return ti.PathInfo.Path() < best.templ.PathInfo.Path() return ti.PathInfo.Path() < best.templ.PathInfo.Path()
} }

View file

@ -920,6 +920,26 @@ func TestPartialHTML(t *testing.T) {
b.AssertFileContent("public/index.html", "<link rel=\"stylesheet\" href=\"/css/style.css\">") b.AssertFileContent("public/index.html", "<link rel=\"stylesheet\" href=\"/css/style.css\">")
} }
func TestPartialPlainTextInHTML(t *testing.T) {
t.Parallel()
files := `
-- hugo.toml --
-- layouts/all.html --
<html>
<head>
{{ partial "mypartial.txt" . }}
</head>
</html>
-- layouts/partials/mypartial.txt --
My <div>partial</div>.
`
b := hugolib.Test(t, files)
b.AssertFileContent("public/index.html", "My &lt;div&gt;partial&lt;/div&gt;.")
}
// Issue #13593. // Issue #13593.
func TestGoatAndNoGoat(t *testing.T) { func TestGoatAndNoGoat(t *testing.T) {
t.Parallel() t.Parallel()
@ -1103,6 +1123,35 @@ All.
b.AssertLogContains("unrecognized render hook") b.AssertLogContains("unrecognized render hook")
} }
func TestLayoutNotFound(t *testing.T) {
t.Parallel()
files := `
-- hugo.toml --
-- layouts/single.html --
Single.
`
b := hugolib.Test(t, files, hugolib.TestOptWarn())
b.AssertLogContains("WARN found no layout file for \"html\" for kind \"home\"")
}
func TestLayoutOverrideThemeWhenThemeOnOldFormatIssue13715(t *testing.T) {
t.Parallel()
files := `
-- hugo.toml --
theme = "mytheme"
-- layouts/list.html --
layouts/list.html
-- themes/mytheme/layouts/_default/list.html --
mytheme/layouts/_default/list.html
`
b := hugolib.Test(t, files)
b.AssertFileContent("public/index.html", "layouts/list.html")
}
func BenchmarkExecuteWithContext(b *testing.B) { func BenchmarkExecuteWithContext(b *testing.B) {
files := ` files := `
-- hugo.toml -- -- hugo.toml --
@ -1197,8 +1246,8 @@ s2.
Category: tplimpl.CategoryShortcode, Category: tplimpl.CategoryShortcode,
Desc: desc, Desc: desc,
} }
v := store.LookupShortcode(q) v, err := store.LookupShortcode(q)
if v == nil { if v == nil || err != nil {
b.Fatal("not found") b.Fatal("not found")
} }
} }
@ -1459,3 +1508,43 @@ mytexts|safeHTML: {{ partial "mytext.txt" . | safeHTML }}
"mytexts|safeHTML: <div>mytext</div>", "mytexts|safeHTML: <div>mytext</div>",
) )
} }
func TestIssue13351(t *testing.T) {
t.Parallel()
files := `
-- hugo.toml --
disableKinds = ['page','rss','section','sitemap','taxonomy','term']
[outputs]
home = ['html','json']
[outputFormats.html]
weight = 1
[outputFormats.json]
weight = 2
-- content/_index.md --
---
title: home
---
a|b
:--|:--
1|2
-- layouts/index.html --
{{ .Content }}
-- layouts/index.json --
{{ .Content }}
`
b := hugolib.Test(t, files)
b.AssertFileContent("public/index.html", "<table>")
b.AssertFileContent("public/index.json", "<table>")
f := strings.ReplaceAll(files, "weight = 1", "weight = 0")
b = hugolib.Test(t, f)
b.AssertFileContent("public/index.html", "<table>")
b.AssertFileContent("public/index.json", "<table>")
f = strings.ReplaceAll(files, "weight = 1", "")
b = hugolib.Test(t, f)
b.AssertFileContent("public/index.html", "<table>")
b.AssertFileContent("public/index.json", "<table>")
}

View file

@ -17,8 +17,10 @@ package transform
import ( import (
"bytes" "bytes"
"context" "context"
"encoding/json"
"encoding/xml" "encoding/xml"
"errors" "errors"
"fmt"
"html" "html"
"html/template" "html/template"
"io" "io"
@ -234,6 +236,7 @@ func (ns *Namespace) ToMath(ctx context.Context, args ...any) (template.HTML, er
MinRuleThickness: 0.04, MinRuleThickness: 0.04,
ErrorColor: "#cc0000", ErrorColor: "#cc0000",
ThrowOnError: true, ThrowOnError: true,
Strict: "error",
}, },
} }
@ -243,8 +246,23 @@ func (ns *Namespace) ToMath(ctx context.Context, args ...any) (template.HTML, er
} }
} }
switch katexInput.Options.Strict {
case "error", "ignore", "warn":
// Valid strict mode, continue
default:
return "", fmt.Errorf("invalid strict mode; expected one of error, ignore, or warn; received %s", katexInput.Options.Strict)
}
type fileCacheEntry struct {
Version string `json:"version"`
Output string `json:"output"`
Warnings []string `json:"warnings,omitempty"`
}
const fileCacheEntryVersion = "v1" // Increment on incompatible changes.
s := hashing.HashString(args...) s := hashing.HashString(args...)
key := "tomath/" + s[:2] + "/" + s[2:] key := "tomath/" + fileCacheEntryVersion + "/" + s[:2] + "/" + s[2:]
fileCache := ns.deps.ResourceSpec.FileCaches.MiscCache() fileCache := ns.deps.ResourceSpec.FileCaches.MiscCache()
v, err := ns.cacheMath.GetOrCreate(key, func(string) (template.HTML, error) { v, err := ns.cacheMath.GetOrCreate(key, func(string) (template.HTML, error) {
@ -265,15 +283,35 @@ func (ns *Namespace) ToMath(ctx context.Context, args ...any) (template.HTML, er
if err != nil { if err != nil {
return nil, err return nil, err
} }
return hugio.NewReadSeekerNoOpCloserFromString(result.Data.Output), nil
e := fileCacheEntry{
Version: fileCacheEntryVersion,
Output: result.Data.Output,
Warnings: result.Header.Warnings,
}
buf := &bytes.Buffer{}
enc := json.NewEncoder(buf)
enc.SetEscapeHTML(false)
if err := enc.Encode(e); err != nil {
return nil, fmt.Errorf("failed to encode file cache entry: %w", err)
}
return hugio.NewReadSeekerNoOpCloserFromBytes(buf.Bytes()), nil
}) })
if err != nil { if err != nil {
return "", err return "", err
} }
s, err := hugio.ReadString(r) var e fileCacheEntry
if err := json.NewDecoder(r).Decode(&e); err != nil {
return "", fmt.Errorf("failed to decode file cache entry: %w", err)
}
return template.HTML(s), err for _, warning := range e.Warnings {
ns.deps.Log.Warnf("transform.ToMath: %s", warning)
}
return template.HTML(e.Output), err
}) })
if err != nil { if err != nil {
return "", err return "", err

View file

@ -495,3 +495,43 @@ DATA
} }
} }
} }
// Issue 13729
func TestToMathStrictMode(t *testing.T) {
t.Parallel()
files := `
-- hugo.toml --
disableKinds = ['page','rss','section','sitemap','taxonomy','term']
-- layouts/all.html --
{{ transform.ToMath "a %" dict }}
-- foo --
`
// strict mode: default
f := strings.ReplaceAll(files, "dict", "")
b, err := hugolib.TestE(t, f)
b.Assert(err.Error(), qt.Contains, "[commentAtEnd]")
// strict mode: error
f = strings.ReplaceAll(files, "dict", `(dict "strict" "error")`)
b, err = hugolib.TestE(t, f)
b.Assert(err.Error(), qt.Contains, "[commentAtEnd]")
// strict mode: ignore
f = strings.ReplaceAll(files, "dict", `(dict "strict" "ignore")`)
b = hugolib.Test(t, f, hugolib.TestOptWarn())
b.AssertLogMatches("")
b.AssertFileContent("public/index.html", `<annotation encoding="application/x-tex">a %</annotation>`)
// strict: warn
f = strings.ReplaceAll(files, "dict", `(dict "strict" "warn")`)
b = hugolib.Test(t, f, hugolib.TestOptWarn())
b.AssertLogMatches("[commentAtEnd]")
b.AssertFileContent("public/index.html", `<annotation encoding="application/x-tex">a %</annotation>`)
// strict mode: invalid value
f = strings.ReplaceAll(files, "dict", `(dict "strict" "foo")`)
b, err = hugolib.TestE(t, f)
b.Assert(err.Error(), qt.Contains, "invalid strict mode")
}