Add hugo.Deps

Fixes #8949
This commit is contained in:
Bjørn Erik Pedersen 2022-01-11 15:07:04 +01:00
parent d82cef5c53
commit 7396aa945a
6 changed files with 130 additions and 6 deletions

View file

@ -21,6 +21,7 @@ import (
"runtime/debug"
"sort"
"strings"
"time"
"github.com/gohugoio/hugo/hugofs/files"
@ -57,6 +58,8 @@ type Info struct {
// This can also be set by the user.
// It can be any string, but it will be all lower case.
Environment string
deps []*Dependency
}
// Version returns the current version as a comparable version string.
@ -77,8 +80,13 @@ func (i Info) IsExtended() bool {
return IsExtended
}
// Deps gets a list of dependencies for this Hugo build.
func (i Info) Deps() []*Dependency {
return i.deps
}
// NewInfo creates a new Hugo Info object.
func NewInfo(environment string) Info {
func NewInfo(environment string, deps []*Dependency) Info {
if environment == "" {
environment = EnvironmentProduction
}
@ -86,6 +94,7 @@ func NewInfo(environment string) Info {
CommitHash: commitHash,
BuildDate: buildDate,
Environment: environment,
deps: deps,
}
}
@ -156,3 +165,27 @@ func IsRunningAsTest() bool {
}
return false
}
// Dependency is a single dependency, which can be either a Hugo Module or a local theme.
type Dependency struct {
// Returns the path to this module.
// This will either be the module path, e.g. "github.com/gohugoio/myshortcodes",
// or the path below your /theme folder, e.g. "mytheme".
Path string
// The module version.
Version string
// Whether this dependency is vendored.
Vendor bool
// Time version was created.
Time time.Time
// In the dependency tree, this is the first module that defines this module
// as a dependency.
Owner *Dependency
// Replaced by this dependency.
Replace *Dependency
}

View file

@ -23,7 +23,7 @@ import (
func TestHugoInfo(t *testing.T) {
c := qt.New(t)
hugoInfo := NewInfo("")
hugoInfo := NewInfo("", nil)
c.Assert(hugoInfo.Version(), qt.Equals, CurrentVersion.Version())
c.Assert(fmt.Sprintf("%T", VersionString("")), qt.Equals, fmt.Sprintf("%T", hugoInfo.Version()))
@ -34,6 +34,6 @@ func TestHugoInfo(t *testing.T) {
c.Assert(hugoInfo.IsProduction(), qt.Equals, true)
c.Assert(hugoInfo.IsExtended(), qt.Equals, IsExtended)
devHugoInfo := NewInfo("development")
devHugoInfo := NewInfo("development", nil)
c.Assert(devHugoInfo.IsProduction(), qt.Equals, false)
}

View file

@ -49,3 +49,67 @@ hugo.IsProduction
{{% note "Use the Hugo Generator Tag" %}}
We highly recommend using `hugo.Generator` in your website's `<head>`. `hugo.Generator` is included by default in all themes hosted on [themes.gohugo.io](https://themes.gohugo.io). The generator tag allows the Hugo team to track the usage and popularity of Hugo.
{{% /note %}}
hugo.Deps
: See [hugo.Deps](#hugodeps)
## hugo.Deps
{{< new-in "0.92.0" >}}
`hugo.Deps` returns a list of dependencies for a project (either Hugo Modules or local theme components).
Eeach dependency contains:
Path (string)
: Returns the path to this module. This will either be the module path, e.g. "github.com/gohugoio/myshortcodes", or the path below your /theme folder, e.g. "mytheme".
Version (string)
: The module version.
Vendor (bool)
: Whether this dependency is vendored.
Time (time.Time)
: Time version was created.
Owner
: In the dependency tree, this is the first module that defines this module as a dependency.
Replace (*Dependency)
: Replaced by this dependency.
An example table listing the dependencies:
```html
<h2>Dependencies</h2>
<table class="table table-dark">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Path</th>
<th scope="col">Version</th>
<th scope="col">Time</th>
<th scope="col">Vendor</th>
</tr>
</thead>
<tbody>
{{ range $index, $element := hugo.Deps }}
<tr>
<th scope="row">{{ add $index 1 }}</th>
<td>{{ with $element.Owner }}{{.Path }}{{ else }}PROJECT{{ end }}</td>
<td>
{{ $element.Path }}
{{ with $element.Replace}}
=> {{ .Path }}
{{ end }}
</td>
<td>{{ $element.Version }}</td>
<td>{{ with $element.Time }}{{ . }}{{ end }}</td>
<td>{{ $element.Vendor }}</td>
</tr>
{{ end }}
</tbody>
</table>
```

View file

@ -162,7 +162,7 @@ Some **Markdown** in JSON shortcode.
b.WithContent("blog/mybundle/mydata.csv", "Bundled CSV")
const (
commonPageTemplate = `|{{ .Kind }}|{{ .Title }}|{{ .Path }}|{{ .Summary }}|{{ .Content }}|RelPermalink: {{ .RelPermalink }}|WordCount: {{ .WordCount }}|Pages: {{ .Pages }}|Data Pages: Pages({{ len .Data.Pages }})|Resources: {{ len .Resources }}|Summary: {{ .Summary }}`
commonPageTemplate = `|{{ .Kind }}|{{ .Title }}|{{ .File.Path }}|{{ .Summary }}|{{ .Content }}|RelPermalink: {{ .RelPermalink }}|WordCount: {{ .WordCount }}|Pages: {{ .Pages }}|Data Pages: Pages({{ len .Data.Pages }})|Resources: {{ len .Resources }}|Summary: {{ .Summary }}`
commonPaginatorTemplate = `|Paginator: {{ with .Paginator }}{{ .PageNumber }}{{ else }}NIL{{ end }}`
commonListTemplateNoPaginator = `|{{ $pages := .Pages }}{{ if .IsHome }}{{ $pages = .Site.RegularPages }}{{ end }}{{ range $i, $e := ($pages | first 1) }}|Render {{ $i }}: {{ .Kind }}|{{ .Render "li" }}|{{ end }}|Site params: {{ $.Site.Params.hugo }}|RelPermalink: {{ .RelPermalink }}`
commonListTemplate = commonPaginatorTemplate + `|{{ $pages := .Pages }}{{ if .IsHome }}{{ $pages = .Site.RegularPages }}{{ end }}{{ range $i, $e := ($pages | first 1) }}|Render {{ $i }}: {{ .Kind }}|{{ .Render "li" }}|{{ end }}|Site params: {{ $.Site.Params.hugo }}|RelPermalink: {{ .RelPermalink }}`

View file

@ -31,6 +31,7 @@ import (
"time"
"github.com/gohugoio/hugo/common/types"
"github.com/gohugoio/hugo/modules"
"golang.org/x/text/unicode/norm"
"github.com/gohugoio/hugo/common/paths"
@ -1333,6 +1334,32 @@ func (s *Site) initializeSiteInfo() error {
}
}
// Assemble dependencies to be used in hugo.Deps.
// TODO(bep) another reminder: We need to clean up this Site vs HugoSites construct.
var deps []*hugo.Dependency
var depFromMod func(m modules.Module) *hugo.Dependency
depFromMod = func(m modules.Module) *hugo.Dependency {
dep := &hugo.Dependency{
Path: m.Path(),
Version: m.Version(),
Time: m.Time(),
Vendor: m.Vendor(),
}
// These are pointers, but this all came from JSON so there's no recursive navigation,
// so just create new values.
if m.Replace() != nil {
dep.Replace = depFromMod(m.Replace())
}
if m.Owner() != nil {
dep.Owner = depFromMod(m.Owner())
}
return dep
}
for _, m := range s.Paths.AllModules {
deps = append(deps, depFromMod(m))
}
s.Info = &SiteInfo{
title: lang.GetString("title"),
Author: lang.GetStringMap("author"),
@ -1351,7 +1378,7 @@ func (s *Site) initializeSiteInfo() error {
permalinks: permalinks,
owner: s.h,
s: s,
hugoInfo: hugo.NewInfo(s.Cfg.GetString("environment")),
hugoInfo: hugo.NewInfo(s.Cfg.GetString("environment"), deps),
}
rssOutputFormat, found := s.outputFormats[page.KindHome].GetByName(output.RSSFormat.Name)

View file

@ -120,7 +120,7 @@ func (t testSite) Data() map[string]interface{} {
// NewDummyHugoSite creates a new minimal test site.
func NewDummyHugoSite(cfg config.Provider) Site {
return testSite{
h: hugo.NewInfo(hugo.EnvironmentProduction),
h: hugo.NewInfo(hugo.EnvironmentProduction, nil),
l: langs.NewLanguage("en", cfg),
}
}