mirror of
https://github.com/gohugoio/hugo.git
synced 2024-05-20 16:22:49 +00:00
Compare commits
16 commits
f77322d0ac
...
079a72dde8
Author | SHA1 | Date | |
---|---|---|---|
079a72dde8 | |||
1961327536 | |||
cc3574ef4f | |||
fe84cc218e | |||
babcb339a8 | |||
7203a95a60 | |||
fb084390cd | |||
fb51b698b3 | |||
6b867972ec | |||
509ab08c1b | |||
2d75f539e1 | |||
15a4b9b337 | |||
10a8448eee | |||
722c486a34 | |||
f40f50ead0 | |||
cf5d0c1f91 |
2
LICENSE
2
LICENSE
|
@ -186,7 +186,7 @@
|
||||||
same "printed page" as the copyright notice for easier
|
same "printed page" as the copyright notice for easier
|
||||||
identification within third-party archives.
|
identification within third-party archives.
|
||||||
|
|
||||||
Copyright 2022 The Hugo Authors.
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -4,4 +4,4 @@
|
||||||
|
|
||||||
Please report (suspected) security vulnerabilities to **[bjorn.erik.pedersen@gmail.com](mailto:bjorn.erik.pedersen@gmail.com)**. You will receive a response from us within 48 hours. If we can confirm the issue, we will release a patch as soon as possible depending on the complexity of the issue but historically within days.
|
Please report (suspected) security vulnerabilities to **[bjorn.erik.pedersen@gmail.com](mailto:bjorn.erik.pedersen@gmail.com)**. You will receive a response from us within 48 hours. If we can confirm the issue, we will release a patch as soon as possible depending on the complexity of the issue but historically within days.
|
||||||
|
|
||||||
Also see [Hugo's Security Model](https://gohugo.io/about/security-model/).
|
Also see [Hugo's Security Model](https://gohugo.io/about/security/).
|
||||||
|
|
4
cache/dynacache/dynacache.go
vendored
4
cache/dynacache/dynacache.go
vendored
|
@ -67,7 +67,7 @@ func New(opts Options) *Cache {
|
||||||
evictedIdentities := collections.NewStack[identity.Identity]()
|
evictedIdentities := collections.NewStack[identity.Identity]()
|
||||||
|
|
||||||
onEvict := func(k, v any) {
|
onEvict := func(k, v any) {
|
||||||
if !opts.Running {
|
if !opts.Watching {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
identity.WalkIdentitiesShallow(v, func(level int, id identity.Identity) bool {
|
identity.WalkIdentitiesShallow(v, func(level int, id identity.Identity) bool {
|
||||||
|
@ -97,7 +97,7 @@ type Options struct {
|
||||||
CheckInterval time.Duration
|
CheckInterval time.Duration
|
||||||
MaxSize int
|
MaxSize int
|
||||||
MinMaxSize int
|
MinMaxSize int
|
||||||
Running bool
|
Watching bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Options for a partition.
|
// Options for a partition.
|
||||||
|
|
|
@ -209,7 +209,7 @@ func (c *newCommand) newSiteNextStepsText(path string, format string) string {
|
||||||
1. Change the current directory to ` + path + `.
|
1. Change the current directory to ` + path + `.
|
||||||
2. Create or install a theme:
|
2. Create or install a theme:
|
||||||
- Create a new theme with the command "hugo new theme <THEMENAME>"
|
- Create a new theme with the command "hugo new theme <THEMENAME>"
|
||||||
- Install a theme from https://themes.gohugo.io/
|
- Or, install a theme from https://themes.gohugo.io/
|
||||||
3. Edit hugo.` + format + `, setting the "theme" property to the theme name.
|
3. Edit hugo.` + format + `, setting the "theme" property to the theme name.
|
||||||
4. Create new content with the command "hugo new content `)
|
4. Create new content with the command "hugo new content `)
|
||||||
|
|
||||||
|
|
|
@ -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: 125,
|
Minor: 126,
|
||||||
PatchLevel: 2,
|
PatchLevel: 0,
|
||||||
Suffix: "",
|
Suffix: "-DEV",
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,6 +71,9 @@ func (c ConfigLanguage) Environment() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c ConfigLanguage) IsMultihost() bool {
|
func (c ConfigLanguage) IsMultihost() bool {
|
||||||
|
if len(c.m.Languages)-len(c.config.C.DisabledLanguages) <= 1 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
return c.m.IsMultihost
|
return c.m.IsMultihost
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
2
deps/deps.go
vendored
2
deps/deps.go
vendored
|
@ -155,7 +155,7 @@ func (d *Deps) Init() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if d.MemCache == nil {
|
if d.MemCache == nil {
|
||||||
d.MemCache = dynacache.New(dynacache.Options{Running: d.Conf.Running(), Log: d.Log})
|
d.MemCache = dynacache.New(dynacache.Options{Watching: d.Conf.Watching(), Log: d.Log})
|
||||||
}
|
}
|
||||||
|
|
||||||
if d.PathSpec == nil {
|
if d.PathSpec == nil {
|
||||||
|
|
4
go.mod
4
go.mod
|
@ -64,8 +64,8 @@ require (
|
||||||
github.com/spf13/cobra v1.8.0
|
github.com/spf13/cobra v1.8.0
|
||||||
github.com/spf13/fsync v0.10.1
|
github.com/spf13/fsync v0.10.1
|
||||||
github.com/spf13/pflag v1.0.5
|
github.com/spf13/pflag v1.0.5
|
||||||
github.com/tdewolff/minify/v2 v2.20.19
|
github.com/tdewolff/minify/v2 v2.20.20
|
||||||
github.com/tdewolff/parse/v2 v2.7.12
|
github.com/tdewolff/parse/v2 v2.7.13
|
||||||
github.com/yuin/goldmark v1.7.1
|
github.com/yuin/goldmark v1.7.1
|
||||||
github.com/yuin/goldmark-emoji v1.0.2
|
github.com/yuin/goldmark-emoji v1.0.2
|
||||||
go.uber.org/automaxprocs v1.5.3
|
go.uber.org/automaxprocs v1.5.3
|
||||||
|
|
8
go.sum
8
go.sum
|
@ -429,10 +429,10 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o
|
||||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
github.com/tdewolff/minify/v2 v2.20.19 h1:tX0SR0LUrIqGoLjXnkIzRSIbKJ7PaNnSENLD4CyH6Xo=
|
github.com/tdewolff/minify/v2 v2.20.20 h1:vhULb+VsW2twkplgsawAoUY957efb+EdiZ7zu5fUhhk=
|
||||||
github.com/tdewolff/minify/v2 v2.20.19/go.mod h1:ulkFoeAVWMLEyjuDz1ZIWOA31g5aWOawCFRp9R/MudM=
|
github.com/tdewolff/minify/v2 v2.20.20/go.mod h1:GYaLXFpIIwsX99apQHXfGdISUdlA98wmaoWxjT9C37k=
|
||||||
github.com/tdewolff/parse/v2 v2.7.12 h1:tgavkHc2ZDEQVKy1oWxwIyh5bP4F5fEh/JmBwPP/3LQ=
|
github.com/tdewolff/parse/v2 v2.7.13 h1:iSiwOUkCYLNfapHoqdLcqZVgvQ0jrsao8YYKP/UJYTI=
|
||||||
github.com/tdewolff/parse/v2 v2.7.12/go.mod h1:3FbJWZp3XT9OWVN3Hmfp0p/a08v4h8J9W1aghka0soA=
|
github.com/tdewolff/parse/v2 v2.7.13/go.mod h1:3FbJWZp3XT9OWVN3Hmfp0p/a08v4h8J9W1aghka0soA=
|
||||||
github.com/tdewolff/test v1.0.11-0.20231101010635-f1265d231d52/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
|
github.com/tdewolff/test v1.0.11-0.20231101010635-f1265d231d52/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
|
||||||
github.com/tdewolff/test v1.0.11-0.20240106005702-7de5f7df4739 h1:IkjBCtQOOjIn03u/dMQK9g+Iw9ewps4mCl1nB8Sscbo=
|
github.com/tdewolff/test v1.0.11-0.20240106005702-7de5f7df4739 h1:IkjBCtQOOjIn03u/dMQK9g+Iw9ewps4mCl1nB8Sscbo=
|
||||||
github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0=
|
github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0=
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
package hugolib
|
package hugolib
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
@ -241,3 +242,52 @@ iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAA
|
||||||
"p1|<p><a href=\"p2\">P2</a>", "<img src=\"pixel.png\" alt=\"Pixel\">")
|
"p1|<p><a href=\"p2\">P2</a>", "<img src=\"pixel.png\" alt=\"Pixel\">")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRenderHooksDefaultEscape(t *testing.T) {
|
||||||
|
files := `
|
||||||
|
-- hugo.toml --
|
||||||
|
[markup.goldmark.renderHooks]
|
||||||
|
[markup.goldmark.renderHooks.image]
|
||||||
|
enableDefault = ENABLE
|
||||||
|
[markup.goldmark.renderHooks.link]
|
||||||
|
enableDefault = ENABLE
|
||||||
|
[markup.goldmark.parser]
|
||||||
|
wrapStandAloneImageWithinParagraph = false
|
||||||
|
[markup.goldmark.parser.attribute]
|
||||||
|
block = true
|
||||||
|
title = true
|
||||||
|
-- content/_index.md --
|
||||||
|
---
|
||||||
|
title: "Home"
|
||||||
|
---
|
||||||
|
Link: [text-"<>&](/destination-"<> 'title-"<>&')
|
||||||
|
|
||||||
|
Image: ![alt-"<>&](/destination-"<> 'title-"<>&')
|
||||||
|
{class="><script>alert()</script>" id="baz"}
|
||||||
|
|
||||||
|
-- layouts/index.html --
|
||||||
|
{{ .Content }}
|
||||||
|
`
|
||||||
|
|
||||||
|
for _, enabled := range []bool{true, false} {
|
||||||
|
enabled := enabled
|
||||||
|
t.Run(fmt.Sprint(enabled), func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
b := Test(t, strings.ReplaceAll(files, "ENABLE", fmt.Sprint(enabled)))
|
||||||
|
|
||||||
|
// The escaping is slightly different between the two.
|
||||||
|
if enabled {
|
||||||
|
b.AssertFileContent("public/index.html",
|
||||||
|
"Link: <a href=\"/destination-%22%3C%3E\" title=\"title-"<>&\">text-"<>&</a>",
|
||||||
|
"img alt=\"alt-"<>&\" src=\"/destination-%22%3C%3E\" title=\"title-"<>&\">",
|
||||||
|
"><script>",
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
b.AssertFileContent("public/index.html",
|
||||||
|
"Link: <a href=\"/destination-%22%3C%3E\" title=\"title-"<>&\">text-"<>&</a>",
|
||||||
|
"Image: <img src=\"/destination-%22%3C%3E\" alt=\"alt-"<>&\" title=\"title-"<>&\">",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -252,3 +252,31 @@ Files: {{ range $files }}{{ .Permalink }}|{{ end }}$
|
||||||
b.AssertFileContent("public/en/enpages/mybundle-en/file2.txt", "File 2 en.")
|
b.AssertFileContent("public/en/enpages/mybundle-en/file2.txt", "File 2 en.")
|
||||||
b.AssertFileContent("public/fr/section/mybundle/file2.txt", "File 2 en.")
|
b.AssertFileContent("public/fr/section/mybundle/file2.txt", "File 2 en.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMultihostAllButOneLanguageDisabledIssue12288(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
files := `
|
||||||
|
-- hugo.toml --
|
||||||
|
defaultContentLanguage = "en"
|
||||||
|
disableLanguages = ["fr"]
|
||||||
|
#baseURL = "https://example.com"
|
||||||
|
[languages]
|
||||||
|
[languages.en]
|
||||||
|
baseURL = "https://example.en"
|
||||||
|
weight = 1
|
||||||
|
[languages.fr]
|
||||||
|
baseURL = "https://example.fr"
|
||||||
|
weight = 2
|
||||||
|
-- assets/css/main.css --
|
||||||
|
body { color: red; }
|
||||||
|
-- layouts/index.html --
|
||||||
|
{{ $css := resources.Get "css/main.css" | minify }}
|
||||||
|
CSS: {{ $css.Permalink }}|{{ $css.RelPermalink }}|
|
||||||
|
`
|
||||||
|
|
||||||
|
b := Test(t, files)
|
||||||
|
|
||||||
|
b.AssertFileContent("public/css/main.min.css", "body{color:red}")
|
||||||
|
b.AssertFileContent("public/index.html", "CSS: https://example.en/css/main.min.css|/css/main.min.css|")
|
||||||
|
}
|
||||||
|
|
|
@ -38,12 +38,20 @@ import (
|
||||||
|
|
||||||
type TestOpt func(*IntegrationTestConfig)
|
type TestOpt func(*IntegrationTestConfig)
|
||||||
|
|
||||||
|
// TestOptRunning will enable running in integration tests.
|
||||||
func TestOptRunning() TestOpt {
|
func TestOptRunning() TestOpt {
|
||||||
return func(c *IntegrationTestConfig) {
|
return func(c *IntegrationTestConfig) {
|
||||||
c.Running = true
|
c.Running = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestOptWatching will enable watching in integration tests.
|
||||||
|
func TestOptWatching() TestOpt {
|
||||||
|
return func(c *IntegrationTestConfig) {
|
||||||
|
c.Watching = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Enable tracing in integration tests.
|
// Enable tracing in integration tests.
|
||||||
// THis should only be used during development and not committed to the repo.
|
// THis should only be used during development and not committed to the repo.
|
||||||
func TestOptTrace() TestOpt {
|
func TestOptTrace() TestOpt {
|
||||||
|
@ -570,6 +578,10 @@ func (s *IntegrationTestBuilder) initBuilder() error {
|
||||||
"running": s.Cfg.Running,
|
"running": s.Cfg.Running,
|
||||||
"watch": s.Cfg.Running,
|
"watch": s.Cfg.Running,
|
||||||
})
|
})
|
||||||
|
} else if s.Cfg.Watching {
|
||||||
|
flags.Set("internal", maps.Params{
|
||||||
|
"watch": s.Cfg.Watching,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.Cfg.WorkingDir != "" {
|
if s.Cfg.WorkingDir != "" {
|
||||||
|
@ -817,6 +829,11 @@ type IntegrationTestConfig struct {
|
||||||
// Whether to simulate server mode.
|
// Whether to simulate server mode.
|
||||||
Running bool
|
Running bool
|
||||||
|
|
||||||
|
// Watch for changes.
|
||||||
|
// This is (currently) always set to true when Running is set.
|
||||||
|
// Note that the CLI for the server does allow for --watch=false, but that is not used in these test.
|
||||||
|
Watching bool
|
||||||
|
|
||||||
// Will print the log buffer after the build
|
// Will print the log buffer after the build
|
||||||
Verbose bool
|
Verbose bool
|
||||||
|
|
||||||
|
|
|
@ -175,7 +175,7 @@ func (pco *pageContentOutput) RenderShortcodes(ctx context.Context) (template.HT
|
||||||
// This content will be parsed and rendered by Goldmark.
|
// This content will be parsed and rendered by Goldmark.
|
||||||
// Wrap it in a special Hugo markup to assign the correct Page from
|
// Wrap it in a special Hugo markup to assign the correct Page from
|
||||||
// the stack.
|
// the stack.
|
||||||
c = hugocontext.Wrap(c, pco.po.p.pid)
|
return template.HTML(hugocontext.Wrap(c, pco.po.p.pid)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return helpers.BytesToHTML(c), nil
|
return helpers.BytesToHTML(c), nil
|
||||||
|
|
|
@ -121,14 +121,23 @@ func TestRebuildEditTextFileInBranchBundle(t *testing.T) {
|
||||||
b.AssertRenderCountContent(1)
|
b.AssertRenderCountContent(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRebuildRenameTextFileInLeafBundle(t *testing.T) {
|
func testRebuildBothWatchingAndRunning(t *testing.T, files string, withB func(b *IntegrationTestBuilder)) {
|
||||||
b := TestRunning(t, rebuildFilesSimple)
|
t.Helper()
|
||||||
b.AssertFileContent("public/mysection/mysectionbundle/index.html", "My Section Bundle Text 2 Content.", "Len Resources: 2|")
|
for _, opt := range []TestOpt{TestOptWatching(), TestOptRunning()} {
|
||||||
|
b := Test(t, files, opt)
|
||||||
|
withB(b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
b.RenameFile("content/mysection/mysectionbundle/mysectionbundletext.txt", "content/mysection/mysectionbundle/mysectionbundletext2.txt").Build()
|
func TestRebuildRenameTextFileInLeafBundle(t *testing.T) {
|
||||||
b.AssertFileContent("public/mysection/mysectionbundle/index.html", "mysectionbundletext2", "My Section Bundle Text 2 Content.", "Len Resources: 2|")
|
testRebuildBothWatchingAndRunning(t, rebuildFilesSimple, func(b *IntegrationTestBuilder) {
|
||||||
b.AssertRenderCountPage(3)
|
b.AssertFileContent("public/mysection/mysectionbundle/index.html", "My Section Bundle Text 2 Content.", "Len Resources: 2|")
|
||||||
b.AssertRenderCountContent(3)
|
|
||||||
|
b.RenameFile("content/mysection/mysectionbundle/mysectionbundletext.txt", "content/mysection/mysectionbundle/mysectionbundletext2.txt").Build()
|
||||||
|
b.AssertFileContent("public/mysection/mysectionbundle/index.html", "mysectionbundletext2", "My Section Bundle Text 2 Content.", "Len Resources: 2|")
|
||||||
|
b.AssertRenderCountPage(3)
|
||||||
|
b.AssertRenderCountContent(3)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRebuilEditContentFileInLeafBundle(t *testing.T) {
|
func TestRebuilEditContentFileInLeafBundle(t *testing.T) {
|
||||||
|
@ -367,8 +376,6 @@ My short.
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRebuildBaseof(t *testing.T) {
|
func TestRebuildBaseof(t *testing.T) {
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
files := `
|
files := `
|
||||||
-- hugo.toml --
|
-- hugo.toml --
|
||||||
title = "Hugo Site"
|
title = "Hugo Site"
|
||||||
|
@ -383,12 +390,13 @@ Baseof: {{ .Title }}|
|
||||||
Home: {{ .Title }}|{{ .Content }}|
|
Home: {{ .Title }}|{{ .Content }}|
|
||||||
{{ end }}
|
{{ end }}
|
||||||
`
|
`
|
||||||
b := Test(t, files, TestOptRunning())
|
testRebuildBothWatchingAndRunning(t, files, func(b *IntegrationTestBuilder) {
|
||||||
b.AssertFileContent("public/index.html", "Baseof: Hugo Site|", "Home: Hugo Site||")
|
b.AssertFileContent("public/index.html", "Baseof: Hugo Site|", "Home: Hugo Site||")
|
||||||
b.EditFileReplaceFunc("layouts/_default/baseof.html", func(s string) string {
|
b.EditFileReplaceFunc("layouts/_default/baseof.html", func(s string) string {
|
||||||
return strings.Replace(s, "Baseof", "Baseof Edited", 1)
|
return strings.Replace(s, "Baseof", "Baseof Edited", 1)
|
||||||
}).Build()
|
}).Build()
|
||||||
b.AssertFileContent("public/index.html", "Baseof Edited: Hugo Site|", "Home: Hugo Site||")
|
b.AssertFileContent("public/index.html", "Baseof Edited: Hugo Site|", "Home: Hugo Site||")
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRebuildSingleWithBaseof(t *testing.T) {
|
func TestRebuildSingleWithBaseof(t *testing.T) {
|
||||||
|
|
|
@ -123,14 +123,14 @@ func NewHugoSites(cfg deps.DepsCfg) (*HugoSites, error) {
|
||||||
HandlerPost: logHookLast,
|
HandlerPost: logHookLast,
|
||||||
Stdout: cfg.LogOut,
|
Stdout: cfg.LogOut,
|
||||||
Stderr: cfg.LogOut,
|
Stderr: cfg.LogOut,
|
||||||
StoreErrors: conf.Running(),
|
StoreErrors: conf.Watching(),
|
||||||
SuppressStatements: conf.IgnoredLogs(),
|
SuppressStatements: conf.IgnoredLogs(),
|
||||||
}
|
}
|
||||||
logger = loggers.New(logOpts)
|
logger = loggers.New(logOpts)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
memCache := dynacache.New(dynacache.Options{Running: conf.Running(), Log: logger})
|
memCache := dynacache.New(dynacache.Options{Watching: conf.Watching(), Log: logger})
|
||||||
|
|
||||||
firstSiteDeps := &deps.Deps{
|
firstSiteDeps := &deps.Deps{
|
||||||
Fs: cfg.Fs,
|
Fs: cfg.Fs,
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
# Release env.
|
# Release env.
|
||||||
# These will be replaced by script before release.
|
# These will be replaced by script before release.
|
||||||
HUGORELEASER_TAG=v0.125.1
|
HUGORELEASER_TAG=v0.125.4
|
||||||
HUGORELEASER_COMMITISH=68c5ad638c2072969e47262926b912e80fd71a77
|
HUGORELEASER_COMMITISH=cc3574ef4f41fccbe88d9443ed066eb10867ada2
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ func New() goldmark.Extender {
|
||||||
|
|
||||||
// Wrap wraps the given byte slice in a Hugo context that used to determine the correct Page
|
// Wrap wraps the given byte slice in a Hugo context that used to determine the correct Page
|
||||||
// in .RenderShortcodes.
|
// in .RenderShortcodes.
|
||||||
func Wrap(b []byte, pid uint64) []byte {
|
func Wrap(b []byte, pid uint64) string {
|
||||||
buf := bufferpool.GetBuffer()
|
buf := bufferpool.GetBuffer()
|
||||||
defer bufferpool.PutBuffer(buf)
|
defer bufferpool.PutBuffer(buf)
|
||||||
buf.Write(prefix)
|
buf.Write(prefix)
|
||||||
|
@ -45,7 +45,7 @@ func Wrap(b []byte, pid uint64) []byte {
|
||||||
buf.Write(b)
|
buf.Write(b)
|
||||||
buf.Write(prefix)
|
buf.Write(prefix)
|
||||||
buf.Write(closingDelimAndNewline)
|
buf.Write(closingDelimAndNewline)
|
||||||
return buf.Bytes()
|
return buf.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
var kindHugoContext = ast.NewNodeKind("HugoContext")
|
var kindHugoContext = ast.NewNodeKind("HugoContext")
|
||||||
|
|
|
@ -24,7 +24,7 @@ func TestWrap(t *testing.T) {
|
||||||
|
|
||||||
b := []byte("test")
|
b := []byte("test")
|
||||||
|
|
||||||
c.Assert(string(Wrap(b, 42)), qt.Equals, "{{__hugo_ctx pid=42}}\ntest{{__hugo_ctx/}}\n")
|
c.Assert(Wrap(b, 42), qt.Equals, "{{__hugo_ctx pid=42}}\ntest{{__hugo_ctx/}}\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkWrap(b *testing.B) {
|
func BenchmarkWrap(b *testing.B) {
|
||||||
|
|
|
@ -261,7 +261,10 @@ func (c *collector) add(owner *moduleAdapter, moduleImport Import) (*moduleAdapt
|
||||||
// This will select the latest release-version (not beta etc.).
|
// This will select the latest release-version (not beta etc.).
|
||||||
versionQuery = "upgrade"
|
versionQuery = "upgrade"
|
||||||
}
|
}
|
||||||
if err := c.Get(fmt.Sprintf("%s@%s", modulePath, versionQuery)); err != nil {
|
|
||||||
|
// Note that we cannot use c.Get for this, as that may
|
||||||
|
// trigger a new module collection and potentially create a infinite loop.
|
||||||
|
if err := c.get(fmt.Sprintf("%s@%s", modulePath, versionQuery)); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := c.loadModules(); err != nil {
|
if err := c.loadModules(); err != nil {
|
||||||
|
|
|
@ -138,7 +138,7 @@ func (c *Client) FromRemote(uri string, optionsm map[string]any) (resource.Resou
|
||||||
|
|
||||||
if res.StatusCode != http.StatusNotFound {
|
if res.StatusCode != http.StatusNotFound {
|
||||||
if res.StatusCode < 200 || res.StatusCode > 299 {
|
if res.StatusCode < 200 || res.StatusCode > 299 {
|
||||||
return nil, temporaryHTTPStatusCodes[res.StatusCode], toHTTPError(fmt.Errorf("failed to fetch remote resource: %s", http.StatusText(res.StatusCode)), res, !isHeadMethod)
|
return nil, temporaryHTTPStatusCodes[res.StatusCode], toHTTPError(fmt.Errorf("failed to fetch remote resource from '%s': %s", uri, http.StatusText(res.StatusCode)), res, !isHeadMethod)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
{{- $src = .RelPermalink -}}
|
{{- $src = .RelPermalink -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
{{- $attributes := merge .Attributes (dict "alt" .Text "src" $src "title" .Title) -}}
|
{{- $attributes := merge .Attributes (dict "alt" .Text "src" $src "title" (.Title | transform.HTMLEscape)) -}}
|
||||||
<img
|
<img
|
||||||
{{- range $k, $v := $attributes -}}
|
{{- range $k, $v := $attributes -}}
|
||||||
{{- if $v -}}
|
{{- if $v -}}
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
{{- $attributes := dict "href" $href "title" .Title -}}
|
{{- $attributes := dict "href" $href "title" (.Title | transform.HTMLEscape) -}}
|
||||||
<a
|
<a
|
||||||
{{- range $k, $v := $attributes -}}
|
{{- range $k, $v := $attributes -}}
|
||||||
{{- if $v -}}
|
{{- if $v -}}
|
||||||
|
|
|
@ -48,7 +48,7 @@
|
||||||
<title>{{ if eq .Title .Site.Title }}{{ .Site.Title }}{{ else }}{{ with .Title }}{{ . }} on {{ end }}{{ .Site.Title }}{{ end }}</title>
|
<title>{{ if eq .Title .Site.Title }}{{ .Site.Title }}{{ else }}{{ with .Title }}{{ . }} on {{ end }}{{ .Site.Title }}{{ end }}</title>
|
||||||
<link>{{ .Permalink }}</link>
|
<link>{{ .Permalink }}</link>
|
||||||
<description>Recent content {{ if ne .Title .Site.Title }}{{ with .Title }}in {{ . }} {{ end }}{{ end }}on {{ .Site.Title }}</description>
|
<description>Recent content {{ if ne .Title .Site.Title }}{{ with .Title }}in {{ . }} {{ end }}{{ end }}on {{ .Site.Title }}</description>
|
||||||
<generator>Hugo {{ hugo.Version }}</generator>
|
<generator>Hugo</generator>
|
||||||
<language>{{ site.Language.LanguageCode }}</language>{{ with $authorEmail }}
|
<language>{{ site.Language.LanguageCode }}</language>{{ with $authorEmail }}
|
||||||
<managingEditor>{{.}}{{ with $authorName }} ({{ . }}){{ end }}</managingEditor>{{ end }}{{ with $authorEmail }}
|
<managingEditor>{{.}}{{ with $authorName }} ({{ . }}){{ end }}</managingEditor>{{ end }}{{ with $authorEmail }}
|
||||||
<webMaster>{{ . }}{{ with $authorName }} ({{ . }}){{ end }}</webMaster>{{ end }}{{ with .Site.Copyright }}
|
<webMaster>{{ . }}{{ with $authorName }} ({{ . }}){{ end }}</webMaster>{{ end }}{{ with .Site.Copyright }}
|
||||||
|
|
|
@ -4,11 +4,11 @@
|
||||||
<meta property="og:site_name" content="{{ . }}">
|
<meta property="og:site_name" content="{{ . }}">
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
||||||
{{- with or .Title site.Title site.Params.title | plainify}}
|
{{- with or .Title site.Title site.Params.title | plainify }}
|
||||||
<meta property="og:title" content="{{ . }}">
|
<meta property="og:title" content="{{ . }}">
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
||||||
{{- with or .Description .Summary site.Params.description | plainify }}
|
{{- with or .Description .Summary site.Params.description | plainify | htmlUnescape | chomp }}
|
||||||
<meta property="og:description" content="{{ . }}">
|
<meta property="og:description" content="{{ . }}">
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
||||||
|
@ -18,7 +18,9 @@
|
||||||
|
|
||||||
{{- if .IsPage }}
|
{{- if .IsPage }}
|
||||||
<meta property="og:type" content="article">
|
<meta property="og:type" content="article">
|
||||||
<meta property="article:section" content="{{ .Section }}">
|
{{- with .Section }}
|
||||||
|
<meta property="article:section" content="{{ . }}">
|
||||||
|
{{- end }}
|
||||||
{{- $ISO8601 := "2006-01-02T15:04:05-07:00" }}
|
{{- $ISO8601 := "2006-01-02T15:04:05-07:00" }}
|
||||||
{{- with .PublishDate }}
|
{{- with .PublishDate }}
|
||||||
<meta property="article:published_time" {{ .Format $ISO8601 | printf "content=%q" | safeHTMLAttr }}>
|
<meta property="article:published_time" {{ .Format $ISO8601 | printf "content=%q" | safeHTMLAttr }}>
|
||||||
|
|
|
@ -8,10 +8,10 @@ Renders an embedded YouTube video.
|
||||||
@param {int} [end] The time, measured in seconds from the start of the video, when the player should stop playing the video.
|
@param {int} [end] The time, measured in seconds from the start of the video, when the player should stop playing the video.
|
||||||
@param {string} [id] The video id. Optional if the id is provided as first positional argument.
|
@param {string} [id] The video id. Optional if the id is provided as first positional argument.
|
||||||
@param {string} [loading=eager] The loading attribute of the iframe element.
|
@param {string} [loading=eager] The loading attribute of the iframe element.
|
||||||
@param {bool} [loop=false] Whether to indefinitely repeat the video.
|
@param {bool} [loop=false] Whether to indefinitely repeat the video. Ignores the start and end arguments after the first play.
|
||||||
@param {bool} [mute=false] Whether to mute the video. Always true when autoplay is true.
|
@param {bool} [mute=false] Whether to mute the video. Always true when autoplay is true.
|
||||||
@param {int} [start] The time, measured in seconds from the start of the video, when the player should start playing the video.
|
@param {int} [start] The time, measured in seconds from the start of the video, when the player should start playing the video.
|
||||||
@param {string} [title] The title attribute of the iframe element. Defaults to the title returned by YouTube oEmbed API.
|
@param {string} [title] The title attribute of the iframe element. Defaults to "YouTube video".
|
||||||
|
|
||||||
@returns {template.HTML}
|
@returns {template.HTML}
|
||||||
|
|
||||||
|
@ -26,20 +26,6 @@ Renders an embedded YouTube video.
|
||||||
{{- if not $pc.Disable }}
|
{{- if not $pc.Disable }}
|
||||||
{{- with $id := or (.Get "id") (.Get 0) }}
|
{{- with $id := or (.Get "id") (.Get 0) }}
|
||||||
|
|
||||||
{{- /* Get data from the YouTube oEmbed API. */}}
|
|
||||||
{{- $q := querify "url" (printf "https://www.youtube.com/watch?v=%s" $id) "format" "json" }}
|
|
||||||
{{- $url := printf "https://www.youtube.com/oembed?%s" $q }}
|
|
||||||
{{- $data := dict }}
|
|
||||||
{{- with resources.GetRemote $url }}
|
|
||||||
{{- with .Err }}
|
|
||||||
{{- erroridf $remoteErrID "The %q shortcode was unable to get remote resource %q. %s. See %s" $.Name $url . $.Position }}
|
|
||||||
{{- else }}
|
|
||||||
{{- $data = .Content | transform.Unmarshal }}
|
|
||||||
{{- end }}
|
|
||||||
{{- else }}
|
|
||||||
{{- erroridf $remoteErrID "The %q shortcode was unable to get remote resource %q. See %s" $.Name $url $.Position }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{/* Set defaults. */}}
|
{{/* Set defaults. */}}
|
||||||
{{- $allowFullScreen := "allowfullscreen" }}
|
{{- $allowFullScreen := "allowfullscreen" }}
|
||||||
{{- $autoplay := 0 }}
|
{{- $autoplay := 0 }}
|
||||||
|
@ -50,7 +36,7 @@ Renders an embedded YouTube video.
|
||||||
{{- $loop := 0 }}
|
{{- $loop := 0 }}
|
||||||
{{- $mute := 0 }}
|
{{- $mute := 0 }}
|
||||||
{{- $start := 0 }}
|
{{- $start := 0 }}
|
||||||
{{- $title := $data.title }}
|
{{- $title := "YouTube video" }}
|
||||||
|
|
||||||
{{- /* Get arguments. */}}
|
{{- /* Get arguments. */}}
|
||||||
{{- if in (slice "false" false 0) ($.Get "allowFullScreen") }}
|
{{- if in (slice "false" false 0) ($.Get "allowFullScreen") }}
|
||||||
|
|
|
@ -71,7 +71,7 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
type templateExecHelper struct {
|
type templateExecHelper struct {
|
||||||
running bool // whether we're in server mode.
|
watching bool // whether we're in server/watch mode.
|
||||||
site reflect.Value
|
site reflect.Value
|
||||||
siteParams reflect.Value
|
siteParams reflect.Value
|
||||||
funcs map[string]reflect.Value
|
funcs map[string]reflect.Value
|
||||||
|
@ -95,7 +95,7 @@ func (t *templateExecHelper) GetFunc(ctx context.Context, tmpl texttemplate.Prep
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *templateExecHelper) Init(ctx context.Context, tmpl texttemplate.Preparer) {
|
func (t *templateExecHelper) Init(ctx context.Context, tmpl texttemplate.Preparer) {
|
||||||
if t.running {
|
if t.watching {
|
||||||
_, ok := tmpl.(identity.IdentityProvider)
|
_, ok := tmpl.(identity.IdentityProvider)
|
||||||
if ok {
|
if ok {
|
||||||
t.trackDependencies(ctx, tmpl, "", reflect.Value{})
|
t.trackDependencies(ctx, tmpl, "", reflect.Value{})
|
||||||
|
@ -129,7 +129,7 @@ func (t *templateExecHelper) GetMethod(ctx context.Context, tmpl texttemplate.Pr
|
||||||
name = "MainSections"
|
name = "MainSections"
|
||||||
}
|
}
|
||||||
|
|
||||||
if t.running {
|
if t.watching {
|
||||||
ctx = t.trackDependencies(ctx, tmpl, name, receiver)
|
ctx = t.trackDependencies(ctx, tmpl, name, receiver)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,7 +151,7 @@ func (t *templateExecHelper) GetMethod(ctx context.Context, tmpl texttemplate.Pr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *templateExecHelper) OnCalled(ctx context.Context, tmpl texttemplate.Preparer, name string, args []reflect.Value, result reflect.Value) {
|
func (t *templateExecHelper) OnCalled(ctx context.Context, tmpl texttemplate.Preparer, name string, args []reflect.Value, result reflect.Value) {
|
||||||
if !t.running {
|
if !t.watching {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -238,7 +238,7 @@ func newTemplateExecuter(d *deps.Deps) (texttemplate.Executer, map[string]reflec
|
||||||
}
|
}
|
||||||
|
|
||||||
exeHelper := &templateExecHelper{
|
exeHelper := &templateExecHelper{
|
||||||
running: d.Conf.Running(),
|
watching: d.Conf.Watching(),
|
||||||
funcs: funcsv,
|
funcs: funcsv,
|
||||||
site: reflect.ValueOf(d.Site),
|
site: reflect.ValueOf(d.Site),
|
||||||
siteParams: reflect.ValueOf(d.Site.Params()),
|
siteParams: reflect.ValueOf(d.Site.Params()),
|
||||||
|
|
|
@ -305,3 +305,109 @@ title: p2
|
||||||
"<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>\n<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"\n xmlns:xhtml=\"http://www.w3.org/1999/xhtml\">\n <url>\n <loc>/p2/</loc>\n </url>\n</urlset>\n",
|
"<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>\n<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"\n xmlns:xhtml=\"http://www.w3.org/1999/xhtml\">\n <url>\n <loc>/p2/</loc>\n </url>\n</urlset>\n",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Issue 12418
|
||||||
|
func TestOpengraph(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
files := `
|
||||||
|
-- hugo.toml --
|
||||||
|
capitalizeListTitles = false
|
||||||
|
disableKinds = ['rss','sitemap']
|
||||||
|
languageCode = 'en-US'
|
||||||
|
[markup.goldmark.renderer]
|
||||||
|
unsafe = true
|
||||||
|
[params]
|
||||||
|
description = "m <em>n</em> and **o** can't."
|
||||||
|
[params.social]
|
||||||
|
facebook_admin = 'foo'
|
||||||
|
[taxonomies]
|
||||||
|
series = 'series'
|
||||||
|
tag = 'tags'
|
||||||
|
-- layouts/_default/list.html --
|
||||||
|
{{ template "_internal/opengraph.html" . }}
|
||||||
|
-- layouts/_default/single.html --
|
||||||
|
{{ template "_internal/opengraph.html" . }}
|
||||||
|
-- content/s1/p1.md --
|
||||||
|
---
|
||||||
|
title: p1
|
||||||
|
date: 2024-04-24T08:00:00-07:00
|
||||||
|
lastmod: 2024-04-24T11:00:00-07:00
|
||||||
|
images: [a.jpg,b.jpg]
|
||||||
|
audio: [c.mp3,d.mp3]
|
||||||
|
videos: [e.mp4,f.mp4]
|
||||||
|
series: [series-1]
|
||||||
|
tags: [t1,t2]
|
||||||
|
---
|
||||||
|
a <em>b</em> and **c** can't.
|
||||||
|
-- content/s1/p2.md --
|
||||||
|
---
|
||||||
|
title: p2
|
||||||
|
series: [series-1]
|
||||||
|
---
|
||||||
|
d <em>e</em> and **f** can't.
|
||||||
|
<!--more-->
|
||||||
|
-- content/s1/p3.md --
|
||||||
|
---
|
||||||
|
title: p3
|
||||||
|
series: [series-1]
|
||||||
|
summary: g <em>h</em> and **i** can't.
|
||||||
|
---
|
||||||
|
-- content/s1/p4.md --
|
||||||
|
---
|
||||||
|
title: p4
|
||||||
|
series: [series-1]
|
||||||
|
description: j <em>k</em> and **l** can't.
|
||||||
|
---
|
||||||
|
-- content/s1/p5.md --
|
||||||
|
---
|
||||||
|
title: p5
|
||||||
|
series: [series-1]
|
||||||
|
---
|
||||||
|
`
|
||||||
|
|
||||||
|
b := hugolib.Test(t, files)
|
||||||
|
|
||||||
|
b.AssertFileContent("public/s1/p1/index.html", `
|
||||||
|
<meta property="og:url" content="/s1/p1/">
|
||||||
|
<meta property="og:title" content="p1">
|
||||||
|
<meta property="og:description" content="a b and c can’t.">
|
||||||
|
<meta property="og:locale" content="en-US">
|
||||||
|
<meta property="og:type" content="article">
|
||||||
|
<meta property="article:section" content="s1">
|
||||||
|
<meta property="article:published_time" content="2024-04-24T08:00:00-07:00">
|
||||||
|
<meta property="article:modified_time" content="2024-04-24T11:00:00-07:00">
|
||||||
|
<meta property="article:tag" content="t1">
|
||||||
|
<meta property="article:tag" content="t2">
|
||||||
|
<meta property="og:image" content="/a.jpg">
|
||||||
|
<meta property="og:image" content="/b.jpg">
|
||||||
|
<meta property="og:audio" content="/c.mp3">
|
||||||
|
<meta property="og:audio" content="/d.mp3">
|
||||||
|
<meta property="og:video" content="/e.mp4">
|
||||||
|
<meta property="og:video" content="/f.mp4">
|
||||||
|
<meta property="og:see_also" content="/s1/p2/">
|
||||||
|
<meta property="og:see_also" content="/s1/p3/">
|
||||||
|
<meta property="og:see_also" content="/s1/p4/">
|
||||||
|
<meta property="og:see_also" content="/s1/p5/">
|
||||||
|
<meta property="fb:admins" content="foo">
|
||||||
|
`,
|
||||||
|
)
|
||||||
|
|
||||||
|
b.AssertFileContent("public/s1/p2/index.html",
|
||||||
|
`<meta property="og:description" content="d e and f can’t.">`,
|
||||||
|
)
|
||||||
|
|
||||||
|
b.AssertFileContent("public/s1/p3/index.html",
|
||||||
|
`<meta property="og:description" content="g h and i can’t.">`,
|
||||||
|
)
|
||||||
|
|
||||||
|
// The markdown is intentionally not rendered to HTML.
|
||||||
|
b.AssertFileContent("public/s1/p4/index.html",
|
||||||
|
`<meta property="og:description" content="j k and **l** can't.">`,
|
||||||
|
)
|
||||||
|
|
||||||
|
// The markdown is intentionally not rendered to HTML.
|
||||||
|
b.AssertFileContent("public/s1/p5/index.html",
|
||||||
|
`<meta property="og:description" content="m n and **o** can't.">`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue