Compare commits

..

1 Commits

Author SHA1 Message Date
Bjørn Erik Pedersen f5fefeda8f deps: Upgrade github.com/bep/lazycache v0.6.0 => v0.7.0 2024-10-27 11:39:30 +01:00
54 changed files with 243 additions and 764 deletions
+7 -7
View File
@@ -6,10 +6,10 @@ name: Test
env:
GOPROXY: https://proxy.golang.org
GO111MODULE: on
SASS_VERSION: 1.80.3
DART_SASS_SHA_LINUX: 7c933edbad0a7d389192c5b79393485c088bd2c4398e32f5754c32af006a9ffd
DART_SASS_SHA_MACOS: 79e060b0e131c3bb3c16926bafc371dc33feab122bfa8c01aa337a072097967b
DART_SASS_SHA_WINDOWS: 0bc4708b37cd1bac4740e83ac5e3176e66b774f77fd5dd364da5b5cfc9bfb469
SASS_VERSION: 1.63.2
DART_SASS_SHA_LINUX: 3ea33c95ad5c35fda6e9a0956199eef38a398f496cfb8750e02479d7d1dd42af
DART_SASS_SHA_MACOS: 11c70f259836b250b44a9cb57fed70e030f21f45069b467d371685855f1eb4f0
DART_SASS_SHA_WINDOWS: cd8cd36a619dd8e27f93d3186c52d70eb7d69472aa6c85f5094b29693e773f64
permissions:
contents: read
jobs:
@@ -112,17 +112,17 @@ jobs:
sass --version;
mage -v check;
env:
HUGO_BUILD_TAGS: extended,withdeploy
HUGO_BUILD_TAGS: extended
- if: matrix.os == 'windows-latest'
# See issue #11052. We limit the build to regular test (no -race flag) on Windows for now.
name: Test
run: |
mage -v test;
env:
HUGO_BUILD_TAGS: extended,withdeploy
HUGO_BUILD_TAGS: extended
- name: Build tags
run: |
go install -tags extended
go install -tags extended,nodeploy
- if: matrix.os == 'ubuntu-latest'
name: Build for dragonfly
run: |
+1 -3
View File
@@ -1,5 +1,3 @@
*.test
imports.*
dist/
public/
imports.*
+2 -2
View File
@@ -21,8 +21,8 @@ COPY --from=xx / /
ARG TARGETPLATFORM
RUN xx-apk add musl-dev gcc g++
# Optionally set HUGO_BUILD_TAGS to "none" or "withdeploy" when building like so:
# docker build --build-arg HUGO_BUILD_TAGS=withdeploy .
# Optionally set HUGO_BUILD_TAGS to "none" or "nodeploy" when building like so:
# docker build --build-arg HUGO_BUILD_TAGS=nodeploy .
#
# We build the extended version by default.
ARG HUGO_BUILD_TAGS="extended"
+2 -3
View File
@@ -33,7 +33,8 @@ A fast and flexible static site generator built with love by [bep], [spf13], and
[![Tests on Linux, MacOS and Windows](https://github.com/gohugoio/hugo/workflows/Test/badge.svg)](https://github.com/gohugoio/hugo/actions?query=workflow%3ATest)
[![Go Report Card](https://goreportcard.com/badge/github.com/gohugoio/hugo)](https://goreportcard.com/report/github.com/gohugoio/hugo)
[Website] | [Installation] | [Documentation] | [Support] | [Contributing] | <a rel="me" href="https://fosstodon.org/@gohugoio">Mastodon</a>
[Website] | [Installation] | [Documentation] | [Support] | [Contributing] | <a rel="me" href="https://fosstodon.org/@gohugoio">Mastodon</a> | <a rel="me" href="https://x.com/gohugoiov2">X</a>
## Overview
Hugo is a [static site generator] written in [Go], optimized for speed and designed for flexibility. With its advanced templating system and fast asset pipelines, Hugo renders a complete site in seconds, often less.
@@ -67,8 +68,6 @@ See the [features] section of the documentation for a comprehensive summary of H
<a href="https://www.linode.com/?utm_campaign=hugosponsor&utm_medium=banner&utm_source=hugogithub" target="_blank"><img src="https://raw.githubusercontent.com/gohugoio/gohugoioTheme/master/assets/images/sponsors/linode-logo_standard_light_medium.png" width="200" alt="Linode"></a>
&nbsp;&nbsp;&nbsp;
<a href="https://route4me.com/" target="_blank"><img src="https://raw.githubusercontent.com/gohugoio/gohugoioTheme/master/assets/images/sponsors/Route4MeLogoBlueOnWhite.svg" width="200" alt="Route Planning & Route Optimization Software"></a>
&nbsp;&nbsp;&nbsp;
<a href="https://www.jetbrains.com/go/?utm_source=OSS&utm_medium=referral&utm_campaign=hugo" target="_blank"><img src="https://raw.githubusercontent.com/gohugoio/gohugoioTheme/master/assets/images/sponsors/goland.svg" width="200" alt="The complete IDE crafted for professional Go developers."></a>
</p>
## Installation
+27 -3
View File
@@ -11,8 +11,21 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//go:build withdeploy
// +build withdeploy
//go:build !nodeploy
// +build !nodeploy
// Copyright 2024 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package commands
@@ -20,6 +33,7 @@ import (
"context"
"github.com/gohugoio/hugo/deploy"
"github.com/gohugoio/hugo/deploy/deployconfig"
"github.com/bep/simplecobra"
"github.com/spf13/cobra"
@@ -46,7 +60,17 @@ documentation.
return deployer.Deploy(ctx)
},
withc: func(cmd *cobra.Command, r *rootCommand) {
applyDeployFlags(cmd, r)
cmd.ValidArgsFunction = cobra.NoFileCompletions
cmd.Flags().String("target", "", "target deployment from deployments section in config file; defaults to the first one")
_ = cmd.RegisterFlagCompletionFunc("target", cobra.NoFileCompletions)
cmd.Flags().Bool("confirm", false, "ask for confirmation before making changes to the target")
cmd.Flags().Bool("dryRun", false, "dry run")
cmd.Flags().Bool("force", false, "force upload of all files")
cmd.Flags().Bool("invalidateCDN", deployconfig.DefaultConfig.InvalidateCDN, "invalidate the CDN cache listed in the deployment target")
cmd.Flags().Int("maxDeletes", deployconfig.DefaultConfig.MaxDeletes, "maximum # of files to delete, or -1 to disable")
_ = cmd.RegisterFlagCompletionFunc("maxDeletes", cobra.NoFileCompletions)
cmd.Flags().Int("workers", deployconfig.DefaultConfig.Workers, "number of workers to transfer files. defaults to 10")
_ = cmd.RegisterFlagCompletionFunc("workers", cobra.NoFileCompletions)
},
}
}
-33
View File
@@ -1,33 +0,0 @@
// Copyright 2024 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package commands
import (
"github.com/gohugoio/hugo/deploy/deployconfig"
"github.com/spf13/cobra"
)
func applyDeployFlags(cmd *cobra.Command, r *rootCommand) {
cmd.ValidArgsFunction = cobra.NoFileCompletions
cmd.Flags().String("target", "", "target deployment from deployments section in config file; defaults to the first one")
_ = cmd.RegisterFlagCompletionFunc("target", cobra.NoFileCompletions)
cmd.Flags().Bool("confirm", false, "ask for confirmation before making changes to the target")
cmd.Flags().Bool("dryRun", false, "dry run")
cmd.Flags().Bool("force", false, "force upload of all files")
cmd.Flags().Bool("invalidateCDN", deployconfig.DefaultConfig.InvalidateCDN, "invalidate the CDN cache listed in the deployment target")
cmd.Flags().Int("maxDeletes", deployconfig.DefaultConfig.MaxDeletes, "maximum # of files to delete, or -1 to disable")
_ = cmd.RegisterFlagCompletionFunc("maxDeletes", cobra.NoFileCompletions)
cmd.Flags().Int("workers", deployconfig.DefaultConfig.Workers, "number of workers to transfer files. defaults to 10")
_ = cmd.RegisterFlagCompletionFunc("workers", cobra.NoFileCompletions)
}
+3 -5
View File
@@ -11,8 +11,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//go:build !withdeploy
// +build !withdeploy
//go:build nodeploy
// +build nodeploy
// Copyright 2024 The Hugo Authors. All rights reserved.
//
@@ -31,7 +31,6 @@ package commands
import (
"context"
"errors"
"github.com/bep/simplecobra"
"github.com/spf13/cobra"
@@ -41,10 +40,9 @@ func newDeployCommand() simplecobra.Commander {
return &simpleCommand{
name: "deploy",
run: func(ctx context.Context, cd *simplecobra.Commandeer, r *rootCommand, args []string) error {
return errors.New("deploy not supported in this version of Hugo; install a release with 'withdeploy' in the archive filename or build yourself with the 'withdeploy' build tag. Also see https://github.com/gohugoio/hugo/pull/12995")
return nil
},
withc: func(cmd *cobra.Command, r *rootCommand) {
applyDeployFlags(cmd, r)
cmd.Hidden = true
},
}
-2
View File
@@ -21,8 +21,6 @@ const (
ErrRemoteGetCSV = "error-remote-getcsv"
WarnFrontMatterParamsOverrides = "warning-frontmatter-params-overrides"
WarnRenderShortcodesInHTML = "warning-rendershortcodes-in-html"
WarnGoldmarkRawHTML = "warning-goldmark-raw-html"
)
// Field/method names with special meaning.
-19
View File
@@ -1,19 +0,0 @@
// Copyright 2024 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//go:build withdeploy
// +build withdeploy
package hugo
var IsWithdeploy = true
-19
View File
@@ -1,19 +0,0 @@
// Copyright 2024 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//go:build !withdeploy
// +build !withdeploy
package hugo
var IsWithdeploy = false
-3
View File
@@ -152,9 +152,6 @@ func BuildVersionString() string {
if IsExtended {
version += "+extended"
}
if IsWithdeploy {
version += "+withdeploy"
}
osArch := bi.GoOS + "/" + bi.GoArch
+1 -1
View File
@@ -17,7 +17,7 @@ package hugo
// This should be the only one.
var CurrentVersion = Version{
Major: 0,
Minor: 138,
Minor: 137,
PatchLevel: 0,
Suffix: "-DEV",
}
+2 -2
View File
@@ -11,8 +11,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//go:build withdeploy
// +build withdeploy
//go:build !nodeploy
// +build !nodeploy
package deploy
+2 -2
View File
@@ -11,8 +11,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//go:build withdeploy
// +build withdeploy
//go:build !nodeploy
// +build !nodeploy
package deploy
+2 -2
View File
@@ -11,8 +11,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//go:build !solaris && withdeploy
// +build !solaris,withdeploy
//go:build !solaris && !nodeploy
// +build !solaris,!nodeploy
package deploy
+2 -2
View File
@@ -11,8 +11,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//go:build withdeploy
// +build withdeploy
//go:build !nodeploy
// +build !nodeploy
package deploy
+2 -2
View File
@@ -11,8 +11,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//go:build withdeploy
// +build withdeploy
//go:build !nodeploy
// +build !nodeploy
package deployconfig
+2 -2
View File
@@ -11,8 +11,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//go:build withdeploy
// +build withdeploy
//go:build !nodeploy
// +build !nodeploy
package deploy
+1 -1
View File
@@ -11,7 +11,7 @@ require (
github.com/bep/gitmap v1.6.0
github.com/bep/goat v0.5.0
github.com/bep/godartsass v1.2.0
github.com/bep/godartsass/v2 v2.2.0
github.com/bep/godartsass/v2 v2.1.0
github.com/bep/golibsass v1.2.0
github.com/bep/gowebp v0.3.0
github.com/bep/helpers v0.5.0
-2
View File
@@ -133,8 +133,6 @@ github.com/bep/godartsass v1.2.0 h1:E2VvQrxAHAFwbjyOIExAMmogTItSKodoKuijNrGm5yU=
github.com/bep/godartsass v1.2.0/go.mod h1:6LvK9RftsXMxGfsA0LDV12AGc4Jylnu6NgHL+Q5/pE8=
github.com/bep/godartsass/v2 v2.1.0 h1:fq5Y1xYf4diu4tXABiekZUCA+5l/dmNjGKCeQwdy+s0=
github.com/bep/godartsass/v2 v2.1.0/go.mod h1:AcP8QgC+OwOXEq6im0WgDRYK7scDsmZCEW62o1prQLo=
github.com/bep/godartsass/v2 v2.2.0 h1:3hO9Dt4BOnxkKmRxc+OpoKVFrDvBycpSCXEdElVAMVI=
github.com/bep/godartsass/v2 v2.2.0/go.mod h1:AcP8QgC+OwOXEq6im0WgDRYK7scDsmZCEW62o1prQLo=
github.com/bep/golibsass v1.2.0 h1:nyZUkKP/0psr8nT6GR2cnmt99xS93Ji82ZD9AgOK6VI=
github.com/bep/golibsass v1.2.0/go.mod h1:DL87K8Un/+pWUS75ggYv41bliGiolxzDKWJAq3eJ1MA=
github.com/bep/gowebp v0.3.0 h1:MhmMrcf88pUY7/PsEhMgEP0T6fDUnRTMpN8OclDrbrY=
+5 -5
View File
@@ -246,11 +246,11 @@ func (fs *RootMappingFs) Mounts(base string) ([]FileMetaInfo, error) {
return nil, nil
}
fss := make([]FileMetaInfo, 0, len(roots))
for _, r := range roots {
fss := make([]FileMetaInfo, len(roots))
for i, r := range roots {
if r.fiSingleFile != nil {
// A single file mount.
fss = append(fss, r.fiSingleFile)
fss[i] = r.fiSingleFile
continue
}
bfs := NewBasePathFs(fs.Fs, r.To)
@@ -261,9 +261,9 @@ func (fs *RootMappingFs) Mounts(base string) ([]FileMetaInfo, error) {
fs = decorateDirs(fs, r.Meta)
fi, err := fs.Stat("")
if err != nil {
continue
return nil, fmt.Errorf("RootMappingFs.Dirs: %w", err)
}
fss = append(fss, fi.(FileMetaInfo))
fss[i] = fi.(FileMetaInfo)
}
return fss, nil
+8 -8
View File
@@ -71,9 +71,9 @@ tags_weight: %d
{{ $pageGroups := slice $cool $blue }}
{{ $weighted := slice $wp1 $wp2 }}
{{ printf "pages:%d:%T:%s|%s" (len $pages) $pages (index $pages 0).Path (index $pages 1).Path }}
{{ printf "pageGroups:%d:%T:%s|%s" (len $pageGroups) $pageGroups (index (index $pageGroups 0).Pages 0).Path (index (index $pageGroups 1).Pages 0).Path}}
{{ printf "weightedPages:%d:%T" (len $weighted) $weighted | safeHTML }}
{{ printf "pages:%d:%T:%v/%v" (len $pages) $pages (index $pages 0) (index $pages 1) }}
{{ printf "pageGroups:%d:%T:%v/%v" (len $pageGroups) $pageGroups (index (index $pageGroups 0).Pages 0) (index (index $pageGroups 1).Pages 0)}}
{{ printf "weightedPages:%d::%T:%v" (len $weighted) $weighted $weighted | safeHTML }}
`)
b.CreateSites().Build(BuildCfg{})
@@ -82,9 +82,9 @@ tags_weight: %d
c.Assert(len(b.H.Sites[0].RegularPages()), qt.Equals, 2)
b.AssertFileContent("public/index.html",
"pages:2:page.Pages:/page1|/page2",
"pageGroups:2:page.PagesGroup:/page1|/page2",
`weightedPages:2:page.WeightedPages`)
"pages:2:page.Pages:Page(/page1)/Page(/page2)",
"pageGroups:2:page.PagesGroup:Page(/page1)/Page(/page2)",
`weightedPages:2::page.WeightedPages:[WeightedPage(10,"Page") WeightedPage(20,"Page")]`)
}
func TestUnionFunc(t *testing.T) {
@@ -189,7 +189,7 @@ tags_weight: %d
{{ $appendStrings := slice "a" "b" | append "c" "d" "e" }}
{{ $appendStringsSlice := slice "a" "b" "c" | append (slice "c" "d") }}
{{ printf "pages:%d:%T:%s|%s" (len $pages) $pages (index $pages 0).Path (index $pages 1).Path }}
{{ printf "pages:%d:%T:%v/%v" (len $pages) $pages (index $pages 0) (index $pages 1) }}
{{ printf "appendPages:%d:%T:%v/%v" (len $appendPages) $appendPages (index $appendPages 0).Kind (index $appendPages 8).Kind }}
{{ printf "appendStrings:%T:%v" $appendStrings $appendStrings }}
{{ printf "appendStringsSlice:%T:%v" $appendStringsSlice $appendStringsSlice }}
@@ -207,7 +207,7 @@ tags_weight: %d
c.Assert(len(b.H.Sites[0].RegularPages()), qt.Equals, 2)
b.AssertFileContent("public/index.html",
"pages:2:page.Pages:/page2|/page1",
"pages:2:page.Pages:Page(/page2)/Page(/page1)",
"appendPages:9:page.Pages:home/page",
"appendStrings:[]string:[a b c d e]",
"appendStringsSlice:[]string:[a b c c d]",
+4 -8
View File
@@ -37,7 +37,6 @@ import (
"github.com/gohugoio/hugo/hugolib/doctree"
"github.com/gohugoio/hugo/hugolib/pagesfromdata"
"github.com/gohugoio/hugo/identity"
"github.com/gohugoio/hugo/lazy"
"github.com/gohugoio/hugo/media"
"github.com/gohugoio/hugo/output"
"github.com/gohugoio/hugo/resources"
@@ -110,11 +109,6 @@ type pageMap struct {
cfg contentMapConfig
}
// Invoked on rebuilds.
func (m *pageMap) Reset() {
m.pageReverseIndex.Reset()
}
// pageTrees holds pages and resources in a tree structure for all sites/languages.
// Each site gets its own tree set via the Shape method.
type pageTrees struct {
@@ -964,7 +958,9 @@ type contentTreeReverseIndex struct {
}
func (c *contentTreeReverseIndex) Reset() {
c.init.ResetWithLock().Unlock()
c.contentTreeReverseIndexMap = &contentTreeReverseIndexMap{
m: make(map[any]contentNodeI),
}
}
func (c *contentTreeReverseIndex) Get(key any) contentNodeI {
@@ -976,7 +972,7 @@ func (c *contentTreeReverseIndex) Get(key any) contentNodeI {
}
type contentTreeReverseIndexMap struct {
init lazy.OnceMore
init sync.Once
m map[any]contentNodeI
}
+3 -30
View File
@@ -220,18 +220,6 @@ target = 'content'
source = 'content2'
target = 'content/c2'
[[module.mounts]]
source = 'content3'
target = 'content/watchdisabled'
disableWatch = true
[[module.mounts]]
source = 'content4'
target = 'content/excludedsome'
excludeFiles = 'p1.md'
[[module.mounts]]
source = 'content5'
target = 'content/excludedall'
excludeFiles = '/**'
[[module.mounts]]
source = "hugo_stats.json"
target = "assets/watching/hugo_stats.json"
-- hugo_stats.json --
@@ -242,27 +230,12 @@ foo
-- themes/t1/layouts/_default/single.html --
{{ .Content }}
-- themes/t1/static/f1.txt --
-- content3/p1.md --
-- content4/p1.md --
-- content4/p2.md --
-- content5/p3.md --
-- content5/p4.md --
`
b := hugolib.Test(t, files)
bfs := b.H.BaseFs
watchFilenames := toSlashes(bfs.WatchFilenames())
// content3 has disableWatch = true
// content5 has excludeFiles = '/**'
b.Assert(watchFilenames, qt.DeepEquals, []string{"/hugo_stats.json", "/content", "/content2", "/content4", "/themes/t1/layouts", "/themes/t1/layouts/_default", "/themes/t1/static"})
}
func toSlashes(in []string) []string {
out := make([]string, len(in))
for i, s := range in {
out[i] = filepath.ToSlash(s)
}
return out
watchFilenames := bfs.WatchFilenames()
// []string{"/hugo_stats.json", "/content", "/content2", "/themes/t1/layouts", "/themes/t1/layouts/_default", "/themes/t1/static"}
b.Assert(watchFilenames, qt.HasLen, 6)
}
func TestNoSymlinks(t *testing.T) {
-23
View File
@@ -2,7 +2,6 @@ package hugolib
import (
"bytes"
"context"
"encoding/base64"
"errors"
"fmt"
@@ -33,7 +32,6 @@ import (
"github.com/gohugoio/hugo/htesting"
"github.com/gohugoio/hugo/hugofs"
"github.com/spf13/afero"
"github.com/spf13/cast"
"golang.org/x/text/unicode/norm"
"golang.org/x/tools/txtar"
)
@@ -296,12 +294,6 @@ func (s *IntegrationTestBuilder) AssertFileContent(filename string, matches ...s
}
}
func (s *IntegrationTestBuilder) AssertFileContentEquals(filename string, match string) {
s.Helper()
content := s.FileContent(filename)
s.Assert(content, qt.Equals, match, qt.Commentf(match))
}
func (s *IntegrationTestBuilder) AssertFileContentExact(filename string, matches ...string) {
s.Helper()
content := s.FileContent(filename)
@@ -310,16 +302,6 @@ func (s *IntegrationTestBuilder) AssertFileContentExact(filename string, matches
}
}
func (s *IntegrationTestBuilder) AssertNoRenderShortcodesArtifacts() {
s.Helper()
for _, p := range s.H.Pages() {
content, err := p.Content(context.Background())
s.Assert(err, qt.IsNil)
comment := qt.Commentf("Page: %s\n%s", p.Path(), content)
s.Assert(strings.Contains(cast.ToString(content), "__hugo_ctx"), qt.IsFalse, comment)
}
}
func (s *IntegrationTestBuilder) AssertPublishDir(matches ...string) {
s.AssertFs(s.fs.PublishDir, matches...)
}
@@ -853,11 +835,6 @@ type IntegrationTestConfig struct {
// The files to use on txtar format, see
// https://pkg.go.dev/golang.org/x/exp/cmd/txtar
// There are some conentions used in this test setup.
// - §§§ can be used to wrap code fences.
// - §§ can be used to wrap multiline strings.
// - filenames prefixed with sourcefilename: will be read from the file system relative to the current dir.
// - filenames with a .png or .jpg extension will be treated as binary and base64 decoded.
TxtarString string
// COnfig to use as the base. We will also read the config from the txtar.
+106 -18
View File
@@ -105,6 +105,94 @@ Menu Main: {{ partial "menu.html" (dict "page" . "menu" "main") }}`,
"/sect3/|Sect3s|Sect3s|0|-|-|")
}
// related issue #7594
func TestMenusSort(t *testing.T) {
b := newTestSitesBuilder(t).WithSimpleConfigFile()
b.WithTemplatesAdded("index.html", `
{{ range $k, $v := .Site.Menus.main }}
Default1|{{ $k }}|{{ $v.Weight }}|{{ $v.Name }}|{{ .URL }}|{{ $v.Page }}{{ end }}
{{ range $k, $v := .Site.Menus.main.ByWeight }}
ByWeight|{{ $k }}|{{ $v.Weight }}|{{ $v.Name }}|{{ .URL }}|{{ $v.Page }}{{ end }}
{{ range $k, $v := (.Site.Menus.main.ByWeight).Reverse }}
Reverse|{{ $k }}|{{ $v.Weight }}|{{ $v.Name }}|{{ .URL }}|{{ $v.Page }}{{ end }}
{{ range $k, $v := .Site.Menus.main }}
Default2|{{ $k }}|{{ $v.Weight }}|{{ $v.Name }}|{{ .URL }}|{{ $v.Page }}{{ end }}
{{ range $k, $v := .Site.Menus.main.ByWeight }}
ByWeight|{{ $k }}|{{ $v.Weight }}|{{ $v.Name }}|{{ .URL }}|{{ $v.Page }}{{ end }}
{{ range $k, $v := .Site.Menus.main }}
Default3|{{ $k }}|{{ $v.Weight }}|{{ $v.Name }}|{{ .URL }}|{{ $v.Page }}{{ end }}
`)
b.WithContent("_index.md", `
---
title: Home
menu:
main:
weight: 100
---`)
b.WithContent("blog/A.md", `
---
title: "A"
menu:
main:
weight: 10
---
`)
b.WithContent("blog/B.md", `
---
title: "B"
menu:
main:
weight: 20
---
`)
b.WithContent("blog/C.md", `
---
title: "C"
menu:
main:
weight: 30
---
`)
b.Build(BuildCfg{})
b.AssertFileContent("public/index.html",
`Default1|0|10|A|/blog/a/|Page(/blog/a)
Default1|1|20|B|/blog/b/|Page(/blog/b)
Default1|2|30|C|/blog/c/|Page(/blog/c)
Default1|3|100|Home|/|Page(/)
ByWeight|0|10|A|/blog/a/|Page(/blog/a)
ByWeight|1|20|B|/blog/b/|Page(/blog/b)
ByWeight|2|30|C|/blog/c/|Page(/blog/c)
ByWeight|3|100|Home|/|Page(/)
Reverse|0|100|Home|/|Page(/)
Reverse|1|30|C|/blog/c/|Page(/blog/c)
Reverse|2|20|B|/blog/b/|Page(/blog/b)
Reverse|3|10|A|/blog/a/|Page(/blog/a)
Default2|0|10|A|/blog/a/|Page(/blog/a)
Default2|1|20|B|/blog/b/|Page(/blog/b)
Default2|2|30|C|/blog/c/|Page(/blog/c)
Default2|3|100|Home|/|Page(/)
ByWeight|0|10|A|/blog/a/|Page(/blog/a)
ByWeight|1|20|B|/blog/b/|Page(/blog/b)
ByWeight|2|30|C|/blog/c/|Page(/blog/c)
ByWeight|3|100|Home|/|Page(/)
Default3|0|10|A|/blog/a/|Page(/blog/a)
Default3|1|20|B|/blog/b/|Page(/blog/b)
Default3|2|30|C|/blog/c/|Page(/blog/c)
Default3|3|100|Home|/|Page(/)`,
)
}
func TestMenusFrontMatter(t *testing.T) {
b := newTestSitesBuilder(t).WithSimpleConfigFile()
@@ -349,8 +437,8 @@ url = "/blog/post3"
commonTempl := `
Main: {{ len .Site.Menus.main }}
{{ range .Site.Menus.main }}
{{ .Title }}|HasMenuCurrent: {{ $.HasMenuCurrent "main" . }}|Page: {{ .Page.Path }}
{{ .Title }}|IsMenuCurrent: {{ $.IsMenuCurrent "main" . }}|Page: {{ .Page.Path }}
{{ .Title }}|HasMenuCurrent: {{ $.HasMenuCurrent "main" . }}|Page: {{ .Page }}
{{ .Title }}|IsMenuCurrent: {{ $.IsMenuCurrent "main" . }}|Page: {{ .Page }}
{{ end }}
`
@@ -406,34 +494,34 @@ title: "Contact: With No Menu Defined"
b.AssertFileContent("public/index.html", `
Main: 5
Home|HasMenuCurrent: false|Page: /
Blog|HasMenuCurrent: false|Page: /blog
My Post 2: With Menu Defined|HasMenuCurrent: false|Page: /blog/post2
My Post 3|HasMenuCurrent: false|Page: /blog/post3
Contact Us|HasMenuCurrent: false|Page: /contact
Home|HasMenuCurrent: false|Page: Page(/)
Blog|HasMenuCurrent: false|Page: Page(/blog)
My Post 2: With Menu Defined|HasMenuCurrent: false|Page: Page(/blog/post2)
My Post 3|HasMenuCurrent: false|Page: Page(/blog/post3)
Contact Us|HasMenuCurrent: false|Page: Page(/contact)
`)
b.AssertFileContent("public/blog/post1/index.html", `
Home|HasMenuCurrent: false|Page: /
Blog|HasMenuCurrent: true|Page: /blog
Home|HasMenuCurrent: false|Page: Page(/)
Blog|HasMenuCurrent: true|Page: Page(/blog)
`)
b.AssertFileContent("public/blog/post2/index.html", `
Home|HasMenuCurrent: false|Page: /
Blog|HasMenuCurrent: true|Page: /blog
Blog|IsMenuCurrent: false|Page: /blog
Home|HasMenuCurrent: false|Page: Page(/)
Blog|HasMenuCurrent: true|Page: Page(/blog)
Blog|IsMenuCurrent: false|Page: Page(/blog)
`)
b.AssertFileContent("public/blog/post3/index.html", `
Home|HasMenuCurrent: false|Page: /
Blog|HasMenuCurrent: true|Page: /blog
Home|HasMenuCurrent: false|Page: Page(/)
Blog|HasMenuCurrent: true|Page: Page(/blog)
`)
b.AssertFileContent("public/contact/index.html", `
Contact Us|HasMenuCurrent: false|Page: /contact
Contact Us|IsMenuCurrent: true|Page: /contact
Blog|HasMenuCurrent: false|Page: /blog
Blog|IsMenuCurrent: false|Page: /blog
Contact Us|HasMenuCurrent: false|Page: Page(/contact)
Contact Us|IsMenuCurrent: true|Page: Page(/contact)
Blog|HasMenuCurrent: false|Page: Page(/blog)
Blog|IsMenuCurrent: false|Page: Page(/blog)
`)
}
+1 -18
View File
@@ -16,9 +16,7 @@ package hugolib
import (
"context"
"fmt"
"path/filepath"
"strconv"
"strings"
"sync"
"sync/atomic"
@@ -360,22 +358,7 @@ func (p *pageState) Site() page.Site {
}
func (p *pageState) String() string {
var sb strings.Builder
if p.File() != nil {
// The forward slashes even on Windows is motivated by
// getting stable tests.
// This information is meant for getting positional information in logs,
// so the direction of the slashes should not matter.
sb.WriteString(filepath.ToSlash(p.File().Filename()))
if p.File().IsContentAdapter() {
// Also include the path.
sb.WriteString(":")
sb.WriteString(p.Path())
}
} else {
sb.WriteString(p.Path())
}
return sb.String()
return fmt.Sprintf("Page(%s)", p.Path())
}
// IsTranslated returns whether this content file is translated to
-147
View File
@@ -14,7 +14,6 @@
package hugolib
import (
"path/filepath"
"strings"
"testing"
)
@@ -70,7 +69,6 @@ Content: {{ .Content }}|
b := Test(t, files)
b.AssertNoRenderShortcodesArtifacts()
b.AssertFileContent("public/p1/index.html",
"Fragments: [p1-h1 p2-h1 p2-h2 p2-h3 p2-withmarkdown p3-h1 p3-h2 p3-withmarkdown]|",
"HasShortcode Level 1: true|",
@@ -117,7 +115,6 @@ JSON: {{ .Content }}
b := Test(t, files)
b.AssertNoRenderShortcodesArtifacts()
b.AssertFileContent("public/p1/index.html", "Myshort HTML")
b.AssertFileContent("public/p1/index.json", "Myshort JSON")
}
@@ -150,11 +147,9 @@ Myshort Original.
{{ .Content }}
`
b := TestRunning(t, files)
b.AssertNoRenderShortcodesArtifacts()
b.AssertFileContent("public/p1/index.html", "Myshort Original.")
b.EditFileReplaceAll("layouts/shortcodes/myshort.html", "Original", "Edited").Build()
b.AssertNoRenderShortcodesArtifacts()
b.AssertFileContent("public/p1/index.html", "Myshort Edited.")
}
@@ -197,14 +192,12 @@ Myshort Original.
},
).Build()
b.AssertNoRenderShortcodesArtifacts()
b.AssertFileContent("public/p1/index.html", "Original")
b.EditFileReplaceFunc("content/p2.md", func(s string) string {
return strings.Replace(s, "Original", "Edited", 1)
})
b.Build()
b.AssertNoRenderShortcodesArtifacts()
b.AssertFileContent("public/p1/index.html", "Edited")
}
@@ -240,10 +233,8 @@ Myshort Original.
`
b := TestRunning(t, files)
b.AssertNoRenderShortcodesArtifacts()
b.AssertFileContent("public/mysection/index.html", "p1-h1")
b.EditFileReplaceAll("content/mysection/_index.md", "p1-h1", "p1-h1 Edited").Build()
b.AssertNoRenderShortcodesArtifacts()
b.AssertFileContent("public/mysection/index.html", "p1-h1 Edited")
}
@@ -323,8 +314,6 @@ iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAA
b := Test(t, files)
b.AssertNoRenderShortcodesArtifacts()
b.AssertFileContent("public/markdown/index.html",
// Images.
"Image: /posts/p1/pixel1.png|\nImage: /posts/p1/pixel2.png|\n|\nImage: /markdown/pixel3.png|</p>\n|",
@@ -344,139 +333,3 @@ iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAA
b.AssertFileContent("public/html/index.html", "! hugo_ctx")
}
// Issue 12854.
func TestRenderShortcodesWithHTML(t *testing.T) {
t.Parallel()
files := `
-- hugo.toml --
disableLiveReload = true
disableKinds = ["home", "taxonomy", "term"]
markup.goldmark.renderer.unsafe = true
-- content/p1.md --
---
title: "p1"
---
{{% include "p2" %}}
-- content/p2.md --
---
title: "p2"
---
Hello <b>world</b>. Some **bold** text. Some Unicode: 神真美好.
-- layouts/shortcodes/include.html --
{{ with site.GetPage (.Get 0) }}
<div>{{ .RenderShortcodes }}</div>
{{ end }}
-- layouts/_default/single.html --
{{ .Content }}
`
b := TestRunning(t, files, TestOptWarn())
b.AssertNoRenderShortcodesArtifacts()
b.AssertLogContains(filepath.ToSlash("WARN .RenderShortcodes detected inside HTML block in \"/content/p1.md\"; this may not be what you intended, see https://gohugo.io/methods/page/rendershortcodes/#limitations\nYou can suppress this warning by adding the following to your site configuration:\nignoreLogs = ['warning-rendershortcodes-in-html']"))
b.AssertFileContent("public/p1/index.html", "<div>Hello <b>world</b>. Some **bold** text. Some Unicode: 神真美好.\n</div>")
b.EditFileReplaceAll("content/p2.md", "Hello", "Hello Edited").Build()
b.AssertNoRenderShortcodesArtifacts()
b.AssertFileContent("public/p1/index.html", "<div>Hello Edited <b>world</b>. Some **bold** text. Some Unicode: 神真美好.\n</div>")
}
func TestRenderShortcodesIncludeMarkdownFileWithoutTrailingNewline(t *testing.T) {
t.Parallel()
files := `
-- hugo.toml --
disableLiveReload = true
disableKinds = ["home", "taxonomy", "term"]
markup.goldmark.renderer.unsafe = true
-- content/p1.md --
---
title: "p1"
---
Content p1 id-1000.{{% include "p2" %}}{{% include "p3" %}}
§§§ go
code_p1
§§§
§§§ go
code_p1_2
§§§
§§§ go
code_p1_3
§§§
-- content/p2.md --
---
title: "p2"
---
§§§ bash
code_p2
§§§
Foo.
-- content/p3.md --
---
title: "p3"
---
§§§ php
code_p3
§§§
-- layouts/shortcodes/include.html --
{{ with site.GetPage (.Get 0) -}}
{{ .RenderShortcodes -}}
{{ end -}}
-- layouts/_default/single.html --
{{ .Content }}
-- layouts/_default/_markup/render-codeblock.html --
<code>{{ .Inner | safeHTML }}</code>
`
b := TestRunning(t, files, TestOptWarn())
b.AssertNoRenderShortcodesArtifacts()
b.AssertFileContentEquals("public/p1/index.html", "<p>Content p1 id-1000.</p>\n<code>code_p2</code><p>Foo.\n</p>\n<code>code_p3</code><p></p>\n<code>code_p1</code><code>code_p1_2</code><code>code_p1_3</code>")
b.EditFileReplaceAll("content/p1.md", "id-1000.", "id-100.").Build()
b.AssertNoRenderShortcodesArtifacts()
b.AssertFileContentEquals("public/p1/index.html", "<p>Content p1 id-100.</p>\n<code>code_p2</code><p>Foo.\n</p>\n<code>code_p3</code><p></p>\n<code>code_p1</code><code>code_p1_2</code><code>code_p1_3</code>")
b.EditFileReplaceAll("content/p2.md", "code_p2", "codep2").Build()
b.AssertNoRenderShortcodesArtifacts()
b.AssertFileContentEquals("public/p1/index.html", "<p>Content p1 id-100.</p>\n<code>codep2</code><p>Foo.\n</p>\n<code>code_p3</code><p></p>\n<code>code_p1</code><code>code_p1_2</code><code>code_p1_3</code>")
b.EditFileReplaceAll("content/p3.md", "code_p3", "code_p3_edited").Build()
b.AssertNoRenderShortcodesArtifacts()
b.AssertFileContentEquals("public/p1/index.html", "<p>Content p1 id-100.</p>\n<code>codep2</code><p>Foo.\n</p>\n<code>code_p3_edited</code><p></p>\n<code>code_p1</code><code>code_p1_2</code><code>code_p1_3</code>")
}
// Issue 13004.
func TestRenderShortcodesIncludeShortRefEdit(t *testing.T) {
t.Parallel()
files := `
-- hugo.toml --
disableLiveReload = true
disableKinds = ["home", "taxonomy", "term", "section", "rss", "sitemap", "robotsTXT", "404"]
-- content/first/p1.md --
---
title: "p1"
---
## p1-h1
{{% include "p2" %}}
-- content/second/p2.md --
---
title: "p2"
---
### p2-h1
This is some **markup**.
-- layouts/shortcodes/include.html --
{{ $p := site.GetPage (.Get 0) -}}
{{ $p.RenderShortcodes -}}
-- layouts/_default/single.html --
{{ .Content }}
`
b := TestRunning(t, files)
b.AssertNoRenderShortcodesArtifacts()
b.AssertFileContentEquals("public/first/p1/index.html", "<h2 id=\"p1-h1\">p1-h1</h2>\n<p></p>\n<h3 id=\"p2-h1\">p2-h1</h3>\n<p>This is some <strong>markup</strong>.\n</p>\n")
b.EditFileReplaceAll("content/second/p2.md", "p2-h1", "p2-h1-edited").Build()
b.AssertNoRenderShortcodesArtifacts()
b.AssertFileContentEquals("public/first/p1/index.html", "<h2 id=\"p1-h1\">p1-h1</h2>\n<p></p>\n<h3 id=\"p2-h1-edited\">p2-h1-edited</h3>\n<p>This is some <strong>markup</strong>.\n</p>\n")
}
-4
View File
@@ -125,7 +125,3 @@ func newPageForRenderHook(p *pageState) page.Page {
func (p *pageForRenderHooks) Unwrapv() any {
return p.p
}
func (p *pageForRenderHooks) String() string {
return p.p.String()
}
-1
View File
@@ -1351,7 +1351,6 @@ func (s *Site) getLanguagePermalinkLang(alwaysInSubDir bool) string {
func (s *Site) resetBuildState(sourceChanged bool) {
s.relatedDocsHandler = s.relatedDocsHandler.Clone()
s.init.Reset()
s.pageMap.Reset()
}
func (s *Site) errorCollator(results <-chan error, errs chan<- error) {
+2 -4
View File
@@ -1,9 +1,7 @@
# Release env.
# These will be replaced by script before release.
HUGORELEASER_TAG=v0.137.1
HUGORELEASER_COMMITISH=17e15b2148cee6da923acd7adf2ec31ea6b3415c
HUGORELEASER_TAG=v0.136.5
HUGORELEASER_COMMITISH=46cccb021bc6425455f4eec093f5cc4a32f1d12c
-48
View File
@@ -119,24 +119,6 @@ archive_alias_replacements = { "linux-amd64.tar.gz" = "Linux-64bit.tar.gz" }
[[builds.os.archs]]
goarch = "amd64"
[[builds]]
path = "container1/unix/extended-withdeploy"
[builds.build_settings]
flags = ["-buildmode", "exe", "-tags", "extended,withdeploy"]
env = ["CGO_ENABLED=1"]
[[builds.os]]
goos = "darwin"
[builds.os.build_settings]
env = ["CGO_ENABLED=1", "CC=o64-clang", "CXX=o64-clang++"]
[[builds.os.archs]]
goarch = "universal"
[[builds.os]]
goos = "linux"
[[builds.os.archs]]
goarch = "amd64"
[[builds]]
path = "container2/linux/extended"
@@ -185,35 +167,12 @@ archive_alias_replacements = { "linux-amd64.tar.gz" = "Linux-64bit.tar.gz" }
[[builds.os.archs]]
goarch = "amd64"
[[builds]]
path = "container1/windows/extended-withdeploy"
[builds.build_settings]
flags = ["-buildmode", "exe", "-tags", "extended,withdeploy"]
env = [
"CGO_ENABLED=1",
"CC=x86_64-w64-mingw32-gcc",
"CXX=x86_64-w64-mingw32-g++",
]
ldflags = "-s -w -X github.com/gohugoio/hugo/common/hugo.vendorInfo=gohugoio -extldflags '-static'"
[[builds.os]]
goos = "windows"
[builds.os.build_settings]
binary = "hugo.exe"
[[builds.os.archs]]
goarch = "amd64"
[[archives]]
paths = ["builds/container1/unix/regular/**"]
[[archives]]
paths = ["builds/container1/unix/extended/**"]
[archives.archive_settings]
name_template = "{{ .Project }}_extended_{{ .Tag | trimPrefix `v` }}_{{ .Goos }}-{{ .Goarch }}"
[[archives]]
paths = ["builds/container1/unix/extended-withdeploy/**"]
[archives.archive_settings]
name_template = "{{ .Project }}_extended_withdeploy_{{ .Tag | trimPrefix `v` }}_{{ .Goos }}-{{ .Goarch }}"
[[archives]]
# Only extended builds in container2.
paths = ["builds/container2/**"]
@@ -231,13 +190,6 @@ archive_alias_replacements = { "linux-amd64.tar.gz" = "Linux-64bit.tar.gz" }
[archives.archive_settings.type]
format = "zip"
extension = ".zip"
[[archives]]
paths = ["builds/**/windows/extended-withdeploy/**"]
[archives.archive_settings]
name_template = "{{ .Project }}_extended_withdeploy_{{ .Tag | trimPrefix `v` }}_{{ .Goos }}-{{ .Goarch }}"
[archives.archive_settings.type]
format = "zip"
extension = ".zip"
[[archives]]
paths = ["builds/**/regular/linux/{arm64,amd64}"]
[archives.archive_settings]
+1 -1
View File
@@ -36,7 +36,7 @@ type Init struct {
prev *Init
children []*Init
init OnceMore
init onceMore
out any
err error
f func(context.Context) (any, error)
+6 -6
View File
@@ -18,19 +18,19 @@ import (
"sync/atomic"
)
// OnceMore is similar to sync.Once.
// onceMore is similar to sync.Once.
//
// Additional features are:
// * it can be reset, so the action can be repeated if needed
// * it has methods to check if it's done or in progress
type OnceMore struct {
type onceMore struct {
mu sync.Mutex
lock uint32
done uint32
}
func (t *OnceMore) Do(f func()) {
func (t *onceMore) Do(f func()) {
if atomic.LoadUint32(&t.done) == 1 {
return
}
@@ -53,15 +53,15 @@ func (t *OnceMore) Do(f func()) {
f()
}
func (t *OnceMore) InProgress() bool {
func (t *onceMore) InProgress() bool {
return atomic.LoadUint32(&t.lock) == 1
}
func (t *OnceMore) Done() bool {
func (t *onceMore) Done() bool {
return atomic.LoadUint32(&t.done) == 1
}
func (t *OnceMore) ResetWithLock() *sync.Mutex {
func (t *onceMore) ResetWithLock() *sync.Mutex {
t.mu.Lock()
defer atomic.StoreUint32(&t.done, 0)
return &t.mu
+1 -1
View File
@@ -334,7 +334,7 @@ func buildFlags() []string {
func buildTags() string {
// To build the extended Hugo SCSS/SASS enabled version, build with
// HUGO_BUILD_TAGS=extended mage install etc.
// To build with `hugo deploy`, use HUGO_BUILD_TAGS=withdeploy
// To build without `hugo deploy` for smaller binary, use HUGO_BUILD_TAGS=nodeploy
if envtags := os.Getenv("HUGO_BUILD_TAGS"); envtags != "" {
return envtags
}
-29
View File
@@ -1,29 +0,0 @@
// Copyright 2024 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//go:build !withdeploy
// +build !withdeploy
package main
import (
"testing"
"github.com/rogpeppe/go-internal/testscript"
)
func TestWithdeploy(t *testing.T) {
p := commonTestScriptsParam
p.Dir = "testscripts/withdeploy-off"
testscript.Run(t, p)
}
-29
View File
@@ -1,29 +0,0 @@
// Copyright 2024 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//go:build withdeploy
// +build withdeploy
package main
import (
"testing"
"github.com/rogpeppe/go-internal/testscript"
)
func TestWithdeploy(t *testing.T) {
p := commonTestScriptsParam
p.Dir = "testscripts/withdeploy"
testscript.Run(t, p)
}
+1 -1
View File
@@ -106,7 +106,7 @@ func newMarkdown(pcfg converter.ProviderConfig) goldmark.Markdown {
renderer.WithNodeRenderers(util.Prioritized(emoji.NewHTMLRenderer(), 200)))
var (
extensions = []goldmark.Extender{
hugocontext.New(pcfg.Logger),
hugocontext.New(),
newLinks(cfg),
newTocExtension(tocRendererOptions),
blockquotes.New(),
+1 -50
View File
@@ -575,7 +575,7 @@ sc3_begin|{{ .Inner }}|sc3_end
// Issue #7332
"<span>:x:\n</span>",
// Issue #11587
"<p>&#x2714;&#xfe0f;\n</p>",
"<p>&#x2714;&#xfe0f;</p>",
// Should not be converted to emoji
"sc1_begin|:smiley:|sc1_end",
// Should be converted to emoji
@@ -802,52 +802,3 @@ H~2~0
"<p>1<sup>st</sup></p>",
)
}
// Issue 12997.
func TestGoldmarkRawHTMLWarningBlocks(t *testing.T) {
files := `
-- hugo.toml --
disableKinds = ['home','rss','section','sitemap','taxonomy','term']
markup.goldmark.renderer.unsafe = false
-- content/p1.md --
---
title: "p1"
---
<div>Some raw HTML</div>
-- layouts/_default/single.html --
{{ .Content }}
`
b := hugolib.Test(t, files, hugolib.TestOptWarn())
b.AssertFileContent("public/p1/index.html", "<!-- raw HTML omitted -->")
b.AssertLogContains("WARN Raw HTML omitted from \"/content/p1.md\"; see https://gohugo.io/getting-started/configuration-markup/#rendererunsafe\nYou can suppress this warning by adding the following to your site configuration:\nignoreLogs = ['warning-goldmark-raw-html']")
b = hugolib.Test(t, strings.ReplaceAll(files, "markup.goldmark.renderer.unsafe = false", "markup.goldmark.renderer.unsafe = true"), hugolib.TestOptWarn())
b.AssertFileContent("public/p1/index.html", "! <!-- raw HTML omitted -->")
b.AssertLogContains("! WARN")
}
func TestGoldmarkRawHTMLWarningInline(t *testing.T) {
files := `
-- hugo.toml --
disableKinds = ['home','rss','section','sitemap','taxonomy','term']
markup.goldmark.renderer.unsafe = false
-- content/p1.md --
---
title: "p1"
---
<em>raw HTML</em>
-- layouts/_default/single.html --
{{ .Content }}
`
b := hugolib.Test(t, files, hugolib.TestOptWarn())
b.AssertFileContent("public/p1/index.html", "<!-- raw HTML omitted -->")
b.AssertLogContains("WARN Raw HTML omitted from \"/content/p1.md\"; see https://gohugo.io/getting-started/configuration-markup/#rendererunsafe\nYou can suppress this warning by adding the following to your site configuration:\nignoreLogs = ['warning-goldmark-raw-html']")
b = hugolib.Test(t, strings.ReplaceAll(files, "markup.goldmark.renderer.unsafe = false", "markup.goldmark.renderer.unsafe = true"), hugolib.TestOptWarn())
b.AssertFileContent("public/p1/index.html", "! <!-- raw HTML omitted -->")
b.AssertLogContains("! WARN")
}
+20 -121
View File
@@ -16,24 +16,20 @@ package hugocontext
import (
"bytes"
"fmt"
"regexp"
"strconv"
"github.com/gohugoio/hugo/bufferpool"
"github.com/gohugoio/hugo/common/constants"
"github.com/gohugoio/hugo/common/loggers"
"github.com/gohugoio/hugo/markup/goldmark/internal/render"
"github.com/yuin/goldmark"
"github.com/yuin/goldmark/ast"
"github.com/yuin/goldmark/parser"
"github.com/yuin/goldmark/renderer"
"github.com/yuin/goldmark/renderer/html"
"github.com/yuin/goldmark/text"
"github.com/yuin/goldmark/util"
)
func New(logger loggers.Logger) goldmark.Extender {
return &hugoContextExtension{logger: logger}
func New() goldmark.Extender {
return &hugoContextExtension{}
}
// Wrap wraps the given byte slice in a Hugo context that used to determine the correct Page
@@ -41,19 +37,14 @@ func New(logger loggers.Logger) goldmark.Extender {
func Wrap(b []byte, pid uint64) string {
buf := bufferpool.GetBuffer()
defer bufferpool.PutBuffer(buf)
buf.Write(hugoCtxPrefix)
buf.Write(prefix)
buf.WriteString(" pid=")
buf.WriteString(strconv.FormatUint(pid, 10))
buf.Write(hugoCtxEndDelim)
buf.Write(endDelim)
buf.WriteByte('\n')
buf.Write(b)
// To make sure that we're able to parse it, make sure it ends with a newline.
if len(b) > 0 && b[len(b)-1] != '\n' {
buf.WriteByte('\n')
}
buf.Write(hugoCtxPrefix)
buf.Write(hugoCtxClosingDelim)
buf.WriteByte('\n')
buf.Write(prefix)
buf.Write(closingDelimAndNewline)
return buf.String()
}
@@ -98,130 +89,45 @@ func (h *HugoContext) Kind() ast.NodeKind {
}
var (
hugoCtxPrefix = []byte("{{__hugo_ctx")
hugoCtxEndDelim = []byte("}}")
hugoCtxClosingDelim = []byte("/}}")
hugoCtxRe = regexp.MustCompile(`{{__hugo_ctx( pid=\d+)?/?}}\n?`)
prefix = []byte("{{__hugo_ctx")
endDelim = []byte("}}")
closingDelimAndNewline = []byte("/}}\n")
)
var _ parser.InlineParser = (*hugoContextParser)(nil)
type hugoContextParser struct{}
func (a *hugoContextParser) Trigger() []byte {
return []byte{'{'}
}
func (s *hugoContextParser) Parse(parent ast.Node, reader text.Reader, pc parser.Context) ast.Node {
line, _ := reader.PeekLine()
if !bytes.HasPrefix(line, hugoCtxPrefix) {
func (s *hugoContextParser) Parse(parent ast.Node, block text.Reader, pc parser.Context) ast.Node {
line, _ := block.PeekLine()
if !bytes.HasPrefix(line, prefix) {
return nil
}
end := bytes.Index(line, hugoCtxEndDelim)
end := bytes.Index(line, endDelim)
if end == -1 {
return nil
}
reader.Advance(end + len(hugoCtxEndDelim) + 1) // +1 for the newline
block.Advance(end + len(endDelim) + 1) // +1 for the newline
if line[end-1] == '/' {
return &HugoContext{Closing: true}
}
attrBytes := line[len(hugoCtxPrefix)+1 : end]
attrBytes := line[len(prefix)+1 : end]
h := &HugoContext{}
h.parseAttrs(attrBytes)
return h
}
type hugoContextRenderer struct {
logger loggers.Logger
html.Config
func (a *hugoContextParser) Trigger() []byte {
return []byte{'{'}
}
func (r *hugoContextRenderer) SetOption(name renderer.OptionName, value any) {
r.Config.SetOption(name, value)
}
type hugoContextRenderer struct{}
func (r *hugoContextRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) {
reg.Register(kindHugoContext, r.handleHugoContext)
reg.Register(ast.KindRawHTML, r.renderRawHTML)
reg.Register(ast.KindHTMLBlock, r.renderHTMLBlock)
}
func (r *hugoContextRenderer) stripHugoCtx(b []byte) ([]byte, bool) {
if !bytes.Contains(b, hugoCtxPrefix) {
return b, false
}
return hugoCtxRe.ReplaceAll(b, nil), true
}
func (r *hugoContextRenderer) logRawHTMLEmittedWarn(w util.BufWriter) {
r.logger.Warnidf(constants.WarnGoldmarkRawHTML, "Raw HTML omitted from %q; see https://gohugo.io/getting-started/configuration-markup/#rendererunsafe", r.getPage(w))
}
func (r *hugoContextRenderer) getPage(w util.BufWriter) any {
var p any
ctx, ok := w.(*render.Context)
if ok {
p, _ = render.GetPageAndPageInner(ctx)
}
return p
}
// HTML rendering based on Goldmark implementation.
func (r *hugoContextRenderer) renderHTMLBlock(
w util.BufWriter, source []byte, node ast.Node, entering bool,
) (ast.WalkStatus, error) {
n := node.(*ast.HTMLBlock)
if entering {
if r.Unsafe {
l := n.Lines().Len()
for i := 0; i < l; i++ {
line := n.Lines().At(i)
linev := line.Value(source)
var stripped bool
linev, stripped = r.stripHugoCtx(linev)
if stripped {
r.logger.Warnidf(constants.WarnRenderShortcodesInHTML, ".RenderShortcodes detected inside HTML block in %q; this may not be what you intended, see https://gohugo.io/methods/page/rendershortcodes/#limitations", r.getPage(w))
}
r.Writer.SecureWrite(w, linev)
}
} else {
r.logRawHTMLEmittedWarn(w)
_, _ = w.WriteString("<!-- raw HTML omitted -->\n")
}
} else {
if n.HasClosure() {
if r.Unsafe {
closure := n.ClosureLine
r.Writer.SecureWrite(w, closure.Value(source))
} else {
_, _ = w.WriteString("<!-- raw HTML omitted -->\n")
}
}
}
return ast.WalkContinue, nil
}
func (r *hugoContextRenderer) renderRawHTML(
w util.BufWriter, source []byte, node ast.Node, entering bool,
) (ast.WalkStatus, error) {
if !entering {
return ast.WalkSkipChildren, nil
}
if r.Unsafe {
n := node.(*ast.RawHTML)
l := n.Segments.Len()
for i := 0; i < l; i++ {
segment := n.Segments.At(i)
_, _ = w.Write(segment.Value(source))
}
return ast.WalkSkipChildren, nil
}
r.logRawHTMLEmittedWarn(w)
_, _ = w.WriteString("<!-- raw HTML omitted -->")
return ast.WalkSkipChildren, nil
}
func (r *hugoContextRenderer) handleHugoContext(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
@@ -242,9 +148,7 @@ func (r *hugoContextRenderer) handleHugoContext(w util.BufWriter, source []byte,
return ast.WalkContinue, nil
}
type hugoContextExtension struct {
logger loggers.Logger
}
type hugoContextExtension struct{}
func (a *hugoContextExtension) Extend(m goldmark.Markdown) {
m.Parser().AddOptions(
@@ -255,12 +159,7 @@ func (a *hugoContextExtension) Extend(m goldmark.Markdown) {
m.Renderer().AddOptions(
renderer.WithNodeRenderers(
util.Prioritized(&hugoContextRenderer{
logger: a.logger,
Config: html.Config{
Writer: html.DefaultWriter,
},
}, 50),
util.Prioritized(&hugoContextRenderer{}, 50),
),
)
}
@@ -24,7 +24,7 @@ func TestWrap(t *testing.T) {
b := []byte("test")
c.Assert(Wrap(b, 42), qt.Equals, "{{__hugo_ctx pid=42}}\ntest\n{{__hugo_ctx/}}\n")
c.Assert(Wrap(b, 42), qt.Equals, "{{__hugo_ctx pid=42}}\ntest{{__hugo_ctx/}}\n")
}
func BenchmarkWrap(b *testing.B) {
-2
View File
@@ -17,7 +17,6 @@ package page
import (
"context"
"fmt"
"html/template"
"github.com/gohugoio/hugo/markup/converter"
@@ -181,7 +180,6 @@ type Page interface {
ContentProvider
TableOfContentsProvider
PageWithoutContent
fmt.Stringer
}
type PageFragment interface {
@@ -161,13 +161,13 @@ includecontent: {{ hugo.Context.MarkupScope }}|{{ $p.Markup.Render.Content }}|
b := hugolib.Test(t, files)
b.AssertFileContentExact("public/p1/index.html", "Render heading: title: P1 scope: |", "Foo scope: |")
b.AssertFileContent("public/p1/index.html", "Render heading: title: P1 scope: |", "Foo scope: |")
b.AssertFileContentExact("public/index.html",
"Begin:\nincludecontent: home|Render heading: title: P3 scope: home|Foo scope: home|\n|\n:End",
b.AssertFileContent("public/index.html",
"Render heading: title: P1 scope: home|",
"Foo scope: home|",
"Begin:\nincluderendershortcodes: home|</p>\nRender heading: title: P2 scope: home|<p>|:End",
"Begin:\nincludecontent: home|Render heading: title: P3 scope: home|Foo scope: home|\n|\n:End",
)
}
@@ -29,7 +29,7 @@ import (
"github.com/gohugoio/hugo/resources"
"github.com/gohugoio/hugo/resources/internal"
"github.com/gohugoio/hugo/resources/resource_transformers/tocss/sass"
"github.com/gohugoio/hugo/resources/resource_transformers/tocss/internal/sass"
"github.com/spf13/afero"
@@ -85,7 +85,7 @@ func (t *transform) Transform(ctx *resources.ResourceTransformationCtx) error {
c: t.c,
dependencyManager: ctx.DependencyManager,
varsStylesheet: godartsass.Import{Content: sass.CreateVarsStyleSheet(sass.TranspilerDart, opts.Vars)},
varsStylesheet: godartsass.Import{Content: sass.CreateVarsStyleSheet(opts.Vars)},
},
OutputStyle: godartsass.ParseOutputStyle(opts.OutputStyle),
EnableSourceMap: opts.EnableSourceMap,
@@ -24,14 +24,9 @@ import (
const (
HugoVarsNamespace = "hugo:vars"
// Transpiler implementation can be controlled from the client by
// setting the 'transpiler' option.
// Default is currently 'libsass', but that may change.
TranspilerDart = "dartsass"
TranspilerLibSass = "libsass"
)
func CreateVarsStyleSheet(transpiler string, vars map[string]any) string {
func CreateVarsStyleSheet(vars map[string]any) string {
if vars == nil {
return ""
}
@@ -54,22 +49,12 @@ func CreateVarsStyleSheet(transpiler string, vars map[string]any) string {
varsSlice = append(varsSlice, fmt.Sprintf("%s%s: %v;", prefix, k, v))
} else {
// unquote will preserve quotes around URLs etc. if needed.
if transpiler == TranspilerDart {
varsSlice = append(varsSlice, fmt.Sprintf("%s%s: string.unquote(%q);", prefix, k, v))
} else {
varsSlice = append(varsSlice, fmt.Sprintf("%s%s: unquote(%q);", prefix, k, v))
}
varsSlice = append(varsSlice, fmt.Sprintf("%s%s: unquote(%q);", prefix, k, v))
}
}
}
sort.Strings(varsSlice)
if transpiler == TranspilerDart {
varsStylesheet = `@use "sass:string";` + "\n" + strings.Join(varsSlice, "\n")
} else {
varsStylesheet = strings.Join(varsSlice, "\n")
}
varsStylesheet = strings.Join(varsSlice, "\n")
return varsStylesheet
}
@@ -31,7 +31,7 @@ import (
"github.com/gohugoio/hugo/identity"
"github.com/gohugoio/hugo/media"
"github.com/gohugoio/hugo/resources"
"github.com/gohugoio/hugo/resources/resource_transformers/tocss/sass"
"github.com/gohugoio/hugo/resources/resource_transformers/tocss/internal/sass"
)
// Used in tests. This feature requires Hugo to be built with the extended tag.
@@ -64,7 +64,7 @@ func (t *toCSSTransformation) Transform(ctx *resources.ResourceTransformationCtx
}
}
varsStylesheet := sass.CreateVarsStyleSheet(sass.TranspilerLibSass, options.from.Vars)
varsStylesheet := sass.CreateVarsStyleSheet(options.from.Vars)
// To allow for overrides of SCSS files anywhere in the project/theme hierarchy, we need
// to help libsass revolve the filename by looking in the composite filesystem first.
+5
View File
@@ -1,12 +1,17 @@
# Test the gen commands.
# Note that adding new commands will require updating the NUM_COMMANDS value.
env NUM_COMMANDS=44
hugo gen -h
stdout 'Generate documentation for your project using Hugo''s documentation engine, including syntax highlighting for various programming languages\.'
hugo gen doc --dir clidocs
checkfilecount $NUM_COMMANDS clidocs
hugo gen man -h
stdout 'up-to-date man pages'
hugo gen man --dir manpages
checkfilecount $NUM_COMMANDS manpages
hugo gen chromastyles -h
stdout 'Generate CSS stylesheet for the Chroma code highlighter'
@@ -1,3 +0,0 @@
! hugo deploy --force
# Issue 13012
stderr 'deploy not supported in this version of Hugo'
+12 -5
View File
@@ -15,7 +15,6 @@ import (
"github.com/gohugoio/hugo/resources/resource_transformers/babel"
"github.com/gohugoio/hugo/resources/resource_transformers/cssjs"
"github.com/gohugoio/hugo/resources/resource_transformers/tocss/dartsass"
"github.com/gohugoio/hugo/resources/resource_transformers/tocss/sass"
"github.com/gohugoio/hugo/resources/resource_transformers/tocss/scss"
"github.com/gohugoio/hugo/tpl/internal"
"github.com/gohugoio/hugo/tpl/internal/resourcehelpers"
@@ -85,13 +84,21 @@ func (ns *Namespace) Sass(args ...any) (resource.Resource, error) {
return nil, errors.New("must not provide more arguments than resource object and options")
}
const (
// Transpiler implementation can be controlled from the client by
// setting the 'transpiler' option.
// Default is currently 'libsass', but that may change.
transpilerDart = "dartsass"
transpilerLibSass = "libsass"
)
var (
r resources.ResourceTransformer
m map[string]any
targetPath string
err error
ok bool
transpiler = sass.TranspilerLibSass
transpiler = transpilerLibSass
)
r, targetPath, ok = resourcehelpers.ResolveIfFirstArgIsString(args)
@@ -106,15 +113,15 @@ func (ns *Namespace) Sass(args ...any) (resource.Resource, error) {
if m != nil {
if t, _, found := maps.LookupEqualFold(m, "transpiler"); found {
switch t {
case sass.TranspilerDart, sass.TranspilerLibSass:
case transpilerDart, transpilerLibSass:
transpiler = cast.ToString(t)
default:
return nil, fmt.Errorf("unsupported transpiler %q; valid values are %q or %q", t, sass.TranspilerLibSass, sass.TranspilerDart)
return nil, fmt.Errorf("unsupported transpiler %q; valid values are %q or %q", t, transpilerLibSass, transpilerDart)
}
}
}
if transpiler == sass.TranspilerLibSass {
if transpiler == transpilerLibSass {
var options scss.Options
if targetPath != "" {
options.TargetPath = paths.ToSlashTrimLeading(targetPath)
@@ -18,8 +18,6 @@ import (
qt "github.com/frankban/quicktest"
"github.com/gohugoio/hugo/hugolib"
"github.com/gohugoio/hugo/resources/resource_transformers/tocss/dartsass"
"github.com/gohugoio/hugo/resources/resource_transformers/tocss/scss"
)
func TestCopy(t *testing.T) {
@@ -240,45 +238,3 @@ match /files/C*: 2|
b.AssertFileContent("public/files/b.txt", "I am b.txt")
b.AssertFileContent("public/files/C.txt", "I am C.txt")
}
// Issue #12961
func TestDartSassVars(t *testing.T) {
t.Parallel()
if !scss.Supports() || !dartsass.Supports() {
t.Skip()
}
files := `
-- hugo.toml --
disableKinds = ['page','section','rss','sitemap','taxonomy','term']
-- layouts/index.html --
{{ $opts := dict "transpiler" "dartsass" "outputStyle" "compressed" "vars" (dict "color" "red") }}
{{ with resources.Get "dartsass.scss" | css.Sass $opts }}
{{ .Content }}
{{ end }}
{{ $opts := dict "transpiler" "libsass" "outputStyle" "compressed" "vars" (dict "color" "blue") }}
{{ with resources.Get "libsass.scss" | css.Sass $opts }}
{{ .Content }}
{{ end }}
-- assets/dartsass.scss --
@use "hugo:vars" as v;
.dartsass {
color: v.$color;
}
-- assets/libsass.scss --
@import "hugo:vars";
.libsass {
color: $color;
}
`
b := hugolib.Test(t, files, hugolib.TestOptWarn())
b.AssertFileContent("public/index.html",
".dartsass{color:red}",
".libsass{color:blue}",
)
b.AssertLogContains("! WARN Dart Sass: hugo:vars")
}
@@ -1 +0,0 @@
{{- $noop := .Inner -}}
-16
View File
@@ -584,19 +584,3 @@ title: p5
`<meta name="twitter:description" content="m n and **o** can&#39;t.">`,
)
}
func TestCommentShortcode(t *testing.T) {
t.Parallel()
files := `
-- hugo.toml --
disableKinds = ['page','rss','section','sitemap','taxonomy','term']
-- layouts/index.html --
{{ .Content }}
-- content/_index.md --
a{{< comment >}}b{{< /comment >}}c
`
b := hugolib.Test(t, files)
b.AssertFileContent("public/index.html", "<p>ac</p>")
}