Skip to content

Commit

Permalink
Add hugo.Deps
Browse files Browse the repository at this point in the history
Fixes #8949
  • Loading branch information
bep committed Jan 11, 2022
1 parent d82cef5 commit 7396aa9
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 6 deletions.
35 changes: 34 additions & 1 deletion common/hugo/hugo.go
Expand Up @@ -21,6 +21,7 @@ import (
"runtime/debug"
"sort"
"strings"
"time"

"github.com/gohugoio/hugo/hugofs/files"

Expand Down Expand Up @@ -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.
Expand All @@ -77,15 +80,21 @@ 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
}
return Info{
CommitHash: commitHash,
BuildDate: buildDate,
Environment: environment,
deps: deps,
}
}

Expand Down Expand Up @@ -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
}
4 changes: 2 additions & 2 deletions common/hugo/hugo_test.go
Expand Up @@ -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()))
Expand All @@ -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)
}
64 changes: 64 additions & 0 deletions docs/content/en/functions/hugo.md
Expand Up @@ -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>
```
2 changes: 1 addition & 1 deletion hugolib/hugo_smoke_test.go
Expand Up @@ -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 }}`
Expand Down
29 changes: 28 additions & 1 deletion hugolib/site.go
Expand Up @@ -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"
Expand Down Expand Up @@ -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"),
Expand All @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion resources/page/site.go
Expand Up @@ -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),
}
}

0 comments on commit 7396aa9

Please sign in to comment.