mirror of
https://github.com/gohugoio/hugo.git
synced 2026-08-24 15:28:54 +00:00
Move common/hugo/HugoInfo to resources/page
* This break the circular dependency between hugolib and resources/page, and allow HugoInfo to use the proper Page ans Site interfaces. * It's a little misplaced, but it makes everything easier to maintain and test, so that's well worth it.
This commit is contained in:
+1
-1
@@ -246,7 +246,7 @@ func (f *fileServer) createEndpoint(i int) (*http.ServeMux, net.Listener, string
|
|||||||
logger := f.c.r.logger
|
logger := f.c.r.logger
|
||||||
|
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
r.Printf("Environment: %q\n", f.c.hugoTry().Deps.Site.Hugo().Environment)
|
r.Printf("Environment: %q\n", f.c.hugoTry().Deps.Site.Hugo().Environment())
|
||||||
mainTarget := "disk"
|
mainTarget := "disk"
|
||||||
if f.c.r.renderToMemory {
|
if f.c.r.renderToMemory {
|
||||||
mainTarget = "memory"
|
mainTarget = "memory"
|
||||||
|
|||||||
+16
-142
@@ -16,7 +16,6 @@ package hugo
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"html/template"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
@@ -25,17 +24,16 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/bep/helpers/contexthelpers"
|
||||||
"github.com/bep/logg"
|
"github.com/bep/logg"
|
||||||
|
|
||||||
"github.com/bep/godartsass/v2"
|
"github.com/bep/godartsass/v2"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/common/hexec"
|
"github.com/gohugoio/hugo/common/hexec"
|
||||||
"github.com/gohugoio/hugo/common/hstore"
|
|
||||||
"github.com/gohugoio/hugo/common/loggers"
|
"github.com/gohugoio/hugo/common/loggers"
|
||||||
"github.com/gohugoio/hugo/common/version"
|
"github.com/gohugoio/hugo/common/version"
|
||||||
"github.com/gohugoio/hugo/hugofs/files"
|
"github.com/gohugoio/hugo/hugofs/files"
|
||||||
|
|
||||||
"github.com/bep/helpers/contexthelpers"
|
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
|
|
||||||
iofs "io/fs"
|
iofs "io/fs"
|
||||||
@@ -56,99 +54,24 @@ var (
|
|||||||
vendorInfo string
|
vendorInfo string
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ hstore.StoreProvider = (*HugoInfo)(nil)
|
// BuildInfo holds build information extracted from runtime/debug.
|
||||||
|
type BuildInfo struct {
|
||||||
// HugoInfo contains information about the current Hugo environment
|
Revision string
|
||||||
type HugoInfo struct {
|
RevisionTime string
|
||||||
CommitHash string
|
GoVersion string
|
||||||
BuildDate string
|
|
||||||
|
|
||||||
// The build environment.
|
|
||||||
// Defaults are "production" (hugo) and "development" (hugo server).
|
|
||||||
// This can also be set by the user.
|
|
||||||
// It can be any string, but it will be all lower case.
|
|
||||||
Environment string
|
|
||||||
|
|
||||||
// version of go that the Hugo binary was built with
|
|
||||||
GoVersion string
|
|
||||||
|
|
||||||
conf ConfigProvider
|
|
||||||
deps []*Dependency
|
|
||||||
|
|
||||||
sitesProvider SitesProvider
|
|
||||||
|
|
||||||
store *hstore.Scratch
|
|
||||||
|
|
||||||
// Context gives access to some of the context scoped variables.
|
|
||||||
Context Context
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Version returns the current version as a comparable version string.
|
// GetBuildInfo returns the build info for the current binary.
|
||||||
func (i HugoInfo) Version() version.VersionString {
|
func GetBuildInfo() *BuildInfo {
|
||||||
return CurrentVersion.Version()
|
bi := getBuildInfo()
|
||||||
}
|
if bi == nil {
|
||||||
|
|
||||||
// Generator a Hugo meta generator HTML tag.
|
|
||||||
func (i HugoInfo) Generator() template.HTML {
|
|
||||||
return template.HTML(fmt.Sprintf(`<meta name="generator" content="Hugo %s">`, CurrentVersion.String()))
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsDevelopment reports whether the current running environment is "development".
|
|
||||||
func (i HugoInfo) IsDevelopment() bool {
|
|
||||||
return i.Environment == EnvironmentDevelopment
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsProduction reports whether the current running environment is "production".
|
|
||||||
func (i HugoInfo) IsProduction() bool {
|
|
||||||
return i.Environment == EnvironmentProduction
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsServer reports whether the built-in server is running.
|
|
||||||
func (i HugoInfo) IsServer() bool {
|
|
||||||
return i.conf.Running()
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsExtended reports whether the Hugo binary is the extended version.
|
|
||||||
func (i HugoInfo) IsExtended() bool {
|
|
||||||
return IsExtended
|
|
||||||
}
|
|
||||||
|
|
||||||
// WorkingDir returns the project working directory.
|
|
||||||
func (i HugoInfo) WorkingDir() string {
|
|
||||||
return i.conf.WorkingDir()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deps gets a list of dependencies for this Hugo build.
|
|
||||||
func (i HugoInfo) Deps() []*Dependency {
|
|
||||||
return i.deps
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i HugoInfo) Store() *hstore.Scratch {
|
|
||||||
return i.store
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sites returns all sites for all dimensions.
|
|
||||||
func (i HugoInfo) Sites() any {
|
|
||||||
if i.sitesProvider == nil {
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return i.sitesProvider.Sites()
|
return &BuildInfo{
|
||||||
|
Revision: bi.Revision,
|
||||||
|
RevisionTime: bi.RevisionTime,
|
||||||
|
GoVersion: bi.GoVersion,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type contextKey uint8
|
type contextKey uint8
|
||||||
@@ -159,6 +82,7 @@ const (
|
|||||||
|
|
||||||
var markupScope = contexthelpers.NewContextDispatcher[string](contextKeyMarkupScope)
|
var markupScope = contexthelpers.NewContextDispatcher[string](contextKeyMarkupScope)
|
||||||
|
|
||||||
|
// Context gives access to some of the context scoped variables.
|
||||||
type Context struct{}
|
type Context struct{}
|
||||||
|
|
||||||
func (c Context) MarkupScope(ctx context.Context) string {
|
func (c Context) MarkupScope(ctx context.Context) string {
|
||||||
@@ -175,56 +99,6 @@ func GetMarkupScope(ctx context.Context) string {
|
|||||||
return markupScope.Get(ctx)
|
return markupScope.Get(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConfigProvider represents the config options that are relevant for HugoInfo.
|
|
||||||
type ConfigProvider interface {
|
|
||||||
Environment() string
|
|
||||||
Running() bool
|
|
||||||
WorkingDir() string
|
|
||||||
IsMultihost() bool
|
|
||||||
IsMultilingual() bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// SitesProvider provides access to all sites.
|
|
||||||
type SitesProvider interface {
|
|
||||||
Sites() any
|
|
||||||
}
|
|
||||||
|
|
||||||
// HugoInfoOptions defines the providers required to initialize HugoInfo.
|
|
||||||
type HugoInfoOptions struct {
|
|
||||||
Conf ConfigProvider
|
|
||||||
SitesProvider SitesProvider
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewInfo creates a new Hugo Info object.
|
|
||||||
func NewInfo(opts HugoInfoOptions, deps []*Dependency) HugoInfo {
|
|
||||||
if opts.Conf.Environment() == "" {
|
|
||||||
panic("environment not set")
|
|
||||||
}
|
|
||||||
var (
|
|
||||||
commitHash string
|
|
||||||
buildDate string
|
|
||||||
goVersion string
|
|
||||||
)
|
|
||||||
|
|
||||||
bi := getBuildInfo()
|
|
||||||
if bi != nil {
|
|
||||||
commitHash = bi.Revision
|
|
||||||
buildDate = bi.RevisionTime
|
|
||||||
goVersion = bi.GoVersion
|
|
||||||
}
|
|
||||||
|
|
||||||
return HugoInfo{
|
|
||||||
CommitHash: commitHash,
|
|
||||||
BuildDate: buildDate,
|
|
||||||
Environment: opts.Conf.Environment(),
|
|
||||||
conf: opts.Conf,
|
|
||||||
deps: deps,
|
|
||||||
sitesProvider: opts.SitesProvider,
|
|
||||||
store: hstore.NewScratch(),
|
|
||||||
GoVersion: goVersion,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetExecEnviron creates and gets the common os/exec environment used in the
|
// GetExecEnviron creates and gets the common os/exec environment used in the
|
||||||
// external programs we interact with via os/exec, e.g. postcss.
|
// external programs we interact with via os/exec, e.g. postcss.
|
||||||
func GetExecEnviron(workDir string, cfg config.AllProvider, fs afero.Fs) []string {
|
func GetExecEnviron(workDir string, cfg config.AllProvider, fs afero.Fs) []string {
|
||||||
|
|||||||
+10
-69
@@ -15,49 +15,12 @@ package hugo
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/bep/logg"
|
"github.com/bep/logg"
|
||||||
qt "github.com/frankban/quicktest"
|
qt "github.com/frankban/quicktest"
|
||||||
"github.com/gohugoio/hugo/common/version"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestHugoInfo(t *testing.T) {
|
|
||||||
c := qt.New(t)
|
|
||||||
|
|
||||||
opts := HugoInfoOptions{
|
|
||||||
Conf: testConfig{environment: "production", workingDir: "/mywork", running: false},
|
|
||||||
}
|
|
||||||
hugoInfo := NewInfo(opts, nil)
|
|
||||||
|
|
||||||
c.Assert(hugoInfo.Version(), qt.Equals, CurrentVersion.Version())
|
|
||||||
c.Assert(fmt.Sprintf("%T", version.VersionString("")), qt.Equals, fmt.Sprintf("%T", hugoInfo.Version()))
|
|
||||||
c.Assert(hugoInfo.WorkingDir(), qt.Equals, "/mywork")
|
|
||||||
|
|
||||||
bi := getBuildInfo()
|
|
||||||
if bi != nil {
|
|
||||||
c.Assert(hugoInfo.CommitHash, qt.Equals, bi.Revision)
|
|
||||||
c.Assert(hugoInfo.BuildDate, qt.Equals, bi.RevisionTime)
|
|
||||||
c.Assert(hugoInfo.GoVersion, qt.Equals, bi.GoVersion)
|
|
||||||
}
|
|
||||||
c.Assert(hugoInfo.Environment, qt.Equals, "production")
|
|
||||||
c.Assert(string(hugoInfo.Generator()), qt.Contains, fmt.Sprintf("Hugo %s", hugoInfo.Version()))
|
|
||||||
c.Assert(hugoInfo.IsDevelopment(), qt.Equals, false)
|
|
||||||
c.Assert(hugoInfo.IsProduction(), qt.Equals, true)
|
|
||||||
c.Assert(hugoInfo.IsExtended(), qt.Equals, IsExtended)
|
|
||||||
c.Assert(hugoInfo.IsServer(), qt.Equals, false)
|
|
||||||
|
|
||||||
opts = HugoInfoOptions{
|
|
||||||
Conf: testConfig{environment: "development", running: true},
|
|
||||||
}
|
|
||||||
devHugoInfo := NewInfo(opts, nil)
|
|
||||||
|
|
||||||
c.Assert(devHugoInfo.IsDevelopment(), qt.Equals, true)
|
|
||||||
c.Assert(devHugoInfo.IsProduction(), qt.Equals, false)
|
|
||||||
c.Assert(devHugoInfo.IsServer(), qt.Equals, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDeprecationLogLevelFromVersion(t *testing.T) {
|
func TestDeprecationLogLevelFromVersion(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
|
|
||||||
@@ -79,42 +42,20 @@ func TestDeprecationLogLevelFromVersion(t *testing.T) {
|
|||||||
func TestMarkupScope(t *testing.T) {
|
func TestMarkupScope(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
|
|
||||||
opts := HugoInfoOptions{
|
|
||||||
Conf: testConfig{environment: "production", workingDir: "/mywork", running: false},
|
|
||||||
}
|
|
||||||
info := NewInfo(opts, nil)
|
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
ctx = SetMarkupScope(ctx, "foo")
|
ctx = SetMarkupScope(ctx, "foo")
|
||||||
|
|
||||||
c.Assert(info.Context.MarkupScope(ctx), qt.Equals, "foo")
|
var hugoCtx Context
|
||||||
|
c.Assert(hugoCtx.MarkupScope(ctx), qt.Equals, "foo")
|
||||||
|
c.Assert(GetMarkupScope(ctx), qt.Equals, "foo")
|
||||||
}
|
}
|
||||||
|
|
||||||
type testConfig struct {
|
func TestGetBuildInfo(t *testing.T) {
|
||||||
environment string
|
c := qt.New(t)
|
||||||
running bool
|
|
||||||
workingDir string
|
|
||||||
multihost bool
|
|
||||||
multilingual bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c testConfig) Environment() string {
|
bi := GetBuildInfo()
|
||||||
return c.environment
|
// In test mode, build info may or may not be available.
|
||||||
}
|
if bi != nil {
|
||||||
|
c.Assert(bi.GoVersion, qt.Not(qt.Equals), "")
|
||||||
func (c testConfig) Running() bool {
|
}
|
||||||
return c.running
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c testConfig) WorkingDir() string {
|
|
||||||
return c.workingDir
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c testConfig) IsMultihost() bool {
|
|
||||||
return c.multihost
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c testConfig) IsMultilingual() bool {
|
|
||||||
return c.multilingual
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"iter"
|
"iter"
|
||||||
"slices"
|
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
@@ -42,7 +41,6 @@ import (
|
|||||||
"github.com/gohugoio/hugo/common/hmaps"
|
"github.com/gohugoio/hugo/common/hmaps"
|
||||||
"github.com/gohugoio/hugo/common/hsync"
|
"github.com/gohugoio/hugo/common/hsync"
|
||||||
"github.com/gohugoio/hugo/common/htime"
|
"github.com/gohugoio/hugo/common/htime"
|
||||||
"github.com/gohugoio/hugo/common/hugo"
|
|
||||||
"github.com/gohugoio/hugo/common/loggers"
|
"github.com/gohugoio/hugo/common/loggers"
|
||||||
"github.com/gohugoio/hugo/common/para"
|
"github.com/gohugoio/hugo/common/para"
|
||||||
"github.com/gohugoio/hugo/common/terminal"
|
"github.com/gohugoio/hugo/common/terminal"
|
||||||
@@ -71,7 +69,7 @@ type HugoSites struct {
|
|||||||
|
|
||||||
Configs *allconfig.Configs
|
Configs *allconfig.Configs
|
||||||
|
|
||||||
hugoInfo hugo.HugoInfo
|
hugoInfo page.HugoInfo
|
||||||
|
|
||||||
// Render output formats for all sites.
|
// Render output formats for all sites.
|
||||||
renderFormats output.Formats
|
renderFormats output.Formats
|
||||||
@@ -124,14 +122,18 @@ type HugoSites struct {
|
|||||||
buildCounter atomic.Uint64
|
buildCounter atomic.Uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
// hugoSitesSitesProvider is a wrapper that implements hugo.SitesProvider.
|
// hugoSitesSitesProvider is a wrapper that implements page.SitesProvider.
|
||||||
// This avoids naming conflict with HugoSites.Sites field.
|
// This avoids naming conflict with HugoSites.Sites field.
|
||||||
type hugoSitesSitesProvider struct {
|
type hugoSitesSitesProvider struct {
|
||||||
h *HugoSites
|
h *HugoSites
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sp hugoSitesSitesProvider) Sites() any {
|
func (sp hugoSitesSitesProvider) Sites() page.Sites {
|
||||||
return slices.Collect(sp.h.allSites(nil))
|
sites := make(page.Sites, 0)
|
||||||
|
for s := range sp.h.allSites(nil) {
|
||||||
|
sites = append(sites, s.Site())
|
||||||
|
}
|
||||||
|
return sites
|
||||||
}
|
}
|
||||||
|
|
||||||
type progressReporter struct {
|
type progressReporter struct {
|
||||||
|
|||||||
@@ -607,6 +607,7 @@ func (ps *pageState) initCommonProviders(pp pagePaths) error {
|
|||||||
ps.targetPathDescriptor = pp.targetPathDescriptor
|
ps.targetPathDescriptor = pp.targetPathDescriptor
|
||||||
ps.RefProvider = newPageRef(ps)
|
ps.RefProvider = newPageRef(ps)
|
||||||
ps.SitesProvider = ps.s
|
ps.SitesProvider = ps.s
|
||||||
|
ps.SiteProvider = ps
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ type pageCommon struct {
|
|||||||
page.RawContentProvider
|
page.RawContentProvider
|
||||||
page.RefProvider
|
page.RefProvider
|
||||||
page.ShortcodeInfoProvider
|
page.ShortcodeInfoProvider
|
||||||
|
page.SiteProvider
|
||||||
page.SitesProvider
|
page.SitesProvider
|
||||||
page.TranslationsProvider
|
page.TranslationsProvider
|
||||||
page.TreeProvider
|
page.TreeProvider
|
||||||
|
|||||||
+11
-9
@@ -520,11 +520,19 @@ func newHugoSites(
|
|||||||
// Create a sites provider that avoids naming conflict with HugoSites.Sites field.
|
// Create a sites provider that avoids naming conflict with HugoSites.Sites field.
|
||||||
sp := hugoSitesSitesProvider{h: h}
|
sp := hugoSitesSitesProvider{h: h}
|
||||||
|
|
||||||
opts := hugo.HugoInfoOptions{
|
opts := page.HugoInfoOptions{
|
||||||
Conf: h.Configs.GetFirstLanguageConfig(),
|
Conf: h.Configs.GetFirstLanguageConfig(),
|
||||||
SitesProvider: sp,
|
SitesProvider: sp,
|
||||||
|
Deps: dependencies,
|
||||||
}
|
}
|
||||||
h.hugoInfo = hugo.NewInfo(opts, dependencies)
|
|
||||||
|
if bi := hugo.GetBuildInfo(); bi != nil {
|
||||||
|
opts.CommitHash = bi.Revision
|
||||||
|
opts.BuildDate = bi.RevisionTime
|
||||||
|
opts.GoVersion = bi.GoVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
h.hugoInfo = page.NewHugoInfo(opts)
|
||||||
|
|
||||||
var prototype *deps.Deps
|
var prototype *deps.Deps
|
||||||
|
|
||||||
@@ -668,13 +676,7 @@ func (s *Site) MainSections() []string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Returns a struct with some information about the build.
|
// Returns a struct with some information about the build.
|
||||||
func (s *Site) Hugo() hugo.HugoInfo {
|
func (s *Site) Hugo() page.HugoInfo {
|
||||||
if s.h == nil {
|
|
||||||
panic("site: hugo: h not initialized")
|
|
||||||
}
|
|
||||||
if s.h.hugoInfo.Environment == "" {
|
|
||||||
panic("site: hugo: hugoInfo not initialized")
|
|
||||||
}
|
|
||||||
return s.h.hugoInfo
|
return s.h.hugoInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,158 @@
|
|||||||
|
// Copyright 2026 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 page
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"html/template"
|
||||||
|
|
||||||
|
"github.com/gohugoio/hugo/common/hstore"
|
||||||
|
"github.com/gohugoio/hugo/common/hugo"
|
||||||
|
"github.com/gohugoio/hugo/common/version"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ hstore.StoreProvider = (*HugoInfo)(nil)
|
||||||
|
|
||||||
|
type hugoInfoProviders struct {
|
||||||
|
SitesProvider
|
||||||
|
}
|
||||||
|
|
||||||
|
// HugoInfo contains information about the current Hugo environment.
|
||||||
|
type HugoInfo struct {
|
||||||
|
CommitHash string
|
||||||
|
BuildDate string
|
||||||
|
|
||||||
|
// Version of Go that the Hugo binary was built with.
|
||||||
|
GoVersion string
|
||||||
|
|
||||||
|
// Avoid exporting the embedded providers directly, as they may be used by the template layer.
|
||||||
|
hugoInfoProviders
|
||||||
|
|
||||||
|
// Context gives access to some of the context scoped variables.
|
||||||
|
Context hugo.Context
|
||||||
|
|
||||||
|
opts HugoInfoOptions
|
||||||
|
store *hstore.Scratch
|
||||||
|
}
|
||||||
|
|
||||||
|
// Version returns the current version as a comparable version string.
|
||||||
|
func (i HugoInfo) Version() version.VersionString {
|
||||||
|
return hugo.CurrentVersion.Version()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generator returns a Hugo meta generator HTML tag.
|
||||||
|
func (i HugoInfo) Generator() template.HTML {
|
||||||
|
return template.HTML(fmt.Sprintf(`<meta name="generator" content="Hugo %s">`, hugo.CurrentVersion.String()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Environment returns the build environment.
|
||||||
|
// Defaults are "production" (hugo) and "development" (hugo server).
|
||||||
|
// This can also be set by the user.
|
||||||
|
// It can be any string, but it will be all lower case.
|
||||||
|
func (i HugoInfo) Environment() string {
|
||||||
|
return i.opts.Conf.Environment()
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsDevelopment reports whether the current running environment is "development".
|
||||||
|
func (i HugoInfo) IsDevelopment() bool {
|
||||||
|
return i.Environment() == hugo.EnvironmentDevelopment
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsProduction reports whether the current running environment is "production".
|
||||||
|
func (i HugoInfo) IsProduction() bool {
|
||||||
|
return i.Environment() == hugo.EnvironmentProduction
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsServer reports whether the built-in server is running.
|
||||||
|
func (i HugoInfo) IsServer() bool {
|
||||||
|
return i.opts.Conf.Running()
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsExtended reports whether the Hugo binary is the extended version.
|
||||||
|
func (i HugoInfo) IsExtended() bool {
|
||||||
|
return hugo.IsExtended
|
||||||
|
}
|
||||||
|
|
||||||
|
// WorkingDir returns the project working directory.
|
||||||
|
func (i HugoInfo) WorkingDir() string {
|
||||||
|
return i.opts.Conf.WorkingDir()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deps gets a list of dependencies for this Hugo build.
|
||||||
|
func (i HugoInfo) Deps() []*hugo.Dependency {
|
||||||
|
return i.opts.Deps
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i HugoInfo) Store() *hstore.Scratch {
|
||||||
|
return i.store
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use hugo.IsMultihost instead.
|
||||||
|
func (i HugoInfo) IsMultiHost() bool {
|
||||||
|
hugo.Deprecate("hugo.IsMultiHost", "Use hugo.IsMultihost instead.", "v0.124.0")
|
||||||
|
return i.opts.Conf.IsMultihost()
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsMultihost reports whether each configured language has a unique baseURL.
|
||||||
|
func (i HugoInfo) IsMultihost() bool {
|
||||||
|
return i.opts.Conf.IsMultihost()
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsMultilingual reports whether there are two or more configured languages.
|
||||||
|
func (i HugoInfo) IsMultilingual() bool {
|
||||||
|
return i.opts.Conf.IsMultilingual()
|
||||||
|
}
|
||||||
|
|
||||||
|
// HugoInfoConfigProvider represents the config options that are relevant for HugoInfo.
|
||||||
|
type HugoInfoConfigProvider interface {
|
||||||
|
Environment() string
|
||||||
|
Running() bool
|
||||||
|
WorkingDir() string
|
||||||
|
IsMultihost() bool
|
||||||
|
IsMultilingual() bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// HugoInfoOptions defines the providers required to initialize HugoInfo.
|
||||||
|
type HugoInfoOptions struct {
|
||||||
|
Conf HugoInfoConfigProvider
|
||||||
|
Deps []*hugo.Dependency
|
||||||
|
SitesProvider SitesProvider
|
||||||
|
CommitHash string
|
||||||
|
BuildDate string
|
||||||
|
GoVersion string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewHugoInfo creates a new Hugo Info object.
|
||||||
|
func NewHugoInfo(opts HugoInfoOptions) HugoInfo {
|
||||||
|
if opts.Conf == nil {
|
||||||
|
panic("config provider not set")
|
||||||
|
}
|
||||||
|
if opts.Conf.Environment() == "" {
|
||||||
|
panic("environment not set")
|
||||||
|
}
|
||||||
|
if opts.SitesProvider == nil {
|
||||||
|
opts.SitesProvider = nopSitesProvider{}
|
||||||
|
}
|
||||||
|
|
||||||
|
return HugoInfo{
|
||||||
|
CommitHash: opts.CommitHash,
|
||||||
|
BuildDate: opts.BuildDate,
|
||||||
|
GoVersion: opts.GoVersion,
|
||||||
|
|
||||||
|
hugoInfoProviders: hugoInfoProviders{SitesProvider: opts.SitesProvider},
|
||||||
|
|
||||||
|
opts: opts,
|
||||||
|
store: hstore.NewScratch(),
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
// Copyright 2026 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 page
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
qt "github.com/frankban/quicktest"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNewHugoInfo(t *testing.T) {
|
||||||
|
c := qt.New(t)
|
||||||
|
|
||||||
|
c.Assert(func() { NewHugoInfo(HugoInfoOptions{}) }, qt.PanicMatches, "config provider not set")
|
||||||
|
|
||||||
|
opts := HugoInfoOptions{
|
||||||
|
Conf: testConfig{environment: "development"},
|
||||||
|
}
|
||||||
|
|
||||||
|
h := NewHugoInfo(opts)
|
||||||
|
|
||||||
|
c.Assert(h.Environment(), qt.Equals, "development")
|
||||||
|
c.Assert(h.Sites(), qt.IsNil)
|
||||||
|
}
|
||||||
+13
-3
@@ -374,6 +374,7 @@ type PageWithoutContent interface {
|
|||||||
resource.TranslationKeyProvider
|
resource.TranslationKeyProvider
|
||||||
TranslationsProvider
|
TranslationsProvider
|
||||||
|
|
||||||
|
SiteProvider
|
||||||
SitesProvider
|
SitesProvider
|
||||||
|
|
||||||
// Helper methods
|
// Helper methods
|
||||||
@@ -453,14 +454,23 @@ type ShortcodeInfoProvider interface {
|
|||||||
HasShortcode(name string) bool
|
HasShortcode(name string) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type nopSitesProvider struct{}
|
||||||
|
|
||||||
|
func (nopSitesProvider) Sites() Sites {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// SitesProvider provide accessors to get sites.
|
// SitesProvider provide accessors to get sites.
|
||||||
type SitesProvider interface {
|
type SitesProvider interface {
|
||||||
// Site returns the current site.
|
// Sites returns all sites for all dimensions.
|
||||||
Site() Site
|
|
||||||
// Sites returns all sites.
|
|
||||||
Sites() Sites
|
Sites() Sites
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SiteProvider provides access to the current site.
|
||||||
|
type SiteProvider interface {
|
||||||
|
Site() Site
|
||||||
|
}
|
||||||
|
|
||||||
// TableOfContentsProvider provides the table of contents for a Page.
|
// TableOfContentsProvider provides the table of contents for a Page.
|
||||||
type TableOfContentsProvider interface {
|
type TableOfContentsProvider interface {
|
||||||
// TableOfContents returns the table of contents for the page rendered as HTML.
|
// TableOfContents returns the table of contents for the page rendered as HTML.
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ type PageMatcher struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m PageMatcher) Matches(p Page) bool {
|
func (m PageMatcher) Matches(p Page) bool {
|
||||||
return m.Match(p.Kind(), p.Path(), p.Site().Hugo().Environment, nil)
|
return m.Match(p.Kind(), p.Path(), p.Site().Hugo().Environment(), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m PageMatcher) Match(kind, path, environment string, sitesMatrix sitesmatrix.VectorProvider) bool {
|
func (m PageMatcher) Match(kind, path, environment string, sitesMatrix sitesmatrix.VectorProvider) bool {
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/common/hmaps"
|
"github.com/gohugoio/hugo/common/hmaps"
|
||||||
"github.com/gohugoio/hugo/common/hugo"
|
|
||||||
"github.com/gohugoio/hugo/common/loggers"
|
"github.com/gohugoio/hugo/common/loggers"
|
||||||
"github.com/gohugoio/hugo/hugolib/sitesmatrix"
|
"github.com/gohugoio/hugo/hugolib/sitesmatrix"
|
||||||
|
|
||||||
@@ -28,21 +27,21 @@ import (
|
|||||||
func TestPageMatcher(t *testing.T) {
|
func TestPageMatcher(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
|
|
||||||
opts := hugo.HugoInfoOptions{
|
opts := HugoInfoOptions{
|
||||||
Conf: testConfig{environment: "development"},
|
Conf: testConfig{environment: "development"},
|
||||||
}
|
}
|
||||||
developmentTestSite := testSite{h: hugo.NewInfo(opts, nil)}
|
developmentTestSite := &testSite{h: NewHugoInfo(opts)}
|
||||||
|
|
||||||
opts = hugo.HugoInfoOptions{
|
opts = HugoInfoOptions{
|
||||||
Conf: testConfig{environment: "production"},
|
Conf: testConfig{environment: "production"},
|
||||||
}
|
}
|
||||||
productionTestSite := testSite{h: hugo.NewInfo(opts, nil)}
|
productionTestSite := &testSite{h: NewHugoInfo(opts)}
|
||||||
|
|
||||||
dec := cascadeConfigDecoder{}
|
dec := cascadeConfigDecoder{}
|
||||||
|
|
||||||
p1, p2, p3 := &testPage{path: "/p1", kind: "section", lang: "en", site: developmentTestSite},
|
p1, p2, p3 := &testPage{path: "/p1", kind: "section", lang: "en", site: developmentTestSite},
|
||||||
&testPage{path: "p2", kind: "page", lang: "no", site: productionTestSite},
|
&testPage{path: "p2", kind: "page", lang: "no", site: productionTestSite},
|
||||||
&testPage{path: "p3", kind: "page", lang: "en"}
|
&testPage{path: "p3", kind: "page", lang: "en", site: developmentTestSite}
|
||||||
|
|
||||||
c.Run("Matches", func(c *qt.C) {
|
c.Run("Matches", func(c *qt.C) {
|
||||||
m := PageMatcher{Kind: "section"}
|
m := PageMatcher{Kind: "section"}
|
||||||
@@ -68,7 +67,7 @@ func TestPageMatcher(t *testing.T) {
|
|||||||
m = PageMatcher{Environment: "development"}
|
m = PageMatcher{Environment: "development"}
|
||||||
c.Assert(m.Matches(p1), qt.Equals, true)
|
c.Assert(m.Matches(p1), qt.Equals, true)
|
||||||
c.Assert(m.Matches(p2), qt.Equals, false)
|
c.Assert(m.Matches(p2), qt.Equals, false)
|
||||||
c.Assert(m.Matches(p3), qt.Equals, false)
|
c.Assert(m.Matches(p3), qt.Equals, true)
|
||||||
|
|
||||||
m = PageMatcher{Environment: "production"}
|
m = PageMatcher{Environment: "production"}
|
||||||
c.Assert(m.Matches(p1), qt.Equals, false)
|
c.Assert(m.Matches(p1), qt.Equals, false)
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ import (
|
|||||||
|
|
||||||
"github.com/gohugoio/hugo/common/hmaps"
|
"github.com/gohugoio/hugo/common/hmaps"
|
||||||
"github.com/gohugoio/hugo/common/hstore"
|
"github.com/gohugoio/hugo/common/hstore"
|
||||||
"github.com/gohugoio/hugo/common/hugo"
|
|
||||||
"github.com/gohugoio/hugo/common/paths"
|
"github.com/gohugoio/hugo/common/paths"
|
||||||
"github.com/gohugoio/hugo/source"
|
"github.com/gohugoio/hugo/source"
|
||||||
|
|
||||||
@@ -196,7 +195,7 @@ func (p *nopPage) HasShortcode(name string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *nopPage) Hugo() (h hugo.HugoInfo) {
|
func (p *nopPage) Hugo() (h HugoInfo) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ import (
|
|||||||
|
|
||||||
"github.com/gohugoio/hugo/config"
|
"github.com/gohugoio/hugo/config"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/common/hugo"
|
|
||||||
"github.com/gohugoio/hugo/langs"
|
"github.com/gohugoio/hugo/langs"
|
||||||
"github.com/gohugoio/hugo/navigation"
|
"github.com/gohugoio/hugo/navigation"
|
||||||
)
|
)
|
||||||
@@ -87,7 +86,7 @@ type Site interface {
|
|||||||
IsDefault() bool
|
IsDefault() bool
|
||||||
|
|
||||||
// Returns a struct with some information about the build.
|
// Returns a struct with some information about the build.
|
||||||
Hugo() hugo.HugoInfo
|
Hugo() HugoInfo
|
||||||
|
|
||||||
// Returns the BaseURL for this Site.
|
// Returns the BaseURL for this Site.
|
||||||
BaseURL() string
|
BaseURL() string
|
||||||
@@ -251,7 +250,7 @@ func (s *siteWrapper) Config() SiteConfig {
|
|||||||
return s.s.Config()
|
return s.s.Config()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *siteWrapper) Hugo() hugo.HugoInfo {
|
func (s *siteWrapper) Hugo() HugoInfo {
|
||||||
return s.s.Hugo()
|
return s.s.Hugo()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -314,11 +313,11 @@ func (s *siteWrapper) CheckReady() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type testSite struct {
|
type testSite struct {
|
||||||
h hugo.HugoInfo
|
h HugoInfo
|
||||||
l *langs.Language
|
l *langs.Language
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t testSite) Hugo() hugo.HugoInfo {
|
func (t testSite) Hugo() HugoInfo {
|
||||||
return t.h
|
return t.h
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -451,11 +450,11 @@ func (s testSite) CheckReady() {
|
|||||||
|
|
||||||
// NewDummyHugoSite creates a new minimal test site.
|
// NewDummyHugoSite creates a new minimal test site.
|
||||||
func NewDummyHugoSite(conf config.AllProvider) Site {
|
func NewDummyHugoSite(conf config.AllProvider) Site {
|
||||||
opts := hugo.HugoInfoOptions{
|
opts := HugoInfoOptions{
|
||||||
Conf: conf,
|
Conf: conf,
|
||||||
}
|
}
|
||||||
return testSite{
|
return testSite{
|
||||||
h: hugo.NewInfo(opts, nil),
|
h: NewHugoInfo(opts),
|
||||||
l: &langs.Language{
|
l: &langs.Language{
|
||||||
Lang: "en",
|
Lang: "en",
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ import (
|
|||||||
|
|
||||||
"github.com/gohugoio/hugo/common/hmaps"
|
"github.com/gohugoio/hugo/common/hmaps"
|
||||||
"github.com/gohugoio/hugo/common/hstore"
|
"github.com/gohugoio/hugo/common/hstore"
|
||||||
"github.com/gohugoio/hugo/common/hugo"
|
|
||||||
"github.com/gohugoio/hugo/common/paths"
|
"github.com/gohugoio/hugo/common/paths"
|
||||||
"github.com/gohugoio/hugo/config"
|
"github.com/gohugoio/hugo/config"
|
||||||
"github.com/gohugoio/hugo/hugofs"
|
"github.com/gohugoio/hugo/hugofs"
|
||||||
@@ -75,7 +74,7 @@ func newTestPageWithFile(filename string) *testPage {
|
|||||||
currentSection: &testPage{
|
currentSection: &testPage{
|
||||||
sectionEntries: []string{"a", "b", "c"},
|
sectionEntries: []string{"a", "b", "c"},
|
||||||
},
|
},
|
||||||
site: testSite{l: l},
|
site: &testSite{l: l},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,7 +85,7 @@ type testPage struct {
|
|||||||
linkTitle string
|
linkTitle string
|
||||||
lang string
|
lang string
|
||||||
section string
|
section string
|
||||||
site testSite
|
site *testSite
|
||||||
|
|
||||||
content string
|
content string
|
||||||
|
|
||||||
@@ -248,7 +247,7 @@ func (p *testPage) HasShortcode(name string) bool {
|
|||||||
panic("testpage: not implemented")
|
panic("testpage: not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *testPage) Hugo() hugo.HugoInfo {
|
func (p *testPage) Hugo() HugoInfo {
|
||||||
panic("testpage: not implemented")
|
panic("testpage: not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -528,6 +527,9 @@ func (p *testPage) SectionsPath() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *testPage) Site() Site {
|
func (p *testPage) Site() Site {
|
||||||
|
if p.site == nil {
|
||||||
|
panic(fmt.Sprintf("testpage: site is nil for %q", p.path))
|
||||||
|
}
|
||||||
return p.site
|
return p.site
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user