From 9d1c46b00627cc8f63c320db06e50070d9e56ba9 Mon Sep 17 00:00:00 2001 From: Nikita Shubin Date: Sun, 26 Apr 2026 13:07:31 +0300 Subject: [PATCH] hugolib: Add support for gitpurism Add possibility to extract and use tags and categories coming from git notes. NOTE: I have no idea of what this is, just mimicking some stuff found here. TODO: - specify git notes branches to scan in config file - actually all meta can be taken from git notes - add condition in config to affect either meta appended or rewritten Signed-off-by: Nikita Shubin --- commands/commandeer.go | 1 + config/allconfig/allconfig.go | 4 ++++ hugolib/hugo_sites.go | 34 ++++++++++++++++++++++----- hugolib/page.go | 4 ++++ hugolib/page__common.go | 1 + hugolib/page__meta.go | 44 +++++++++++++++++++++++++++++++++++ hugolib/page__new.go | 7 ++++++ hugolib/site.go | 3 +++ 8 files changed, 92 insertions(+), 6 deletions(-) diff --git a/commands/commandeer.go b/commands/commandeer.go index 6b222fe9b..9678ff40f 100644 --- a/commands/commandeer.go +++ b/commands/commandeer.go @@ -615,6 +615,7 @@ func applyLocalFlagsBuild(cmd *cobra.Command, r *rootCommand) { cmd.Flags().BoolP("buildExpired", "E", false, "include expired content") cmd.Flags().BoolP("ignoreCache", "", false, "ignores the cache directory") cmd.Flags().Bool("enableGitInfo", false, "add Git revision, date, author, and CODEOWNERS info to the pages") + cmd.Flags().Bool("enableGitPurismInfo", false, "grab meta (tags, categories) from Git notes") cmd.Flags().StringP("layoutDir", "l", "", "filesystem path to layout directory") _ = cmd.MarkFlagDirname("layoutDir") cmd.Flags().BoolVar(&r.gc, "gc", false, "enable to run some cleanup tasks (remove unused cache files) after the build") diff --git a/config/allconfig/allconfig.go b/config/allconfig/allconfig.go index 75613e0de..cdfd42825 100644 --- a/config/allconfig/allconfig.go +++ b/config/allconfig/allconfig.go @@ -703,6 +703,10 @@ type RootConfig struct { // {"identifiers": ["Page"] } EnableGitInfo bool + // When enabled, Hugo will attempt to grab tags and categories from Git notes. + // {"identifiers": ["Page"] } + EnableGitPurismInfo bool + // Enable to track, calculate and print metrics. TemplateMetrics bool diff --git a/hugolib/hugo_sites.go b/hugolib/hugo_sites.go index eea3583a5..59c5b4595 100644 --- a/hugolib/hugo_sites.go +++ b/hugolib/hugo_sites.go @@ -86,6 +86,8 @@ type HugoSites struct { markdownTitleInfo *markdownTitleInfo + gitPurismInfo *gitPurismInfo + // As loaded from the /data dirs data map[string]any @@ -336,6 +338,8 @@ type hugoSitesInit struct { gitInfo hsync.FuncResetter markdownTitleInfo hsync.FuncResetter + + gitPurismInfo hsync.FuncResetter } func (h *HugoSites) Data() map[string]any { @@ -417,6 +421,18 @@ func (h *HugoSites) markdownTitleInfoForPage(p page.Page) (*MarkdownTitleInfo, e return h.markdownTitleInfo.forPage(p), nil } +func (h *HugoSites) gitPurismInfoForPage(p page.Page) (*GitPurismInfo, error) { + if err := h.init.gitPurismInfo.Do(context.Background()); err != nil { + return nil, err + } + + if h.gitPurismInfo == nil { + return nil, nil + } + + return h.gitPurismInfo.forPage(p), nil +} + func (h *HugoSites) reportProgress(f func() (state terminal.ProgressState, progress float64)) { h.progressReporter.mu.Lock() defer h.progressReporter.mu.Unlock() @@ -587,12 +603,6 @@ func (h *HugoSites) loadGitInfo() error { func (h *HugoSites) loadMarkdownTitleInfo() error { // TODO: Make it configurable // if h.Configs.Base.EnableMarkdownTitle { - // cfg := gitInfoConfig{ - // Deps: h.Deps, - // Modules: h.Configs.Modules, - // GitInfoCache: h.Configs.FileCaches.ModuleGitInfoCache(), - // Logger: h.Log, - // } mt, err := newMarkdownTitleInfo(h.Deps.Conf.DirsBase().ContentDir) if err != nil { return err @@ -603,6 +613,18 @@ func (h *HugoSites) loadMarkdownTitleInfo() error { return nil } +func (h *HugoSites) loadGitPurismInfo() error { + if h.Configs.Base.EnableGitPurismInfo { + gpi, err := newGitPurismInfo(h.Deps.Conf.DirsBase().ContentDir) + if err != nil { + return err + } else { + h.gitPurismInfo = gpi + } + } + return nil +} + // Reset resets the sites and template caches etc., making it ready for a full rebuild. func (h *HugoSites) reset() { h.fatalErrorHandler = &fatalErrorHandler{ diff --git a/hugolib/page.go b/hugolib/page.go index 742ff343d..81759da6d 100644 --- a/hugolib/page.go +++ b/hugolib/page.go @@ -329,6 +329,10 @@ func (p *pageState) MarkdownTitleInfo() *MarkdownTitleInfo { return p.markdownTitleInfo } +func (p *pageState) GitPurismInfo() *GitPurismInfo { + return p.gitPurismInfo +} + // GetTerms gets the terms defined on this page in the given taxonomy. // The pages returned will be ordered according to the front matter. func (ps *pageState) GetTerms(taxonomy string) page.Pages { diff --git a/hugolib/page__common.go b/hugolib/page__common.go index 42965e8a0..69458a097 100644 --- a/hugolib/page__common.go +++ b/hugolib/page__common.go @@ -88,6 +88,7 @@ type pageCommon struct { codeowners []string markdownTitleInfo *MarkdownTitleInfo + gitPurismInfo *GitPurismInfo // Positional navigation posNextPrev *nextPrev diff --git a/hugolib/page__meta.go b/hugolib/page__meta.go index 7253be4aa..e290c19d2 100644 --- a/hugolib/page__meta.go +++ b/hugolib/page__meta.go @@ -820,6 +820,50 @@ params: } } + if ps.gitPurismInfo != nil { + if len(ps.gitPurismInfo.Categories) > 0 { + if existing, ok := pcfg.Params["categories"]; ok { + switch v := existing.(type) { + case []string: + pcfg.Params["categories"] = append(v, ps.gitPurismInfo.Categories...) + case []interface{}: + existingStrings := make([]string, 0, len(v)) + for _, iv := range v { + if s, ok := iv.(string); ok { + existingStrings = append(existingStrings, s) + } + } + pcfg.Params["categories"] = append(existingStrings, ps.gitPurismInfo.Categories...) + default: + pcfg.Params["categories"] = ps.gitPurismInfo.Categories + } + } else { + pcfg.Params["categories"] = ps.gitPurismInfo.Categories + } + } + + if len(ps.gitPurismInfo.Tags) > 0 { + if existing, ok := pcfg.Params["tags"]; ok { + switch v := existing.(type) { + case []string: + pcfg.Params["tags"] = append(v, ps.gitPurismInfo.Tags...) + case []interface{}: + existingStrings := make([]string, 0, len(v)) + for _, iv := range v { + if s, ok := iv.(string); ok { + existingStrings = append(existingStrings, s) + } + } + pcfg.Params["tags"] = append(existingStrings, ps.gitPurismInfo.Tags...) + default: + pcfg.Params["tags"] = ps.gitPurismInfo.Tags + } + } else { + pcfg.Params["tags"] = ps.gitPurismInfo.Tags + } + } + } + for k, v := range userParams { pcfg.Params[strings.ToLower(k)] = v } diff --git a/hugolib/page__new.go b/hugolib/page__new.go index 70925e3b8..aff95e5db 100644 --- a/hugolib/page__new.go +++ b/hugolib/page__new.go @@ -101,6 +101,13 @@ func (s *Site) doNewPageFromPageMeta(m *pageMeta, cascades *page.PageMatcherPara return nil, fmt.Errorf("failed to load MarkdownTitle data: %w", err) } ps.markdownTitleInfo = mt + + gpi, err := s.h.gitPurismInfoForPage(ps) + if err != nil { + return nil, fmt.Errorf("failed to load GitPurism data: %w", err) + + } + ps.gitPurismInfo = gpi } ps.pageMenus = &pageMenus{p: ps} diff --git a/hugolib/site.go b/hugolib/site.go index d0431d701..b201d6e7a 100644 --- a/hugolib/site.go +++ b/hugolib/site.go @@ -599,6 +599,9 @@ func newHugoSites( return h.loadMarkdownTitleInfo() }) + h.init.gitPurismInfo = hsync.OnceMoreFunc(func(ctx context.Context) error { + return h.loadGitPurismInfo() + }) return h, nil } -- 2.39.5