Compare commits

...

28 Commits

Author SHA1 Message Date
hugoreleaser 629f84e8ed releaser: Bump versions for release of 0.124.0
[ci skip]
2024-03-16 15:44:32 +00:00
Bjørn Erik Pedersen 76ef3f42fa docs: Regen CLI docs 2024-03-16 15:54:33 +01:00
Bjørn Erik Pedersen 0ccb6cdc04 docs: Regen docshelper 2024-03-16 15:54:02 +01:00
Bjørn Erik Pedersen 1f1c62e6c7 Add segments config + --renderSegments flag
Named segments can be defined in `hugo.toml`.

* Eeach segment consists of zero or more `exclude` filters and zero or more `include` filters.
* Eeach filter consists of one or more field Glob matchers.
* Eeach filter in a section (`exclude` or `include`) is ORed together, each matcher in a filter is ANDed together.

The current list of fields that can be filtered are:

* path as defined in https://gohugo.io/methods/page/path/
* kind
* lang
* output (output format, e.g. html).

It is recommended to put coarse grained filters (e.g. for language and output format) in the excludes section, e.g.:

```toml
[segments.segment1]
  [[segments.segment1.excludes]]
    lang = "n*"
  [[segments.segment1.excludes]]
    no     = "en"
    output = "rss"
  [[segments.segment1.includes]]
    term = "{home,term,taxonomy}"
  [[segments.segment1.includes]]
    path = "{/docs,/docs/**}"
```

By default, Hugo will render all segments, but you can enable filters by setting the `renderSegments` option or `--renderSegments` flag, e.g:

```
hugo --renderSegments segment1,segment2
```

For segment `segment1` in the configuration above, this will:

* Skip rendering of all languages matching `n*`, e.g. `no`.
* Skip rendering of the output format `rss` for the `en` language.
* It will render all pages of kind `home`, `term` or `taxonomy`
* It will render the `/docs` section and all pages below.

Fixes #10106
2024-03-16 15:53:26 +01:00
Bjørn Erik Pedersen f1d755965f Fix .Parent when there are overlapping regular pages inbetween
Fixes #12263
2024-03-16 14:48:04 +01:00
Bjørn Erik Pedersen 558f74f009 hugolib: Remove Site.HomeAbsURL
It's not in use and after #12266 it's also not corret to use on its own (use .Site.Home.Permalink).
2024-03-16 12:49:40 +01:00
Bjørn Erik Pedersen ba03114aa9 deps: Upgrade github.com/gohugoio/hugo-goldmark-extensions/passthrough v0.1.0 => v0.2.0 2024-03-16 11:50:11 +01:00
Joe Mooring 3935faa417 hugolib: Fix sitemap index with monolingual site
Fixes #12266
2024-03-16 11:49:00 +01:00
Joe Mooring d4d49e0f0e hugolib: Deprecate site methods Author, Authors, and Social
Closes #12228
2024-03-15 17:26:45 +01:00
Christian Oliff 78178d0c2a all: Typo fixes 2024-03-15 17:25:52 +01:00
Bjørn Erik Pedersen 68d92ef9dd Fix translationKey handling for term pages
Fixes #12261
2024-03-15 16:54:18 +01:00
Bjørn Erik Pedersen b40f3c7df6 Fix intersect and similar for term entry page collections
Fixes #12254
2024-03-15 16:45:53 +01:00
Bjørn Erik Pedersen 57206e7274 Upgrade to Go 1.22.1
Closes #12250
2024-03-15 16:40:36 +01:00
dependabot[bot] b1f8676347 build(deps): bump github.com/evanw/esbuild from 0.20.1 to 0.20.2
Bumps [github.com/evanw/esbuild](https://github.com/evanw/esbuild) from 0.20.1 to 0.20.2.
- [Release notes](https://github.com/evanw/esbuild/releases)
- [Changelog](https://github.com/evanw/esbuild/blob/main/CHANGELOG.md)
- [Commits](https://github.com/evanw/esbuild/compare/v0.20.1...v0.20.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-15 15:43:18 +01:00
Bjørn Erik Pedersen 07b2e535be Fix server rebuilds when adding sub sections especially on Windows
This commit also optimizes for the case where change events for both file (e.g. `_index.md`) and the container directory comes in the same event batch.

While testing this on Windows 11 (ARM64), I notice that Windows behaves a little oddly when dumping a folder of files into the content tree; it works (at least after this commit), but it seems like the event batching behaves differently compared to other OSes (even older Win versions).

A related tip would be to try starting the server with polling, to see if that improves the situation, e.g.:

```
hugo server --poll 700ms
```

Fixes #12230
2024-03-15 15:42:56 +01:00
Joe Mooring f038a51b3e tpl/tplimpl: Remove deprecated method from sitemapindex.xml 2024-03-14 21:03:19 +01:00
dependabot[bot] b4bff6190c build(deps): bump golang.org/x/tools from 0.18.0 to 0.19.0
Bumps [golang.org/x/tools](https://github.com/golang/tools) from 0.18.0 to 0.19.0.
- [Release notes](https://github.com/golang/tools/releases)
- [Commits](https://github.com/golang/tools/compare/v0.18.0...v0.19.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-14 11:16:50 +01:00
dependabot[bot] d2cebee273 build(deps): bump github.com/tdewolff/minify/v2 from 2.20.17 to 2.20.19
Bumps [github.com/tdewolff/minify/v2](https://github.com/tdewolff/minify) from 2.20.17 to 2.20.19.
- [Release notes](https://github.com/tdewolff/minify/releases)
- [Commits](https://github.com/tdewolff/minify/compare/v2.20.17...v2.20.19)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-14 11:16:07 +01:00
Paul Jolly be914ff34d deps: Upgrade github.com/alecthomas/chroma/v2 to v2.13.0
Closes #11862
2024-03-14 11:04:41 +01:00
Joe Mooring 48a0fea87a tpl/tplimpl: Modify figure shortcode to look for page resource
Closes #12244
Closes #12245
2024-03-14 10:21:40 +02:00
Bjørn Erik Pedersen 9ca1de09dd Fix panic when changing archetype files when servere is running
Fixes #12195
2024-03-13 19:35:28 +02:00
dependabot[bot] e62675002e build(deps): bump golang.org/x/mod from 0.15.0 to 0.16.0
Bumps [golang.org/x/mod](https://github.com/golang/mod) from 0.15.0 to 0.16.0.
- [Commits](https://github.com/golang/mod/compare/v0.15.0...v0.16.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-13 19:23:42 +02:00
Bjørn Erik Pedersen 9668759ad8 Fix front matter date location when value gets inherited from other dates
Fixes #12236
2024-03-13 19:00:50 +02:00
Bjørn Erik Pedersen 9e9b1f110c Fix Name for nested resourced fetched in resources.ByName and similar
Fixes #12214
2024-03-13 18:59:50 +02:00
Joe Mooring dc6a292133 common/hugo: Rename IsMultiHost and IsMultiLingual
hugo.IsMultiHost => hugo.IsMultihost
hugo.IsMultiLingual => hugo.IsMultilingual

Closes #12232
2024-03-13 17:34:42 +02:00
Joe Mooring 4f92f949ea hugolib: Deprecate .Site.MultiLingual in favor of hugo.IsMultiLingual
Closes #12224
2024-03-10 10:47:51 +02:00
Joe Mooring d24ffdde5b snap: Transition to from core20 to core22
Closes #12219
2024-03-09 08:47:53 -08:00
hugoreleaser ca31b95f30 releaser: Prepare repository for 0.124.0-DEV
[ci skip]
2024-03-07 13:28:40 +00:00
94 changed files with 1569 additions and 480 deletions
+2 -2
View File
@@ -4,7 +4,7 @@ parameters:
defaults: &defaults
resource_class: large
docker:
- image: bepsays/ci-hugoreleaser:1.22200.20000
- image: bepsays/ci-hugoreleaser:1.22200.20100
environment: &buildenv
GOMODCACHE: /root/project/gomodcache
version: 2
@@ -60,7 +60,7 @@ jobs:
environment:
<<: [*buildenv]
docker:
- image: bepsays/ci-hugoreleaser-linux-arm64:1.22200.20000
- image: bepsays/ci-hugoreleaser-linux-arm64:1.22200.20100
steps:
- *restore-cache
- &attach-workspace
+1
View File
@@ -521,6 +521,7 @@ func applyLocalFlagsBuildConfig(cmd *cobra.Command, r *rootCommand) {
cmd.Flags().StringP("cacheDir", "", "", "filesystem path to cache directory")
_ = cmd.Flags().SetAnnotation("cacheDir", cobra.BashCompSubdirsInDir, []string{})
cmd.Flags().StringP("contentDir", "c", "", "filesystem path to content directory")
cmd.Flags().StringSliceP("renderSegments", "", []string{}, "named segments to render (configured in the segments config)")
_ = cmd.Flags().SetAnnotation("theme", cobra.BashCompSubdirsInDir, []string{"themes"})
}
+6 -7
View File
@@ -617,9 +617,9 @@ func (c *serverCommand) setBaseURLsInConfig() error {
}
return c.withConfE(func(conf *commonConfig) error {
for i, language := range conf.configs.Languages {
isMultiHost := conf.configs.IsMultihost
isMultihost := conf.configs.IsMultihost
var serverPort int
if isMultiHost {
if isMultihost {
serverPort = c.serverPorts[i].p
} else {
serverPort = c.serverPorts[0].p
@@ -737,9 +737,9 @@ func (c *serverCommand) createServerPorts(cd *simplecobra.Commandeer) error {
flags := cd.CobraCommand.Flags()
var cerr error
c.withConf(func(conf *commonConfig) {
isMultiHost := conf.configs.IsMultihost
isMultihost := conf.configs.IsMultihost
c.serverPorts = make([]serverPortListener, 1)
if isMultiHost {
if isMultihost {
if !c.serverAppend {
cerr = errors.New("--appendPort=false not supported when in multihost mode")
return
@@ -852,7 +852,7 @@ func (c *serverCommand) serve() error {
h *hugolib.HugoSites
)
err := c.withConfE(func(conf *commonConfig) error {
isMultiHost := conf.configs.IsMultihost
isMultihost := conf.configs.IsMultihost
var err error
h, err = c.r.HugFromConfig(conf)
if err != nil {
@@ -862,7 +862,7 @@ func (c *serverCommand) serve() error {
// We need the server to share the same logger as the Hugo build (for error counts etc.)
c.r.logger = h.Log
if isMultiHost {
if isMultihost {
for _, l := range conf.configs.ConfigLangs() {
baseURLs = append(baseURLs, l.BaseURL())
roots = append(roots, l.Language().Lang)
@@ -1005,7 +1005,6 @@ func (c *serverCommand) serve() error {
}
}
}()
if err != nil {
c.r.Println("Error:", err)
}
+13 -1
View File
@@ -111,17 +111,29 @@ func (i HugoInfo) Deps() []*Dependency {
return i.deps
}
// IsMultiHost reports whether each configured language has a unique baseURL.
// Deprecated: Use hugo.IsMultihost instead.
func (i HugoInfo) IsMultiHost() bool {
Deprecate("hugo.IsMultiHost", "Use hugo.IsMultihost instead.", "v0.124.0")
return i.conf.IsMultihost()
}
// IsMultihost reports whether each configured language has a unique baseURL.
func (i HugoInfo) IsMultihost() bool {
return i.conf.IsMultihost()
}
// IsMultilingual reports whether there are two or more configured languages.
func (i HugoInfo) IsMultilingual() bool {
return i.conf.IsMultilingual()
}
// ConfigProvider represents the config options that are relevant for HugoInfo.
type ConfigProvider interface {
Environment() string
Running() bool
WorkingDir() string
IsMultihost() bool
IsMultilingual() bool
}
// NewInfo creates a new Hugo Info object.
+77
View File
@@ -0,0 +1,77 @@
// 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 hugo_test
import (
"strings"
"testing"
"github.com/gohugoio/hugo/hugolib"
)
func TestIsMultilingualAndIsMultihost(t *testing.T) {
t.Parallel()
files := `
-- hugo.toml --
disableKinds = ['page','rss','section','sitemap','taxonomy','term']
defaultContentLanguageInSubdir = true
[languages.de]
baseURL = 'https://de.example.org/'
[languages.en]
baseURL = 'https://en.example.org/'
-- content/_index.md --
---
title: home
---
-- layouts/index.html --
multilingual={{ hugo.IsMultilingual }}
multihost={{ hugo.IsMultihost }}
`
b := hugolib.Test(t, files)
b.AssertFileContent("public/de/index.html",
"multilingual=true",
"multihost=true",
)
b.AssertFileContent("public/en/index.html",
"multilingual=true",
"multihost=true",
)
files = strings.ReplaceAll(files, "baseURL = 'https://de.example.org/'", "")
files = strings.ReplaceAll(files, "baseURL = 'https://en.example.org/'", "")
b = hugolib.Test(t, files)
b.AssertFileContent("public/de/index.html",
"multilingual=true",
"multihost=false",
)
b.AssertFileContent("public/en/index.html",
"multilingual=true",
"multihost=false",
)
files = strings.ReplaceAll(files, "[languages.de]", "")
files = strings.ReplaceAll(files, "[languages.en]", "")
b = hugolib.Test(t, files)
b.AssertFileContent("public/en/index.html",
"multilingual=false",
"multihost=false",
)
}
+9 -4
View File
@@ -65,10 +65,11 @@ func TestDeprecationLogLevelFromVersion(t *testing.T) {
}
type testConfig struct {
environment string
running bool
workingDir string
multihost bool
environment string
running bool
workingDir string
multihost bool
multilingual bool
}
func (c testConfig) Environment() string {
@@ -86,3 +87,7 @@ func (c testConfig) WorkingDir() string {
func (c testConfig) IsMultihost() bool {
return c.multihost
}
func (c testConfig) IsMultilingual() bool {
return c.multilingual
}
+2 -2
View File
@@ -17,7 +17,7 @@ package hugo
// This should be the only one.
var CurrentVersion = Version{
Major: 0,
Minor: 123,
PatchLevel: 8,
Minor: 124,
PatchLevel: 0,
Suffix: "",
}
+7 -7
View File
@@ -239,7 +239,7 @@ const (
// E.g. /blog/my-post.md
PathTypeContentSingle
// All bewlow are bundled content files.
// All below are bundled content files.
// Leaf bundles, e.g. /blog/my-post/index.md
PathTypeLeaf
@@ -313,7 +313,7 @@ func (p *Path) norm(s string) string {
return s
}
// IdentifierBase satifies identity.Identity.
// IdentifierBase satisfies identity.Identity.
func (p *Path) IdentifierBase() string {
return p.Base()
}
@@ -368,7 +368,7 @@ func (p *Path) Name() string {
return p.s
}
// Name returns the last element of path withhout any extension.
// Name returns the last element of path without any extension.
func (p *Path) NameNoExt() string {
if i := p.identifierIndex(0); i != -1 {
return p.s[p.posContainerHigh : p.identifiers[i].Low-1]
@@ -376,7 +376,7 @@ func (p *Path) NameNoExt() string {
return p.s[p.posContainerHigh:]
}
// Name returns the last element of path withhout any language identifier.
// Name returns the last element of path without any language identifier.
func (p *Path) NameNoLang() string {
i := p.identifierIndex(p.posIdentifierLanguage)
if i == -1 {
@@ -386,7 +386,7 @@ func (p *Path) NameNoLang() string {
return p.s[p.posContainerHigh:p.identifiers[i].Low-1] + p.s[p.identifiers[i].High:]
}
// BaseNameNoIdentifier returns the logcical base name for a resource without any idenifier (e.g. no extension).
// BaseNameNoIdentifier returns the logical base name for a resource without any identifier (e.g. no extension).
// For bundles this will be the containing directory's name, e.g. "blog".
func (p *Path) BaseNameNoIdentifier() string {
if p.IsBundle() {
@@ -395,7 +395,7 @@ func (p *Path) BaseNameNoIdentifier() string {
return p.NameNoIdentifier()
}
// NameNoIdentifier returns the last element of path withhout any identifier (e.g. no extension).
// NameNoIdentifier returns the last element of path without any identifier (e.g. no extension).
func (p *Path) NameNoIdentifier() string {
if len(p.identifiers) > 0 {
return p.s[p.posContainerHigh : p.identifiers[len(p.identifiers)-1].Low-1]
@@ -435,7 +435,7 @@ func (p *Path) PathNoIdentifier() string {
return p.base(false, false)
}
// PathRel returns the path relativeto the given owner.
// PathRel returns the path relative to the given owner.
func (p *Path) PathRel(owner *Path) string {
ob := owner.Base()
if !strings.HasSuffix(ob, "/") {
+8
View File
@@ -99,6 +99,14 @@ type Unwrapper interface {
Unwrapv() any
}
// Unwrap returns the underlying value of v if it implements Unwrapper, otherwise v is returned.
func Unwrapv(v any) any {
if u, ok := v.(Unwrapper); ok {
return u.Unwrapv()
}
return v
}
// LowHigh is typically used to represent a slice boundary.
type LowHigh struct {
Low int
+16 -4
View File
@@ -39,6 +39,7 @@ import (
"github.com/gohugoio/hugo/config/services"
"github.com/gohugoio/hugo/deploy/deployconfig"
"github.com/gohugoio/hugo/helpers"
"github.com/gohugoio/hugo/hugolib/segments"
"github.com/gohugoio/hugo/langs"
"github.com/gohugoio/hugo/markup/markup_config"
"github.com/gohugoio/hugo/media"
@@ -103,9 +104,11 @@ type Config struct {
RootConfig
// Author information.
// Deprecated: Use taxonomies instead.
Author map[string]any
// Social links.
// Deprecated: Use .Site.Params instead.
Social map[string]string
// The build configuration section contains build-related configuration options.
@@ -137,6 +140,9 @@ type Config struct {
// a slice of page matcher and params to apply to those pages.
Cascade *config.ConfigNamespace[[]page.PageMatcherParamsConfig, map[page.PageMatcher]maps.Params] `mapstructure:"-"`
// The segments defines segments for the site. Used for partial/segmented builds.
Segments *config.ConfigNamespace[map[string]segments.SegmentConfig, segments.Segments] `mapstructure:"-"`
// Menu configuration.
// <docsmeta>{"refs": ["config:languages:menus"] }</docsmeta>
Menus *config.ConfigNamespace[map[string]navigation.MenuConfig, navigation.Menus] `mapstructure:"-"`
@@ -364,6 +370,7 @@ func (c *Config) CompileConfig(logger loggers.Logger) error {
CreateTitle: helpers.GetTitleFunc(c.TitleCaseStyle),
IsUglyURLSection: isUglyURL,
IgnoreFile: ignoreFile,
SegmentFilter: c.Segments.Config.Get(func(s string) { logger.Warnf("Render segment %q not found in configuration", s) }, c.RootConfig.RenderSegments...),
MainSections: c.MainSections,
Clock: clock,
transientErr: transientErr,
@@ -400,6 +407,7 @@ type ConfigCompiled struct {
CreateTitle func(s string) string
IsUglyURLSection func(section string) bool
IgnoreFile func(filename string) bool
SegmentFilter segments.SegmentFilter
MainSections []string
Clock time.Time
@@ -472,6 +480,10 @@ type RootConfig struct {
// A list of languages to disable.
DisableLanguages []string
// The named segments to render.
// This needs to match the name of the segment in the segments configuration.
RenderSegments []string
// Disable the injection of the Hugo generator tag on the home page.
DisableHugoGeneratorInject bool
@@ -826,7 +838,7 @@ func fromLoadConfigResult(fs afero.Fs, logger loggers.Logger, res config.LoadCon
langConfigMap := make(map[string]*Config)
languagesConfig := cfg.GetStringMap("languages")
var isMultiHost bool
var isMultihost bool
if err := all.CompileConfig(logger); err != nil {
return nil, err
@@ -863,7 +875,7 @@ func fromLoadConfigResult(fs afero.Fs, logger loggers.Logger, res config.LoadCon
}
if kk == "baseurl" {
// baseURL configure don the language level is a multihost setup.
isMultiHost = true
isMultihost = true
}
mergedConfig.Set(kk, vv)
rootv := cfg.Get(kk)
@@ -913,7 +925,7 @@ func fromLoadConfigResult(fs afero.Fs, logger loggers.Logger, res config.LoadCon
}
// Adjust Goldmark config defaults for multilingual, single-host sites.
if len(languagesConfig) > 1 && !isMultiHost && !clone.Markup.Goldmark.DuplicateResourceFiles {
if len(languagesConfig) > 1 && !isMultihost && !clone.Markup.Goldmark.DuplicateResourceFiles {
if !clone.Markup.Goldmark.DuplicateResourceFiles {
if clone.Markup.Goldmark.RenderHooks.Link.EnableDefault == nil {
clone.Markup.Goldmark.RenderHooks.Link.EnableDefault = types.NewBool(true)
@@ -943,7 +955,7 @@ func fromLoadConfigResult(fs afero.Fs, logger loggers.Logger, res config.LoadCon
Base: all,
LanguageConfigMap: langConfigMap,
LoadingInfo: res,
IsMultihost: isMultiHost,
IsMultihost: isMultihost,
}
return cm, nil
+10
View File
@@ -25,11 +25,13 @@ import (
"github.com/gohugoio/hugo/config/security"
"github.com/gohugoio/hugo/config/services"
"github.com/gohugoio/hugo/deploy/deployconfig"
"github.com/gohugoio/hugo/hugolib/segments"
"github.com/gohugoio/hugo/langs"
"github.com/gohugoio/hugo/markup/markup_config"
"github.com/gohugoio/hugo/media"
"github.com/gohugoio/hugo/minifiers"
"github.com/gohugoio/hugo/modules"
"github.com/gohugoio/hugo/navigation"
"github.com/gohugoio/hugo/output"
"github.com/gohugoio/hugo/related"
@@ -120,6 +122,14 @@ var allDecoderSetups = map[string]decodeWeight{
return err
},
},
"segments": {
key: "segments",
decode: func(d decodeWeight, p decodeConfig) error {
var err error
p.c.Segments, err = segments.DecodeSegments(p.p.GetStringMap(d.key))
return err
},
},
"server": {
key: "server",
decode: func(d decodeWeight, p decodeConfig) error {
+2 -2
View File
@@ -52,7 +52,7 @@ func (c ConfigLanguage) LanguagePrefix() string {
return c.Language().Lang
}
if !c.IsMultiLingual() || c.DefaultContentLanguage() == c.Language().Lang {
if !c.IsMultilingual() || c.DefaultContentLanguage() == c.Language().Lang {
return ""
}
return c.Language().Lang
@@ -78,7 +78,7 @@ func (c ConfigLanguage) FastRenderMode() bool {
return c.config.Internal.FastRenderMode
}
func (c ConfigLanguage) IsMultiLingual() bool {
func (c ConfigLanguage) IsMultilingual() bool {
return len(c.m.Languages) > 1
}
+1 -1
View File
@@ -35,7 +35,7 @@ type AllProvider interface {
PathParser() *paths.PathParser
Environment() string
IsMultihost() bool
IsMultiLingual() bool
IsMultilingual() bool
NoBuildLock() bool
BaseConfig() BaseConfig
Dirs() CommonDirs
@@ -2,7 +2,7 @@
For a given taxonomy, renders a list of terms assigned to the page.
@context {page} page The current page.
@context {string} taxonomy The taxonony.
@context {string} taxonomy The taxonomy.
@example: {{ partial "terms.html" (dict "taxonomy" "tags" "page" .) }}
*/}}
+1 -1
View File
@@ -361,7 +361,7 @@ type BuildState struct {
mu sync.Mutex // protects state below.
// A set of ilenames in /public that
// A set of filenames in /public that
// contains a post-processing prefix.
filenamesWithPostPrefix map[string]bool
}
+1
View File
@@ -56,6 +56,7 @@ hugo [flags]
--printPathWarnings print warnings on duplicate target paths etc.
--printUnusedTemplates print warnings on unused templates.
--quiet build in quiet mode
--renderSegments strings named segments to render (configured in the segments config)
--renderToMemory render to memory (mostly useful when running the server)
-s, --source string filesystem path to read files relative from
--templateMetrics display metrics about template executions
+8 -7
View File
@@ -18,13 +18,14 @@ hugo config [command] [flags]
### Options
```
-b, --baseURL string hostname (and path) to the root, e.g. https://spf13.com/
--cacheDir string filesystem path to cache directory
-c, --contentDir string filesystem path to content directory
--format string preferred file format (toml, yaml or json) (default "toml")
-h, --help help for config
--lang string the language to display config for. Defaults to the first language defined.
-t, --theme strings themes to use (located in /themes/THEMENAME/)
-b, --baseURL string hostname (and path) to the root, e.g. https://spf13.com/
--cacheDir string filesystem path to cache directory
-c, --contentDir string filesystem path to content directory
--format string preferred file format (toml, yaml or json) (default "toml")
-h, --help help for config
--lang string the language to display config for. Defaults to the first language defined.
--renderSegments strings named segments to render (configured in the segments config)
-t, --theme strings themes to use (located in /themes/THEMENAME/)
```
### Options inherited from parent commands
@@ -14,11 +14,12 @@ hugo config mounts [flags] [args]
### Options
```
-b, --baseURL string hostname (and path) to the root, e.g. https://spf13.com/
--cacheDir string filesystem path to cache directory
-c, --contentDir string filesystem path to content directory
-h, --help help for mounts
-t, --theme strings themes to use (located in /themes/THEMENAME/)
-b, --baseURL string hostname (and path) to the root, e.g. https://spf13.com/
--cacheDir string filesystem path to cache directory
-c, --contentDir string filesystem path to content directory
-h, --help help for mounts
--renderSegments strings named segments to render (configured in the segments config)
-t, --theme strings themes to use (located in /themes/THEMENAME/)
```
### Options inherited from parent commands
+8 -7
View File
@@ -18,13 +18,14 @@ hugo mod clean [flags] [args]
### Options
```
--all clean entire module cache
-b, --baseURL string hostname (and path) to the root, e.g. https://spf13.com/
--cacheDir string filesystem path to cache directory
-c, --contentDir string filesystem path to content directory
-h, --help help for clean
--pattern string pattern matching module paths to clean (all if not set), e.g. "**hugo*"
-t, --theme strings themes to use (located in /themes/THEMENAME/)
--all clean entire module cache
-b, --baseURL string hostname (and path) to the root, e.g. https://spf13.com/
--cacheDir string filesystem path to cache directory
-c, --contentDir string filesystem path to content directory
-h, --help help for clean
--pattern string pattern matching module paths to clean (all if not set), e.g. "**hugo*"
--renderSegments strings named segments to render (configured in the segments config)
-t, --theme strings themes to use (located in /themes/THEMENAME/)
```
### Options inherited from parent commands
+7 -6
View File
@@ -20,12 +20,13 @@ hugo mod graph [flags] [args]
### Options
```
-b, --baseURL string hostname (and path) to the root, e.g. https://spf13.com/
--cacheDir string filesystem path to cache directory
--clean delete module cache for dependencies that fail verification
-c, --contentDir string filesystem path to content directory
-h, --help help for graph
-t, --theme strings themes to use (located in /themes/THEMENAME/)
-b, --baseURL string hostname (and path) to the root, e.g. https://spf13.com/
--cacheDir string filesystem path to cache directory
--clean delete module cache for dependencies that fail verification
-c, --contentDir string filesystem path to content directory
-h, --help help for graph
--renderSegments strings named segments to render (configured in the segments config)
-t, --theme strings themes to use (located in /themes/THEMENAME/)
```
### Options inherited from parent commands
+6 -5
View File
@@ -25,11 +25,12 @@ hugo mod init [flags] [args]
### Options
```
-b, --baseURL string hostname (and path) to the root, e.g. https://spf13.com/
--cacheDir string filesystem path to cache directory
-c, --contentDir string filesystem path to content directory
-h, --help help for init
-t, --theme strings themes to use (located in /themes/THEMENAME/)
-b, --baseURL string hostname (and path) to the root, e.g. https://spf13.com/
--cacheDir string filesystem path to cache directory
-c, --contentDir string filesystem path to content directory
-h, --help help for init
--renderSegments strings named segments to render (configured in the segments config)
-t, --theme strings themes to use (located in /themes/THEMENAME/)
```
### Options inherited from parent commands
@@ -28,11 +28,12 @@ hugo mod npm pack [flags] [args]
### Options
```
-b, --baseURL string hostname (and path) to the root, e.g. https://spf13.com/
--cacheDir string filesystem path to cache directory
-c, --contentDir string filesystem path to content directory
-h, --help help for pack
-t, --theme strings themes to use (located in /themes/THEMENAME/)
-b, --baseURL string hostname (and path) to the root, e.g. https://spf13.com/
--cacheDir string filesystem path to cache directory
-c, --contentDir string filesystem path to content directory
-h, --help help for pack
--renderSegments strings named segments to render (configured in the segments config)
-t, --theme strings themes to use (located in /themes/THEMENAME/)
```
### Options inherited from parent commands
+6 -5
View File
@@ -14,11 +14,12 @@ hugo mod tidy [flags] [args]
### Options
```
-b, --baseURL string hostname (and path) to the root, e.g. https://spf13.com/
--cacheDir string filesystem path to cache directory
-c, --contentDir string filesystem path to content directory
-h, --help help for tidy
-t, --theme strings themes to use (located in /themes/THEMENAME/)
-b, --baseURL string hostname (and path) to the root, e.g. https://spf13.com/
--cacheDir string filesystem path to cache directory
-c, --contentDir string filesystem path to content directory
-h, --help help for tidy
--renderSegments strings named segments to render (configured in the segments config)
-t, --theme strings themes to use (located in /themes/THEMENAME/)
```
### Options inherited from parent commands
+6 -5
View File
@@ -20,11 +20,12 @@ hugo mod vendor [flags] [args]
### Options
```
-b, --baseURL string hostname (and path) to the root, e.g. https://spf13.com/
--cacheDir string filesystem path to cache directory
-c, --contentDir string filesystem path to content directory
-h, --help help for vendor
-t, --theme strings themes to use (located in /themes/THEMENAME/)
-b, --baseURL string hostname (and path) to the root, e.g. https://spf13.com/
--cacheDir string filesystem path to cache directory
-c, --contentDir string filesystem path to content directory
-h, --help help for vendor
--renderSegments strings named segments to render (configured in the segments config)
-t, --theme strings themes to use (located in /themes/THEMENAME/)
```
### Options inherited from parent commands
+7 -6
View File
@@ -18,12 +18,13 @@ hugo mod verify [flags] [args]
### Options
```
-b, --baseURL string hostname (and path) to the root, e.g. https://spf13.com/
--cacheDir string filesystem path to cache directory
--clean delete module cache for dependencies that fail verification
-c, --contentDir string filesystem path to content directory
-h, --help help for verify
-t, --theme strings themes to use (located in /themes/THEMENAME/)
-b, --baseURL string hostname (and path) to the root, e.g. https://spf13.com/
--cacheDir string filesystem path to cache directory
--clean delete module cache for dependencies that fail verification
-c, --contentDir string filesystem path to content directory
-h, --help help for verify
--renderSegments strings named segments to render (configured in the segments config)
-t, --theme strings themes to use (located in /themes/THEMENAME/)
```
### Options inherited from parent commands
+9 -8
View File
@@ -25,14 +25,15 @@ hugo new content [path] [flags]
### Options
```
-b, --baseURL string hostname (and path) to the root, e.g. https://spf13.com/
--cacheDir string filesystem path to cache directory
-c, --contentDir string filesystem path to content directory
--editor string edit new content with this editor, if provided
-f, --force overwrite file if it already exists
-h, --help help for content
-k, --kind string content type to create
-t, --theme strings themes to use (located in /themes/THEMENAME/)
-b, --baseURL string hostname (and path) to the root, e.g. https://spf13.com/
--cacheDir string filesystem path to cache directory
-c, --contentDir string filesystem path to content directory
--editor string edit new content with this editor, if provided
-f, --force overwrite file if it already exists
-h, --help help for content
-k, --kind string content type to create
--renderSegments strings named segments to render (configured in the segments config)
-t, --theme strings themes to use (located in /themes/THEMENAME/)
```
### Options inherited from parent commands
+44 -43
View File
@@ -28,49 +28,50 @@ hugo server [command] [flags]
### Options
```
--appendPort append port to baseURL (default true)
-b, --baseURL string hostname (and path) to the root, e.g. https://spf13.com/
--bind string interface to which the server will bind (default "127.0.0.1")
-D, --buildDrafts include content marked as draft
-E, --buildExpired include expired content
-F, --buildFuture include content with publishdate in the future
--cacheDir string filesystem path to cache directory
--cleanDestinationDir remove files from destination not found in static directories
-c, --contentDir string filesystem path to content directory
--disableBrowserError do not show build errors in the browser
--disableFastRender enables full re-renders on changes
--disableKinds strings disable different kind of pages (home, RSS etc.)
--disableLiveReload watch without enabling live browser reload on rebuild
--enableGitInfo add Git revision, date, author, and CODEOWNERS info to the pages
--forceSyncStatic copy all files when static is changed.
--gc enable to run some cleanup tasks (remove unused cache files) after the build
-h, --help help for server
--ignoreCache ignores the cache directory
-l, --layoutDir string filesystem path to layout directory
--liveReloadPort int port for live reloading (i.e. 443 in HTTPS proxy situations) (default -1)
--minify minify any supported output format (HTML, XML etc.)
--navigateToChanged navigate to changed content file on live browser reload
--noBuildLock don't create .hugo_build.lock file
--noChmod don't sync permission mode of files
--noHTTPCache prevent HTTP caching
--noTimes don't sync modification time of files
--panicOnWarning panic on first WARNING log
--poll string set this to a poll interval, e.g --poll 700ms, to use a poll based approach to watch for file system changes
-p, --port int port on which the server will listen (default 1313)
--pprof enable the pprof server (port 8080)
--printI18nWarnings print missing translations
--printMemoryUsage print memory usage to screen at intervals
--printPathWarnings print warnings on duplicate target paths etc.
--printUnusedTemplates print warnings on unused templates.
--renderStaticToDisk serve static files from disk and dynamic files from memory
--templateMetrics display metrics about template executions
--templateMetricsHints calculate some improvement hints when combined with --templateMetrics
-t, --theme strings themes to use (located in /themes/THEMENAME/)
--tlsAuto generate and use locally-trusted certificates.
--tlsCertFile string path to TLS certificate file
--tlsKeyFile string path to TLS key file
--trace file write trace to file (not useful in general)
-w, --watch watch filesystem for changes and recreate as needed (default true)
--appendPort append port to baseURL (default true)
-b, --baseURL string hostname (and path) to the root, e.g. https://spf13.com/
--bind string interface to which the server will bind (default "127.0.0.1")
-D, --buildDrafts include content marked as draft
-E, --buildExpired include expired content
-F, --buildFuture include content with publishdate in the future
--cacheDir string filesystem path to cache directory
--cleanDestinationDir remove files from destination not found in static directories
-c, --contentDir string filesystem path to content directory
--disableBrowserError do not show build errors in the browser
--disableFastRender enables full re-renders on changes
--disableKinds strings disable different kind of pages (home, RSS etc.)
--disableLiveReload watch without enabling live browser reload on rebuild
--enableGitInfo add Git revision, date, author, and CODEOWNERS info to the pages
--forceSyncStatic copy all files when static is changed.
--gc enable to run some cleanup tasks (remove unused cache files) after the build
-h, --help help for server
--ignoreCache ignores the cache directory
-l, --layoutDir string filesystem path to layout directory
--liveReloadPort int port for live reloading (i.e. 443 in HTTPS proxy situations) (default -1)
--minify minify any supported output format (HTML, XML etc.)
--navigateToChanged navigate to changed content file on live browser reload
--noBuildLock don't create .hugo_build.lock file
--noChmod don't sync permission mode of files
--noHTTPCache prevent HTTP caching
--noTimes don't sync modification time of files
--panicOnWarning panic on first WARNING log
--poll string set this to a poll interval, e.g --poll 700ms, to use a poll based approach to watch for file system changes
-p, --port int port on which the server will listen (default 1313)
--pprof enable the pprof server (port 8080)
--printI18nWarnings print missing translations
--printMemoryUsage print memory usage to screen at intervals
--printPathWarnings print warnings on duplicate target paths etc.
--printUnusedTemplates print warnings on unused templates.
--renderSegments strings named segments to render (configured in the segments config)
--renderStaticToDisk serve static files from disk and dynamic files from memory
--templateMetrics display metrics about template executions
--templateMetricsHints calculate some improvement hints when combined with --templateMetrics
-t, --theme strings themes to use (located in /themes/THEMENAME/)
--tlsAuto generate and use locally-trusted certificates.
--tlsCertFile string path to TLS certificate file
--tlsKeyFile string path to TLS key file
--trace file write trace to file (not useful in general)
-w, --watch watch filesystem for changes and recreate as needed (default true)
```
### Options inherited from parent commands
+40
View File
@@ -207,6 +207,10 @@ chroma:
- Aliases:
- dax
Name: Dax
- Aliases:
- desktop
- desktop_entry
Name: Desktop file
- Aliases:
- diff
- udiff
@@ -443,6 +447,10 @@ chroma:
- Aliases:
- mason
Name: Mason
- Aliases:
- materialize
- mzsql
Name: Materialize SQL dialect
- Aliases:
- mathematica
- mma
@@ -493,6 +501,9 @@ chroma:
- Aliases:
- natural
Name: Natural
- Aliases:
- ndisasm
Name: NDISASM
- Aliases:
- newspeak
Name: Newspeak
@@ -607,6 +618,9 @@ chroma:
- Aliases:
- prolog
Name: Prolog
- Aliases:
- promela
Name: Promela
- Aliases:
- promql
Name: PromQL
@@ -673,6 +687,9 @@ chroma:
- Aliases:
- registry
Name: reg
- Aliases:
- rego
Name: Rego
- Aliases:
- rst
- rest
@@ -682,6 +699,9 @@ chroma:
- rexx
- arexx
Name: Rexx
- Aliases:
- spec
Name: RPMSpec
- Aliases:
- rb
- ruby
@@ -946,6 +966,7 @@ config:
dir: :cacheDir/modules
maxAge: -1
canonifyURLs: false
capitalizeListTitles: true
cascade: []
cleanDestinationDir: false
contentDir: content
@@ -1585,6 +1606,7 @@ config:
toLower: false
relativeURLs: false
removePathAccents: false
renderSegments: null
resourceDir: resources
sectionPagesMenu: ""
security:
@@ -1607,6 +1629,7 @@ config:
- (?i)GET|POST
urls:
- .*
segments: {}
server:
headers: null
redirects:
@@ -1704,6 +1727,8 @@ config_helpers:
_merge: none
security:
_merge: none
segments:
_merge: none
server:
_merge: none
services:
@@ -2965,6 +2990,21 @@ tpl:
Args: null
Description: ""
Examples: null
IsMultiHost:
Aliases: null
Args: null
Description: ""
Examples: null
IsMultihost:
Aliases: null
Args: null
Description: ""
Examples: null
IsMultilingual:
Aliases: null
Args: null
Description: ""
Examples: null
IsProduction:
Aliases: null
Args: null
+10 -10
View File
@@ -2,7 +2,7 @@ module github.com/gohugoio/hugo
require (
github.com/BurntSushi/locker v0.0.0-20171006230638-a6e239ea1c69
github.com/alecthomas/chroma/v2 v2.12.0
github.com/alecthomas/chroma/v2 v2.13.0
github.com/armon/go-radix v1.0.1-0.20221118154546-54df44f2176c
github.com/aws/aws-sdk-go-v2 v1.24.1
github.com/aws/aws-sdk-go-v2/service/cloudfront v1.32.6
@@ -25,7 +25,7 @@ require (
github.com/cli/safeexec v1.0.1
github.com/disintegration/gift v1.2.1
github.com/dustin/go-humanize v1.0.1
github.com/evanw/esbuild v0.20.1
github.com/evanw/esbuild v0.20.2
github.com/fatih/color v1.16.0
github.com/fortytw2/leaktest v1.3.0
github.com/frankban/quicktest v1.14.6
@@ -35,7 +35,7 @@ require (
github.com/gobuffalo/flect v1.0.2
github.com/gobwas/glob v0.2.3
github.com/gohugoio/go-i18n/v2 v2.1.3-0.20230805085216-e63c13218d0e
github.com/gohugoio/hugo-goldmark-extensions/passthrough v0.1.0
github.com/gohugoio/hugo-goldmark-extensions/passthrough v0.2.0
github.com/gohugoio/locales v0.14.0
github.com/gohugoio/localescompressed v1.0.1
github.com/gohugoio/testmodBuilder/mods v0.0.0-20190520184928-c56af20f2e95
@@ -64,7 +64,7 @@ require (
github.com/spf13/cobra v1.8.0
github.com/spf13/fsync v0.10.1
github.com/spf13/pflag v1.0.5
github.com/tdewolff/minify/v2 v2.20.17
github.com/tdewolff/minify/v2 v2.20.19
github.com/tdewolff/parse/v2 v2.7.12
github.com/yuin/goldmark v1.7.0
github.com/yuin/goldmark-emoji v1.0.2
@@ -72,11 +72,11 @@ require (
gocloud.dev v0.36.0
golang.org/x/exp v0.0.0-20221031165847-c99f073a8326
golang.org/x/image v0.15.0
golang.org/x/mod v0.15.0
golang.org/x/net v0.21.0
golang.org/x/mod v0.16.0
golang.org/x/net v0.22.0
golang.org/x/sync v0.6.0
golang.org/x/text v0.14.0
golang.org/x/tools v0.18.0
golang.org/x/tools v0.19.0
google.golang.org/api v0.152.0
gopkg.in/yaml.v2 v2.4.0
)
@@ -114,7 +114,7 @@ require (
github.com/aws/aws-sdk-go-v2/service/sts v1.26.5 // indirect
github.com/aws/smithy-go v1.19.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect
github.com/dlclark/regexp2 v1.10.0 // indirect
github.com/dlclark/regexp2 v1.11.0 // indirect
github.com/go-openapi/jsonpointer v0.20.2 // indirect
github.com/go-openapi/swag v0.22.8 // indirect
github.com/golang-jwt/jwt/v5 v5.1.0 // indirect
@@ -142,9 +142,9 @@ require (
github.com/pkg/errors v0.9.1 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
go.opencensus.io v0.24.0 // indirect
golang.org/x/crypto v0.19.0 // indirect
golang.org/x/crypto v0.21.0 // indirect
golang.org/x/oauth2 v0.15.0 // indirect
golang.org/x/sys v0.17.0 // indirect
golang.org/x/sys v0.18.0 // indirect
golang.org/x/time v0.5.0 // indirect
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
google.golang.org/appengine v1.6.8 // indirect
+22 -22
View File
@@ -66,10 +66,10 @@ github.com/BurntSushi/locker v0.0.0-20171006230638-a6e239ea1c69/go.mod h1:L1AbZd
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/alecthomas/assert/v2 v2.2.1 h1:XivOgYcduV98QCahG8T5XTezV5bylXe+lBxLG2K2ink=
github.com/alecthomas/chroma/v2 v2.12.0 h1:Wh8qLEgMMsN7mgyG8/qIpegky2Hvzr4By6gEF7cmWgw=
github.com/alecthomas/chroma/v2 v2.12.0/go.mod h1:4TQu7gdfuPjSh76j78ietmqh9LiurGF0EpseFXdKMBw=
github.com/alecthomas/repr v0.2.0 h1:HAzS41CIzNW5syS8Mf9UwXhNH1J9aix/BvDRf1Ml2Yk=
github.com/alecthomas/assert/v2 v2.6.0 h1:o3WJwILtexrEUk3cUVal3oiQY2tfgr/FHWiz/v2n4FU=
github.com/alecthomas/chroma/v2 v2.13.0 h1:VP72+99Fb2zEcYM0MeaWJmV+xQvz5v5cxRHd+ooU1lI=
github.com/alecthomas/chroma/v2 v2.13.0/go.mod h1:BUGjjsD+ndS6eX37YgTchSEG+Jg9Jv1GiZs9sqPqztk=
github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc=
github.com/armon/go-radix v1.0.1-0.20221118154546-54df44f2176c h1:651/eoCRnQ7YtSjAnSzRucrJz+3iGEFt+ysraELS81M=
github.com/armon/go-radix v1.0.1-0.20221118154546-54df44f2176c/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/aws/aws-sdk-go v1.50.7 h1:odKb+uneeGgF2jgAerKjFzpljiyZxleV4SHB7oBK+YA=
@@ -168,8 +168,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/disintegration/gift v1.2.1 h1:Y005a1X4Z7Uc+0gLpSAsKhWi4qLtsdEcMIbbdvdZ6pc=
github.com/disintegration/gift v1.2.1/go.mod h1:Jh2i7f7Q2BM7Ezno3PhfezbR1xpUg9dUg3/RlKGr4HI=
github.com/dlclark/regexp2 v1.10.0 h1:+/GIL799phkJqYW+3YbOd8LCcbHzT0Pbo8zl70MHsq0=
github.com/dlclark/regexp2 v1.10.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI=
github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
@@ -179,8 +179,8 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/evanw/esbuild v0.20.1 h1:ueyMIL19umCcJTSxiBH/QmPipgGt8hEDM24pdfowgEc=
github.com/evanw/esbuild v0.20.1/go.mod h1:D2vIQZqV/vIf/VRHtViaUtViZmG7o+kKmlBfVQuRi48=
github.com/evanw/esbuild v0.20.2 h1:E4Y0iJsothpUCq7y0D+ERfqpJmPWrZpNybJA3x3I4p8=
github.com/evanw/esbuild v0.20.2/go.mod h1:D2vIQZqV/vIf/VRHtViaUtViZmG7o+kKmlBfVQuRi48=
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
@@ -211,8 +211,8 @@ github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
github.com/gohugoio/go-i18n/v2 v2.1.3-0.20230805085216-e63c13218d0e h1:QArsSubW7eDh8APMXkByjQWvuljwPGAGQpJEFn0F0wY=
github.com/gohugoio/go-i18n/v2 v2.1.3-0.20230805085216-e63c13218d0e/go.mod h1:3Ltoo9Banwq0gOtcOwxuHG6omk+AwsQPADyw2vQYOJQ=
github.com/gohugoio/hugo-goldmark-extensions/passthrough v0.1.0 h1:oFQ3f1M3Ook6amHmbqVu/uBRrQ6yjMDFkIv4HQr0f1Y=
github.com/gohugoio/hugo-goldmark-extensions/passthrough v0.1.0/go.mod h1:g9CCh+Ci2IMbPUrVJuXbBTrA+rIIx5+hDQ4EXYaQDoM=
github.com/gohugoio/hugo-goldmark-extensions/passthrough v0.2.0 h1:PCtO5l++psZf48yen2LxQ3JiOXxaRC6v0594NeHvGZg=
github.com/gohugoio/hugo-goldmark-extensions/passthrough v0.2.0/go.mod h1:g9CCh+Ci2IMbPUrVJuXbBTrA+rIIx5+hDQ4EXYaQDoM=
github.com/gohugoio/locales v0.14.0 h1:Q0gpsZwfv7ATHMbcTNepFd59H7GoykzWJIxi113XGDc=
github.com/gohugoio/locales v0.14.0/go.mod h1:ip8cCAv/cnmVLzzXtiTpPwgJ4xhKZranqNqtoIu0b/4=
github.com/gohugoio/localescompressed v1.0.1 h1:KTYMi8fCWYLswFyJAeOtuk/EkXR/KPTHHNN9OS+RTxo=
@@ -427,8 +427,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/tdewolff/minify/v2 v2.20.17 h1:zGqEDhspr3XjSrQI/56vw9IdAhLAaKTLXWnDBsxNVt8=
github.com/tdewolff/minify/v2 v2.20.17/go.mod h1:ulkFoeAVWMLEyjuDz1ZIWOA31g5aWOawCFRp9R/MudM=
github.com/tdewolff/minify/v2 v2.20.19 h1:tX0SR0LUrIqGoLjXnkIzRSIbKJ7PaNnSENLD4CyH6Xo=
github.com/tdewolff/minify/v2 v2.20.19/go.mod h1:ulkFoeAVWMLEyjuDz1ZIWOA31g5aWOawCFRp9R/MudM=
github.com/tdewolff/parse/v2 v2.7.12 h1:tgavkHc2ZDEQVKy1oWxwIyh5bP4F5fEh/JmBwPP/3LQ=
github.com/tdewolff/parse/v2 v2.7.12/go.mod h1:3FbJWZp3XT9OWVN3Hmfp0p/a08v4h8J9W1aghka0soA=
github.com/tdewolff/test v1.0.11-0.20231101010635-f1265d231d52/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
@@ -466,8 +466,8 @@ golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -508,8 +508,8 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8=
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic=
golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -545,8 +545,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -615,8 +615,8 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -685,8 +685,8 @@ golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ=
golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg=
golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw=
golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+1 -1
View File
@@ -42,7 +42,7 @@ var LanguageDirsMerger overlayfs.DirsMerger = func(lofi, bofi []fs.DirEntry) []f
// AppendDirsMerger merges two directories keeping all regular files
// with the first slice as the base.
// Duplicate directories in the secnond slice will be ignored.
// Duplicate directories in the second slice will be ignored.
// This strategy is used for the i18n and data fs where we need all entries.
var AppendDirsMerger overlayfs.DirsMerger = func(lofi, bofi []fs.DirEntry) []fs.DirEntry {
for _, fi1 := range bofi {
+1 -1
View File
@@ -822,7 +822,7 @@ func (f *rootMappingDir) ReadDir(count int) ([]iofs.DirEntry, error) {
return f.fs.collectDirEntries(f.name)
}
// Sentinal error to signal that a file is a directory.
// Sentinel error to signal that a file is a directory.
var errIsDir = errors.New("isDir")
func (f *rootMappingDir) Stat() (iofs.FileInfo, error) {
+21 -21
View File
@@ -508,12 +508,12 @@ func TestLoadConfigFromThemeDir(t *testing.T) {
theme = "test-theme"
[params]
m1 = "mv1"
m1 = "mv1"
`
themeConfig := `
[params]
t1 = "tv1"
t1 = "tv1"
t2 = "tv2"
`
@@ -885,9 +885,9 @@ ThisIsAParam: {{ site.Params.thisIsAParam }}
).BuildE()
b.Assert(err, qt.IsNil)
b.AssertFileContent("public/index.html", `
b.AssertFileContent("public/index.html", `
MyParam: enParamValue
ThisIsAParam: thisIsAParamValue
ThisIsAParam: thisIsAParamValue
`)
}
@@ -919,7 +919,7 @@ title: "My Swedish Section"
-- layouts/index.html --
LanguageCode: {{ eq site.LanguageCode site.Language.LanguageCode }}|{{ site.Language.LanguageCode }}|
{{ range $i, $e := (slice site .Site) }}
{{ $i }}|AllPages: {{ len .AllPages }}|Sections: {{ if .Sections }}true{{ end }}| Author: {{ .Authors }}|BuildDrafts: {{ .BuildDrafts }}|IsMultiLingual: {{ .IsMultiLingual }}|Param: {{ .Language.Params.myparam }}|Language string: {{ .Language }}|Languages: {{ .Languages }}
{{ $i }}|AllPages: {{ len .AllPages }}|Sections: {{ if .Sections }}true{{ end }}| Author: {{ .Authors }}|BuildDrafts: {{ .BuildDrafts }}|IsMultilingual: {{ .IsMultiLingual }}|Param: {{ .Language.Params.myparam }}|Language string: {{ .Language }}|Languages: {{ .Languages }}
{{ end }}
@@ -939,9 +939,9 @@ LanguageCode: {{ eq site.LanguageCode site.Language.LanguageCode }}|{{ site.Lang
b.AssertFileContent("public/index.html", `
AllPages: 4|
Sections: true|
Param: enParamValue
Param: enParamValue
IsMultiLingual: true
Param: enParamValue
Param: enParamValue
IsMultilingual: true
LanguageCode: true|en-US|
`)
@@ -1062,7 +1062,7 @@ Home
).BuildE()
b.Assert(err, qt.IsNil)
b.AssertFileContent("public/index.html", `
b.AssertFileContent("public/index.html", `
Home
`)
@@ -1095,7 +1095,7 @@ HTML.
HTACCESS.
`
b := Test(t, files)
@@ -1111,7 +1111,7 @@ languageCode = "en-US"
-- layouts/index.html --
LanguageCode: {{ .Site.LanguageCode }}|{{ site.Language.LanguageCode }}|
`
b := Test(t, files)
@@ -1137,7 +1137,7 @@ suffixes = ["bar"]
-- layouts/index.html --
Home.
`
b := Test(t, files)
@@ -1164,8 +1164,8 @@ func TestConfigMiscPanics(t *testing.T) {
params:
-- layouts/index.html --
Foo: {{ site.Params.foo }}|
`
b := Test(t, files)
@@ -1188,8 +1188,8 @@ defaultContentLanguage = "en"
weight = 1
-- layouts/index.html --
Foo: {{ site.Params.foo }}|
`
b, err := NewIntegrationTestBuilder(
IntegrationTestConfig{
@@ -1215,8 +1215,8 @@ languageCode = "en"
languageName = "English"
weight = 1
`
b, err := NewIntegrationTestBuilder(
IntegrationTestConfig{
@@ -1241,7 +1241,7 @@ contentDir = "mycontent"
-- layouts/index.html --
Home.
`
b := Test(t, files)
@@ -1343,7 +1343,7 @@ disabled = true
-- layouts/index.html --
Home.
`
b := Test(t, files)
@@ -1438,7 +1438,7 @@ home = ["html"]
-- hugo.toml --
baseURL = "https://example.com"
disableKinds = ["taxonomy", "term", "RSS", "sitemap", "robotsTXT", "page", "section"]
`
runVariant(t, files, nil)
+8 -8
View File
@@ -1500,13 +1500,6 @@ func (sa *sitePagesAssembler) assembleTermsAndTranslations() error {
return false, nil
}
// This is a little out of place, but is conveniently put here.
// Check if translationKey is set by user.
// This is to support the manual way of setting the translationKey in front matter.
if ps.m.pageConfig.TranslationKey != "" {
sa.s.h.translationKeyPages.Append(ps.m.pageConfig.TranslationKey, ps)
}
if sa.pageMap.cfg.taxonomyTermDisabled {
return false, nil
}
@@ -1587,6 +1580,13 @@ func (sa *sitePagesAssembler) assembleResources() error {
Handle: func(s string, n contentNodeI, match doctree.DimensionFlag) (bool, error) {
ps := n.(*pageState)
// This is a little out of place, but is conveniently put here.
// Check if translationKey is set by user.
// This is to support the manual way of setting the translationKey in front matter.
if ps.m.pageConfig.TranslationKey != "" {
sa.s.h.translationKeyPages.Append(ps.m.pageConfig.TranslationKey, ps)
}
// Prepare resources for this page.
ps.shiftToOutputFormat(true, 0)
targetPaths := ps.targetPaths()
@@ -1778,7 +1778,7 @@ func (sa *sitePagesAssembler) addStandalonePages() error {
if sitemapEnabled {
addStandalone("/_sitemap", kinds.KindSitemap, output.SitemapFormat)
skipSitemapIndex := s.Conf.IsMultihost() || !(s.Conf.DefaultContentLanguageInSubdir() || s.Conf.IsMultiLingual())
skipSitemapIndex := s.Conf.IsMultihost() || !(s.Conf.DefaultContentLanguageInSubdir() || s.Conf.IsMultilingual())
if !skipSitemapIndex {
addStandalone("/_sitemapindex", kinds.KindSitemapIndex, output.SitemapIndexFormat)
+2 -2
View File
@@ -315,7 +315,7 @@ func TestStaticFs(t *testing.T) {
checkFileContent(sfs, "f2.txt", c, "Hugo Themes Still Rocks!")
}
func TestStaticFsMultiHost(t *testing.T) {
func TestStaticFsMultihost(t *testing.T) {
c := qt.New(t)
v := config.New()
workDir := "mywork"
@@ -537,7 +537,7 @@ SCSS Match: {{ with resources.Match "**.scss" }}{{ . | len }}|{{ range .}}{{ .Re
b := hugolib.Test(t, files)
b.AssertFileContent("public/index.html", `
b.AssertFileContent("public/index.html", `
SCSS: /scss/app.scss|body { color: blue; }|
SCSS Match: 2|
`)
+5 -1
View File
@@ -269,7 +269,7 @@ func (h *HugoSites) pickOneAndLogTheRest(errors []error) error {
return errors[i]
}
func (h *HugoSites) isMultiLingual() bool {
func (h *HugoSites) isMultilingual() bool {
return len(h.Sites) > 1
}
@@ -410,6 +410,10 @@ type BuildCfg struct {
// shouldRender returns whether this output format should be rendered or not.
func (cfg *BuildCfg) shouldRender(p *pageState) bool {
if p.skipRender() {
return false
}
if !p.renderOnce {
return true
}
+22 -31
View File
@@ -28,16 +28,16 @@ import (
"github.com/bep/logg"
"github.com/gohugoio/hugo/cache/dynacache"
"github.com/gohugoio/hugo/deps"
"github.com/gohugoio/hugo/hugofs"
"github.com/gohugoio/hugo/hugofs/files"
"github.com/gohugoio/hugo/hugofs/glob"
"github.com/gohugoio/hugo/hugolib/segments"
"github.com/gohugoio/hugo/identity"
"github.com/gohugoio/hugo/output"
"github.com/gohugoio/hugo/publisher"
"github.com/gohugoio/hugo/source"
"github.com/gohugoio/hugo/tpl"
"github.com/gohugoio/hugo/hugofs"
"github.com/gohugoio/hugo/common/herrors"
"github.com/gohugoio/hugo/common/loggers"
"github.com/gohugoio/hugo/common/para"
@@ -318,9 +318,20 @@ func (h *HugoSites) render(l logg.LevelLogger, config *BuildCfg) error {
i := 0
for _, s := range h.Sites {
segmentFilter := s.conf.C.SegmentFilter
if segmentFilter.ShouldExcludeCoarse(segments.SegmentMatcherFields{Lang: s.language.Lang}) {
l.Logf("skip language %q not matching segments set in --renderSegments", s.language.Lang)
continue
}
siteRenderContext.languageIdx = s.languagei
h.currentSite = s
for siteOutIdx, renderFormat := range s.renderFormats {
if segmentFilter.ShouldExcludeCoarse(segments.SegmentMatcherFields{Output: renderFormat.Name, Lang: s.language.Lang}) {
l.Logf("skip output format %q for language %q not matching segments set in --renderSegments", renderFormat.Name, s.language.Lang)
continue
}
siteRenderContext.outIdx = siteOutIdx
siteRenderContext.sitesOutIdx = i
i++
@@ -595,8 +606,10 @@ func (h *HugoSites) processPartial(ctx context.Context, l logg.LevelLogger, conf
return sb.String()
}))
// For a list of events for the different OSes, see the test output in https://github.com/bep/fsnotifyeventlister/.
events = h.fileEventsFilter(events)
events = h.fileEventsTranslate(events)
eventInfos := h.fileEventsApplyInfo(events)
logger := h.Log
@@ -631,36 +644,12 @@ func (h *HugoSites) processPartial(ctx context.Context, l logg.LevelLogger, conf
addedContentPaths []*paths.Path
)
for _, ev := range events {
removed := false
added := false
if ev.Op&fsnotify.Remove == fsnotify.Remove {
removed = true
}
fi, statErr := h.Fs.Source.Stat(ev.Name)
// Some editors (Vim) sometimes issue only a Rename operation when writing an existing file
// Sometimes a rename operation means that file has been renamed other times it means
// it's been updated.
if ev.Op.Has(fsnotify.Rename) {
// If the file is still on disk, it's only been updated, if it's not, it's been moved
if statErr != nil {
removed = true
}
}
if ev.Op.Has(fsnotify.Create) {
added = true
}
isChangedDir := statErr == nil && fi.IsDir()
for _, ev := range eventInfos {
cpss := h.BaseFs.ResolvePaths(ev.Name)
pss := make([]*paths.Path, len(cpss))
for i, cps := range cpss {
p := cps.Path
if removed && !paths.HasExt(p) {
if ev.removed && !paths.HasExt(p) {
// Assume this is a renamed/removed directory.
// For deletes, we walk up the tree to find the container (e.g. branch bundle),
// so we will catch this even if it is a file without extension.
@@ -671,7 +660,7 @@ func (h *HugoSites) processPartial(ctx context.Context, l logg.LevelLogger, conf
}
pss[i] = h.Configs.ContentPathParser.Parse(cps.Component, p)
if added && !isChangedDir && cps.Component == files.ComponentFolderContent {
if ev.added && !ev.isChangedDir && cps.Component == files.ComponentFolderContent {
addedContentPaths = append(addedContentPaths, pss[i])
}
@@ -683,9 +672,9 @@ func (h *HugoSites) processPartial(ctx context.Context, l logg.LevelLogger, conf
}
}
if removed {
if ev.removed {
changedPaths.deleted = append(changedPaths.deleted, pss...)
} else if isChangedDir {
} else if ev.isChangedDir {
changedPaths.changedDirs = append(changedPaths.changedDirs, pss...)
} else {
changedPaths.changedFiles = append(changedPaths.changedFiles, pss...)
@@ -792,6 +781,8 @@ func (h *HugoSites) processPartial(ctx context.Context, l logg.LevelLogger, conf
// It's hard to determine the exact change set of this,
// so be very coarse grained for now.
changes = append(changes, identity.GenghisKhan)
case files.ComponentFolderArchetypes:
// Ignore for now.
default:
panic(fmt.Sprintf("unknown component: %q", pathInfo.Component()))
}
+2 -2
View File
@@ -66,12 +66,12 @@ robots|{{ site.Language.Lang }}
404|{{ site.Language.Lang }}
`
b := Test(t, files)
b.Assert(b.H.Conf.IsMultiLingual(), qt.Equals, true)
b.Assert(b.H.Conf.IsMultilingual(), qt.Equals, true)
b.Assert(b.H.Conf.IsMultihost(), qt.Equals, true)
// helpers.PrintFs(b.H.Fs.PublishDir, "", os.Stdout)
+1 -1
View File
@@ -112,6 +112,6 @@ Template: false
Resource1: /js/include.js:END
Resource2: :END
Resource3: :END
Resources: [include.js]
Resources: [/js/include.js]
`)
}
+21
View File
@@ -22,6 +22,7 @@ import (
"github.com/gohugoio/hugo/hugofs"
"github.com/gohugoio/hugo/hugolib/doctree"
"github.com/gohugoio/hugo/hugolib/segments"
"github.com/gohugoio/hugo/identity"
"github.com/gohugoio/hugo/media"
"github.com/gohugoio/hugo/output"
@@ -36,6 +37,7 @@ import (
"github.com/gohugoio/hugo/common/herrors"
"github.com/gohugoio/hugo/common/maps"
"github.com/gohugoio/hugo/common/types"
"github.com/gohugoio/hugo/source"
@@ -151,6 +153,19 @@ func (p *pageState) reusePageOutputContent() bool {
return p.pageOutputTemplateVariationsState.Load() == 1
}
func (p *pageState) skipRender() bool {
b := p.s.conf.C.SegmentFilter.ShouldExcludeFine(
segments.SegmentMatcherFields{
Path: p.Path(),
Kind: p.Kind(),
Lang: p.Lang(),
Output: p.pageOutput.f.Name,
},
)
return b
}
func (po *pageState) isRenderedAny() bool {
for _, o := range po.pageOutputs {
if o.isRendered() {
@@ -731,3 +746,9 @@ func (p pageWithWeight0) Weight0() int {
func (p pageWithWeight0) page() page.Page {
return p.pageState
}
var _ types.Unwrapper = (*pageWithWeight0)(nil)
func (p pageWithWeight0) Unwrapv() any {
return p.pageState
}
+4 -4
View File
@@ -106,9 +106,9 @@ func (p *pageMeta) Aliases() []string {
return p.pageConfig.Aliases
}
// Deprecated: use taxonomies.
// Deprecated: Use taxonomies instead.
func (p *pageMeta) Author() page.Author {
hugo.Deprecate(".Author", "Use taxonomies.", "v0.98.0")
hugo.Deprecate(".Page.Author", "Use taxonomies instead.", "v0.98.0")
authors := p.Authors()
for _, author := range authors {
@@ -117,9 +117,9 @@ func (p *pageMeta) Author() page.Author {
return page.Author{}
}
// Deprecated: use taxonomies.
// Deprecated: Use taxonomies instead.
func (p *pageMeta) Authors() page.AuthorList {
hugo.Deprecate(".Author", "Use taxonomies.", "v0.112.0")
hugo.Deprecate(".Page.Authors", "Use taxonomies instead.", "v0.112.0")
return nil
}
+9 -4
View File
@@ -124,11 +124,16 @@ func (pt pageTree) Parent() page.Page {
return pt.p.s.home
}
_, n := pt.p.s.pageMap.treePages.LongestPrefix(dir, true, nil)
if n != nil {
return n.(page.Page)
for {
_, n := pt.p.s.pageMap.treePages.LongestPrefix(dir, true, nil)
if n == nil {
return pt.p.s.home
}
if pt.p.m.bundled || n.isContentNodeBranch() {
return n.(page.Page)
}
dir = paths.Dir(dir)
}
return nil
}
func (pt pageTree) Ancestors() page.Pages {
+48 -3
View File
@@ -578,7 +578,7 @@ date: 2012-01-12
b.Assert(s.getPageOldVersion("/with-index-no-date").Date().IsZero(), qt.Equals, true)
checkDate(s.getPageOldVersion("/with-index-date"), 2018)
b.Assert(s.Site().LastChange().Year(), qt.Equals, 2018)
b.Assert(s.Site().Lastmod().Year(), qt.Equals, 2018)
}
func TestCreateNewPage(t *testing.T) {
@@ -709,7 +709,7 @@ func TestPageWithShortCodeInSummary(t *testing.T) {
assertFunc := func(t *testing.T, ext string, pages page.Pages) {
p := pages[0]
checkPageTitle(t, p, "Simple")
checkPageContent(t, p, normalizeExpected(ext, "<p>Summary Next Line. <figure><img src=\"/not/real\"/> </figure> . More text here.</p><p>Some more text</p>"))
checkPageContent(t, p, normalizeExpected(ext, "<p>Summary Next Line. <figure><img src=\"/not/real\"> </figure> . More text here.</p><p>Some more text</p>"))
checkPageSummary(t, p, "Summary Next Line. . More text here. Some more text")
checkPageType(t, p, "page")
}
@@ -773,7 +773,7 @@ func TestSummaryManualSplit(t *testing.T) {
title: Simple
---
This is **summary**.
<!--more-->
<!--more-->
This is **content**.
-- layouts/_default/single.html --
Summary: {{ .Summary }}|Truncated: {{ .Truncated }}|
@@ -1350,6 +1350,51 @@ AllTranslations: {{ range .AllTranslations }}{{ .Language.Lang }}|{{ end }}|
)
}
func TestTranslationKeyTermPages(t *testing.T) {
t.Parallel()
files := `
-- hugo.toml --
disableKinds = ['home','rss','section','sitemap','taxonomy']
defaultContentLanguage = 'en'
defaultContentLanguageInSubdir = true
[languages.en]
weight = 1
[languages.pt]
weight = 2
[taxonomies]
category = 'categories'
-- layouts/_default/list.html --
{{ .IsTranslated }}|{{ range .Translations }}{{ .RelPermalink }}|{{ end }}
-- layouts/_default/single.html --
{{ .Title }}|
-- content/p1.en.md --
---
title: p1 (en)
categories: [music]
---
-- content/p1.pt.md --
---
title: p1 (pt)
categories: [música]
---
-- content/categories/music/_index.en.md --
---
title: music
translationKey: foo
---
-- content/categories/música/_index.pt.md --
---
title: música
translationKey: foo
---
`
b := Test(t, files)
b.AssertFileContent("public/en/categories/music/index.html", "true|/pt/categories/m%C3%BAsica/|")
b.AssertFileContent("public/pt/categories/música/index.html", "true|/en/categories/music/|")
}
// Issue #11540.
func TestTranslationKeyResourceSharing(t *testing.T) {
files := `
+1 -1
View File
@@ -161,7 +161,7 @@ func (c *pagesCollector) Collect() (collectErr error) {
// We always start from a directory.
collectErr = c.collectDir(id.p, id.isDir, func(fim hugofs.FileMetaInfo) bool {
if id.delete || id.isDir {
if id.isDir {
if id.isDir && fim.Meta().PathInfo.IsLeafBundle() {
return strings.HasPrefix(fim.Meta().PathInfo.Path(), paths.AddTrailingSlash(id.p.Path()))
}
+18
View File
@@ -1472,3 +1472,21 @@ all: {{ $ab.RelPermalink }}
b.AddFiles("assets/common/c3.css", "c3").Build()
b.AssertFileContent("public/ab.css", "abc1c2 editedc3")
}
func TestRebuildEditArchetypeFile(t *testing.T) {
t.Parallel()
files := `
-- hugo.toml --
baseURL = "https://example.com"
disableLiveReload = true
-- archetypes/default.md --
---
title: "Default"
---
`
b := TestRunning(t, files)
// Just make sure that it doesn't panic.
b.EditFileReplaceAll("archetypes/default.md", "Default", "Default Edited").Build()
}
+257
View File
@@ -0,0 +1,257 @@
// 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 segments
import (
"fmt"
"github.com/gobwas/glob"
"github.com/gohugoio/hugo/common/maps"
"github.com/gohugoio/hugo/common/predicate"
"github.com/gohugoio/hugo/config"
hglob "github.com/gohugoio/hugo/hugofs/glob"
"github.com/mitchellh/mapstructure"
)
// Segments is a collection of named segments.
type Segments struct {
s map[string]excludeInclude
}
type excludeInclude struct {
exclude predicate.P[SegmentMatcherFields]
include predicate.P[SegmentMatcherFields]
}
// ShouldExcludeCoarse returns whether the given fields should be excluded.
// This is used for the coarser grained checks, e.g. language and output format.
// Note that ShouldExcludeCoarse(fields) == ShouldExcludeFine(fields) may
// not always be true, but ShouldExcludeCoarse(fields) == true == ShouldExcludeFine(fields)
// will always be truthful.
func (e excludeInclude) ShouldExcludeCoarse(fields SegmentMatcherFields) bool {
return e.exclude != nil && e.exclude(fields)
}
// ShouldExcludeFine returns whether the given fields should be excluded.
// This is used for the finer grained checks, e.g. on invididual pages.
func (e excludeInclude) ShouldExcludeFine(fields SegmentMatcherFields) bool {
if e.exclude != nil && e.exclude(fields) {
return true
}
return e.include != nil && !e.include(fields)
}
type SegmentFilter interface {
// ShouldExcludeCoarse returns whether the given fields should be excluded on a coarse level.
ShouldExcludeCoarse(SegmentMatcherFields) bool
// ShouldExcludeFine returns whether the given fields should be excluded on a fine level.
ShouldExcludeFine(SegmentMatcherFields) bool
}
type segmentFilter struct {
coarse predicate.P[SegmentMatcherFields]
fine predicate.P[SegmentMatcherFields]
}
func (f segmentFilter) ShouldExcludeCoarse(field SegmentMatcherFields) bool {
return f.coarse(field)
}
func (f segmentFilter) ShouldExcludeFine(fields SegmentMatcherFields) bool {
return f.fine(fields)
}
var (
matchAll = func(SegmentMatcherFields) bool { return true }
matchNothing = func(SegmentMatcherFields) bool { return false }
)
// Get returns a SegmentFilter for the given segments.
func (sms Segments) Get(onNotFound func(s string), ss ...string) SegmentFilter {
if ss == nil {
return segmentFilter{coarse: matchNothing, fine: matchNothing}
}
var sf segmentFilter
for _, s := range ss {
if seg, ok := sms.s[s]; ok {
if sf.coarse == nil {
sf.coarse = seg.ShouldExcludeCoarse
} else {
sf.coarse = sf.coarse.Or(seg.ShouldExcludeCoarse)
}
if sf.fine == nil {
sf.fine = seg.ShouldExcludeFine
} else {
sf.fine = sf.fine.Or(seg.ShouldExcludeFine)
}
} else if onNotFound != nil {
onNotFound(s)
}
}
if sf.coarse == nil {
sf.coarse = matchAll
}
if sf.fine == nil {
sf.fine = matchAll
}
return sf
}
type SegmentConfig struct {
Excludes []SegmentMatcherFields
Includes []SegmentMatcherFields
}
// SegmentMatcherFields is a matcher for a segment include or exclude.
// All of these are Glob patterns.
type SegmentMatcherFields struct {
Kind string
Path string
Lang string
Output string
}
func getGlob(s string) (glob.Glob, error) {
if s == "" {
return nil, nil
}
g, err := hglob.GetGlob(s)
if err != nil {
return nil, fmt.Errorf("failed to compile Glob %q: %w", s, err)
}
return g, nil
}
func compileSegments(f []SegmentMatcherFields) (predicate.P[SegmentMatcherFields], error) {
if f == nil {
return func(SegmentMatcherFields) bool { return false }, nil
}
var (
result predicate.P[SegmentMatcherFields]
section predicate.P[SegmentMatcherFields]
)
addToSection := func(matcherFields SegmentMatcherFields, f func(fields SegmentMatcherFields) string) error {
s1 := f(matcherFields)
g, err := getGlob(s1)
if err != nil {
return err
}
matcher := func(fields SegmentMatcherFields) bool {
s2 := f(fields)
if s2 == "" {
return false
}
return g.Match(s2)
}
if section == nil {
section = matcher
} else {
section = section.And(matcher)
}
return nil
}
for _, fields := range f {
if fields.Kind != "" {
if err := addToSection(fields, func(fields SegmentMatcherFields) string { return fields.Kind }); err != nil {
return result, err
}
}
if fields.Path != "" {
if err := addToSection(fields, func(fields SegmentMatcherFields) string { return fields.Path }); err != nil {
return result, err
}
}
if fields.Lang != "" {
if err := addToSection(fields, func(fields SegmentMatcherFields) string { return fields.Lang }); err != nil {
return result, err
}
}
if fields.Output != "" {
if err := addToSection(fields, func(fields SegmentMatcherFields) string { return fields.Output }); err != nil {
return result, err
}
}
if result == nil {
result = section
} else {
result = result.Or(section)
}
section = nil
}
return result, nil
}
func DecodeSegments(in map[string]any) (*config.ConfigNamespace[map[string]SegmentConfig, Segments], error) {
buildConfig := func(in any) (Segments, any, error) {
sms := Segments{
s: map[string]excludeInclude{},
}
m, err := maps.ToStringMapE(in)
if err != nil {
return sms, nil, err
}
if m == nil {
m = map[string]any{}
}
m = maps.CleanConfigStringMap(m)
var scfgm map[string]SegmentConfig
if err := mapstructure.Decode(m, &scfgm); err != nil {
return sms, nil, err
}
for k, v := range scfgm {
var (
include predicate.P[SegmentMatcherFields]
exclude predicate.P[SegmentMatcherFields]
err error
)
if v.Excludes != nil {
exclude, err = compileSegments(v.Excludes)
if err != nil {
return sms, nil, err
}
}
if v.Includes != nil {
include, err = compileSegments(v.Includes)
if err != nil {
return sms, nil, err
}
}
ei := excludeInclude{
exclude: exclude,
include: include,
}
sms.s[k] = ei
}
return sms, nil, nil
}
ns, err := config.DecodeNamespace[map[string]SegmentConfig](in, buildConfig)
if err != nil {
return nil, fmt.Errorf("failed to decode segments: %w", err)
}
return ns, nil
}
@@ -0,0 +1,76 @@
// 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 segments_test
import (
"testing"
qt "github.com/frankban/quicktest"
"github.com/gohugoio/hugo/hugolib"
)
func TestSegments(t *testing.T) {
files := `
-- hugo.toml --
baseURL = "https://example.org/"
renderSegments = ["docs"]
[languages]
[languages.en]
weight = 1
[languages.no]
weight = 2
[languages.nb]
weight = 3
[segments]
[segments.docs]
[[segments.docs.includes]]
kind = "{home,taxonomy,term}"
[[segments.docs.includes]]
path = "{/docs,/docs/**}"
[[segments.docs.excludes]]
path = "/blog/**"
[[segments.docs.excludes]]
lang = "n*"
output = "rss"
[[segments.docs.excludes]]
output = "json"
-- layouts/_default/single.html --
Single: {{ .Title }}|{{ .RelPermalink }}|
-- layouts/_default/list.html --
List: {{ .Title }}|{{ .RelPermalink }}|
-- content/docs/_index.md --
-- content/docs/section1/_index.md --
-- content/docs/section1/page1.md --
---
title: "Docs Page 1"
tags: ["tag1", "tag2"]
---
-- content/blog/_index.md --
-- content/blog/section1/page1.md --
---
title: "Blog Page 1"
tags: ["tag1", "tag2"]
---
`
b := hugolib.Test(t, files)
b.Assert(b.H.Configs.Base.RootConfig.RenderSegments, qt.DeepEquals, []string{"docs"})
b.AssertFileContent("public/docs/section1/page1/index.html", "Docs Page 1")
b.AssertFileExists("public/blog/section1/page1/index.html", false)
b.AssertFileExists("public/index.html", true)
b.AssertFileExists("public/index.xml", true)
b.AssertFileExists("public/no/index.html", true)
b.AssertFileExists("public/no/index.xml", false)
}
+115
View File
@@ -0,0 +1,115 @@
package segments
import (
"testing"
qt "github.com/frankban/quicktest"
)
func TestCompileSegments(t *testing.T) {
c := qt.New(t)
c.Run("excludes", func(c *qt.C) {
fields := []SegmentMatcherFields{
{
Lang: "n*",
Output: "rss",
},
}
match, err := compileSegments(fields)
c.Assert(err, qt.IsNil)
check := func() {
c.Assert(match, qt.IsNotNil)
c.Assert(match(SegmentMatcherFields{Lang: "no"}), qt.Equals, false)
c.Assert(match(SegmentMatcherFields{Lang: "no", Kind: "page"}), qt.Equals, false)
c.Assert(match(SegmentMatcherFields{Lang: "no", Output: "rss"}), qt.Equals, true)
c.Assert(match(SegmentMatcherFields{Lang: "no", Output: "html"}), qt.Equals, false)
c.Assert(match(SegmentMatcherFields{Kind: "page"}), qt.Equals, false)
c.Assert(match(SegmentMatcherFields{Lang: "no", Output: "rss", Kind: "page"}), qt.Equals, true)
}
check()
fields = []SegmentMatcherFields{
{
Path: "/blog/**",
},
{
Lang: "n*",
Output: "rss",
},
}
match, err = compileSegments(fields)
c.Assert(err, qt.IsNil)
check()
c.Assert(match(SegmentMatcherFields{Path: "/blog/foo"}), qt.Equals, true)
})
c.Run("includes", func(c *qt.C) {
fields := []SegmentMatcherFields{
{
Path: "/docs/**",
},
{
Lang: "no",
Output: "rss",
},
}
match, err := compileSegments(fields)
c.Assert(err, qt.IsNil)
c.Assert(match, qt.IsNotNil)
c.Assert(match(SegmentMatcherFields{Lang: "no"}), qt.Equals, false)
c.Assert(match(SegmentMatcherFields{Kind: "page"}), qt.Equals, false)
c.Assert(match(SegmentMatcherFields{Kind: "page", Path: "/blog/foo"}), qt.Equals, false)
c.Assert(match(SegmentMatcherFields{Lang: "en"}), qt.Equals, false)
c.Assert(match(SegmentMatcherFields{Lang: "no", Output: "rss"}), qt.Equals, true)
c.Assert(match(SegmentMatcherFields{Lang: "no", Output: "html"}), qt.Equals, false)
c.Assert(match(SegmentMatcherFields{Kind: "page", Path: "/docs/foo"}), qt.Equals, true)
})
c.Run("includes variant1", func(c *qt.C) {
c.Skip()
fields := []SegmentMatcherFields{
{
Kind: "home",
},
{
Path: "{/docs,/docs/**}",
},
}
match, err := compileSegments(fields)
c.Assert(err, qt.IsNil)
c.Assert(match, qt.IsNotNil)
c.Assert(match(SegmentMatcherFields{Path: "/blog/foo"}), qt.Equals, false)
c.Assert(match(SegmentMatcherFields{Kind: "page", Path: "/docs/foo"}), qt.Equals, true)
c.Assert(match(SegmentMatcherFields{Kind: "home", Path: "/"}), qt.Equals, true)
})
}
func BenchmarkSegmentsMatch(b *testing.B) {
fields := []SegmentMatcherFields{
{
Path: "/docs/**",
},
{
Lang: "no",
Output: "rss",
},
}
match, err := compileSegments(fields)
if err != nil {
b.Fatal(err)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
match(SegmentMatcherFields{Lang: "no", Output: "rss"})
}
}
+74 -12
View File
@@ -19,6 +19,7 @@ import (
"io"
"mime"
"net/url"
"os"
"path/filepath"
"runtime"
"sort"
@@ -297,7 +298,6 @@ func (s *siteRefLinker) refLink(ref string, source any, relative bool, outputFor
ref = filepath.ToSlash(ref)
refURL, err = url.Parse(ref)
if err != nil {
return s.notFoundURL, err
}
@@ -427,6 +427,73 @@ func (h *HugoSites) fileEventsFilter(events []fsnotify.Event) []fsnotify.Event {
return events[:n]
}
type fileEventInfo struct {
fsnotify.Event
fi os.FileInfo
added bool
removed bool
isChangedDir bool
}
func (h *HugoSites) fileEventsApplyInfo(events []fsnotify.Event) []fileEventInfo {
var infos []fileEventInfo
for _, ev := range events {
removed := false
added := false
if ev.Op&fsnotify.Remove == fsnotify.Remove {
removed = true
}
fi, statErr := h.Fs.Source.Stat(ev.Name)
// Some editors (Vim) sometimes issue only a Rename operation when writing an existing file
// Sometimes a rename operation means that file has been renamed other times it means
// it's been updated.
if ev.Op.Has(fsnotify.Rename) {
// If the file is still on disk, it's only been updated, if it's not, it's been moved
if statErr != nil {
removed = true
}
}
if ev.Op.Has(fsnotify.Create) {
added = true
}
isChangedDir := statErr == nil && fi.IsDir()
infos = append(infos, fileEventInfo{
Event: ev,
fi: fi,
added: added,
removed: removed,
isChangedDir: isChangedDir,
})
}
n := 0
for _, ev := range infos {
// Remove any directories that's also represented by a file.
keep := true
if ev.isChangedDir {
for _, ev2 := range infos {
if ev2.fi != nil && !ev2.fi.IsDir() && filepath.Dir(ev2.Name) == ev.Name {
keep = false
break
}
}
}
if keep {
infos[n] = ev
n++
}
}
infos = infos[:n]
return infos
}
func (h *HugoSites) fileEventsTranslate(events []fsnotify.Event) []fsnotify.Event {
eventMap := make(map[string][]fsnotify.Event)
@@ -531,18 +598,13 @@ func (h *HugoSites) fileEventsContentPaths(p []pathChange) []pathChange {
return keepers
}
// HomeAbsURL is a convenience method giving the absolute URL to the home page.
func (s *Site) HomeAbsURL() string {
base := ""
if len(s.conf.Languages) > 1 {
base = s.Language().Lang
}
return s.AbsURL(base, false)
}
// SitemapAbsURL is a convenience method giving the absolute URL to the sitemap.
func (s *Site) SitemapAbsURL() string {
p := s.HomeAbsURL()
base := ""
if len(s.conf.Languages) > 1 || s.Conf.DefaultContentLanguageInSubdir() {
base = s.Language().Lang
}
p := s.AbsURL(base, false)
if !strings.HasSuffix(p, "/") {
p += "/"
}
@@ -681,7 +743,7 @@ func (s *Site) getLanguagePermalinkLang(alwaysInSubDir bool) string {
return ""
}
if s.h.Conf.IsMultiLingual() && alwaysInSubDir {
if s.h.Conf.IsMultilingual() && alwaysInSubDir {
return s.Language().Lang
}
+16 -8
View File
@@ -361,8 +361,7 @@ func newHugoSites(cfg deps.DepsCfg, d *deps.Deps, pageTrees *pageTrees, sites []
return h, nil
}
// Returns true if we're running in a server.
// Deprecated: use hugo.IsServer instead
// Deprecated: Use hugo.IsServer instead.
func (s *Site) IsServer() bool {
hugo.Deprecate(".Site.IsServer", "Use hugo.IsServer instead.", "v0.120.0")
return s.conf.Internal.Running
@@ -382,8 +381,9 @@ func (s *Site) Copyright() string {
return s.conf.Copyright
}
// Deprecated: Use .Site.Home.OutputFormats.Get "rss" instead.
func (s *Site) RSSLink() template.URL {
hugo.Deprecate("Site.RSSLink", "Use the Output Format's Permalink method instead, e.g. .OutputFormats.Get \"RSS\".Permalink", "v0.114.0")
hugo.Deprecate(".Site.RSSLink", "Use the Output Format's Permalink method instead, e.g. .OutputFormats.Get \"RSS\".Permalink", "v0.114.0")
rssOutputFormat := s.home.OutputFormats().Get("rss")
return template.URL(rssOutputFormat.Permalink())
}
@@ -431,9 +431,9 @@ func (s *Site) BaseURL() string {
return s.conf.C.BaseURL.WithPath
}
// Returns the last modification date of the content.
// Deprecated: Use .Lastmod instead.
// Deprecated: Use .Site.Lastmod instead.
func (s *Site) LastChange() time.Time {
hugo.Deprecate(".Site.LastChange", "Use .Site.Lastmod instead.", "v0.123.0")
return s.lastmod
}
@@ -447,25 +447,31 @@ func (s *Site) Params() maps.Params {
return s.conf.Params
}
// Deprecated: Use taxonomies instead.
func (s *Site) Author() map[string]any {
hugo.Deprecate(".Site.Author", "Use taxonomies instead.", "v0.124.0")
return s.conf.Author
}
// Deprecated: Use taxonomies instead.
func (s *Site) Authors() page.AuthorList {
hugo.Deprecate(".Site.Authors", "Use taxonomies instead.", "v0.124.0")
return page.AuthorList{}
}
// Deprecated: Use .Site.Params instead.
func (s *Site) Social() map[string]string {
hugo.Deprecate(".Site.Social", "Use .Site.Params instead.", "v0.124.0")
return s.conf.Social
}
// Deprecated: Use .Site.Config.Services.Disqus.Shortname instead
// Deprecated: Use .Site.Config.Services.Disqus.Shortname instead.
func (s *Site) DisqusShortname() string {
hugo.Deprecate(".Site.DisqusShortname", "Use .Site.Config.Services.Disqus.Shortname instead.", "v0.120.0")
return s.Config().Services.Disqus.Shortname
}
// Deprecated: Use .Site.Config.Services.GoogleAnalytics.ID instead
// Deprecated: Use .Site.Config.Services.GoogleAnalytics.ID instead.
func (s *Site) GoogleAnalytics() string {
hugo.Deprecate(".Site.GoogleAnalytics", "Use .Site.Config.Services.GoogleAnalytics.ID instead.", "v0.120.0")
return s.Config().Services.GoogleAnalytics.ID
@@ -484,8 +490,10 @@ func (s *Site) BuildDrafts() bool {
return s.conf.BuildDrafts
}
// Deprecated: Use hugo.IsMultilingual instead.
func (s *Site) IsMultiLingual() bool {
return s.h.isMultiLingual()
hugo.Deprecate(".Site.IsMultiLingual", "Use hugo.IsMultilingual instead.", "v0.124.0")
return s.h.isMultilingual()
}
func (s *Site) LanguagePrefix() string {
+2 -2
View File
@@ -271,7 +271,7 @@ func (s *Site) renderAliases() error {
p := n.(*pageState)
// We cannot alias a page that's not rendered.
if p.m.noLink() {
if p.m.noLink() || p.skipRender() {
return false, nil
}
@@ -334,7 +334,7 @@ func (s *Site) renderAliases() error {
// renderMainLanguageRedirect creates a redirect to the main language home,
// depending on if it lives in sub folder (e.g. /en) or not.
func (s *Site) renderMainLanguageRedirect() error {
if s.h.Conf.IsMultihost() || !(s.h.Conf.DefaultContentLanguageInSubdir() || s.h.Conf.IsMultiLingual()) {
if s.h.Conf.IsMultihost() || !(s.h.Conf.DefaultContentLanguageInSubdir() || s.h.Conf.IsMultilingual()) {
// No need for a redirect
return nil
}
+23
View File
@@ -398,3 +398,26 @@ Kind: {{ .Kind }}|RelPermalink: {{ .RelPermalink }}|SectionsPath: {{ .SectionsPa
b.AssertFileContent("public/a/b/c/mybundle/index.html", "Kind: page|RelPermalink: /a/b/c/mybundle/|SectionsPath: /a/b/c|SectionsEntries: [a b c]|Len: 3")
b.AssertFileContent("public/index.html", "Kind: home|RelPermalink: /|SectionsPath: /|SectionsEntries: []|Len: 0")
}
func TestParentWithPageOverlap(t *testing.T) {
files := `
-- hugo.toml --
baseURL = "https://example.com/"
-- content/docs/_index.md --
-- content/docs/logs/_index.md --
-- content/docs/logs/sdk.md --
-- content/docs/logs/sdk_exporters/stdout.md --
-- layouts/_default/list.html --
{{ .RelPermalink }}|{{ with .Parent}}{{ .RelPermalink }}{{ end }}|
-- layouts/_default/single.html --
{{ .RelPermalink }}|{{ with .Parent}}{{ .RelPermalink }}{{ end }}|
`
b := Test(t, files)
b.AssertFileContent("public/index.html", "/||")
b.AssertFileContent("public/docs/index.html", "/docs/|/|")
b.AssertFileContent("public/docs/logs/index.html", "/docs/logs/|/docs/|")
b.AssertFileContent("public/docs/logs/sdk/index.html", "/docs/logs/sdk/|/docs/logs/|")
b.AssertFileContent("public/docs/logs/sdk_exporters/stdout/index.html", "/docs/logs/sdk_exporters/stdout/|/docs/logs/|")
}
+56 -1
View File
@@ -15,6 +15,7 @@ package hugolib
import (
"reflect"
"strings"
"testing"
"github.com/gohugoio/hugo/config"
@@ -127,7 +128,7 @@ func TestParseSitemap(t *testing.T) {
func TestSitemapShouldNotUseListXML(t *testing.T) {
t.Parallel()
files := `
files := `
-- hugo.toml --
baseURL = "https://example.com"
disableKinds = ["term", "taxonomy"]
@@ -170,3 +171,57 @@ type: sitemap
b.AssertFileExists("public/sitemap.xml", true)
}
// Issue 12266
func TestSitemapIssue12266(t *testing.T) {
t.Parallel()
files := `
-- hugo.toml --
baseURL = 'https://example.org/'
disableKinds = ['rss','taxonomy','term']
defaultContentLanguage = 'en'
defaultContentLanguageInSubdir = true
[languages.de]
[languages.en]
`
// Test A: multilingual with defaultContentLanguageInSubdir = true
b := Test(t, files)
b.AssertFileContent("public/sitemap.xml",
"<loc>https://example.org/de/sitemap.xml</loc>",
"<loc>https://example.org/en/sitemap.xml</loc>",
)
b.AssertFileContent("public/de/sitemap.xml", "<loc>https://example.org/de/</loc>")
b.AssertFileContent("public/en/sitemap.xml", "<loc>https://example.org/en/</loc>")
// Test B: multilingual with defaultContentLanguageInSubdir = false
files = strings.ReplaceAll(files, "defaultContentLanguageInSubdir = true", "defaultContentLanguageInSubdir = false")
b = Test(t, files)
b.AssertFileContent("public/sitemap.xml",
"<loc>https://example.org/de/sitemap.xml</loc>",
"<loc>https://example.org/en/sitemap.xml</loc>",
)
b.AssertFileContent("public/de/sitemap.xml", "<loc>https://example.org/de/</loc>")
b.AssertFileContent("public/en/sitemap.xml", "<loc>https://example.org/</loc>")
// Test C: monolingual with defaultContentLanguageInSubdir = false
files = strings.ReplaceAll(files, "[languages.de]", "")
files = strings.ReplaceAll(files, "[languages.en]", "")
b = Test(t, files)
b.AssertFileExists("public/en/sitemap.xml", false)
b.AssertFileContent("public/sitemap.xml", "<loc>https://example.org/</loc>")
// Test D: monolingual with defaultContentLanguageInSubdir = true
files = strings.ReplaceAll(files, "defaultContentLanguageInSubdir = false", "defaultContentLanguageInSubdir = true")
b = Test(t, files)
b.AssertFileContent("public/sitemap.xml", "<loc>https://example.org/en/sitemap.xml</loc>")
b.AssertFileContent("public/en/sitemap.xml", "<loc>https://example.org/en/</loc>")
}
+3 -2
View File
@@ -1,7 +1,8 @@
# Release env.
# These will be replaced by script before release.
HUGORELEASER_TAG=v0.123.7
HUGORELEASER_COMMITISH=312735366b20d64bd61bff8627f593749f86c964
HUGORELEASER_TAG=v0.123.8
HUGORELEASER_COMMITISH=5fed9c591b694f314e5939548e11cc3dcb79a79c
+1 -1
View File
@@ -355,7 +355,7 @@ func (im *identityManager) String() string {
}
func (im *identityManager) forEeachIdentity(fn func(id Identity) bool) bool {
// The absense of a lock here is debliberate. This is currently opnly used on server reloads
// The absence of a lock here is deliberate. This is currently only used on server reloads
// in a single-threaded context.
for id := range im.ids {
if fn(id) {
+1 -1
View File
@@ -134,7 +134,7 @@ var commonTestScriptsParam = testscript.Params{
fmt.Fprintf(ts.Stdout(), "%s %04o %s %s\n", fi.Mode(), fi.Mode().Perm(), fi.ModTime().Format(time.RFC3339Nano), fi.Name())
}
},
// append appends to a file with a leaading newline.
// append appends to a file with a leading newline.
"append": func(ts *testscript.TestScript, neg bool, args []string) {
if len(args) < 2 {
ts.Fatalf("usage: append FILE TEXT")
+1 -1
View File
@@ -147,7 +147,7 @@ type codeBlockContext struct {
ordinal int
// This is only used in error situations and is expensive to create,
// to deleay creation until needed.
// to delay creation until needed.
pos htext.Position
posInit sync.Once
createPos func() htext.Position
+5 -3
View File
@@ -184,9 +184,11 @@ func newMarkdown(pcfg converter.ProviderConfig) goldmark.Markdown {
}
}
extensions = append(extensions, passthrough.NewPassthroughWithDelimiters(
inlineDelimiters,
blockDelimiters,
extensions = append(extensions, passthrough.New(
passthrough.Config{
InlineDelimiters: inlineDelimiters,
BlockDelimiters: blockDelimiters,
},
))
}
+2 -2
View File
@@ -95,7 +95,7 @@ func New(astAttributes []ast.Attribute, ownerType AttributesOwnerType) *Attribut
case []byte:
// Note that we don't do any HTML escaping here.
// We used to do that, but that changed in #9558.
// Noww it's up to the templates to decide.
// Now it's up to the templates to decide.
vv = string(vvv)
default:
panic(fmt.Sprintf("not implemented: %T", vvv))
@@ -175,7 +175,7 @@ func (a *AttributesHolder) OptionsSlice() []Attribute {
// RenderASTAttributes writes the AST attributes to the given as attributes to an HTML element.
// This is used by the default HTML renderers, e.g. for headings etc. where no hook template could be found.
// This performs HTML esacaping of string attributes.
// This performs HTML escaping of string attributes.
func RenderASTAttributes(w hugio.FlexiWriter, attributes ...ast.Attribute) {
for _, attr := range attributes {
+3 -3
View File
@@ -86,7 +86,7 @@ func ApplyProjectConfigDefaults(mod Module, cfgs ...config.AllProvider) error {
first := cfgs[0]
dirsBase := first.DirsBase()
isMultiHost := first.IsMultihost()
isMultihost := first.IsMultihost()
for i, cfg := range cfgs {
dirs := cfg.Dirs()
@@ -113,7 +113,7 @@ func ApplyProjectConfigDefaults(mod Module, cfgs ...config.AllProvider) error {
dir = dirs.AssetDir
case files.ComponentFolderStatic:
// For static dirs, we only care about the language in multihost setups.
dropLang = !isMultiHost
dropLang = !isMultihost
}
var perLang bool
@@ -270,7 +270,7 @@ type Config struct {
// When enabled, we will pick the vendored module closest to the module
// using it.
// The default behaviour is to pick the first.
// The default behavior is to pick the first.
// Note that there can still be only one dependency of a given module path,
// so once it is in use it cannot be redefined.
VendorClosest bool
+1 -1
View File
@@ -29,7 +29,7 @@ import (
const commitPrefix = "releaser:"
// New initialises a ReleaseHandler.
// New initializes a ReleaseHandler.
func New(skipPush, try bool, step int) (*ReleaseHandler, error) {
if step < 1 || step > 2 {
return nil, fmt.Errorf("step must be 1 or 2")
+2 -2
View File
@@ -52,9 +52,9 @@ type AlternativeOutputFormatsProvider interface {
// AuthorProvider provides author information.
type AuthorProvider interface {
// Deprecated.
// Deprecated: Use taxonomies instead.
Author() Author
// Deprecated.
// Deprecated: Use taxonomies instead.
Authors() AuthorList
}
+3
View File
@@ -14,9 +14,11 @@
package page
// AuthorList is a list of all authors and their metadata.
// Deprecated: Use taxonomies instead.
type AuthorList map[string]Author
// Author contains details about the author of a page.
// Deprecated: Use taxonomies instead.
type Author struct {
GivenName string
FamilyName string
@@ -41,4 +43,5 @@ type Author struct {
// - youtube
// - linkedin
// - skype
// Deprecated: Use taxonomies instead.
type AuthorSocial map[string]string
+9 -4
View File
@@ -157,10 +157,11 @@ func TestDecodeCascadeConfig(t *testing.T) {
}
type testConfig struct {
environment string
running bool
workingDir string
multihost bool
environment string
running bool
workingDir string
multihost bool
multilingual bool
}
func (c testConfig) Environment() string {
@@ -179,6 +180,10 @@ func (c testConfig) IsMultihost() bool {
return c.multihost
}
func (c testConfig) IsMultilingual() bool {
return c.multilingual
}
func TestIsGlobWithExtension(t *testing.T) {
c := qt.New(t)
+2
View File
@@ -79,10 +79,12 @@ func (p *nopPage) RSSLink() template.URL {
return ""
}
// Deprecated: Use taxonomies instead.
func (p *nopPage) Author() Author {
return Author{}
}
// Deprecated: Use taxonomies instead.
func (p *nopPage) Authors() AuthorList {
return nil
}
+10 -6
View File
@@ -421,18 +421,22 @@ func (f *frontmatterFieldHandlers) newDateFieldHandler(key string, setter func(d
return false, nil
}
date, err := htime.ToTimeInDefaultLocationE(v, d.Location)
if err != nil {
return false, nil
var date time.Time
if vt, ok := v.(time.Time); ok && vt.Location() == d.Location {
date = vt
} else {
var err error
date, err = htime.ToTimeInDefaultLocationE(v, d.Location)
if err != nil {
return false, nil
}
d.PageConfig.Params[key] = date
}
// We map several date keys to one, so, for example,
// "expirydate", "unpublishdate" will all set .ExpiryDate (first found).
setter(d, date)
// This is the params key as set in front matter.
d.PageConfig.Params[key] = date
return true, nil
}
}
@@ -0,0 +1,45 @@
// 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 pagemeta_test
import (
"testing"
"github.com/gohugoio/hugo/hugolib"
)
func TestLastModEq(t *testing.T) {
files := `
-- hugo.toml --
timeZone = "Europe/London"
-- content/p1.md --
---
title: p1
date: 2024-03-13T06:00:00
---
-- layouts/_default/single.html --
Date: {{ .Date }}
Lastmod: {{ .Lastmod }}
Eq: {{ eq .Date .Lastmod }}
`
b := hugolib.Test(t, files)
b.AssertFileContent("public/p1/index.html", `
Date: 2024-03-13 06:00:00 &#43;0000 GMT
Lastmod: 2024-03-13 06:00:00 &#43;0000 GMT
Eq: true
`)
}
+26 -18
View File
@@ -54,8 +54,7 @@ type Site interface {
// A shortcut to the home
Home() Page
// Returns true if we're running in a server.
// Deprecated: use hugo.IsServer instead
// Deprecated: Use hugo.IsServer instead.
IsServer() bool
// Returns the server port.
@@ -64,7 +63,6 @@ type Site interface {
// Returns the configured title for this Site.
Title() string
// Returns the configured language code for this Site.
// Deprecated: Use .Language.LanguageCode instead.
LanguageCode() string
@@ -86,7 +84,6 @@ type Site interface {
// Returns a taxonomy map.
Taxonomies() TaxonomyList
// Returns the last modification date of the content.
// Deprecated: Use .Lastmod instead.
LastChange() time.Time
@@ -111,13 +108,13 @@ type Site interface {
// Returns the site config.
Config() SiteConfig
// Author is deprecated and will be removed in a future release.
// Deprecated: Use taxonomies instead.
Author() map[string]interface{}
// Authors is deprecated and will be removed in a future release.
// Deprecated: Use taxonomies instead.
Authors() AuthorList
// Returns the social links for this site.
// Deprecated: Use .Site.Params instead.
Social() map[string]string
// Deprecated: Use Config().Services.GoogleAnalytics instead.
@@ -129,13 +126,13 @@ type Site interface {
// BuildDrafts is deprecated and will be removed in a future release.
BuildDrafts() bool
// IsMultiLingual reports whether this site is configured with more than one language.
// Deprecated: Use hugo.IsMultilingual instead.
IsMultiLingual() bool
// LanguagePrefix returns the language prefix for this site.
LanguagePrefix() string
// Deprecated. Use site.Home.OutputFormats.Get "rss" instead.
// Deprecated: Use .Site.Home.OutputFormats.Get "rss" instead.
RSSLink() template.URL
}
@@ -168,19 +165,22 @@ func (s *siteWrapper) Key() string {
return s.s.Language().Lang
}
// // Deprecated: Use .Site.Params instead.
func (s *siteWrapper) Social() map[string]string {
return s.s.Social()
}
// Deprecated: Use taxonomies instead.
func (s *siteWrapper) Author() map[string]interface{} {
return s.s.Author()
}
// Deprecated: Use taxonomies instead.
func (s *siteWrapper) Authors() AuthorList {
return AuthorList{}
return s.s.Authors()
}
// Deprecated: Use .Site.Config.Services.GoogleAnalytics.ID instead
// Deprecated: Use .Site.Config.Services.GoogleAnalytics.ID instead.
func (s *siteWrapper) GoogleAnalytics() string {
return s.s.GoogleAnalytics()
}
@@ -217,7 +217,7 @@ func (s *siteWrapper) Home() Page {
return s.s.Home()
}
// Deprecated: use hugo.IsServer instead
// Deprecated: Use hugo.IsServer instead.
func (s *siteWrapper) IsServer() bool {
return s.s.IsServer()
}
@@ -262,9 +262,9 @@ func (s *siteWrapper) Taxonomies() TaxonomyList {
return s.s.Taxonomies()
}
// Deprecated: Use .Site.Lastmod instead.
func (s *siteWrapper) LastChange() time.Time {
hugo.Deprecate(".Site.LastChange", "Use .Site.Lastmod instead.", "v0.123.0")
return s.s.Lastmod()
return s.s.LastChange()
}
func (s *siteWrapper) Lastmod() time.Time {
@@ -295,11 +295,12 @@ func (s *siteWrapper) BuildDrafts() bool {
return s.s.BuildDrafts()
}
// Deprecated: Use hugo.IsMultilingual instead.
func (s *siteWrapper) IsMultiLingual() bool {
return s.s.IsMultiLingual()
}
// Deprecated: Use .Site.Config.Services.Disqus.Shortname instead
// Deprecated: Use .Site.Config.Services.Disqus.Shortname instead.
func (s *siteWrapper) DisqusShortname() string {
return s.s.DisqusShortname()
}
@@ -308,6 +309,7 @@ func (s *siteWrapper) LanguagePrefix() string {
return s.s.LanguagePrefix()
}
// Deprecated: Use .Site.Home.OutputFormats.Get "rss" instead.
func (s *siteWrapper) RSSLink() template.URL {
return s.s.RSSLink()
}
@@ -322,14 +324,17 @@ type testSite struct {
l *langs.Language
}
// Deprecated: Use taxonomies instead.
func (s testSite) Author() map[string]interface{} {
return nil
}
// Deprecated: Use taxonomies instead.
func (s testSite) Authors() AuthorList {
return AuthorList{}
}
// Deprecated: Use .Site.Params instead.
func (s testSite) Social() map[string]string {
return make(map[string]string)
}
@@ -342,6 +347,7 @@ func (t testSite) ServerPort() int {
return 1313
}
// Deprecated: Use .Site.Lastmod instead.
func (testSite) LastChange() (t time.Time) {
return
}
@@ -386,7 +392,7 @@ func (t testSite) Languages() langs.Languages {
return nil
}
// Deprecated: Use .Site.Config.Services.GoogleAnalytics.ID instead
// Deprecated: Use .Site.Config.Services.GoogleAnalytics.ID instead.
func (t testSite) GoogleAnalytics() string {
return ""
}
@@ -395,7 +401,7 @@ func (t testSite) MainSections() []string {
return nil
}
// Deprecated: use hugo.IsServer instead
// Deprecated: Use hugo.IsServer instead.
func (t testSite) IsServer() bool {
return false
}
@@ -444,7 +450,7 @@ func (s testSite) Config() SiteConfig {
return SiteConfig{}
}
// Deprecated: Use .Site.Config.Services.Disqus.Shortname instead
// Deprecated: Use .Site.Config.Services.Disqus.Shortname instead.
func (testSite) DisqusShortname() string {
return ""
}
@@ -453,6 +459,7 @@ func (s testSite) BuildDrafts() bool {
return false
}
// Deprecated: Use hugo.IsMultilingual instead.
func (s testSite) IsMultiLingual() bool {
return false
}
@@ -461,6 +468,7 @@ func (s testSite) Param(key any) (any, error) {
return nil, nil
}
// Deprecated: Use .Site.Home.OutputFormats.Get "rss" instead.
func (s testSite) RSSLink() template.URL {
return ""
}
+2
View File
@@ -127,10 +127,12 @@ func (p *testPage) AlternativeOutputFormats() OutputFormats {
panic("testpage: not implemented")
}
// Deprecated: Use taxonomies instead.
func (p *testPage) Author() Author {
return Author{}
}
// Deprecated: Use taxonomies instead.
func (p *testPage) Authors() AuthorList {
return nil
}
+12 -10
View File
@@ -18,6 +18,7 @@ import (
"fmt"
"strings"
"github.com/gohugoio/hugo/common/paths"
"github.com/gohugoio/hugo/hugofs/glob"
"github.com/spf13/cast"
)
@@ -61,13 +62,14 @@ func (r Resources) Get(name any) Resource {
if err != nil {
panic(err)
}
namestr = strings.ToLower(namestr)
namestr = paths.AddLeadingSlash(namestr)
// First check the Name.
// Note that this can be modified by the user in the front matter,
// also, it does not contain any language code.
for _, resource := range r {
if strings.EqualFold(namestr, resource.Name()) {
if strings.EqualFold(namestr, paths.AddLeadingSlash(resource.Name())) {
return resource
}
}
@@ -75,7 +77,7 @@ func (r Resources) Get(name any) Resource {
// Finally, check the normalized name.
for _, resource := range r {
if nop, ok := resource.(NameNormalizedProvider); ok {
if strings.EqualFold(namestr, nop.NameNormalized()) {
if strings.EqualFold(namestr, paths.AddLeadingSlash(nop.NameNormalized())) {
return resource
}
}
@@ -92,21 +94,21 @@ func (r Resources) GetMatch(pattern any) Resource {
panic(err)
}
g, err := glob.GetGlob(patternstr)
g, err := glob.GetGlob(paths.AddLeadingSlash(patternstr))
if err != nil {
panic(err)
}
for _, resource := range r {
if g.Match(resource.Name()) {
if g.Match(paths.AddLeadingSlash(resource.Name())) {
return resource
}
}
// Finally, check the original name.
// Finally, check the normalized name.
for _, resource := range r {
if nop, ok := resource.(NameNormalizedProvider); ok {
if g.Match(nop.NameNormalized()) {
if g.Match(paths.AddLeadingSlash(nop.NameNormalized())) {
return resource
}
}
@@ -130,14 +132,14 @@ func (r Resources) Match(pattern any) Resources {
panic(err)
}
g, err := glob.GetGlob(patternstr)
g, err := glob.GetGlob(paths.AddLeadingSlash(patternstr))
if err != nil {
panic(err)
}
var matches Resources
for _, resource := range r {
if g.Match(resource.Name()) {
if g.Match(paths.AddLeadingSlash(resource.Name())) {
matches = append(matches, resource)
}
}
@@ -145,7 +147,7 @@ func (r Resources) Match(pattern any) Resources {
// Fall back to the normalized name.
for _, resource := range r {
if nop, ok := resource.(NameNormalizedProvider); ok {
if g.Match(nop.NameNormalized()) {
if g.Match(paths.AddLeadingSlash(nop.NameNormalized())) {
matches = append(matches, resource)
}
}
@@ -134,8 +134,8 @@ func (c *Client) match(name, pattern string, matchFunc func(r resource.Resource)
OpenReadSeekCloser: func() (hugio.ReadSeekCloser, error) {
return meta.Open()
},
NameNormalized: meta.PathInfo.Name(),
NameOriginal: meta.PathInfo.Unnormalized().Name(),
NameNormalized: meta.PathInfo.Path(),
NameOriginal: meta.PathInfo.Unnormalized().Path(),
GroupIdentity: meta.PathInfo,
TargetPath: meta.PathInfo.Unnormalized().Path(),
})
@@ -11,7 +11,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// Package dartsass integrates with the Dass Sass Embedded protocol to transpile
// Package dartsass integrates with the Dart Sass Embedded protocol to transpile
// SCSS/SASS.
package dartsass
@@ -181,7 +181,7 @@ func (t importResolver) CanonicalizeURL(url string) (string, error) {
}
}
// Not found, let Dart Dass handle it
// Not found, let Dart Sass handle it
return "", nil
}
+2 -1
View File
@@ -16,7 +16,8 @@ import (
)
func main() {
// The current is built with 446a5dcf5a3230ce9832682d8f521071d8a34a2b (go 1.22 dev. Thu Oct 5 12:20:11 2023 -0700)
// The current is built with db6097f8cb [release-branch.go1.22] go1.22.1
// TODO(bep) preserve the staticcheck.conf file.
fmt.Println("Forking ...")
defer fmt.Println("Done ...")
+29 -25
View File
@@ -1,5 +1,5 @@
name: hugo
base: core20
base: core22
confinement: strict
adopt-info: hugo
title: Hugo
@@ -75,19 +75,19 @@ environment:
npm_config_userconfig: $SNAP_USER_DATA/.npmrc
pandoc_datadir: $SNAP/usr/share/pandoc
PYTHONHOME: /usr:$SNAP/usr
RUBYLIB: $SNAP/usr/lib/ruby/vendor_ruby/2.7.0:$SNAP/usr/lib/$SNAPCRAFT_ARCH_TRIPLET/ruby/vendor_ruby/2.7.0:$SNAP/usr/lib/ruby/vendor_ruby:$SNAP/usr/lib/ruby/2.7.0:$SNAP/usr/lib/$SNAPCRAFT_ARCH_TRIPLET/ruby/2.7.0
RUBYLIB: $SNAP/usr/lib/ruby/vendor_ruby/3.0.0:$SNAP/usr/lib/$CRAFT_ARCH_TRIPLET/ruby/vendor_ruby/3.0.0:$SNAP/usr/lib/ruby/vendor_ruby:$SNAP/usr/lib/ruby/3.0.0:$SNAP/usr/lib/$CRAFT_ARCH_TRIPLET/ruby/3.0.0
# HUGO_SECURITY_EXEC_OSENV
#
# Default value:
# (?i)^((HTTPS?|NO)_PROXY|PATH(EXT)?|APPDATA|TE?MP|TERM|GO\w+|(XDG_CONFIG_)?HOME|USERPROFILE|SSH_AUTH_SOCK|DISPLAY|LANG)$
# (?i)^((HTTPS?|NO)_PROXY|PATH(EXT)?|APPDATA|TE?MP|TERM|GO\w+|(XDG_CONFIG_)?HOME|USERPROFILE|SSH_AUTH_SOCK|DISPLAY|LANG|SYSTEMDRIVE)$
# Bundled applications require additional access:
# git: GIT_EXEC_PATH and LD_LIBRARY_PATH
# npx: npm_config_{cache,init_module,userconfig}
# pandoc: pandoc_datadir
# rst2html: PYTHONHOME and SNAP
# asciidoctor: RUBYLIB
HUGO_SECURITY_EXEC_OSENV: (?i)^((HTTPS?|NO)_PROXY|PATH(EXT)?|APPDATA|TE?MP|TERM|GO\w+|(XDG_CONFIG_)?HOME|USERPROFILE|SSH_AUTH_SOCK|DISPLAY|LANG|GIT_EXEC_PATH|LD_LIBRARY_PATH|npm_config_(cache|init_module|userconfig)|pandoc_datadir|PYTHONHOME|SNAP|RUBYLIB)$
HUGO_SECURITY_EXEC_OSENV: (?i)^((HTTPS?|NO)_PROXY|PATH(EXT)?|APPDATA|TE?MP|TERM|GO\w+|(XDG_CONFIG_)?HOME|USERPROFILE|SSH_AUTH_SOCK|DISPLAY|LANG|SYSTEMDRIVE|GIT_EXEC_PATH|LD_LIBRARY_PATH|npm_config_(cache|init_module|userconfig)|pandoc_datadir|PYTHONHOME|SNAP|RUBYLIB)$
apps:
hugo:
command: bin/hugo
@@ -116,7 +116,7 @@ parts:
go:
plugin: nil
stage-snaps:
- go/1.21/stable
- go/1.22/stable
prime:
- bin/go
- pkg/tool
@@ -129,12 +129,12 @@ parts:
- git
- go
override-pull: |
snapcraftctl pull
snapcraftctl set-version "$(git describe --tags --always --match 'v[0-9]*' | sed 's/^v//; s/-/+git/; s/-g/./')"
craftctl default
craftctl set version=$(git describe --tags --always --match 'v[0-9]*' | sed 's/^v//; s/-/+git/; s/-g/./')
if grep -q 'Suffix:\s*""' common/hugo/version_current.go; then
snapcraftctl set-grade "stable"
craftctl set grade=stable
else
snapcraftctl set-grade "devel"
craftctl set grade=devel
fi
override-build: |
echo "\nStarting override-build:"
@@ -152,15 +152,15 @@ parts:
echo " * Building shell completion..."
./hugo completion bash > hugo-completion
echo " * Installing to ${SNAPCRAFT_PART_INSTALL}..."
install -d $SNAPCRAFT_PART_INSTALL/bin
cp -av hugo $SNAPCRAFT_PART_INSTALL/bin/
mv -v hugo-completion $SNAPCRAFT_PART_INSTALL/
echo " * Installing to ${CRAFT_PART_INSTALL}..."
install -d $CRAFT_PART_INSTALL/bin
cp -av hugo $CRAFT_PART_INSTALL/bin/
mv -v hugo-completion $CRAFT_PART_INSTALL/
echo " * Stripping binary..."
ls -l $SNAPCRAFT_PART_INSTALL/bin/hugo
strip --remove-section=.comment --remove-section=.note $SNAPCRAFT_PART_INSTALL/bin/hugo
ls -l $SNAPCRAFT_PART_INSTALL/bin/hugo
ls -l $CRAFT_PART_INSTALL/bin/hugo
strip --remove-section=.comment --remove-section=.note $CRAFT_PART_INSTALL/bin/hugo
ls -l $CRAFT_PART_INSTALL/bin/hugo
asciidoctor:
plugin: nil
@@ -168,8 +168,12 @@ parts:
- asciidoctor
override-build: |
set -ex
snapcraftctl build
sed -i '1s|#!/usr/bin/ruby|#!/usr/bin/env ruby|' $SNAPCRAFT_PART_INSTALL/usr/bin/asciidoctor
craftctl default
sed -i '1s|#!/usr/bin/ruby|#!/usr/bin/env ruby|' $CRAFT_PART_INSTALL/usr/bin/asciidoctor
# don't try and flock() gemspecs since this is blocked by AppArmor - see
# https://github.com/rubygems/rubygems/pull/5278 in particular
# https://github.com/rubygems/rubygems/pull/5278/commits/27b682c81226838b1254ac5843a3f5b1cb20f076
sed -i 's|!solaris_platform|win_platform|' $CRAFT_PART_INSTALL/usr/lib/ruby/vendor_ruby/rubygems.rb
dart-sass:
plugin: nil
@@ -177,8 +181,8 @@ parts:
- curl
override-build: |
set -ex
snapcraftctl build
case "$SNAPCRAFT_TARGET_ARCH" in
craftctl default
case "$CRAFT_TARGET_ARCH" in
amd64) arch=x64 ;;
arm64) arch=arm64 ;;
armhf) arch=arm ;;
@@ -189,8 +193,8 @@ parts:
url=$(curl -s https://api.github.com/repos/sass/dart-sass/releases/latest | awk -F\" "/browser_download_url.*-linux-${arch}.tar.gz/{print \$(NF-1)}")
curl -LO --retry-connrefused --retry 10 "${url}"
tar xf dart-sass-*-linux-${arch}.tar.gz
install -d $SNAPCRAFT_PART_INSTALL/bin
cp -av dart-sass/* $SNAPCRAFT_PART_INSTALL/bin/
install -d $CRAFT_PART_INSTALL/bin
cp -av dart-sass/* $CRAFT_PART_INSTALL/bin/
fi
node:
@@ -209,7 +213,7 @@ parts:
- python3-docutils
override-build: |
set -ex
snapcraftctl build
sed -i "s|'/usr/share/docutils/'|os.path.expandvars('\$SNAP/usr/share/docutils/')|" $SNAPCRAFT_PART_INSTALL/usr/lib/python3/dist-packages/docutils/__init__.py
craftctl default
sed -i "s|'/usr/share/docutils/'|os.path.expandvars('\$SNAP/usr/share/docutils/')|" $CRAFT_PART_INSTALL/usr/lib/python3/dist-packages/docutils/__init__.py
organize:
usr/share/docutils/scripts/python3: usr/bin
+1 -1
View File
@@ -61,7 +61,7 @@ func (fi *File) Extension() string {
func (fi *File) Ext() string { return fi.p().Ext() }
// Lang returns a file's language (e.g. "sv").
// Deprecated: use .Page.Language.Lang instead.
// Deprecated: Use .Page.Language.Lang instead.
func (fi *File) Lang() string {
hugo.Deprecate(".Page.File.Lang", "Use .Page.Language.Lang instead.", "v0.123.0")
return fi.fim.Meta().Lang
+1 -1
View File
@@ -16,4 +16,4 @@ checkfilecount $NUM_COMMANDS manpages
hugo gen chromastyles -h
stdout 'Generate CSS stylesheet for the Chroma code highlighter'
hugo gen chromastyles --style monokai
stdout '/\* LineHighlight \*/ \.chroma \.hl \{ background-color: #3c3d38 \}'
stdout '/\* LineHighlight \*/ \.chroma \.hl \{ background-color:#3c3d38 \}'
@@ -1,13 +0,0 @@
hugo
stdout 'IsMultiHost: true'
-- hugo.toml --
title = "Hugo IsMultiHost Test"
[languages.en]
baseURL = "https://example.org"
[languages.zh]
baseURL = "https://zh.example.org"
-- layouts/index.html --
{{ warnf "IsMultiHost: %v" hugo.IsMultiHost }}
+4 -4
View File
@@ -617,10 +617,10 @@ type intersector struct {
}
func (i *intersector) appendIfNotSeen(v reflect.Value) {
vi := v.Interface()
if !i.seen[vi] {
k := normalize(v)
if !i.seen[k] {
i.r = reflect.Append(i.r, v)
i.seen[vi] = true
i.seen[k] = true
}
}
@@ -638,7 +638,7 @@ func (i *intersector) handleValuePair(l1vv, l2vv reflect.Value) {
i.appendIfNotSeen(l1vv)
}
case kind == reflect.Ptr, kind == reflect.Struct:
if l1vv.Interface() == l2vv.Interface() {
if types.Unwrapv(l1vv.Interface()) == types.Unwrapv(l2vv.Interface()) {
i.appendIfNotSeen(l1vv)
}
case kind == reflect.Interface:
@@ -230,3 +230,51 @@ boolf = false
"false",
)
}
func TestTermEntriesCollectionsIssue12254(t *testing.T) {
t.Parallel()
files := `
-- hugo.toml --
capitalizeListTitles = false
disableKinds = ['rss','sitemap']
-- content/p1.md --
---
title: p1
categories: [cat-a]
tags: ['tag-b','tag-a','tag-c']
---
-- content/p2.md --
---
title: p2
categories: [cat-a]
tags: ['tag-b','tag-a']
---
-- content/p3.md --
---
title: p3
categories: [cat-a]
tags: ['tag-b']
---
-- layouts/_default/term.html --
{{ $list1 := .Pages }}
{{ range $i, $e := site.Taxonomies.tags.ByCount }}
{{ $list2 := .Pages }}
{{ $i }}: List1: {{ len $list1 }}|
{{ $i }}: List2: {{ len $list2 }}|
{{ $i }}: Intersect: {{ intersect $.Pages .Pages | len }}|
{{ $i }}: Union: {{ union $.Pages .Pages | len }}|
{{ $i }}: SymDiff: {{ symdiff $.Pages .Pages | len }}|
{{ $i }}: Uniq: {{ append $.Pages .Pages | uniq | len }}|
{{ end }}
`
b := hugolib.Test(t, files)
b.AssertFileContent("public/categories/cat-a/index.html",
"0: List1: 3|\n0: List2: 3|\n0: Intersect: 3|\n0: Union: 3|\n0: SymDiff: 0|\n0: Uniq: 3|\n\n\n1: List1: 3|",
"1: List2: 2|\n1: Intersect: 2|\n1: Union: 3|\n1: SymDiff: 1|\n1: Uniq: 3|\n\n\n2: List1: 3|\n2: List2: 1|",
"2: Intersect: 1|\n2: Union: 3|\n2: SymDiff: 2|\n2: Uniq: 3|",
)
}
+2 -1
View File
@@ -18,6 +18,7 @@ import (
"fmt"
"reflect"
"github.com/gohugoio/hugo/common/types"
"github.com/mitchellh/hashstructure"
)
@@ -60,7 +61,7 @@ func normalize(v reflect.Value) any {
return f
}
}
return v.Interface()
return types.Unwrapv(v.Interface())
}
// collects identities from the slices in seqs into a set. Numeric values are normalized,
@@ -6,14 +6,14 @@ package fmtsort_test
import (
"fmt"
"github.com/gohugoio/hugo/tpl/internal/go_templates/fmtsort"
"math"
"reflect"
"runtime"
"sort"
"strings"
"testing"
"unsafe"
"github.com/gohugoio/hugo/tpl/internal/go_templates/fmtsort"
)
var compareTests = [][]reflect.Value{
@@ -191,14 +191,14 @@ func sprintKey(key reflect.Value) string {
var (
ints [3]int
chans = makeChans()
// pin runtime.Pinner
pin runtime.Pinner
)
func makeChans() []chan int {
cs := []chan int{make(chan int), make(chan int), make(chan int)}
// Order channels by address. See issue #49431.
for i := range cs {
reflect.ValueOf(cs[i]).UnsafePointer()
pin.Pin(reflect.ValueOf(cs[i]).UnsafePointer())
}
sort.Slice(cs, func(i, j int) bool {
return uintptr(reflect.ValueOf(cs[i]).UnsafePointer()) < uintptr(reflect.ValueOf(cs[j]).UnsafePointer())
+20 -2
View File
@@ -172,13 +172,31 @@ func jsValEscaper(args ...any) string {
// cyclic data. This may be an unacceptable DoS risk.
b, err := json.Marshal(a)
if err != nil {
// Put a space before comment so that if it is flush against
// While the standard JSON marshaller does not include user controlled
// information in the error message, if a type has a MarshalJSON method,
// the content of the error message is not guaranteed. Since we insert
// the error into the template, as part of a comment, we attempt to
// prevent the error from either terminating the comment, or the script
// block itself.
//
// In particular we:
// * replace "*/" comment end tokens with "* /", which does not
// terminate the comment
// * replace "</script" with "\x3C/script", and "<!--" with
// "\x3C!--", which prevents confusing script block termination
// semantics
//
// We also put a space before the comment so that if it is flush against
// a division operator it is not turned into a line comment:
// x/{{y}}
// turning into
// x//* error marshaling y:
// second line of error message */null
return fmt.Sprintf(" /* %s */null ", strings.ReplaceAll(err.Error(), "*/", "* /"))
errStr := err.Error()
errStr = strings.ReplaceAll(errStr, "*/", "* /")
errStr = strings.ReplaceAll(errStr, "</script", `\x3C/script`)
errStr = strings.ReplaceAll(errStr, "<!--", `\x3C!--`)
return fmt.Sprintf(" /* %s */null ", errStr)
}
// TODO: maybe post-process output to prevent it from containing
@@ -8,6 +8,7 @@
package template
import (
"errors"
"math"
"strings"
"testing"
@@ -106,61 +107,72 @@ func TestNextJsCtx(t *testing.T) {
}
}
type jsonErrType struct{}
func (e *jsonErrType) MarshalJSON() ([]byte, error) {
return nil, errors.New("beep */ boop </script blip <!--")
}
func TestJSValEscaper(t *testing.T) {
tests := []struct {
x any
js string
x any
js string
skipNest bool
}{
{int(42), " 42 "},
{uint(42), " 42 "},
{int16(42), " 42 "},
{uint16(42), " 42 "},
{int32(-42), " -42 "},
{uint32(42), " 42 "},
{int16(-42), " -42 "},
{uint16(42), " 42 "},
{int64(-42), " -42 "},
{uint64(42), " 42 "},
{uint64(1) << 53, " 9007199254740992 "},
{int(42), " 42 ", false},
{uint(42), " 42 ", false},
{int16(42), " 42 ", false},
{uint16(42), " 42 ", false},
{int32(-42), " -42 ", false},
{uint32(42), " 42 ", false},
{int16(-42), " -42 ", false},
{uint16(42), " 42 ", false},
{int64(-42), " -42 ", false},
{uint64(42), " 42 ", false},
{uint64(1) << 53, " 9007199254740992 ", false},
// ulp(1 << 53) > 1 so this loses precision in JS
// but it is still a representable integer literal.
{uint64(1)<<53 + 1, " 9007199254740993 "},
{float32(1.0), " 1 "},
{float32(-1.0), " -1 "},
{float32(0.5), " 0.5 "},
{float32(-0.5), " -0.5 "},
{float32(1.0) / float32(256), " 0.00390625 "},
{float32(0), " 0 "},
{math.Copysign(0, -1), " -0 "},
{float64(1.0), " 1 "},
{float64(-1.0), " -1 "},
{float64(0.5), " 0.5 "},
{float64(-0.5), " -0.5 "},
{float64(0), " 0 "},
{math.Copysign(0, -1), " -0 "},
{"", `""`},
{"foo", `"foo"`},
{uint64(1)<<53 + 1, " 9007199254740993 ", false},
{float32(1.0), " 1 ", false},
{float32(-1.0), " -1 ", false},
{float32(0.5), " 0.5 ", false},
{float32(-0.5), " -0.5 ", false},
{float32(1.0) / float32(256), " 0.00390625 ", false},
{float32(0), " 0 ", false},
{math.Copysign(0, -1), " -0 ", false},
{float64(1.0), " 1 ", false},
{float64(-1.0), " -1 ", false},
{float64(0.5), " 0.5 ", false},
{float64(-0.5), " -0.5 ", false},
{float64(0), " 0 ", false},
{math.Copysign(0, -1), " -0 ", false},
{"", `""`, false},
{"foo", `"foo"`, false},
// Newlines.
{"\r\n\u2028\u2029", `"\r\n\u2028\u2029"`},
{"\r\n\u2028\u2029", `"\r\n\u2028\u2029"`, false},
// "\v" == "v" on IE 6 so use "\u000b" instead.
{"\t\x0b", `"\t\u000b"`},
{struct{ X, Y int }{1, 2}, `{"X":1,"Y":2}`},
{[]any{}, "[]"},
{[]any{42, "foo", nil}, `[42,"foo",null]`},
{[]string{"<!--", "</script>", "-->"}, `["\u003c!--","\u003c/script\u003e","--\u003e"]`},
{"<!--", `"\u003c!--"`},
{"-->", `"--\u003e"`},
{"<![CDATA[", `"\u003c![CDATA["`},
{"]]>", `"]]\u003e"`},
{"</script", `"\u003c/script"`},
{"\U0001D11E", "\"\U0001D11E\""}, // or "\uD834\uDD1E"
{nil, " null "},
{"\t\x0b", `"\t\u000b"`, false},
{struct{ X, Y int }{1, 2}, `{"X":1,"Y":2}`, false},
{[]any{}, "[]", false},
{[]any{42, "foo", nil}, `[42,"foo",null]`, false},
{[]string{"<!--", "</script>", "-->"}, `["\u003c!--","\u003c/script\u003e","--\u003e"]`, false},
{"<!--", `"\u003c!--"`, false},
{"-->", `"--\u003e"`, false},
{"<![CDATA[", `"\u003c![CDATA["`, false},
{"]]>", `"]]\u003e"`, false},
{"</script", `"\u003c/script"`, false},
{"\U0001D11E", "\"\U0001D11E\"", false}, // or "\uD834\uDD1E"
{nil, " null ", false},
{&jsonErrType{}, " /* json: error calling MarshalJSON for type *template.jsonErrType: beep * / boop \\x3C/script blip \\x3C!-- */null ", true},
}
for _, test := range tests {
if js := jsValEscaper(test.x); js != test.js {
t.Errorf("%+v: want\n\t%q\ngot\n\t%q", test.x, test.js, js)
}
if test.skipNest {
continue
}
// Make sure that escaping corner cases are not broken
// by nesting.
a := []any{test.x}
@@ -6,6 +6,7 @@ package testenv
import (
"context"
"errors"
"fmt"
"os"
"os/exec"
@@ -60,6 +61,13 @@ func tryExec() error {
// may as well use the same path so that this branch can be tested without
// an ios environment.
if !testing.Testing() {
// This isn't a standard 'go test' binary, so we don't know how to
// self-exec in a way that should succeed without side effects.
// Just forget it.
return errors.New("can't probe for exec support with a non-test executable")
}
// We know that this is a test executable. We should be able to run it with a
// no-op flag to check for overall exec support.
exe, err := os.Executable()
@@ -17,5 +17,5 @@ import (
var Sigquit = os.Kill
func syscallIsNotSupported(err error) bool {
return errors.Is(err, fs.ErrPermission)
return errors.Is(err, fs.ErrPermission) || errors.Is(err, errors.ErrUnsupported)
}
@@ -54,8 +54,8 @@ func TestGoToolLocation(t *testing.T) {
}
}
// Modified by Hugo.
func TestHasGoBuild(t *testing.T) {
// Removed by Hugo.
}
func TestMustHaveExec(t *testing.T) {
@@ -73,7 +73,7 @@ func TestMustHaveExec(t *testing.T) {
t.Errorf("expected MustHaveExec to skip on %v", runtime.GOOS)
}
case "ios":
if b := testenv.Builder(); strings.HasSuffix(b, "-corellium") && !hasExec {
if b := testenv.Builder(); isCorelliumBuilder(b) && !hasExec {
// Most ios environments can't exec, but the corellium builder can.
t.Errorf("expected MustHaveExec not to skip on %v", b)
}
@@ -106,3 +106,23 @@ func TestCleanCmdEnvPWD(t *testing.T) {
}
t.Error("PWD not set in cmd.Env")
}
func isCorelliumBuilder(builderName string) bool {
// Support both the old infra's builder names and the LUCI builder names.
// The former's names are ad-hoc so we could maintain this invariant on
// the builder side. The latter's names are structured, and "corellium" will
// appear as a "host" suffix after the GOOS and GOARCH, which always begin
// with an underscore.
return strings.HasSuffix(builderName, "-corellium") || strings.Contains(builderName, "_corellium")
}
func isEmulatedBuilder(builderName string) bool {
// Support both the old infra's builder names and the LUCI builder names.
// The former's names are ad-hoc so we could maintain this invariant on
// the builder side. The latter's names are structured, and the signifier
// of emulation "emu" will appear as a "host" suffix after the GOOS and
// GOARCH because it modifies the run environment in such a way that it
// the target GOOS and GOARCH may not match the host. This suffix always
// begins with an underscore.
return strings.HasSuffix(builderName, "-emu") || strings.Contains(builderName, "_emu")
}
@@ -35,7 +35,7 @@ func syscallIsNotSupported(err error) bool {
}
}
if errors.Is(err, fs.ErrPermission) {
if errors.Is(err, fs.ErrPermission) || errors.Is(err, errors.ErrUnsupported) {
return true
}
@@ -284,7 +284,6 @@ func (a *ActionNode) tree() *Tree {
func (a *ActionNode) Copy() Node {
return a.tr.newAction(a.Pos, a.Line, a.Pipe.CopyPipe())
}
// CommandNode holds a command (a pipeline inside an evaluating action).
@@ -171,3 +171,70 @@ Home.
b.AssertFileExists("public/a.txt", true) // failing test
b.AssertFileExists("public/b.txt", true) // failing test
}
func TestGlobalResourcesNotPublishedRegressionIssue12214(t *testing.T) {
t.Parallel()
files := `
-- hugo.toml --
disableKinds = ['page','rss','section','sitemap','taxonomy','term']
-- assets/files/a.txt --
I am a.txt
-- assets/files/b.txt --
I am b.txt
-- assets/files/c.txt --
I am c.txt
-- assets/files/C.txt --
I am C.txt
-- layouts/index.html --
Home.
{{ with resources.ByType "text" }}
{{ with .Get "files/a.txt" }}
{{ .Publish }}
files/a.txt: {{ .Name }}
{{ end }}
{{ with .Get "/files/a.txt" }}
/files/a.txt: {{ .Name }}
{{ end }}
{{ with .GetMatch "files/*b*" }}
{{ .Publish }}
files/*b*: {{ .Name }}
{{ end }}
{{ with .GetMatch "files/C*" }}
{{ .Publish }}
files/C*: {{ .Name }}
{{ end }}
{{ with .GetMatch "files/c*" }}
{{ .Publish }}
files/c*: {{ .Name }}
{{ end }}
{{ with .GetMatch "/files/c*" }}
/files/c*: {{ .Name }}
{{ end }}
{{ with .Match "files/C*" }}
match files/C*: {{ len . }}|
{{ end }}
{{ with .Match "/files/C*" }}
match /files/C*: {{ len . }}|
{{ end }}
{{ end }}
`
b := hugolib.Test(t, files)
b.AssertFileContent("public/index.html", `
files/a.txt: /files/a.txt
# There are both C.txt and c.txt in the assets, but the Glob matching is case insensitive, so GetMatch returns the first.
files/C*: /files/C.txt
files/c*: /files/C.txt
files/*b*: /files/b.txt
/files/c*: /files/C.txt
/files/a.txt: /files/a.txt
match files/C*: 2|
match /files/C*: 2|
`)
b.AssertFileContent("public/files/a.txt", "I am a.txt")
b.AssertFileContent("public/files/b.txt", "I am b.txt")
b.AssertFileContent("public/files/C.txt", "I am C.txt")
}
@@ -3,8 +3,8 @@
{{ range . }}
<sitemap>
<loc>{{ .SitemapAbsURL }}</loc>
{{ if not .LastChange.IsZero }}
<lastmod>{{ .LastChange.Format "2006-01-02T15:04:05-07:00" | safeHTML }}</lastmod>
{{ if not .Lastmod.IsZero }}
<lastmod>{{ .Lastmod.Format "2006-01-02T15:04:05-07:00" | safeHTML }}</lastmod>
{{ end }}
</sitemap>
{{ end }}
+4 -11
View File
@@ -34,18 +34,11 @@
{{ end }}{{ end }}
{{- end }}
{{- /* Deprecate site.Social.facebook_admin in favor of site.Params.social.facebook_admin */}}
{{- $facebookAdmin := "" }}
{{- /* Facebook Page Admin ID for Domain Insights */}}
{{- with site.Params.social }}
{{- if reflect.IsMap . }}
{{- $facebookAdmin = .facebook_admin }}
{{- end }}
{{- else }}
{{- with site.Social.facebook_admin }}
{{- $facebookAdmin = . }}
{{- warnf "The social key in site configuration is deprecated. Use params.social.facebook_admin instead." }}
{{- with .facebook_admin }}
<meta property="fb:admins" content="{{ . }}" />
{{- end }}
{{- end }}
{{- end }}
{{- /* Facebook Page Admin ID for Domain Insights */}}
{{ with $facebookAdmin }}<meta property="fb:admins" content="{{ . }}" />{{ end }}
@@ -1,29 +1,38 @@
<figure{{ with .Get "class" }} class="{{ . }}"{{ end }}>
{{- if .Get "link" -}}
<a href="{{ .Get "link" }}"{{ with .Get "target" }} target="{{ . }}"{{ end }}{{ with .Get "rel" }} rel="{{ . }}"{{ end }}>
{{- if .Get "link" -}}
<a href="{{ .Get "link" }}"{{ with .Get "target" }} target="{{ . }}"{{ end }}{{ with .Get "rel" }} rel="{{ . }}"{{ end }}>
{{- end -}}
{{- $u := urls.Parse (.Get "src") -}}
{{- $src := $u.String -}}
{{- if not $u.IsAbs -}}
{{- with or (.Page.Resources.Get $u.Path) (resources.Get $u.Path) -}}
{{- $src = .RelPermalink -}}
{{- end -}}
<img src="{{ .Get "src" }}"
{{- if or (.Get "alt") (.Get "caption") }}
alt="{{ with .Get "alt" }}{{ . }}{{ else }}{{ .Get "caption" | markdownify| plainify }}{{ end }}"
{{- end -}}
{{- with .Get "width" }} width="{{ . }}"{{ end -}}
{{- with .Get "height" }} height="{{ . }}"{{ end -}}
{{- with .Get "loading" }} loading="{{ . }}"{{ end -}}
/><!-- Closing img tag -->
{{- if .Get "link" }}</a>{{ end -}}
{{- if or (or (.Get "title") (.Get "caption")) (.Get "attr") -}}
<figcaption>
{{ with (.Get "title") -}}
<h4>{{ . }}</h4>
{{- end -}}
{{- if or (.Get "caption") (.Get "attr") -}}<p>
{{- .Get "caption" | markdownify -}}
{{- with .Get "attrlink" }}
<a href="{{ . }}">
{{- end -}}
{{- .Get "attr" | markdownify -}}
{{- if .Get "attrlink" }}</a>{{ end }}</p>
{{- end }}
</figcaption>
{{- end }}
{{- end -}}
<img src="{{ $src }}"
{{- if or (.Get "alt") (.Get "caption") }}
alt="{{ with .Get "alt" }}{{ . }}{{ else }}{{ .Get "caption" | markdownify| plainify }}{{ end }}"
{{- end -}}
{{- with .Get "width" }} width="{{ . }}"{{ end -}}
{{- with .Get "height" }} height="{{ . }}"{{ end -}}
{{- with .Get "loading" }} loading="{{ . }}"{{ end -}}
><!-- Closing img tag -->
{{- if .Get "link" }}</a>{{ end -}}
{{- if or (or (.Get "title") (.Get "caption")) (.Get "attr") -}}
<figcaption>
{{ with (.Get "title") -}}
<h4>{{ . }}</h4>
{{- end -}}
{{- if or (.Get "caption") (.Get "attr") -}}<p>
{{- .Get "caption" | markdownify -}}
{{- with .Get "attrlink" }}
<a href="{{ . }}">
{{- end -}}
{{- .Get "attr" | markdownify -}}
{{- if .Get "attrlink" }}</a>{{ end }}</p>
{{- end }}
</figcaption>
{{- end }}
</figure>
@@ -8,23 +8,15 @@
<meta name="twitter:title" content="{{ .Title }}"/>
<meta name="twitter:description" content="{{ with .Description }}{{ . }}{{ else }}{{if .IsPage}}{{ .Summary }}{{ else }}{{ with .Site.Params.description }}{{ . }}{{ end }}{{ end }}{{ end -}}"/>
{{- /* Deprecate site.Social.twitter in favor of site.Params.social.twitter */}}
{{- $twitterSite := "" }}
{{- with site.Params.social }}
{{- if reflect.IsMap . }}
{{- $twitterSite = .twitter }}
{{- end }}
{{- else }}
{{- with site.Social.twitter }}
{{- $twitterSite = . }}
{{- warnf "The social key in site configuration is deprecated. Use params.social.twitter instead." }}
{{- with .twitter }}
{{- $content := . }}
{{- if not (strings.HasPrefix . "@") }}
{{- $content = printf "@%v" . }}
{{- end }}
<meta name="twitter:site" content="{{ $content }}"/>
{{- end }}
{{- end }}
{{- end }}
{{- with $twitterSite }}
{{- $content := . }}
{{- if not (strings.HasPrefix . "@") }}
{{- $content = printf "@%v" $twitterSite }}
{{- end }}
<meta name="twitter:site" content="{{ $content }}"/>
{{- end }}