Skip to content

Commit 1f1c62e

Browse files
committed
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 gohugoio#10106
1 parent f1d7559 commit 1f1c62e

10 files changed

+501
-3
lines changed

commands/commandeer.go

+1
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,7 @@ func applyLocalFlagsBuildConfig(cmd *cobra.Command, r *rootCommand) {
521521
cmd.Flags().StringP("cacheDir", "", "", "filesystem path to cache directory")
522522
_ = cmd.Flags().SetAnnotation("cacheDir", cobra.BashCompSubdirsInDir, []string{})
523523
cmd.Flags().StringP("contentDir", "c", "", "filesystem path to content directory")
524+
cmd.Flags().StringSliceP("renderSegments", "", []string{}, "named segments to render (configured in the segments config)")
524525
_ = cmd.Flags().SetAnnotation("theme", cobra.BashCompSubdirsInDir, []string{"themes"})
525526
}
526527

config/allconfig/allconfig.go

+10
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import (
3939
"github.com/gohugoio/hugo/config/services"
4040
"github.com/gohugoio/hugo/deploy/deployconfig"
4141
"github.com/gohugoio/hugo/helpers"
42+
"github.com/gohugoio/hugo/hugolib/segments"
4243
"github.com/gohugoio/hugo/langs"
4344
"github.com/gohugoio/hugo/markup/markup_config"
4445
"github.com/gohugoio/hugo/media"
@@ -139,6 +140,9 @@ type Config struct {
139140
// a slice of page matcher and params to apply to those pages.
140141
Cascade *config.ConfigNamespace[[]page.PageMatcherParamsConfig, map[page.PageMatcher]maps.Params] `mapstructure:"-"`
141142

143+
// The segments defines segments for the site. Used for partial/segmented builds.
144+
Segments *config.ConfigNamespace[map[string]segments.SegmentConfig, segments.Segments] `mapstructure:"-"`
145+
142146
// Menu configuration.
143147
// <docsmeta>{"refs": ["config:languages:menus"] }</docsmeta>
144148
Menus *config.ConfigNamespace[map[string]navigation.MenuConfig, navigation.Menus] `mapstructure:"-"`
@@ -366,6 +370,7 @@ func (c *Config) CompileConfig(logger loggers.Logger) error {
366370
CreateTitle: helpers.GetTitleFunc(c.TitleCaseStyle),
367371
IsUglyURLSection: isUglyURL,
368372
IgnoreFile: ignoreFile,
373+
SegmentFilter: c.Segments.Config.Get(func(s string) { logger.Warnf("Render segment %q not found in configuration", s) }, c.RootConfig.RenderSegments...),
369374
MainSections: c.MainSections,
370375
Clock: clock,
371376
transientErr: transientErr,
@@ -402,6 +407,7 @@ type ConfigCompiled struct {
402407
CreateTitle func(s string) string
403408
IsUglyURLSection func(section string) bool
404409
IgnoreFile func(filename string) bool
410+
SegmentFilter segments.SegmentFilter
405411
MainSections []string
406412
Clock time.Time
407413

@@ -474,6 +480,10 @@ type RootConfig struct {
474480
// A list of languages to disable.
475481
DisableLanguages []string
476482

483+
// The named segments to render.
484+
// This needs to match the name of the segment in the segments configuration.
485+
RenderSegments []string
486+
477487
// Disable the injection of the Hugo generator tag on the home page.
478488
DisableHugoGeneratorInject bool
479489

config/allconfig/alldecoders.go

+10
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,13 @@ import (
2525
"github.com/gohugoio/hugo/config/security"
2626
"github.com/gohugoio/hugo/config/services"
2727
"github.com/gohugoio/hugo/deploy/deployconfig"
28+
"github.com/gohugoio/hugo/hugolib/segments"
2829
"github.com/gohugoio/hugo/langs"
2930
"github.com/gohugoio/hugo/markup/markup_config"
3031
"github.com/gohugoio/hugo/media"
3132
"github.com/gohugoio/hugo/minifiers"
3233
"github.com/gohugoio/hugo/modules"
34+
3335
"github.com/gohugoio/hugo/navigation"
3436
"github.com/gohugoio/hugo/output"
3537
"github.com/gohugoio/hugo/related"
@@ -120,6 +122,14 @@ var allDecoderSetups = map[string]decodeWeight{
120122
return err
121123
},
122124
},
125+
"segments": {
126+
key: "segments",
127+
decode: func(d decodeWeight, p decodeConfig) error {
128+
var err error
129+
p.c.Segments, err = segments.DecodeSegments(p.p.GetStringMap(d.key))
130+
return err
131+
},
132+
},
123133
"server": {
124134
key: "server",
125135
decode: func(d decodeWeight, p decodeConfig) error {

hugolib/hugo_sites.go

+4
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,10 @@ type BuildCfg struct {
410410

411411
// shouldRender returns whether this output format should be rendered or not.
412412
func (cfg *BuildCfg) shouldRender(p *pageState) bool {
413+
if p.skipRender() {
414+
return false
415+
}
416+
413417
if !p.renderOnce {
414418
return true
415419
}

hugolib/hugo_sites_build.go

+13-2
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,16 @@ import (
2828
"github.com/bep/logg"
2929
"github.com/gohugoio/hugo/cache/dynacache"
3030
"github.com/gohugoio/hugo/deps"
31+
"github.com/gohugoio/hugo/hugofs"
3132
"github.com/gohugoio/hugo/hugofs/files"
3233
"github.com/gohugoio/hugo/hugofs/glob"
34+
"github.com/gohugoio/hugo/hugolib/segments"
3335
"github.com/gohugoio/hugo/identity"
3436
"github.com/gohugoio/hugo/output"
3537
"github.com/gohugoio/hugo/publisher"
3638
"github.com/gohugoio/hugo/source"
3739
"github.com/gohugoio/hugo/tpl"
3840

39-
"github.com/gohugoio/hugo/hugofs"
40-
4141
"github.com/gohugoio/hugo/common/herrors"
4242
"github.com/gohugoio/hugo/common/loggers"
4343
"github.com/gohugoio/hugo/common/para"
@@ -318,9 +318,20 @@ func (h *HugoSites) render(l logg.LevelLogger, config *BuildCfg) error {
318318

319319
i := 0
320320
for _, s := range h.Sites {
321+
segmentFilter := s.conf.C.SegmentFilter
322+
if segmentFilter.ShouldExcludeCoarse(segments.SegmentMatcherFields{Lang: s.language.Lang}) {
323+
l.Logf("skip language %q not matching segments set in --renderSegments", s.language.Lang)
324+
continue
325+
}
326+
321327
siteRenderContext.languageIdx = s.languagei
322328
h.currentSite = s
323329
for siteOutIdx, renderFormat := range s.renderFormats {
330+
if segmentFilter.ShouldExcludeCoarse(segments.SegmentMatcherFields{Output: renderFormat.Name, Lang: s.language.Lang}) {
331+
l.Logf("skip output format %q for language %q not matching segments set in --renderSegments", renderFormat.Name, s.language.Lang)
332+
continue
333+
}
334+
324335
siteRenderContext.outIdx = siteOutIdx
325336
siteRenderContext.sitesOutIdx = i
326337
i++

hugolib/page.go

+14
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222

2323
"github.com/gohugoio/hugo/hugofs"
2424
"github.com/gohugoio/hugo/hugolib/doctree"
25+
"github.com/gohugoio/hugo/hugolib/segments"
2526
"github.com/gohugoio/hugo/identity"
2627
"github.com/gohugoio/hugo/media"
2728
"github.com/gohugoio/hugo/output"
@@ -152,6 +153,19 @@ func (p *pageState) reusePageOutputContent() bool {
152153
return p.pageOutputTemplateVariationsState.Load() == 1
153154
}
154155

156+
func (p *pageState) skipRender() bool {
157+
b := p.s.conf.C.SegmentFilter.ShouldExcludeFine(
158+
segments.SegmentMatcherFields{
159+
Path: p.Path(),
160+
Kind: p.Kind(),
161+
Lang: p.Lang(),
162+
Output: p.pageOutput.f.Name,
163+
},
164+
)
165+
166+
return b
167+
}
168+
155169
func (po *pageState) isRenderedAny() bool {
156170
for _, o := range po.pageOutputs {
157171
if o.isRendered() {

0 commit comments

Comments
 (0)