mirror of
https://github.com/gohugoio/hugo.git
synced 2026-09-01 19:22:38 +00:00
Compare commits
77 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2fd4a7d3d6 | |||
| 5a4ac2dac1 | |||
| db1562e134 | |||
| 5b18e10841 | |||
| d7497b28c1 | |||
| d276e901b3 | |||
| 94459680ba | |||
| 9202117ba0 | |||
| a6fa290f67 | |||
| 0bbc2fb523 | |||
| 94e8a90769 | |||
| a461e9d01a | |||
| 48c98a8d24 | |||
| bbd455fe79 | |||
| 8309a2b1c1 | |||
| 2b7231097f | |||
| 13ff4ded76 | |||
| c3289eb5b8 | |||
| 9539069f5e | |||
| 0e305d6958 | |||
| 5adb81ce39 | |||
| 1c0e7c1ae1 | |||
| cad2d8cc70 | |||
| b80853de90 | |||
| 423594e03a | |||
| 64afb7ca51 | |||
| 004bec2e9a | |||
| 9f2e76af65 | |||
| f1d1576822 | |||
| 5930173cd0 | |||
| 3476b53343 | |||
| e792d27017 | |||
| 9d6495d774 | |||
| 42cc5f88b6 | |||
| a6488e7bad | |||
| 65a78cae1e | |||
| 4d6d1d08da | |||
| b60e1bbdfe | |||
| 61cf3c9f63 | |||
| 31fbc081c9 | |||
| cebd886ac1 | |||
| 38f778cfcc | |||
| 48fb9e4de3 | |||
| 0958167b38 | |||
| b37183e48d | |||
| 04ccde3e94 | |||
| 0fcd9a5d87 | |||
| 4146084367 | |||
| 3bc742bea0 | |||
| 1a796d723c | |||
| 64b7b7a897 | |||
| 5ef8a9f32c | |||
| 3bc34666c8 | |||
| 63b236603e | |||
| b107b4b291 | |||
| a4ac188c19 | |||
| b82d95575d | |||
| 4e14cf7607 | |||
| 5697348e17 | |||
| f98e570b17 | |||
| cdb8b0842b | |||
| a360cab75a | |||
| c97fed08f9 | |||
| 53a6210d82 | |||
| 7182809d96 | |||
| 1f8cd2614d | |||
| 9d76b8fa34 | |||
| d706529720 | |||
| 4576c82ed4 | |||
| ff02d41721 | |||
| 63bb2a5b18 | |||
| 7d8011ed63 | |||
| b9a1be2f99 | |||
| 0978245039 | |||
| ff37df830c | |||
| 5857d5524a | |||
| d86eca5bb2 |
@@ -1,6 +1,6 @@
|
||||
defaults: &defaults
|
||||
docker:
|
||||
- image: bepsays/ci-goreleaser:1.1700.600
|
||||
- image: bepsays/ci-goreleaser:1.1800.000
|
||||
environment:
|
||||
CGO_ENABLED: "0"
|
||||
|
||||
|
||||
@@ -7,7 +7,11 @@ jobs:
|
||||
GO111MODULE: on
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [1.16.x, 1.17.x]
|
||||
# Note: We upgraded to Go 1.18 in Hugo v0.95.0
|
||||
# Go 1.18 had some breaking changes on the source level which means Hugo cannot be built
|
||||
# with older Go versions, but the improvements in Go 1.18 were too good to pass on (e.g. break and continue).
|
||||
# Note that you don't need Go (or Go 1.18) to run a pre-built binary.
|
||||
go-version: [1.18.x]
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
@@ -24,7 +28,7 @@ jobs:
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Install Mage
|
||||
run: go get github.com/magefile/mage@07afc7d24f4d6d6442305d49552f04fbda5ccb3e
|
||||
run: go install github.com/magefile/mage@07afc7d24f4d6d6442305d49552f04fbda5ccb3e
|
||||
- name: Install asciidoctor
|
||||
uses: reitzig/actions-asciidoctor@7570212ae20b63653481675fb1ff62d1073632b0
|
||||
- name: Checkout code
|
||||
|
||||
+3
-1
@@ -1,5 +1,7 @@
|
||||
# Contributing to Hugo
|
||||
|
||||
**Note March 16th 2022:** We are currently very constrained on human resources to do code reviews, so we currently require any new Pull Requests to be limited to bug fixes closing an existing issue. Also, we have updated to Go 1.18, but we will currently not accept any generic rewrites, "interface{} to any" replacements and similar.
|
||||
|
||||
We welcome contributions to Hugo of any kind including documentation, themes,
|
||||
organization, tutorials, blog posts, bug reports, issues, feature requests,
|
||||
feature implementations, pull requests, answering questions on the forum,
|
||||
@@ -124,7 +126,7 @@ go install
|
||||
For some convenient build and test targets, you also will want to install Mage:
|
||||
|
||||
```bash
|
||||
go get github.com/magefile/mage
|
||||
go install github.com/magefile/mage
|
||||
```
|
||||
|
||||
Now, to make a change to Hugo's source:
|
||||
|
||||
+2
-2
@@ -2,7 +2,7 @@
|
||||
# Twitter: https://twitter.com/gohugoio
|
||||
# Website: https://gohugo.io/
|
||||
|
||||
FROM golang:1.16-alpine AS build
|
||||
FROM golang:1.18-alpine AS build
|
||||
|
||||
# Optionally set HUGO_BUILD_TAGS to "extended" or "nodeploy" when building like so:
|
||||
# docker build --build-arg HUGO_BUILD_TAGS=extended .
|
||||
@@ -20,7 +20,7 @@ COPY . /go/src/github.com/gohugoio/hugo/
|
||||
# gcc/g++ are required to build SASS libraries for extended version
|
||||
RUN apk update && \
|
||||
apk add --no-cache gcc g++ musl-dev git && \
|
||||
go get github.com/magefile/mage
|
||||
go install github.com/magefile/mage
|
||||
|
||||
RUN mage hugo && mage install
|
||||
|
||||
|
||||
@@ -54,11 +54,11 @@ Use the [installation instructions in the Hugo documentation](https://gohugo.io/
|
||||
#### Prerequisite Tools
|
||||
|
||||
* [Git](https://git-scm.com/)
|
||||
* [Go (we test it with the last 2 major versions; but note that Hugo 0.81.0 only builds with >= Go 1.16.)](https://golang.org/dl/)
|
||||
* [Go (we test it with the last 2 major versions; but note that Hugo 0.95.0 only builds with >= Go 1.18.)](https://golang.org/dl/)
|
||||
|
||||
#### Fetch from GitHub
|
||||
|
||||
Since Hugo 0.48, Hugo uses the Go Modules support built into Go 1.11 to build. The easiest is to clone Hugo in a directory outside of `GOPATH`, as in the following example:
|
||||
To fetch and build the source from GitHub:
|
||||
|
||||
```bash
|
||||
mkdir $HOME/src
|
||||
@@ -85,6 +85,8 @@ git clone git@github.com:gohugoio/hugo.git
|
||||
```
|
||||
## Contributing to Hugo
|
||||
|
||||
**Note March 16th 2022:** We are currently very constrained on human resources to do code reviews, so we currently require any new Pull Requests to be limited to bug fixes closing an existing issue. Also, we have updated to Go 1.18, but we will currently not accept any generic rewrites, "interface{} to any" replacements and similar.
|
||||
|
||||
For a complete guide to contributing to Hugo, see the [Contribution Guide](CONTRIBUTING.md).
|
||||
|
||||
We welcome contributions to Hugo of any kind including documentation, themes,
|
||||
|
||||
@@ -20,7 +20,7 @@ import (
|
||||
)
|
||||
|
||||
var bufferPool = &sync.Pool{
|
||||
New: func() interface{} {
|
||||
New: func() any {
|
||||
return &bytes.Buffer{}
|
||||
},
|
||||
}
|
||||
|
||||
Vendored
+2
-2
@@ -30,7 +30,7 @@ type Cache struct {
|
||||
}
|
||||
|
||||
type cacheEntry struct {
|
||||
value interface{}
|
||||
value any
|
||||
err error
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ func (c *Cache) Clear() {
|
||||
// create will be called and cached.
|
||||
// This method is thread safe. It also guarantees that the create func for a given
|
||||
// key is invoked only once for this cache.
|
||||
func (c *Cache) GetOrCreate(key string, create func() (interface{}, error)) (interface{}, error) {
|
||||
func (c *Cache) GetOrCreate(key string, create func() (any, error)) (any, error) {
|
||||
c.mu.RLock()
|
||||
entry, found := c.cache[key]
|
||||
c.mu.RUnlock()
|
||||
|
||||
+3
-3
@@ -28,7 +28,7 @@ func TestNamedCache(t *testing.T) {
|
||||
cache := New()
|
||||
|
||||
counter := 0
|
||||
create := func() (interface{}, error) {
|
||||
create := func() (any, error) {
|
||||
counter++
|
||||
return counter, nil
|
||||
}
|
||||
@@ -58,8 +58,8 @@ func TestNamedCacheConcurrent(t *testing.T) {
|
||||
|
||||
cache := New()
|
||||
|
||||
create := func(i int) func() (interface{}, error) {
|
||||
return func() (interface{}, error) {
|
||||
create := func(i int) func() (any, error) {
|
||||
return func() (any, error) {
|
||||
return i, nil
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -505,7 +505,7 @@ func typeName(name, pkg string) string {
|
||||
|
||||
func uniqueNonEmptyStrings(s []string) []string {
|
||||
var unique []string
|
||||
set := map[string]interface{}{}
|
||||
set := map[string]any{}
|
||||
for _, val := range s {
|
||||
if val == "" {
|
||||
continue
|
||||
|
||||
@@ -85,7 +85,7 @@ type I interface {
|
||||
Method3(myint int, mystring string)
|
||||
Method5() (string, error)
|
||||
Method6() *net.IP
|
||||
Method7() interface{}
|
||||
Method7() any
|
||||
Method8() herrors.ErrorContext
|
||||
method2()
|
||||
method9() os.FileInfo
|
||||
|
||||
+12
-4
@@ -17,6 +17,7 @@ import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
@@ -88,7 +89,8 @@ type commandeer struct {
|
||||
// Used in cases where we get flooded with events in server mode.
|
||||
debounce func(f func())
|
||||
|
||||
serverPorts []int
|
||||
serverPorts []serverPortListener
|
||||
|
||||
languagesConfigured bool
|
||||
languages langs.Languages
|
||||
doLiveReload bool
|
||||
@@ -105,6 +107,11 @@ type commandeer struct {
|
||||
buildErr error
|
||||
}
|
||||
|
||||
type serverPortListener struct {
|
||||
p int
|
||||
ln net.Listener
|
||||
}
|
||||
|
||||
func newCommandeerHugoState() *commandeerHugoState {
|
||||
return &commandeerHugoState{
|
||||
created: make(chan struct{}),
|
||||
@@ -120,14 +127,14 @@ func (c *commandeer) errCount() int {
|
||||
return int(c.logger.LogCounters().ErrorCounter.Count())
|
||||
}
|
||||
|
||||
func (c *commandeer) getErrorWithContext() interface{} {
|
||||
func (c *commandeer) getErrorWithContext() any {
|
||||
errCount := c.errCount()
|
||||
|
||||
if errCount == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
m := make(map[string]interface{})
|
||||
m := make(map[string]any)
|
||||
|
||||
m["Error"] = errors.New(removeErrorPrefixFromLog(c.logger.Errors()))
|
||||
m["Version"] = hugo.BuildVersionString()
|
||||
@@ -146,7 +153,7 @@ func (c *commandeer) getErrorWithContext() interface{} {
|
||||
return m
|
||||
}
|
||||
|
||||
func (c *commandeer) Set(key string, value interface{}) {
|
||||
func (c *commandeer) Set(key string, value any) {
|
||||
if c.configured {
|
||||
panic("commandeer cannot be changed")
|
||||
}
|
||||
@@ -420,6 +427,7 @@ func (c *commandeer) loadConfig() error {
|
||||
if h == nil || c.failOnInitErr {
|
||||
err = createErr
|
||||
}
|
||||
|
||||
c.hugoSites = h
|
||||
// TODO(bep) improve.
|
||||
if c.buildLock == nil && h != nil {
|
||||
|
||||
@@ -150,7 +150,7 @@ func (b *commandsBuilder) newHugoCmd() *hugoCmd {
|
||||
Hugo is a Fast and Flexible Static Site Generator
|
||||
built with love by spf13 and friends in Go.
|
||||
|
||||
Complete documentation is available at http://gohugo.io/.`,
|
||||
Complete documentation is available at https://gohugo.io/.`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
defer cc.timeTrack(time.Now(), "Total")
|
||||
cfgInit := func(c *commandeer) error {
|
||||
@@ -294,7 +294,7 @@ func (cc *hugoBuilderCommon) handleFlags(cmd *cobra.Command) {
|
||||
cmd.Flags().BoolP("ignoreCache", "", false, "ignores the cache directory")
|
||||
cmd.Flags().StringP("destination", "d", "", "filesystem path to write files to")
|
||||
cmd.Flags().StringSliceP("theme", "t", []string{}, "themes to use (located in /themes/THEMENAME/)")
|
||||
cmd.Flags().StringVarP(&cc.baseURL, "baseURL", "b", "", "hostname (and path) to the root, e.g. http://spf13.com/")
|
||||
cmd.Flags().StringVarP(&cc.baseURL, "baseURL", "b", "", "hostname (and path) to the root, e.g. https://spf13.com/")
|
||||
cmd.Flags().Bool("enableGitInfo", false, "add Git revision, date, author, and CODEOWNERS info to the pages")
|
||||
cmd.Flags().BoolVar(&cc.gc, "gc", false, "enable to run some cleanup tasks (remove unused cache files) after the build")
|
||||
cmd.Flags().StringVar(&cc.poll, "poll", "", "set this to a poll interval, e.g --poll 700ms, to use a poll based approach to watch for file system changes")
|
||||
|
||||
@@ -366,6 +366,8 @@ URL = "hugocloud://hugotestbucket"
|
||||
writeFile(t, filepath.Join(d, "config", "testing", "params.toml"), `myparam="paramtesting"`)
|
||||
writeFile(t, filepath.Join(d, "config", "production", "params.toml"), `myparam="paramproduction"`)
|
||||
|
||||
writeFile(t, filepath.Join(d, "static", "myfile.txt"), `Hello World!`)
|
||||
|
||||
writeFile(t, filepath.Join(d, contentDir, "p1.md"), `
|
||||
---
|
||||
title: "P1"
|
||||
|
||||
+7
-7
@@ -145,13 +145,13 @@ func (m *modMounts) MarshalJSON() ([]byte, error) {
|
||||
if m.verbose {
|
||||
config := m.m.Config()
|
||||
return json.Marshal(&struct {
|
||||
Path string `json:"path"`
|
||||
Version string `json:"version"`
|
||||
Time time.Time `json:"time"`
|
||||
Owner string `json:"owner"`
|
||||
Dir string `json:"dir"`
|
||||
Meta map[string]interface{} `json:"meta"`
|
||||
HugoVersion modules.HugoVersion `json:"hugoVersion"`
|
||||
Path string `json:"path"`
|
||||
Version string `json:"version"`
|
||||
Time time.Time `json:"time"`
|
||||
Owner string `json:"owner"`
|
||||
Dir string `json:"dir"`
|
||||
Meta map[string]any `json:"meta"`
|
||||
HugoVersion modules.HugoVersion `json:"hugoVersion"`
|
||||
|
||||
Mounts []modMount `json:"mounts"`
|
||||
}{
|
||||
|
||||
+1
-1
@@ -202,7 +202,7 @@ func (cc *convertCmd) convertAndSavePage(p page.Page, site *hugolib.Site, target
|
||||
type parsedFile struct {
|
||||
frontMatterFormat metadecoders.Format
|
||||
frontMatterSource []byte
|
||||
frontMatter map[string]interface{}
|
||||
frontMatter map[string]any
|
||||
|
||||
// Everything after Front Matter
|
||||
content []byte
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//go:build !nodeploy
|
||||
// +build !nodeploy
|
||||
|
||||
package commands
|
||||
|
||||
+1
-1
@@ -49,7 +49,7 @@ url: %s
|
||||
Long: `Generate Markdown documentation for the Hugo CLI.
|
||||
|
||||
This command is, mostly, used to create up-to-date documentation
|
||||
of Hugo's command-line interface for http://gohugo.io/.
|
||||
of Hugo's command-line interface for https://gohugo.io/.
|
||||
|
||||
It creates one Markdown file per command with front matter suitable
|
||||
for rendering in Hugo.`,
|
||||
|
||||
+3
-3
@@ -53,15 +53,15 @@ func (c commandError) isUserError() bool {
|
||||
return c.userError
|
||||
}
|
||||
|
||||
func newUserError(a ...interface{}) commandError {
|
||||
func newUserError(a ...any) commandError {
|
||||
return commandError{s: fmt.Sprintln(a...), userError: true}
|
||||
}
|
||||
|
||||
func newSystemError(a ...interface{}) commandError {
|
||||
func newSystemError(a ...any) commandError {
|
||||
return commandError{s: fmt.Sprintln(a...), userError: false}
|
||||
}
|
||||
|
||||
func newSystemErrorF(format string, a ...interface{}) commandError {
|
||||
func newSystemErrorF(format string, a ...any) commandError {
|
||||
return commandError{s: fmt.Sprintf(format, a...), userError: false}
|
||||
}
|
||||
|
||||
|
||||
@@ -235,7 +235,7 @@ func (i *importCmd) createSiteFromJekyll(jekyllRoot, targetDir string, jekyllPos
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *importCmd) loadJekyllConfig(fs afero.Fs, jekyllRoot string) map[string]interface{} {
|
||||
func (i *importCmd) loadJekyllConfig(fs afero.Fs, jekyllRoot string) map[string]any {
|
||||
path := filepath.Join(jekyllRoot, "_config.yml")
|
||||
|
||||
exists, err := helpers.Exists(path, fs)
|
||||
@@ -265,7 +265,7 @@ func (i *importCmd) loadJekyllConfig(fs afero.Fs, jekyllRoot string) map[string]
|
||||
return c
|
||||
}
|
||||
|
||||
func (i *importCmd) createConfigFromJekyll(fs afero.Fs, inpath string, kind metadecoders.Format, jekyllConfig map[string]interface{}) (err error) {
|
||||
func (i *importCmd) createConfigFromJekyll(fs afero.Fs, inpath string, kind metadecoders.Format, jekyllConfig map[string]any) (err error) {
|
||||
title := "My New Hugo Site"
|
||||
baseURL := "http://example.org/"
|
||||
|
||||
@@ -285,7 +285,7 @@ func (i *importCmd) createConfigFromJekyll(fs afero.Fs, inpath string, kind meta
|
||||
}
|
||||
}
|
||||
|
||||
in := map[string]interface{}{
|
||||
in := map[string]any{
|
||||
"baseURL": baseURL,
|
||||
"title": title,
|
||||
"languageCode": "en-us",
|
||||
@@ -423,7 +423,7 @@ func convertJekyllPost(path, relPath, targetDir string, draft bool) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func convertJekyllMetaData(m interface{}, postName string, postDate time.Time, draft bool) (interface{}, error) {
|
||||
func convertJekyllMetaData(m any, postName string, postDate time.Time, draft bool) (any, error) {
|
||||
metadata, err := maps.ToStringMapE(m)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -475,7 +475,7 @@ func convertJekyllMetaData(m interface{}, postName string, postDate time.Time, d
|
||||
return metadata, nil
|
||||
}
|
||||
|
||||
func convertJekyllContent(m interface{}, content string) (string, error) {
|
||||
func convertJekyllContent(m any, content string) (string, error) {
|
||||
metadata, _ := maps.ToStringMapE(m)
|
||||
|
||||
lines := strings.Split(content, "\n")
|
||||
|
||||
@@ -47,44 +47,44 @@ func TestParseJekyllFilename(t *testing.T) {
|
||||
func TestConvertJekyllMetadata(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
testDataList := []struct {
|
||||
metadata interface{}
|
||||
metadata any
|
||||
postName string
|
||||
postDate time.Time
|
||||
draft bool
|
||||
expect string
|
||||
}{
|
||||
{
|
||||
map[interface{}]interface{}{},
|
||||
map[any]any{},
|
||||
"testPost", time.Date(2015, 10, 1, 0, 0, 0, 0, time.UTC), false,
|
||||
`{"date":"2015-10-01T00:00:00Z"}`,
|
||||
},
|
||||
{
|
||||
map[interface{}]interface{}{},
|
||||
map[any]any{},
|
||||
"testPost", time.Date(2015, 10, 1, 0, 0, 0, 0, time.UTC), true,
|
||||
`{"date":"2015-10-01T00:00:00Z","draft":true}`,
|
||||
},
|
||||
{
|
||||
map[interface{}]interface{}{"Permalink": "/permalink.html", "layout": "post"},
|
||||
map[any]any{"Permalink": "/permalink.html", "layout": "post"},
|
||||
"testPost", time.Date(2015, 10, 1, 0, 0, 0, 0, time.UTC), false,
|
||||
`{"date":"2015-10-01T00:00:00Z","url":"/permalink.html"}`,
|
||||
},
|
||||
{
|
||||
map[interface{}]interface{}{"permalink": "/permalink.html"},
|
||||
map[any]any{"permalink": "/permalink.html"},
|
||||
"testPost", time.Date(2015, 10, 1, 0, 0, 0, 0, time.UTC), false,
|
||||
`{"date":"2015-10-01T00:00:00Z","url":"/permalink.html"}`,
|
||||
},
|
||||
{
|
||||
map[interface{}]interface{}{"category": nil, "permalink": 123},
|
||||
map[any]any{"category": nil, "permalink": 123},
|
||||
"testPost", time.Date(2015, 10, 1, 0, 0, 0, 0, time.UTC), false,
|
||||
`{"date":"2015-10-01T00:00:00Z"}`,
|
||||
},
|
||||
{
|
||||
map[interface{}]interface{}{"Excerpt_Separator": "sep"},
|
||||
map[any]any{"Excerpt_Separator": "sep"},
|
||||
"testPost", time.Date(2015, 10, 1, 0, 0, 0, 0, time.UTC), false,
|
||||
`{"date":"2015-10-01T00:00:00Z","excerpt_separator":"sep"}`,
|
||||
},
|
||||
{
|
||||
map[interface{}]interface{}{"category": "book", "layout": "post", "Others": "Goods", "Date": "2015-10-01 12:13:11"},
|
||||
map[any]any{"category": "book", "layout": "post", "Others": "Goods", "Date": "2015-10-01 12:13:11"},
|
||||
"testPost", time.Date(2015, 10, 1, 0, 0, 0, 0, time.UTC), false,
|
||||
`{"Others":"Goods","categories":["book"],"date":"2015-10-01T12:13:11Z"}`,
|
||||
},
|
||||
@@ -102,69 +102,69 @@ func TestConvertJekyllMetadata(t *testing.T) {
|
||||
func TestConvertJekyllContent(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
testDataList := []struct {
|
||||
metadata interface{}
|
||||
metadata any
|
||||
content string
|
||||
expect string
|
||||
}{
|
||||
{
|
||||
map[interface{}]interface{}{},
|
||||
map[any]any{},
|
||||
"Test content\r\n<!-- more -->\npart2 content", "Test content\n<!--more-->\npart2 content",
|
||||
},
|
||||
{
|
||||
map[interface{}]interface{}{},
|
||||
map[any]any{},
|
||||
"Test content\n<!-- More -->\npart2 content", "Test content\n<!--more-->\npart2 content",
|
||||
},
|
||||
{
|
||||
map[interface{}]interface{}{"excerpt_separator": "<!--sep-->"},
|
||||
map[any]any{"excerpt_separator": "<!--sep-->"},
|
||||
"Test content\n<!--sep-->\npart2 content",
|
||||
"---\nexcerpt_separator: <!--sep-->\n---\nTest content\n<!--more-->\npart2 content",
|
||||
},
|
||||
{map[interface{}]interface{}{}, "{% raw %}text{% endraw %}", "text"},
|
||||
{map[interface{}]interface{}{}, "{%raw%} text2 {%endraw %}", "text2"},
|
||||
{map[any]any{}, "{% raw %}text{% endraw %}", "text"},
|
||||
{map[any]any{}, "{%raw%} text2 {%endraw %}", "text2"},
|
||||
{
|
||||
map[interface{}]interface{}{},
|
||||
map[any]any{},
|
||||
"{% highlight go %}\nvar s int\n{% endhighlight %}",
|
||||
"{{< highlight go >}}\nvar s int\n{{< / highlight >}}",
|
||||
},
|
||||
{
|
||||
map[interface{}]interface{}{},
|
||||
map[any]any{},
|
||||
"{% highlight go linenos hl_lines=\"1 2\" %}\nvar s string\nvar i int\n{% endhighlight %}",
|
||||
"{{< highlight go \"linenos=table,hl_lines=1 2\" >}}\nvar s string\nvar i int\n{{< / highlight >}}",
|
||||
},
|
||||
|
||||
// Octopress image tag
|
||||
{
|
||||
map[interface{}]interface{}{},
|
||||
map[any]any{},
|
||||
"{% img http://placekitten.com/890/280 %}",
|
||||
"{{< figure src=\"http://placekitten.com/890/280\" >}}",
|
||||
},
|
||||
{
|
||||
map[interface{}]interface{}{},
|
||||
map[any]any{},
|
||||
"{% img left http://placekitten.com/320/250 Place Kitten #2 %}",
|
||||
"{{< figure class=\"left\" src=\"http://placekitten.com/320/250\" title=\"Place Kitten #2\" >}}",
|
||||
},
|
||||
{
|
||||
map[interface{}]interface{}{},
|
||||
map[any]any{},
|
||||
"{% img right http://placekitten.com/300/500 150 250 'Place Kitten #3' %}",
|
||||
"{{< figure class=\"right\" src=\"http://placekitten.com/300/500\" width=\"150\" height=\"250\" title=\"Place Kitten #3\" >}}",
|
||||
},
|
||||
{
|
||||
map[interface{}]interface{}{},
|
||||
map[any]any{},
|
||||
"{% img right http://placekitten.com/300/500 150 250 'Place Kitten #4' 'An image of a very cute kitten' %}",
|
||||
"{{< figure class=\"right\" src=\"http://placekitten.com/300/500\" width=\"150\" height=\"250\" title=\"Place Kitten #4\" alt=\"An image of a very cute kitten\" >}}",
|
||||
},
|
||||
{
|
||||
map[interface{}]interface{}{},
|
||||
map[any]any{},
|
||||
"{% img http://placekitten.com/300/500 150 250 'Place Kitten #4' 'An image of a very cute kitten' %}",
|
||||
"{{< figure src=\"http://placekitten.com/300/500\" width=\"150\" height=\"250\" title=\"Place Kitten #4\" alt=\"An image of a very cute kitten\" >}}",
|
||||
},
|
||||
{
|
||||
map[interface{}]interface{}{},
|
||||
map[any]any{},
|
||||
"{% img right /placekitten/300/500 'Place Kitten #4' 'An image of a very cute kitten' %}",
|
||||
"{{< figure class=\"right\" src=\"/placekitten/300/500\" title=\"Place Kitten #4\" alt=\"An image of a very cute kitten\" >}}",
|
||||
},
|
||||
{
|
||||
map[interface{}]interface{}{"category": "book", "layout": "post", "Date": "2015-10-01 12:13:11"},
|
||||
map[any]any{"category": "book", "layout": "post", "Date": "2015-10-01 12:13:11"},
|
||||
"somecontent",
|
||||
"---\nDate: \"2015-10-01 12:13:11\"\ncategory: book\nlayout: post\n---\nsomecontent",
|
||||
},
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//go:build !darwin
|
||||
// +build !darwin
|
||||
|
||||
package commands
|
||||
|
||||
+5
-5
@@ -32,7 +32,7 @@ type listCmd struct {
|
||||
*baseBuilderCmd
|
||||
}
|
||||
|
||||
func (lc *listCmd) buildSites(config map[string]interface{}) (*hugolib.HugoSites, error) {
|
||||
func (lc *listCmd) buildSites(config map[string]any) (*hugolib.HugoSites, error) {
|
||||
cfgInit := func(c *commandeer) error {
|
||||
for key, value := range config {
|
||||
c.Set(key, value)
|
||||
@@ -75,7 +75,7 @@ List requires a subcommand, e.g. ` + "`hugo list drafts`.",
|
||||
Short: "List all drafts",
|
||||
Long: `List all of the drafts in your content directory.`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
sites, err := cc.buildSites(map[string]interface{}{"buildDrafts": true})
|
||||
sites, err := cc.buildSites(map[string]any{"buildDrafts": true})
|
||||
if err != nil {
|
||||
return newSystemError("Error building sites", err)
|
||||
}
|
||||
@@ -94,7 +94,7 @@ List requires a subcommand, e.g. ` + "`hugo list drafts`.",
|
||||
Short: "List all posts dated in the future",
|
||||
Long: `List all of the posts in your content directory which will be posted in the future.`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
sites, err := cc.buildSites(map[string]interface{}{"buildFuture": true})
|
||||
sites, err := cc.buildSites(map[string]any{"buildFuture": true})
|
||||
if err != nil {
|
||||
return newSystemError("Error building sites", err)
|
||||
}
|
||||
@@ -122,7 +122,7 @@ List requires a subcommand, e.g. ` + "`hugo list drafts`.",
|
||||
Short: "List all posts already expired",
|
||||
Long: `List all of the posts in your content directory which has already expired.`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
sites, err := cc.buildSites(map[string]interface{}{"buildExpired": true})
|
||||
sites, err := cc.buildSites(map[string]any{"buildExpired": true})
|
||||
if err != nil {
|
||||
return newSystemError("Error building sites", err)
|
||||
}
|
||||
@@ -150,7 +150,7 @@ List requires a subcommand, e.g. ` + "`hugo list drafts`.",
|
||||
Short: "List all posts",
|
||||
Long: `List all of the posts in your content directory, include drafts, future and expired pages.`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
sites, err := cc.buildSites(map[string]interface{}{
|
||||
sites, err := cc.buildSites(map[string]any{
|
||||
"buildExpired": true,
|
||||
"buildDrafts": true,
|
||||
"buildFuture": true,
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//go:build nodeploy
|
||||
// +build nodeploy
|
||||
|
||||
package commands
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//go:build release
|
||||
// +build release
|
||||
|
||||
// Copyright 2017-present The Hugo Authors. All rights reserved.
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//go:build !release
|
||||
// +build !release
|
||||
|
||||
// Copyright 2018 The Hugo Authors. All rights reserved.
|
||||
|
||||
+68
-38
@@ -15,6 +15,7 @@ package commands
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
@@ -32,6 +33,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/gohugoio/hugo/common/paths"
|
||||
"golang.org/x/sync/errgroup"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
@@ -46,7 +48,7 @@ import (
|
||||
|
||||
type serverCmd struct {
|
||||
// Can be used to stop the server. Useful in tests
|
||||
stop <-chan bool
|
||||
stop chan bool
|
||||
|
||||
disableLiveReload bool
|
||||
navigateToChanged bool
|
||||
@@ -68,7 +70,7 @@ func (b *commandsBuilder) newServerCmd() *serverCmd {
|
||||
return b.newServerCmdSignaled(nil)
|
||||
}
|
||||
|
||||
func (b *commandsBuilder) newServerCmdSignaled(stop <-chan bool) *serverCmd {
|
||||
func (b *commandsBuilder) newServerCmdSignaled(stop chan bool) *serverCmd {
|
||||
cc := &serverCmd{stop: stop}
|
||||
|
||||
cc.baseBuilderCmd = b.newBuilderCmd(&cobra.Command{
|
||||
@@ -87,7 +89,13 @@ By default hugo will also watch your files for any changes you make and
|
||||
automatically rebuild the site. It will then live reload any open browser pages
|
||||
and push the latest content to them. As most Hugo sites are built in a fraction
|
||||
of a second, you will be able to save and see your changes nearly instantly.`,
|
||||
RunE: cc.server,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
err := cc.server(cmd, args)
|
||||
if err != nil && cc.stop != nil {
|
||||
cc.stop <- true
|
||||
}
|
||||
return err
|
||||
},
|
||||
})
|
||||
|
||||
cc.cmd.Flags().IntVarP(&cc.serverPort, "port", "p", 1313, "port on which the server will listen")
|
||||
@@ -128,8 +136,6 @@ func (f noDirFile) Readdir(count int) ([]os.FileInfo, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var serverPorts []int
|
||||
|
||||
func (sc *serverCmd) server(cmd *cobra.Command, args []string) error {
|
||||
// If a Destination is provided via flag write to disk
|
||||
destination, _ := cmd.Flags().GetString("destination")
|
||||
@@ -139,7 +145,7 @@ func (sc *serverCmd) server(cmd *cobra.Command, args []string) error {
|
||||
|
||||
var serverCfgInit sync.Once
|
||||
|
||||
cfgInit := func(c *commandeer) error {
|
||||
cfgInit := func(c *commandeer) (rerr error) {
|
||||
c.Set("renderToMemory", !sc.renderToDisk)
|
||||
if cmd.Flags().Changed("navigateToChanged") {
|
||||
c.Set("navigateToChanged", sc.navigateToChanged)
|
||||
@@ -162,59 +168,60 @@ func (sc *serverCmd) server(cmd *cobra.Command, args []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
var err error
|
||||
|
||||
// We can only do this once.
|
||||
serverCfgInit.Do(func() {
|
||||
serverPorts = make([]int, 1)
|
||||
c.serverPorts = make([]serverPortListener, 1)
|
||||
|
||||
if c.languages.IsMultihost() {
|
||||
if !sc.serverAppend {
|
||||
err = newSystemError("--appendPort=false not supported when in multihost mode")
|
||||
rerr = newSystemError("--appendPort=false not supported when in multihost mode")
|
||||
}
|
||||
serverPorts = make([]int, len(c.languages))
|
||||
c.serverPorts = make([]serverPortListener, len(c.languages))
|
||||
}
|
||||
|
||||
currentServerPort := sc.serverPort
|
||||
|
||||
for i := 0; i < len(serverPorts); i++ {
|
||||
for i := 0; i < len(c.serverPorts); i++ {
|
||||
l, err := net.Listen("tcp", net.JoinHostPort(sc.serverInterface, strconv.Itoa(currentServerPort)))
|
||||
if err == nil {
|
||||
l.Close()
|
||||
serverPorts[i] = currentServerPort
|
||||
c.serverPorts[i] = serverPortListener{ln: l, p: currentServerPort}
|
||||
} else {
|
||||
if i == 0 && sc.cmd.Flags().Changed("port") {
|
||||
// port set explicitly by user -- he/she probably meant it!
|
||||
err = newSystemErrorF("Server startup failed: %s", err)
|
||||
rerr = newSystemErrorF("Server startup failed: %s", err)
|
||||
return
|
||||
}
|
||||
c.logger.Println("port", sc.serverPort, "already in use, attempting to use an available port")
|
||||
sp, err := helpers.FindAvailablePort()
|
||||
l, sp, err := helpers.TCPListen()
|
||||
if err != nil {
|
||||
err = newSystemError("Unable to find alternative port to use:", err)
|
||||
rerr = newSystemError("Unable to find alternative port to use:", err)
|
||||
return
|
||||
}
|
||||
serverPorts[i] = sp.Port
|
||||
c.serverPorts[i] = serverPortListener{ln: l, p: sp.Port}
|
||||
}
|
||||
|
||||
currentServerPort = serverPorts[i] + 1
|
||||
currentServerPort = c.serverPorts[i].p + 1
|
||||
}
|
||||
})
|
||||
|
||||
c.serverPorts = serverPorts
|
||||
if rerr != nil {
|
||||
return
|
||||
}
|
||||
|
||||
c.Set("port", sc.serverPort)
|
||||
if sc.liveReloadPort != -1 {
|
||||
c.Set("liveReloadPort", sc.liveReloadPort)
|
||||
} else {
|
||||
c.Set("liveReloadPort", serverPorts[0])
|
||||
c.Set("liveReloadPort", c.serverPorts[0].p)
|
||||
}
|
||||
|
||||
isMultiHost := c.languages.IsMultihost()
|
||||
for i, language := range c.languages {
|
||||
var serverPort int
|
||||
if isMultiHost {
|
||||
serverPort = serverPorts[i]
|
||||
serverPort = c.serverPorts[i].p
|
||||
} else {
|
||||
serverPort = serverPorts[0]
|
||||
serverPort = c.serverPorts[0].p
|
||||
}
|
||||
|
||||
baseURL, err := sc.fixURL(language, sc.baseURL, serverPort)
|
||||
@@ -229,7 +236,7 @@ func (sc *serverCmd) server(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
return
|
||||
}
|
||||
|
||||
if err := memStats(); err != nil {
|
||||
@@ -298,7 +305,7 @@ func getRootWatchDirsStr(baseDir string, watchDirs []string) string {
|
||||
type fileServer struct {
|
||||
baseURLs []string
|
||||
roots []string
|
||||
errorTemplate func(err interface{}) (io.Reader, error)
|
||||
errorTemplate func(err any) (io.Reader, error)
|
||||
c *commandeer
|
||||
s *serverCmd
|
||||
}
|
||||
@@ -314,10 +321,11 @@ func (f *fileServer) rewriteRequest(r *http.Request, toPath string) *http.Reques
|
||||
return r2
|
||||
}
|
||||
|
||||
func (f *fileServer) createEndpoint(i int) (*http.ServeMux, string, string, error) {
|
||||
func (f *fileServer) createEndpoint(i int) (*http.ServeMux, net.Listener, string, string, error) {
|
||||
baseURL := f.baseURLs[i]
|
||||
root := f.roots[i]
|
||||
port := f.c.serverPorts[i]
|
||||
port := f.c.serverPorts[i].p
|
||||
listener := f.c.serverPorts[i].ln
|
||||
|
||||
publishDir := f.c.Cfg.GetString("publishDir")
|
||||
|
||||
@@ -347,7 +355,7 @@ func (f *fileServer) createEndpoint(i int) (*http.ServeMux, string, string, erro
|
||||
// We're only interested in the path
|
||||
u, err := url.Parse(baseURL)
|
||||
if err != nil {
|
||||
return nil, "", "", errors.Wrap(err, "Invalid baseURL")
|
||||
return nil, nil, "", "", errors.Wrap(err, "Invalid baseURL")
|
||||
}
|
||||
|
||||
decorate := func(h http.Handler) http.Handler {
|
||||
@@ -453,7 +461,7 @@ func (f *fileServer) createEndpoint(i int) (*http.ServeMux, string, string, erro
|
||||
|
||||
endpoint := net.JoinHostPort(f.s.serverInterface, strconv.Itoa(port))
|
||||
|
||||
return mu, u.String(), endpoint, nil
|
||||
return mu, listener, u.String(), endpoint, nil
|
||||
}
|
||||
|
||||
var logErrorRe = regexp.MustCompile(`(?s)ERROR \d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} `)
|
||||
@@ -491,7 +499,7 @@ func (c *commandeer) serve(s *serverCmd) error {
|
||||
roots: roots,
|
||||
c: c,
|
||||
s: s,
|
||||
errorTemplate: func(ctx interface{}) (io.Reader, error) {
|
||||
errorTemplate: func(ctx any) (io.Reader, error) {
|
||||
b := &bytes.Buffer{}
|
||||
err := c.hugo().Tmpl().Execute(templ, b, ctx)
|
||||
return b, err
|
||||
@@ -506,9 +514,17 @@ func (c *commandeer) serve(s *serverCmd) error {
|
||||
|
||||
sigs := make(chan os.Signal, 1)
|
||||
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
|
||||
var servers []*http.Server
|
||||
|
||||
wg1, ctx := errgroup.WithContext(context.Background())
|
||||
|
||||
for i := range baseURLs {
|
||||
mu, serverURL, endpoint, err := srv.createEndpoint(i)
|
||||
mu, listener, serverURL, endpoint, err := srv.createEndpoint(i)
|
||||
srv := &http.Server{
|
||||
Addr: endpoint,
|
||||
Handler: mu,
|
||||
}
|
||||
servers = append(servers, srv)
|
||||
|
||||
if doLiveReload {
|
||||
u, err := url.Parse(helpers.SanitizeURL(baseURLs[i]))
|
||||
@@ -520,13 +536,13 @@ func (c *commandeer) serve(s *serverCmd) error {
|
||||
mu.HandleFunc(u.Path+"/livereload", livereload.Handler)
|
||||
}
|
||||
jww.FEEDBACK.Printf("Web Server is available at %s (bind address %s)\n", serverURL, s.serverInterface)
|
||||
go func() {
|
||||
err = http.ListenAndServe(endpoint, mu)
|
||||
if err != nil {
|
||||
c.logger.Errorf("Error: %s\n", err.Error())
|
||||
os.Exit(1)
|
||||
wg1.Go(func() error {
|
||||
err = srv.Serve(listener)
|
||||
if err != nil && err != http.ErrServerClosed {
|
||||
return err
|
||||
}
|
||||
}()
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
jww.FEEDBACK.Println("Press Ctrl+C to stop")
|
||||
@@ -542,7 +558,21 @@ func (c *commandeer) serve(s *serverCmd) error {
|
||||
|
||||
c.hugo().Close()
|
||||
|
||||
return nil
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
wg2, ctx := errgroup.WithContext(ctx)
|
||||
for _, srv := range servers {
|
||||
srv := srv
|
||||
wg2.Go(func() error {
|
||||
return srv.Shutdown(ctx)
|
||||
})
|
||||
}
|
||||
|
||||
err1, err2 := wg1.Wait(), wg2.Wait()
|
||||
if err1 != nil {
|
||||
return err1
|
||||
}
|
||||
return err2
|
||||
}
|
||||
|
||||
// fixURL massages the baseURL into a form needed for serving
|
||||
|
||||
+94
-31
@@ -17,6 +17,7 @@ import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -24,6 +25,8 @@ import (
|
||||
|
||||
"github.com/gohugoio/hugo/config"
|
||||
"github.com/gohugoio/hugo/helpers"
|
||||
"golang.org/x/net/context"
|
||||
"golang.org/x/sync/errgroup"
|
||||
|
||||
qt "github.com/frankban/quicktest"
|
||||
)
|
||||
@@ -31,11 +34,11 @@ import (
|
||||
func TestServer(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
|
||||
homeContent, err := runServerTestAndGetHome(c, "")
|
||||
r := runServerTest(c, true, "")
|
||||
|
||||
c.Assert(err, qt.IsNil)
|
||||
c.Assert(homeContent, qt.Contains, "List: Hugo Commands")
|
||||
c.Assert(homeContent, qt.Contains, "Environment: development")
|
||||
c.Assert(r.err, qt.IsNil)
|
||||
c.Assert(r.homeContent, qt.Contains, "List: Hugo Commands")
|
||||
c.Assert(r.homeContent, qt.Contains, "Environment: development")
|
||||
}
|
||||
|
||||
// Issue 9518
|
||||
@@ -48,58 +51,118 @@ func TestServerPanicOnConfigError(t *testing.T) {
|
||||
linenos='table'
|
||||
`
|
||||
|
||||
_, err := runServerTestAndGetHome(c, config)
|
||||
r := runServerTest(c, false, config)
|
||||
|
||||
c.Assert(err, qt.IsNotNil)
|
||||
c.Assert(err.Error(), qt.Contains, "cannot parse 'Highlight.LineNos' as bool:")
|
||||
c.Assert(r.err, qt.IsNotNil)
|
||||
c.Assert(r.err.Error(), qt.Contains, "cannot parse 'Highlight.LineNos' as bool:")
|
||||
}
|
||||
|
||||
func runServerTestAndGetHome(c *qt.C, config string) (string, error) {
|
||||
func TestServerFlags(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
|
||||
assertPublic := func(c *qt.C, r serverTestResult, renderStaticToDisk bool) {
|
||||
c.Assert(r.err, qt.IsNil)
|
||||
c.Assert(r.homeContent, qt.Contains, "Environment: development")
|
||||
c.Assert(r.publicDirnames["myfile.txt"], qt.Equals, renderStaticToDisk)
|
||||
|
||||
}
|
||||
|
||||
for _, test := range []struct {
|
||||
flag string
|
||||
assert func(c *qt.C, r serverTestResult)
|
||||
}{
|
||||
{"", func(c *qt.C, r serverTestResult) {
|
||||
assertPublic(c, r, false)
|
||||
}},
|
||||
{"--renderToDisk", func(c *qt.C, r serverTestResult) {
|
||||
assertPublic(c, r, true)
|
||||
}},
|
||||
} {
|
||||
c.Run(test.flag, func(c *qt.C) {
|
||||
config := `
|
||||
baseURL="https://example.org"
|
||||
`
|
||||
|
||||
var args []string
|
||||
if test.flag != "" {
|
||||
args = strings.Split(test.flag, "=")
|
||||
}
|
||||
|
||||
r := runServerTest(c, true, config, args...)
|
||||
|
||||
test.assert(c, r)
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
type serverTestResult struct {
|
||||
err error
|
||||
homeContent string
|
||||
publicDirnames map[string]bool
|
||||
}
|
||||
|
||||
func runServerTest(c *qt.C, getHome bool, config string, args ...string) (result serverTestResult) {
|
||||
dir, clean, err := createSimpleTestSite(c, testSiteConfig{configTOML: config})
|
||||
defer clean()
|
||||
c.Assert(err, qt.IsNil)
|
||||
|
||||
// Let us hope that this port is available on all systems ...
|
||||
port := 1331
|
||||
sp, err := helpers.FindAvailablePort()
|
||||
c.Assert(err, qt.IsNil)
|
||||
port := sp.Port
|
||||
|
||||
defer func() {
|
||||
os.RemoveAll(dir)
|
||||
}()
|
||||
|
||||
errors := make(chan error)
|
||||
stop := make(chan bool)
|
||||
|
||||
b := newCommandsBuilder()
|
||||
scmd := b.newServerCmdSignaled(stop)
|
||||
|
||||
cmd := scmd.getCommand()
|
||||
cmd.SetArgs([]string{"-s=" + dir, fmt.Sprintf("-p=%d", port)})
|
||||
args = append([]string{"-s=" + dir, fmt.Sprintf("-p=%d", port)}, args...)
|
||||
cmd.SetArgs(args)
|
||||
|
||||
go func() {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
wg, ctx := errgroup.WithContext(ctx)
|
||||
|
||||
wg.Go(func() error {
|
||||
_, err := cmd.ExecuteC()
|
||||
if err != nil {
|
||||
errors <- err
|
||||
}
|
||||
}()
|
||||
return err
|
||||
})
|
||||
|
||||
select {
|
||||
// There is no way to know exactly when the server is ready for connections.
|
||||
// We could improve by something like https://golang.org/pkg/net/http/httptest/#Server
|
||||
// But for now, let us sleep and pray!
|
||||
case <-time.After(2 * time.Second):
|
||||
case err := <-errors:
|
||||
return "", err
|
||||
if getHome {
|
||||
// Esp. on slow CI machines, we need to wait a little before the web
|
||||
// server is ready.
|
||||
time.Sleep(567 * time.Millisecond)
|
||||
resp, err := http.Get(fmt.Sprintf("http://localhost:%d/", port))
|
||||
c.Check(err, qt.IsNil)
|
||||
if err == nil {
|
||||
defer resp.Body.Close()
|
||||
result.homeContent = helpers.ReaderToString(resp.Body)
|
||||
}
|
||||
}
|
||||
|
||||
resp, err := http.Get("http://localhost:1331/")
|
||||
c.Assert(err, qt.IsNil)
|
||||
defer resp.Body.Close()
|
||||
homeContent := helpers.ReaderToString(resp.Body)
|
||||
select {
|
||||
case <-stop:
|
||||
case stop <- true:
|
||||
}
|
||||
|
||||
// Stop the server.
|
||||
stop <- true
|
||||
pubFiles, err := os.ReadDir(filepath.Join(dir, "public"))
|
||||
c.Check(err, qt.IsNil)
|
||||
result.publicDirnames = make(map[string]bool)
|
||||
for _, f := range pubFiles {
|
||||
result.publicDirnames[f.Name()] = true
|
||||
}
|
||||
|
||||
result.err = wg.Wait()
|
||||
|
||||
return
|
||||
|
||||
return homeContent, nil
|
||||
}
|
||||
|
||||
func TestFixURL(t *testing.T) {
|
||||
|
||||
@@ -21,7 +21,7 @@ import (
|
||||
// Append appends from to a slice to and returns the resulting slice.
|
||||
// If length of from is one and the only element is a slice of same type as to,
|
||||
// it will be appended.
|
||||
func Append(to interface{}, from ...interface{}) (interface{}, error) {
|
||||
func Append(to any, from ...any) (any, error) {
|
||||
tov, toIsNil := indirect(reflect.ValueOf(to))
|
||||
|
||||
toIsNil = toIsNil || to == nil
|
||||
@@ -73,8 +73,8 @@ func Append(to interface{}, from ...interface{}) (interface{}, error) {
|
||||
return tov.Interface(), nil
|
||||
}
|
||||
|
||||
func appendToInterfaceSliceFromValues(slice1, slice2 reflect.Value) ([]interface{}, error) {
|
||||
var tos []interface{}
|
||||
func appendToInterfaceSliceFromValues(slice1, slice2 reflect.Value) ([]any, error) {
|
||||
var tos []any
|
||||
|
||||
for _, slice := range []reflect.Value{slice1, slice2} {
|
||||
for i := 0; i < slice.Len(); i++ {
|
||||
@@ -85,8 +85,8 @@ func appendToInterfaceSliceFromValues(slice1, slice2 reflect.Value) ([]interface
|
||||
return tos, nil
|
||||
}
|
||||
|
||||
func appendToInterfaceSlice(tov reflect.Value, from ...interface{}) ([]interface{}, error) {
|
||||
var tos []interface{}
|
||||
func appendToInterfaceSlice(tov reflect.Value, from ...any) ([]any, error) {
|
||||
var tos []any
|
||||
|
||||
for i := 0; i < tov.Len(); i++ {
|
||||
tos = append(tos, tov.Index(i).Interface())
|
||||
|
||||
@@ -25,25 +25,25 @@ func TestAppend(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
|
||||
for _, test := range []struct {
|
||||
start interface{}
|
||||
addend []interface{}
|
||||
expected interface{}
|
||||
start any
|
||||
addend []any
|
||||
expected any
|
||||
}{
|
||||
{[]string{"a", "b"}, []interface{}{"c"}, []string{"a", "b", "c"}},
|
||||
{[]string{"a", "b"}, []interface{}{"c", "d", "e"}, []string{"a", "b", "c", "d", "e"}},
|
||||
{[]string{"a", "b"}, []interface{}{[]string{"c", "d", "e"}}, []string{"a", "b", "c", "d", "e"}},
|
||||
{[]string{"a"}, []interface{}{"b", template.HTML("c")}, []interface{}{"a", "b", template.HTML("c")}},
|
||||
{nil, []interface{}{"a", "b"}, []string{"a", "b"}},
|
||||
{nil, []interface{}{nil}, []interface{}{nil}},
|
||||
{[]interface{}{}, []interface{}{[]string{"c", "d", "e"}}, []string{"c", "d", "e"}},
|
||||
{[]string{"a", "b"}, []any{"c"}, []string{"a", "b", "c"}},
|
||||
{[]string{"a", "b"}, []any{"c", "d", "e"}, []string{"a", "b", "c", "d", "e"}},
|
||||
{[]string{"a", "b"}, []any{[]string{"c", "d", "e"}}, []string{"a", "b", "c", "d", "e"}},
|
||||
{[]string{"a"}, []any{"b", template.HTML("c")}, []any{"a", "b", template.HTML("c")}},
|
||||
{nil, []any{"a", "b"}, []string{"a", "b"}},
|
||||
{nil, []any{nil}, []any{nil}},
|
||||
{[]any{}, []any{[]string{"c", "d", "e"}}, []string{"c", "d", "e"}},
|
||||
{
|
||||
tstSlicers{&tstSlicer{"a"}, &tstSlicer{"b"}},
|
||||
[]interface{}{&tstSlicer{"c"}},
|
||||
[]any{&tstSlicer{"c"}},
|
||||
tstSlicers{&tstSlicer{"a"}, &tstSlicer{"b"}, &tstSlicer{"c"}},
|
||||
},
|
||||
{
|
||||
&tstSlicers{&tstSlicer{"a"}, &tstSlicer{"b"}},
|
||||
[]interface{}{&tstSlicer{"c"}},
|
||||
[]any{&tstSlicer{"c"}},
|
||||
tstSlicers{
|
||||
&tstSlicer{"a"},
|
||||
&tstSlicer{"b"},
|
||||
@@ -52,26 +52,26 @@ func TestAppend(t *testing.T) {
|
||||
},
|
||||
{
|
||||
testSlicerInterfaces{&tstSlicerIn1{"a"}, &tstSlicerIn1{"b"}},
|
||||
[]interface{}{&tstSlicerIn1{"c"}},
|
||||
[]any{&tstSlicerIn1{"c"}},
|
||||
testSlicerInterfaces{&tstSlicerIn1{"a"}, &tstSlicerIn1{"b"}, &tstSlicerIn1{"c"}},
|
||||
},
|
||||
//https://github.com/gohugoio/hugo/issues/5361
|
||||
{
|
||||
[]string{"a", "b"},
|
||||
[]interface{}{tstSlicers{&tstSlicer{"a"}, &tstSlicer{"b"}}},
|
||||
[]interface{}{"a", "b", &tstSlicer{"a"}, &tstSlicer{"b"}},
|
||||
[]any{tstSlicers{&tstSlicer{"a"}, &tstSlicer{"b"}}},
|
||||
[]any{"a", "b", &tstSlicer{"a"}, &tstSlicer{"b"}},
|
||||
},
|
||||
{
|
||||
[]string{"a", "b"},
|
||||
[]interface{}{&tstSlicer{"a"}},
|
||||
[]interface{}{"a", "b", &tstSlicer{"a"}},
|
||||
[]any{&tstSlicer{"a"}},
|
||||
[]any{"a", "b", &tstSlicer{"a"}},
|
||||
},
|
||||
// Errors
|
||||
{"", []interface{}{[]string{"a", "b"}}, false},
|
||||
{"", []any{[]string{"a", "b"}}, false},
|
||||
// No string concatenation.
|
||||
{
|
||||
"ab",
|
||||
[]interface{}{"c"},
|
||||
[]any{"c"},
|
||||
false,
|
||||
},
|
||||
} {
|
||||
|
||||
@@ -17,5 +17,5 @@ package collections
|
||||
|
||||
// Grouper defines a very generic way to group items by a given key.
|
||||
type Grouper interface {
|
||||
Group(key interface{}, items interface{}) (interface{}, error)
|
||||
Group(key any, items any) (any, error)
|
||||
}
|
||||
|
||||
@@ -21,11 +21,11 @@ import (
|
||||
// in collections.Slice template func to get types such as Pages, PageGroups etc.
|
||||
// instead of the less useful []interface{}.
|
||||
type Slicer interface {
|
||||
Slice(items interface{}) (interface{}, error)
|
||||
Slice(items any) (any, error)
|
||||
}
|
||||
|
||||
// Slice returns a slice of all passed arguments.
|
||||
func Slice(args ...interface{}) interface{} {
|
||||
func Slice(args ...any) any {
|
||||
if len(args) == 0 {
|
||||
return args
|
||||
}
|
||||
@@ -66,8 +66,8 @@ func Slice(args ...interface{}) interface{} {
|
||||
}
|
||||
|
||||
// StringSliceToInterfaceSlice converts ss to []interface{}.
|
||||
func StringSliceToInterfaceSlice(ss []string) []interface{} {
|
||||
result := make([]interface{}, len(ss))
|
||||
func StringSliceToInterfaceSlice(ss []string) []any {
|
||||
result := make([]any, len(ss))
|
||||
for i, s := range ss {
|
||||
result[i] = s
|
||||
}
|
||||
|
||||
@@ -46,8 +46,8 @@ type tstSlicer struct {
|
||||
TheName string
|
||||
}
|
||||
|
||||
func (p *tstSlicerIn1) Slice(in interface{}) (interface{}, error) {
|
||||
items := in.([]interface{})
|
||||
func (p *tstSlicerIn1) Slice(in any) (any, error) {
|
||||
items := in.([]any)
|
||||
result := make(testSlicerInterfaces, len(items))
|
||||
for i, v := range items {
|
||||
switch vv := v.(type) {
|
||||
@@ -60,8 +60,8 @@ func (p *tstSlicerIn1) Slice(in interface{}) (interface{}, error) {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (p *tstSlicerIn2) Slice(in interface{}) (interface{}, error) {
|
||||
items := in.([]interface{})
|
||||
func (p *tstSlicerIn2) Slice(in any) (any, error) {
|
||||
items := in.([]any)
|
||||
result := make(testSlicerInterfaces, len(items))
|
||||
for i, v := range items {
|
||||
switch vv := v.(type) {
|
||||
@@ -82,8 +82,8 @@ func (p *tstSlicerIn2) Name() string {
|
||||
return p.TheName
|
||||
}
|
||||
|
||||
func (p *tstSlicer) Slice(in interface{}) (interface{}, error) {
|
||||
items := in.([]interface{})
|
||||
func (p *tstSlicer) Slice(in any) (any, error) {
|
||||
items := in.([]any)
|
||||
result := make(tstSlicers, len(items))
|
||||
for i, v := range items {
|
||||
switch vv := v.(type) {
|
||||
@@ -103,17 +103,17 @@ func TestSlice(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
|
||||
for i, test := range []struct {
|
||||
args []interface{}
|
||||
expected interface{}
|
||||
args []any
|
||||
expected any
|
||||
}{
|
||||
{[]interface{}{"a", "b"}, []string{"a", "b"}},
|
||||
{[]interface{}{&tstSlicer{"a"}, &tstSlicer{"b"}}, tstSlicers{&tstSlicer{"a"}, &tstSlicer{"b"}}},
|
||||
{[]interface{}{&tstSlicer{"a"}, "b"}, []interface{}{&tstSlicer{"a"}, "b"}},
|
||||
{[]interface{}{}, []interface{}{}},
|
||||
{[]interface{}{nil}, []interface{}{nil}},
|
||||
{[]interface{}{5, "b"}, []interface{}{5, "b"}},
|
||||
{[]interface{}{&tstSlicerIn1{"a"}, &tstSlicerIn2{"b"}}, testSlicerInterfaces{&tstSlicerIn1{"a"}, &tstSlicerIn2{"b"}}},
|
||||
{[]interface{}{&tstSlicerIn1{"a"}, &tstSlicer{"b"}}, []interface{}{&tstSlicerIn1{"a"}, &tstSlicer{"b"}}},
|
||||
{[]any{"a", "b"}, []string{"a", "b"}},
|
||||
{[]any{&tstSlicer{"a"}, &tstSlicer{"b"}}, tstSlicers{&tstSlicer{"a"}, &tstSlicer{"b"}}},
|
||||
{[]any{&tstSlicer{"a"}, "b"}, []any{&tstSlicer{"a"}, "b"}},
|
||||
{[]any{}, []any{}},
|
||||
{[]any{nil}, []any{nil}},
|
||||
{[]any{5, "b"}, []any{5, "b"}},
|
||||
{[]any{&tstSlicerIn1{"a"}, &tstSlicerIn2{"b"}}, testSlicerInterfaces{&tstSlicerIn1{"a"}, &tstSlicerIn2{"b"}}},
|
||||
{[]any{&tstSlicerIn1{"a"}, &tstSlicer{"b"}}, []any{&tstSlicerIn1{"a"}, &tstSlicer{"b"}}},
|
||||
} {
|
||||
errMsg := qt.Commentf("[%d] %v", i, test.args)
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ type ErrorSender interface {
|
||||
// Recover is a helper function that can be used to capture panics.
|
||||
// Put this at the top of a method/function that crashes in a template:
|
||||
// defer herrors.Recover()
|
||||
func Recover(args ...interface{}) {
|
||||
func Recover(args ...any) {
|
||||
if r := recover(); r != nil {
|
||||
fmt.Println("ERR:", r)
|
||||
args = append(args, "stacktrace from panic: \n"+string(debug.Stack()), "\n")
|
||||
|
||||
@@ -128,7 +128,7 @@ type Exec struct {
|
||||
|
||||
// New will fail if name is not allowed according to the configured security policy.
|
||||
// Else a configured Runner will be returned ready to be Run.
|
||||
func (e *Exec) New(name string, arg ...interface{}) (Runner, error) {
|
||||
func (e *Exec) New(name string, arg ...any) (Runner, error) {
|
||||
if err := e.sc.CheckAllowedExec(name); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -146,8 +146,8 @@ func (e *Exec) New(name string, arg ...interface{}) (Runner, error) {
|
||||
}
|
||||
|
||||
// Npx is a convenience method to create a Runner running npx --no-install <name> <args.
|
||||
func (e *Exec) Npx(name string, arg ...interface{}) (Runner, error) {
|
||||
arg = append(arg[:0], append([]interface{}{"--no-install", name}, arg[0:]...)...)
|
||||
func (e *Exec) Npx(name string, arg ...any) (Runner, error) {
|
||||
arg = append(arg[:0], append([]any{"--no-install", name}, arg[0:]...)...)
|
||||
return e.New("npx", arg...)
|
||||
}
|
||||
|
||||
@@ -205,7 +205,7 @@ type commandeer struct {
|
||||
env []string
|
||||
}
|
||||
|
||||
func (c *commandeer) command(arg ...interface{}) (*cmdWrapper, error) {
|
||||
func (c *commandeer) command(arg ...any) (*cmdWrapper, error) {
|
||||
if c == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ package hreflect
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
"sync"
|
||||
|
||||
"github.com/gohugoio/hugo/common/types"
|
||||
)
|
||||
@@ -61,7 +62,7 @@ func IsFloat(kind reflect.Kind) bool {
|
||||
|
||||
// IsTruthful returns whether in represents a truthful value.
|
||||
// See IsTruthfulValue
|
||||
func IsTruthful(in interface{}) bool {
|
||||
func IsTruthful(in any) bool {
|
||||
switch v := in.(type) {
|
||||
case reflect.Value:
|
||||
return IsTruthfulValue(v)
|
||||
@@ -115,6 +116,58 @@ func IsTruthfulValue(val reflect.Value) (truth bool) {
|
||||
return
|
||||
}
|
||||
|
||||
type methodKey struct {
|
||||
typ reflect.Type
|
||||
name string
|
||||
}
|
||||
|
||||
type methods struct {
|
||||
sync.RWMutex
|
||||
cache map[methodKey]int
|
||||
}
|
||||
|
||||
var methodCache = &methods{cache: make(map[methodKey]int)}
|
||||
|
||||
// GetMethodByName is the same as reflect.Value.MethodByName, but it caches the
|
||||
// type lookup.
|
||||
func GetMethodByName(v reflect.Value, name string) reflect.Value {
|
||||
index := GetMethodIndexByName(v.Type(), name)
|
||||
|
||||
if index == -1 {
|
||||
return reflect.Value{}
|
||||
}
|
||||
|
||||
return v.Method(index)
|
||||
}
|
||||
|
||||
// GetMethodIndexByName returns the index of the method with the given name, or
|
||||
// -1 if no such method exists.
|
||||
func GetMethodIndexByName(tp reflect.Type, name string) int {
|
||||
k := methodKey{tp, name}
|
||||
methodCache.RLock()
|
||||
index, found := methodCache.cache[k]
|
||||
methodCache.RUnlock()
|
||||
if found {
|
||||
return index
|
||||
}
|
||||
|
||||
methodCache.Lock()
|
||||
defer methodCache.Unlock()
|
||||
|
||||
m, ok := tp.MethodByName(name)
|
||||
index = m.Index
|
||||
if !ok {
|
||||
index = -1
|
||||
}
|
||||
methodCache.cache[k] = index
|
||||
|
||||
if !ok {
|
||||
return -1
|
||||
}
|
||||
|
||||
return m.Index
|
||||
}
|
||||
|
||||
// Based on: https://github.com/golang/go/blob/178a2c42254166cffed1b25fb1d3c7a5727cada6/src/text/template/exec.go#L931
|
||||
func indirectInterface(v reflect.Value) reflect.Value {
|
||||
if v.Kind() != reflect.Interface {
|
||||
|
||||
@@ -30,6 +30,16 @@ func TestIsTruthful(t *testing.T) {
|
||||
c.Assert(IsTruthful(time.Time{}), qt.Equals, false)
|
||||
}
|
||||
|
||||
func TestGetMethodByName(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
v := reflect.ValueOf(&testStruct{})
|
||||
tp := v.Type()
|
||||
|
||||
c.Assert(GetMethodIndexByName(tp, "Method1"), qt.Equals, 0)
|
||||
c.Assert(GetMethodIndexByName(tp, "Method3"), qt.Equals, 2)
|
||||
c.Assert(GetMethodIndexByName(tp, "Foo"), qt.Equals, -1)
|
||||
}
|
||||
|
||||
func BenchmarkIsTruthFul(b *testing.B) {
|
||||
v := reflect.ValueOf("Hugo")
|
||||
|
||||
@@ -40,3 +50,37 @@ func BenchmarkIsTruthFul(b *testing.B) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type testStruct struct{}
|
||||
|
||||
func (t *testStruct) Method1() string {
|
||||
return "Hugo"
|
||||
}
|
||||
|
||||
func (t *testStruct) Method2() string {
|
||||
return "Hugo"
|
||||
}
|
||||
|
||||
func (t *testStruct) Method3() string {
|
||||
return "Hugo"
|
||||
}
|
||||
|
||||
func (t *testStruct) Method4() string {
|
||||
return "Hugo"
|
||||
}
|
||||
|
||||
func (t *testStruct) Method5() string {
|
||||
return "Hugo"
|
||||
}
|
||||
|
||||
func BenchmarkGetMethodByName(b *testing.B) {
|
||||
v := reflect.ValueOf(&testStruct{})
|
||||
methods := []string{"Method1", "Method2", "Method3", "Method4", "Method5"}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
for _, method := range methods {
|
||||
_ = GetMethodByName(v, method)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,7 +134,7 @@ func (f TimeFormatter) Format(t time.Time, layout string) string {
|
||||
return s
|
||||
}
|
||||
|
||||
func ToTimeInDefaultLocationE(i interface{}, location *time.Location) (tim time.Time, err error) {
|
||||
func ToTimeInDefaultLocationE(i any, location *time.Location) (tim time.Time, err error) {
|
||||
switch vv := i.(type) {
|
||||
case toml.LocalDate:
|
||||
return vv.AsTime(location), nil
|
||||
|
||||
+60
-9
@@ -21,6 +21,7 @@ import (
|
||||
"runtime/debug"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/gohugoio/hugo/hugofs/files"
|
||||
@@ -37,13 +38,6 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
// commitHash contains the current Git revision.
|
||||
// Use mage to build to make sure this gets set.
|
||||
commitHash string
|
||||
|
||||
// buildDate contains the date of the current build.
|
||||
buildDate string
|
||||
|
||||
// vendorInfo contains vendor notes about the current build.
|
||||
vendorInfo string
|
||||
)
|
||||
@@ -90,6 +84,17 @@ func NewInfo(environment string, deps []*Dependency) Info {
|
||||
if environment == "" {
|
||||
environment = EnvironmentProduction
|
||||
}
|
||||
var (
|
||||
commitHash string
|
||||
buildDate string
|
||||
)
|
||||
|
||||
bi := getBuildInfo()
|
||||
if bi != nil {
|
||||
commitHash = bi.Revision
|
||||
buildDate = bi.RevisionTime
|
||||
}
|
||||
|
||||
return Info{
|
||||
CommitHash: commitHash,
|
||||
BuildDate: buildDate,
|
||||
@@ -125,6 +130,52 @@ func GetExecEnviron(workDir string, cfg config.Provider, fs afero.Fs) []string {
|
||||
return env
|
||||
}
|
||||
|
||||
type buildInfo struct {
|
||||
VersionControlSystem string
|
||||
Revision string
|
||||
RevisionTime string
|
||||
Modified bool
|
||||
|
||||
GoOS string
|
||||
GoArch string
|
||||
|
||||
*debug.BuildInfo
|
||||
}
|
||||
|
||||
var bInfo *buildInfo
|
||||
var bInfoInit sync.Once
|
||||
|
||||
func getBuildInfo() *buildInfo {
|
||||
bInfoInit.Do(func() {
|
||||
bi, ok := debug.ReadBuildInfo()
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
bInfo = &buildInfo{BuildInfo: bi}
|
||||
|
||||
for _, s := range bInfo.Settings {
|
||||
switch s.Key {
|
||||
case "vcs":
|
||||
bInfo.VersionControlSystem = s.Value
|
||||
case "vcs.revision":
|
||||
bInfo.Revision = s.Value
|
||||
case "vcs.time":
|
||||
bInfo.RevisionTime = s.Value
|
||||
case "vcs.modified":
|
||||
bInfo.Modified = s.Value == "true"
|
||||
case "GOOS":
|
||||
bInfo.GoOS = s.Value
|
||||
case "GOARCH":
|
||||
bInfo.GoArch = s.Value
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
return bInfo
|
||||
}
|
||||
|
||||
// GetDependencyList returns a sorted dependency list on the format package="version".
|
||||
// It includes both Go dependencies and (a manually maintained) list of C(++) dependencies.
|
||||
func GetDependencyList() []string {
|
||||
@@ -143,8 +194,8 @@ func GetDependencyList() []string {
|
||||
)
|
||||
}
|
||||
|
||||
bi, ok := debug.ReadBuildInfo()
|
||||
if !ok {
|
||||
bi := getBuildInfo()
|
||||
if bi == nil {
|
||||
return deps
|
||||
}
|
||||
|
||||
|
||||
@@ -27,8 +27,12 @@ func TestHugoInfo(t *testing.T) {
|
||||
|
||||
c.Assert(hugoInfo.Version(), qt.Equals, CurrentVersion.Version())
|
||||
c.Assert(fmt.Sprintf("%T", VersionString("")), qt.Equals, fmt.Sprintf("%T", hugoInfo.Version()))
|
||||
c.Assert(hugoInfo.CommitHash, qt.Equals, commitHash)
|
||||
c.Assert(hugoInfo.BuildDate, qt.Equals, buildDate)
|
||||
|
||||
bi := getBuildInfo()
|
||||
if bi != nil {
|
||||
c.Assert(hugoInfo.CommitHash, qt.Equals, bi.Revision)
|
||||
c.Assert(hugoInfo.BuildDate, qt.Equals, bi.RevisionTime)
|
||||
}
|
||||
c.Assert(hugoInfo.Environment, qt.Equals, "production")
|
||||
c.Assert(string(hugoInfo.Generator()), qt.Contains, fmt.Sprintf("Hugo %s", hugoInfo.Version()))
|
||||
c.Assert(hugoInfo.IsProduction(), qt.Equals, true)
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//go:build extended
|
||||
// +build extended
|
||||
|
||||
package hugo
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//go:build !extended
|
||||
// +build !extended
|
||||
|
||||
package hugo
|
||||
|
||||
+14
-9
@@ -58,13 +58,13 @@ func (h VersionString) String() string {
|
||||
}
|
||||
|
||||
// Compare implements the compare.Comparer interface.
|
||||
func (h VersionString) Compare(other interface{}) int {
|
||||
func (h VersionString) Compare(other any) int {
|
||||
v := MustParseVersion(h.String())
|
||||
return compareVersionsWithSuffix(v.Number, v.PatchLevel, v.Suffix, other)
|
||||
}
|
||||
|
||||
// Eq implements the compare.Eqer interface.
|
||||
func (h VersionString) Eq(other interface{}) bool {
|
||||
func (h VersionString) Eq(other any) bool {
|
||||
s, err := cast.ToStringE(other)
|
||||
if err != nil {
|
||||
return false
|
||||
@@ -131,16 +131,21 @@ func BuildVersionString() string {
|
||||
program := "hugo"
|
||||
|
||||
version := "v" + CurrentVersion.String()
|
||||
if commitHash != "" {
|
||||
version += "-" + strings.ToUpper(commitHash)
|
||||
|
||||
bi := getBuildInfo()
|
||||
if bi == nil {
|
||||
return version
|
||||
}
|
||||
if bi.Revision != "" {
|
||||
version += "-" + bi.Revision
|
||||
}
|
||||
if IsExtended {
|
||||
version += "+extended"
|
||||
}
|
||||
|
||||
osArch := runtime.GOOS + "/" + runtime.GOARCH
|
||||
osArch := bi.GoOS + "/" + bi.GoArch
|
||||
|
||||
date := buildDate
|
||||
date := bi.RevisionTime
|
||||
if date == "" {
|
||||
date = "unknown"
|
||||
}
|
||||
@@ -166,15 +171,15 @@ func version(version float32, patchVersion int, suffix string) string {
|
||||
// running Hugo version.
|
||||
// It returns -1 if the given version is less than, 0 if equal and 1 if greater than
|
||||
// the running version.
|
||||
func CompareVersion(version interface{}) int {
|
||||
func CompareVersion(version any) int {
|
||||
return compareVersionsWithSuffix(CurrentVersion.Number, CurrentVersion.PatchLevel, CurrentVersion.Suffix, version)
|
||||
}
|
||||
|
||||
func compareVersions(inVersion float32, inPatchVersion int, in interface{}) int {
|
||||
func compareVersions(inVersion float32, inPatchVersion int, in any) int {
|
||||
return compareVersionsWithSuffix(inVersion, inPatchVersion, "", in)
|
||||
}
|
||||
|
||||
func compareVersionsWithSuffix(inVersion float32, inPatchVersion int, suffix string, in interface{}) int {
|
||||
func compareVersionsWithSuffix(inVersion float32, inPatchVersion int, suffix string, in any) int {
|
||||
var c int
|
||||
switch d := in.(type) {
|
||||
case float64:
|
||||
|
||||
@@ -16,7 +16,7 @@ package hugo
|
||||
// CurrentVersion represents the current build version.
|
||||
// This should be the only one.
|
||||
var CurrentVersion = Version{
|
||||
Number: 0.93,
|
||||
PatchLevel: 3,
|
||||
Number: 0.96,
|
||||
PatchLevel: 0,
|
||||
Suffix: "",
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ import (
|
||||
// IgnorableLogger is a logger that ignores certain log statements.
|
||||
type IgnorableLogger interface {
|
||||
Logger
|
||||
Errorsf(statementID, format string, v ...interface{})
|
||||
Errorsf(statementID, format string, v ...any)
|
||||
Apply(logger Logger) IgnorableLogger
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ func NewIgnorableLogger(logger Logger, statements ...string) IgnorableLogger {
|
||||
}
|
||||
|
||||
// Errorsf logs statementID as an ERROR if not configured as ignoreable.
|
||||
func (l ignorableLogger) Errorsf(statementID, format string, v ...interface{}) {
|
||||
func (l ignorableLogger) Errorsf(statementID, format string, v ...any) {
|
||||
if l.statements[statementID] {
|
||||
// Ignore.
|
||||
return
|
||||
|
||||
+20
-20
@@ -58,21 +58,21 @@ func (w prefixWriter) Write(p []byte) (n int, err error) {
|
||||
}
|
||||
|
||||
type Logger interface {
|
||||
Printf(format string, v ...interface{})
|
||||
Println(v ...interface{})
|
||||
Printf(format string, v ...any)
|
||||
Println(v ...any)
|
||||
PrintTimerIfDelayed(start time.Time, name string)
|
||||
Debug() *log.Logger
|
||||
Debugf(format string, v ...interface{})
|
||||
Debugln(v ...interface{})
|
||||
Debugf(format string, v ...any)
|
||||
Debugln(v ...any)
|
||||
Info() *log.Logger
|
||||
Infof(format string, v ...interface{})
|
||||
Infoln(v ...interface{})
|
||||
Infof(format string, v ...any)
|
||||
Infoln(v ...any)
|
||||
Warn() *log.Logger
|
||||
Warnf(format string, v ...interface{})
|
||||
Warnln(v ...interface{})
|
||||
Warnf(format string, v ...any)
|
||||
Warnln(v ...any)
|
||||
Error() *log.Logger
|
||||
Errorf(format string, v ...interface{})
|
||||
Errorln(v ...interface{})
|
||||
Errorf(format string, v ...any)
|
||||
Errorln(v ...any)
|
||||
Errors() string
|
||||
|
||||
Out() io.Writer
|
||||
@@ -101,11 +101,11 @@ type logger struct {
|
||||
errors *bytes.Buffer
|
||||
}
|
||||
|
||||
func (l *logger) Printf(format string, v ...interface{}) {
|
||||
func (l *logger) Printf(format string, v ...any) {
|
||||
l.FEEDBACK.Printf(format, v...)
|
||||
}
|
||||
|
||||
func (l *logger) Println(v ...interface{}) {
|
||||
func (l *logger) Println(v ...any) {
|
||||
l.FEEDBACK.Println(v...)
|
||||
}
|
||||
|
||||
@@ -113,19 +113,19 @@ func (l *logger) Debug() *log.Logger {
|
||||
return l.DEBUG
|
||||
}
|
||||
|
||||
func (l *logger) Debugf(format string, v ...interface{}) {
|
||||
func (l *logger) Debugf(format string, v ...any) {
|
||||
l.DEBUG.Printf(format, v...)
|
||||
}
|
||||
|
||||
func (l *logger) Debugln(v ...interface{}) {
|
||||
func (l *logger) Debugln(v ...any) {
|
||||
l.DEBUG.Println(v...)
|
||||
}
|
||||
|
||||
func (l *logger) Infof(format string, v ...interface{}) {
|
||||
func (l *logger) Infof(format string, v ...any) {
|
||||
l.INFO.Printf(format, v...)
|
||||
}
|
||||
|
||||
func (l *logger) Infoln(v ...interface{}) {
|
||||
func (l *logger) Infoln(v ...any) {
|
||||
l.INFO.Println(v...)
|
||||
}
|
||||
|
||||
@@ -135,14 +135,14 @@ func (l *logger) Info() *log.Logger {
|
||||
|
||||
const panicOnWarningMessage = "Warning trapped. Remove the --panicOnWarning flag to continue."
|
||||
|
||||
func (l *logger) Warnf(format string, v ...interface{}) {
|
||||
func (l *logger) Warnf(format string, v ...any) {
|
||||
l.WARN.Printf(format, v...)
|
||||
if PanicOnWarning {
|
||||
panic(panicOnWarningMessage)
|
||||
}
|
||||
}
|
||||
|
||||
func (l *logger) Warnln(v ...interface{}) {
|
||||
func (l *logger) Warnln(v ...any) {
|
||||
l.WARN.Println(v...)
|
||||
if PanicOnWarning {
|
||||
panic(panicOnWarningMessage)
|
||||
@@ -153,11 +153,11 @@ func (l *logger) Warn() *log.Logger {
|
||||
return l.WARN
|
||||
}
|
||||
|
||||
func (l *logger) Errorf(format string, v ...interface{}) {
|
||||
func (l *logger) Errorf(format string, v ...any) {
|
||||
l.ERROR.Printf(format, v...)
|
||||
}
|
||||
|
||||
func (l *logger) Errorln(v ...interface{}) {
|
||||
func (l *logger) Errorln(v ...any) {
|
||||
l.ERROR.Println(v...)
|
||||
}
|
||||
|
||||
|
||||
+19
-19
@@ -24,12 +24,12 @@ import (
|
||||
)
|
||||
|
||||
// ToStringMapE converts in to map[string]interface{}.
|
||||
func ToStringMapE(in interface{}) (map[string]interface{}, error) {
|
||||
func ToStringMapE(in any) (map[string]any, error) {
|
||||
switch vv := in.(type) {
|
||||
case Params:
|
||||
return vv, nil
|
||||
case map[string]string:
|
||||
var m = map[string]interface{}{}
|
||||
var m = map[string]any{}
|
||||
for k, v := range vv {
|
||||
m[k] = v
|
||||
}
|
||||
@@ -43,7 +43,7 @@ func ToStringMapE(in interface{}) (map[string]interface{}, error) {
|
||||
// ToParamsAndPrepare converts in to Params and prepares it for use.
|
||||
// If in is nil, an empty map is returned.
|
||||
// See PrepareParams.
|
||||
func ToParamsAndPrepare(in interface{}) (Params, bool) {
|
||||
func ToParamsAndPrepare(in any) (Params, bool) {
|
||||
if types.IsNil(in) {
|
||||
return Params{}, true
|
||||
}
|
||||
@@ -56,7 +56,7 @@ func ToParamsAndPrepare(in interface{}) (Params, bool) {
|
||||
}
|
||||
|
||||
// MustToParamsAndPrepare calls ToParamsAndPrepare and panics if it fails.
|
||||
func MustToParamsAndPrepare(in interface{}) Params {
|
||||
func MustToParamsAndPrepare(in any) Params {
|
||||
if p, ok := ToParamsAndPrepare(in); ok {
|
||||
return p
|
||||
} else {
|
||||
@@ -65,13 +65,13 @@ func MustToParamsAndPrepare(in interface{}) Params {
|
||||
}
|
||||
|
||||
// ToStringMap converts in to map[string]interface{}.
|
||||
func ToStringMap(in interface{}) map[string]interface{} {
|
||||
func ToStringMap(in any) map[string]any {
|
||||
m, _ := ToStringMapE(in)
|
||||
return m
|
||||
}
|
||||
|
||||
// ToStringMapStringE converts in to map[string]string.
|
||||
func ToStringMapStringE(in interface{}) (map[string]string, error) {
|
||||
func ToStringMapStringE(in any) (map[string]string, error) {
|
||||
m, err := ToStringMapE(in)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -80,26 +80,26 @@ func ToStringMapStringE(in interface{}) (map[string]string, error) {
|
||||
}
|
||||
|
||||
// ToStringMapString converts in to map[string]string.
|
||||
func ToStringMapString(in interface{}) map[string]string {
|
||||
func ToStringMapString(in any) map[string]string {
|
||||
m, _ := ToStringMapStringE(in)
|
||||
return m
|
||||
}
|
||||
|
||||
// ToStringMapBool converts in to bool.
|
||||
func ToStringMapBool(in interface{}) map[string]bool {
|
||||
func ToStringMapBool(in any) map[string]bool {
|
||||
m, _ := ToStringMapE(in)
|
||||
return cast.ToStringMapBool(m)
|
||||
}
|
||||
|
||||
// ToSliceStringMap converts in to []map[string]interface{}.
|
||||
func ToSliceStringMap(in interface{}) ([]map[string]interface{}, error) {
|
||||
func ToSliceStringMap(in any) ([]map[string]any, error) {
|
||||
switch v := in.(type) {
|
||||
case []map[string]interface{}:
|
||||
case []map[string]any:
|
||||
return v, nil
|
||||
case []interface{}:
|
||||
var s []map[string]interface{}
|
||||
case []any:
|
||||
var s []map[string]any
|
||||
for _, entry := range v {
|
||||
if vv, ok := entry.(map[string]interface{}); ok {
|
||||
if vv, ok := entry.(map[string]any); ok {
|
||||
s = append(s, vv)
|
||||
}
|
||||
}
|
||||
@@ -146,7 +146,7 @@ func (r KeyRenamer) getNewKey(keyPath string) string {
|
||||
|
||||
// Rename renames the keys in the given map according
|
||||
// to the patterns in the current KeyRenamer.
|
||||
func (r KeyRenamer) Rename(m map[string]interface{}) {
|
||||
func (r KeyRenamer) Rename(m map[string]any) {
|
||||
r.renamePath("", m)
|
||||
}
|
||||
|
||||
@@ -158,15 +158,15 @@ func (KeyRenamer) keyPath(k1, k2 string) string {
|
||||
return k1 + "/" + k2
|
||||
}
|
||||
|
||||
func (r KeyRenamer) renamePath(parentKeyPath string, m map[string]interface{}) {
|
||||
func (r KeyRenamer) renamePath(parentKeyPath string, m map[string]any) {
|
||||
for key, val := range m {
|
||||
keyPath := r.keyPath(parentKeyPath, key)
|
||||
switch val.(type) {
|
||||
case map[interface{}]interface{}:
|
||||
case map[any]any:
|
||||
val = cast.ToStringMap(val)
|
||||
r.renamePath(keyPath, val.(map[string]interface{}))
|
||||
case map[string]interface{}:
|
||||
r.renamePath(keyPath, val.(map[string]interface{}))
|
||||
r.renamePath(keyPath, val.(map[string]any))
|
||||
case map[string]any:
|
||||
r.renamePath(keyPath, val.(map[string]any))
|
||||
}
|
||||
|
||||
newKey := r.getNewKey(keyPath)
|
||||
|
||||
+21
-21
@@ -27,7 +27,7 @@ func TestPrepareParams(t *testing.T) {
|
||||
expected Params
|
||||
}{
|
||||
{
|
||||
map[string]interface{}{
|
||||
map[string]any{
|
||||
"abC": 32,
|
||||
},
|
||||
Params{
|
||||
@@ -35,16 +35,16 @@ func TestPrepareParams(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
map[string]interface{}{
|
||||
map[string]any{
|
||||
"abC": 32,
|
||||
"deF": map[interface{}]interface{}{
|
||||
"deF": map[any]any{
|
||||
23: "A value",
|
||||
24: map[string]interface{}{
|
||||
24: map[string]any{
|
||||
"AbCDe": "A value",
|
||||
"eFgHi": "Another value",
|
||||
},
|
||||
},
|
||||
"gHi": map[string]interface{}{
|
||||
"gHi": map[string]any{
|
||||
"J": 25,
|
||||
},
|
||||
"jKl": map[string]string{
|
||||
@@ -85,23 +85,23 @@ func TestToSliceStringMap(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
|
||||
tests := []struct {
|
||||
input interface{}
|
||||
expected []map[string]interface{}
|
||||
input any
|
||||
expected []map[string]any
|
||||
}{
|
||||
{
|
||||
input: []map[string]interface{}{
|
||||
input: []map[string]any{
|
||||
{"abc": 123},
|
||||
},
|
||||
expected: []map[string]interface{}{
|
||||
expected: []map[string]any{
|
||||
{"abc": 123},
|
||||
},
|
||||
}, {
|
||||
input: []interface{}{
|
||||
map[string]interface{}{
|
||||
input: []any{
|
||||
map[string]any{
|
||||
"def": 456,
|
||||
},
|
||||
},
|
||||
expected: []map[string]interface{}{
|
||||
expected: []map[string]any{
|
||||
{"def": 456},
|
||||
},
|
||||
},
|
||||
@@ -116,7 +116,7 @@ func TestToSliceStringMap(t *testing.T) {
|
||||
|
||||
func TestToParamsAndPrepare(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
_, ok := ToParamsAndPrepare(map[string]interface{}{"A": "av"})
|
||||
_, ok := ToParamsAndPrepare(map[string]any{"A": "av"})
|
||||
c.Assert(ok, qt.IsTrue)
|
||||
|
||||
params, ok := ToParamsAndPrepare(nil)
|
||||
@@ -127,33 +127,33 @@ func TestToParamsAndPrepare(t *testing.T) {
|
||||
func TestRenameKeys(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
|
||||
m := map[string]interface{}{
|
||||
m := map[string]any{
|
||||
"a": 32,
|
||||
"ren1": "m1",
|
||||
"ren2": "m1_2",
|
||||
"sub": map[string]interface{}{
|
||||
"subsub": map[string]interface{}{
|
||||
"sub": map[string]any{
|
||||
"subsub": map[string]any{
|
||||
"REN1": "m2",
|
||||
"ren2": "m2_2",
|
||||
},
|
||||
},
|
||||
"no": map[string]interface{}{
|
||||
"no": map[string]any{
|
||||
"ren1": "m2",
|
||||
"ren2": "m2_2",
|
||||
},
|
||||
}
|
||||
|
||||
expected := map[string]interface{}{
|
||||
expected := map[string]any{
|
||||
"a": 32,
|
||||
"new1": "m1",
|
||||
"new2": "m1_2",
|
||||
"sub": map[string]interface{}{
|
||||
"subsub": map[string]interface{}{
|
||||
"sub": map[string]any{
|
||||
"subsub": map[string]any{
|
||||
"new1": "m2",
|
||||
"ren2": "m2_2",
|
||||
},
|
||||
},
|
||||
"no": map[string]interface{}{
|
||||
"no": map[string]any{
|
||||
"ren1": "m2",
|
||||
"ren2": "m2_2",
|
||||
},
|
||||
|
||||
+11
-11
@@ -21,11 +21,11 @@ import (
|
||||
)
|
||||
|
||||
// Params is a map where all keys are lower case.
|
||||
type Params map[string]interface{}
|
||||
type Params map[string]any
|
||||
|
||||
// Get does a lower case and nested search in this map.
|
||||
// It will return nil if none found.
|
||||
func (p Params) Get(indices ...string) interface{} {
|
||||
func (p Params) Get(indices ...string) any {
|
||||
v, _, _ := getNested(p, indices)
|
||||
return v
|
||||
}
|
||||
@@ -142,7 +142,7 @@ func (p Params) SetDefaultMergeStrategy(s ParamsMergeStrategy) {
|
||||
p[mergeStrategyKey] = s
|
||||
}
|
||||
|
||||
func getNested(m map[string]interface{}, indices []string) (interface{}, string, map[string]interface{}) {
|
||||
func getNested(m map[string]any, indices []string) (any, string, map[string]any) {
|
||||
if len(indices) == 0 {
|
||||
return nil, "", nil
|
||||
}
|
||||
@@ -164,7 +164,7 @@ func getNested(m map[string]interface{}, indices []string) (interface{}, string,
|
||||
switch m2 := v.(type) {
|
||||
case Params:
|
||||
return getNested(m2, indices[1:])
|
||||
case map[string]interface{}:
|
||||
case map[string]any:
|
||||
return getNested(m2, indices[1:])
|
||||
default:
|
||||
return nil, "", nil
|
||||
@@ -175,7 +175,7 @@ func getNested(m map[string]interface{}, indices []string) (interface{}, string,
|
||||
// It will first try the exact match and then try to find it as a nested map value,
|
||||
// using the given separator, e.g. "mymap.name".
|
||||
// It assumes that all the maps given have lower cased keys.
|
||||
func GetNestedParam(keyStr, separator string, candidates ...Params) (interface{}, error) {
|
||||
func GetNestedParam(keyStr, separator string, candidates ...Params) (any, error) {
|
||||
keyStr = strings.ToLower(keyStr)
|
||||
|
||||
// Try exact match first
|
||||
@@ -195,7 +195,7 @@ func GetNestedParam(keyStr, separator string, candidates ...Params) (interface{}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func GetNestedParamFn(keyStr, separator string, lookupFn func(key string) interface{}) (interface{}, string, map[string]interface{}, error) {
|
||||
func GetNestedParamFn(keyStr, separator string, lookupFn func(key string) any) (any, string, map[string]any, error) {
|
||||
keySegments := strings.Split(keyStr, separator)
|
||||
if len(keySegments) == 0 {
|
||||
return nil, "", nil, nil
|
||||
@@ -211,7 +211,7 @@ func GetNestedParamFn(keyStr, separator string, lookupFn func(key string) interf
|
||||
}
|
||||
|
||||
switch m := first.(type) {
|
||||
case map[string]interface{}:
|
||||
case map[string]any:
|
||||
v, key, owner := getNested(m, keySegments[1:])
|
||||
return v, key, owner, nil
|
||||
case Params:
|
||||
@@ -236,7 +236,7 @@ const (
|
||||
mergeStrategyKey = "_merge"
|
||||
)
|
||||
|
||||
func toMergeStrategy(v interface{}) ParamsMergeStrategy {
|
||||
func toMergeStrategy(v any) ParamsMergeStrategy {
|
||||
s := ParamsMergeStrategy(cast.ToString(v))
|
||||
switch s {
|
||||
case ParamsMergeStrategyDeep, ParamsMergeStrategyNone, ParamsMergeStrategyShallow:
|
||||
@@ -260,13 +260,13 @@ func PrepareParams(m Params) {
|
||||
retyped = true
|
||||
} else {
|
||||
switch vv := v.(type) {
|
||||
case map[interface{}]interface{}:
|
||||
case map[any]any:
|
||||
var p Params = cast.ToStringMap(v)
|
||||
v = p
|
||||
PrepareParams(p)
|
||||
retyped = true
|
||||
case map[string]interface{}:
|
||||
var p Params = v.(map[string]interface{})
|
||||
case map[string]any:
|
||||
var p Params = v.(map[string]any)
|
||||
v = p
|
||||
PrepareParams(p)
|
||||
retyped = true
|
||||
|
||||
@@ -20,13 +20,13 @@ import (
|
||||
)
|
||||
|
||||
func TestGetNestedParam(t *testing.T) {
|
||||
m := map[string]interface{}{
|
||||
m := map[string]any{
|
||||
"string": "value",
|
||||
"first": 1,
|
||||
"with_underscore": 2,
|
||||
"nested": map[string]interface{}{
|
||||
"nested": map[string]any{
|
||||
"color": "blue",
|
||||
"nestednested": map[string]interface{}{
|
||||
"nestednested": map[string]any{
|
||||
"color": "green",
|
||||
},
|
||||
},
|
||||
@@ -34,7 +34,7 @@ func TestGetNestedParam(t *testing.T) {
|
||||
|
||||
c := qt.New(t)
|
||||
|
||||
must := func(keyStr, separator string, candidates ...Params) interface{} {
|
||||
must := func(keyStr, separator string, candidates ...Params) any {
|
||||
v, err := GetNestedParam(keyStr, separator, candidates...)
|
||||
c.Assert(err, qt.IsNil)
|
||||
return v
|
||||
@@ -53,14 +53,14 @@ func TestGetNestedParam(t *testing.T) {
|
||||
func TestGetNestedParamFnNestedNewKey(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
|
||||
nested := map[string]interface{}{
|
||||
nested := map[string]any{
|
||||
"color": "blue",
|
||||
}
|
||||
m := map[string]interface{}{
|
||||
m := map[string]any{
|
||||
"nested": nested,
|
||||
}
|
||||
|
||||
existing, nestedKey, owner, err := GetNestedParamFn("nested.new", ".", func(key string) interface{} {
|
||||
existing, nestedKey, owner, err := GetNestedParamFn("nested.new", ".", func(key string) any {
|
||||
return m[key]
|
||||
})
|
||||
|
||||
|
||||
+14
-14
@@ -24,7 +24,7 @@ import (
|
||||
|
||||
// Scratch is a writable context used for stateful operations in Page/Node rendering.
|
||||
type Scratch struct {
|
||||
values map[string]interface{}
|
||||
values map[string]any
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
@@ -50,8 +50,8 @@ func NewScratcher() Scratcher {
|
||||
// Supports numeric values and strings.
|
||||
//
|
||||
// If the first add for a key is an array or slice, then the next value(s) will be appended.
|
||||
func (c *Scratch) Add(key string, newAddend interface{}) (string, error) {
|
||||
var newVal interface{}
|
||||
func (c *Scratch) Add(key string, newAddend any) (string, error) {
|
||||
var newVal any
|
||||
c.mu.RLock()
|
||||
existingAddend, found := c.values[key]
|
||||
c.mu.RUnlock()
|
||||
@@ -82,7 +82,7 @@ func (c *Scratch) Add(key string, newAddend interface{}) (string, error) {
|
||||
|
||||
// Set stores a value with the given key in the Node context.
|
||||
// This value can later be retrieved with Get.
|
||||
func (c *Scratch) Set(key string, value interface{}) string {
|
||||
func (c *Scratch) Set(key string, value any) string {
|
||||
c.mu.Lock()
|
||||
c.values[key] = value
|
||||
c.mu.Unlock()
|
||||
@@ -98,7 +98,7 @@ func (c *Scratch) Delete(key string) string {
|
||||
}
|
||||
|
||||
// Get returns a value previously set by Add or Set.
|
||||
func (c *Scratch) Get(key string) interface{} {
|
||||
func (c *Scratch) Get(key string) any {
|
||||
c.mu.RLock()
|
||||
val := c.values[key]
|
||||
c.mu.RUnlock()
|
||||
@@ -109,7 +109,7 @@ func (c *Scratch) Get(key string) interface{} {
|
||||
// Values returns the raw backing map. Note that you should just use
|
||||
// this method on the locally scoped Scratch instances you obtain via newScratch, not
|
||||
// .Page.Scratch etc., as that will lead to concurrency issues.
|
||||
func (c *Scratch) Values() map[string]interface{} {
|
||||
func (c *Scratch) Values() map[string]any {
|
||||
c.mu.RLock()
|
||||
defer c.mu.RUnlock()
|
||||
return c.values
|
||||
@@ -117,14 +117,14 @@ func (c *Scratch) Values() map[string]interface{} {
|
||||
|
||||
// SetInMap stores a value to a map with the given key in the Node context.
|
||||
// This map can later be retrieved with GetSortedMapValues.
|
||||
func (c *Scratch) SetInMap(key string, mapKey string, value interface{}) string {
|
||||
func (c *Scratch) SetInMap(key string, mapKey string, value any) string {
|
||||
c.mu.Lock()
|
||||
_, found := c.values[key]
|
||||
if !found {
|
||||
c.values[key] = make(map[string]interface{})
|
||||
c.values[key] = make(map[string]any)
|
||||
}
|
||||
|
||||
c.values[key].(map[string]interface{})[mapKey] = value
|
||||
c.values[key].(map[string]any)[mapKey] = value
|
||||
c.mu.Unlock()
|
||||
return ""
|
||||
}
|
||||
@@ -134,14 +134,14 @@ func (c *Scratch) DeleteInMap(key string, mapKey string) string {
|
||||
c.mu.Lock()
|
||||
_, found := c.values[key]
|
||||
if found {
|
||||
delete(c.values[key].(map[string]interface{}), mapKey)
|
||||
delete(c.values[key].(map[string]any), mapKey)
|
||||
}
|
||||
c.mu.Unlock()
|
||||
return ""
|
||||
}
|
||||
|
||||
// GetSortedMapValues returns a sorted map previously filled with SetInMap.
|
||||
func (c *Scratch) GetSortedMapValues(key string) interface{} {
|
||||
func (c *Scratch) GetSortedMapValues(key string) any {
|
||||
c.mu.RLock()
|
||||
|
||||
if c.values[key] == nil {
|
||||
@@ -149,7 +149,7 @@ func (c *Scratch) GetSortedMapValues(key string) interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
unsortedMap := c.values[key].(map[string]interface{})
|
||||
unsortedMap := c.values[key].(map[string]any)
|
||||
c.mu.RUnlock()
|
||||
var keys []string
|
||||
for mapKey := range unsortedMap {
|
||||
@@ -158,7 +158,7 @@ func (c *Scratch) GetSortedMapValues(key string) interface{} {
|
||||
|
||||
sort.Strings(keys)
|
||||
|
||||
sortedArray := make([]interface{}, len(unsortedMap))
|
||||
sortedArray := make([]any, len(unsortedMap))
|
||||
for i, mapKey := range keys {
|
||||
sortedArray[i] = unsortedMap[mapKey]
|
||||
}
|
||||
@@ -168,5 +168,5 @@ func (c *Scratch) GetSortedMapValues(key string) interface{} {
|
||||
|
||||
// NewScratch returns a new instance of Scratch.
|
||||
func NewScratch() *Scratch {
|
||||
return &Scratch{values: make(map[string]interface{})}
|
||||
return &Scratch{values: make(map[string]any)}
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ func TestScratchAddTypedSliceToInterfaceSlice(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
|
||||
scratch := NewScratch()
|
||||
scratch.Set("slice", []interface{}{})
|
||||
scratch.Set("slice", []any{})
|
||||
|
||||
_, err := scratch.Add("slice", []int{1, 2})
|
||||
c.Assert(err, qt.IsNil)
|
||||
@@ -107,7 +107,7 @@ func TestScratchAddDifferentTypedSliceToInterfaceSlice(t *testing.T) {
|
||||
|
||||
_, err := scratch.Add("slice", []int{1, 2})
|
||||
c.Assert(err, qt.IsNil)
|
||||
c.Assert(scratch.Get("slice"), qt.DeepEquals, []interface{}{"foo", 1, 2})
|
||||
c.Assert(scratch.Get("slice"), qt.DeepEquals, []any{"foo", 1, 2})
|
||||
}
|
||||
|
||||
func TestScratchSet(t *testing.T) {
|
||||
@@ -185,7 +185,7 @@ func TestScratchSetInMap(t *testing.T) {
|
||||
scratch.SetInMap("key", "zyx", "Zyx")
|
||||
scratch.SetInMap("key", "abc", "Abc (updated)")
|
||||
scratch.SetInMap("key", "def", "Def")
|
||||
c.Assert(scratch.GetSortedMapValues("key"), qt.DeepEquals, []interface{}{0: "Abc (updated)", 1: "Def", 2: "Lux", 3: "Zyx"})
|
||||
c.Assert(scratch.GetSortedMapValues("key"), qt.DeepEquals, []any{0: "Abc (updated)", 1: "Def", 2: "Lux", 3: "Zyx"})
|
||||
}
|
||||
|
||||
func TestScratchDeleteInMap(t *testing.T) {
|
||||
@@ -199,7 +199,7 @@ func TestScratchDeleteInMap(t *testing.T) {
|
||||
scratch.DeleteInMap("key", "abc")
|
||||
scratch.SetInMap("key", "def", "Def")
|
||||
scratch.DeleteInMap("key", "lmn") // Do nothing
|
||||
c.Assert(scratch.GetSortedMapValues("key"), qt.DeepEquals, []interface{}{0: "Def", 1: "Lux", 2: "Zyx"})
|
||||
c.Assert(scratch.GetSortedMapValues("key"), qt.DeepEquals, []any{0: "Def", 1: "Lux", 2: "Zyx"})
|
||||
}
|
||||
|
||||
func TestScratchGetSortedMapValues(t *testing.T) {
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@ import (
|
||||
|
||||
// DoArithmetic performs arithmetic operations (+,-,*,/) using reflection to
|
||||
// determine the type of the two terms.
|
||||
func DoArithmetic(a, b interface{}, op rune) (interface{}, error) {
|
||||
func DoArithmetic(a, b any, op rune) (any, error) {
|
||||
av := reflect.ValueOf(a)
|
||||
bv := reflect.ValueOf(b)
|
||||
var ai, bi int64
|
||||
|
||||
@@ -24,10 +24,10 @@ func TestDoArithmetic(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
|
||||
for _, test := range []struct {
|
||||
a interface{}
|
||||
b interface{}
|
||||
a any
|
||||
b any
|
||||
op rune
|
||||
expect interface{}
|
||||
expect any
|
||||
}{
|
||||
{3, 2, '+', int64(5)},
|
||||
{3, 2, '-', int64(1)},
|
||||
|
||||
@@ -24,7 +24,7 @@ func TestGetRelativePath(t *testing.T) {
|
||||
tests := []struct {
|
||||
path string
|
||||
base string
|
||||
expect interface{}
|
||||
expect any
|
||||
}{
|
||||
{filepath.FromSlash("/a/b"), filepath.FromSlash("/a"), filepath.FromSlash("b")},
|
||||
{filepath.FromSlash("/a/b/c/"), filepath.FromSlash("/a"), filepath.FromSlash("b/c/")},
|
||||
|
||||
@@ -69,7 +69,7 @@ func createPositionStringFormatter(formatStr string) func(p Position) string {
|
||||
format := replacer.Replace(formatStr)
|
||||
|
||||
f := func(pos Position) string {
|
||||
args := make([]interface{}, len(identifiersFound))
|
||||
args := make([]any, len(identifiersFound))
|
||||
for i, id := range identifiersFound {
|
||||
switch id {
|
||||
case ":file":
|
||||
|
||||
@@ -24,7 +24,7 @@ import (
|
||||
)
|
||||
|
||||
var accentTransformerPool = &sync.Pool{
|
||||
New: func() interface{} {
|
||||
New: func() any {
|
||||
return transform.Chain(norm.NFD, runes.Remove(runes.In(unicode.Mn)), norm.NFC)
|
||||
},
|
||||
}
|
||||
|
||||
@@ -25,13 +25,13 @@ import (
|
||||
|
||||
// ToDuration converts v to time.Duration.
|
||||
// See ToDurationE if you need to handle errors.
|
||||
func ToDuration(v interface{}) time.Duration {
|
||||
func ToDuration(v any) time.Duration {
|
||||
d, _ := ToDurationE(v)
|
||||
return d
|
||||
}
|
||||
|
||||
// ToDurationE converts v to time.Duration.
|
||||
func ToDurationE(v interface{}) (time.Duration, error) {
|
||||
func ToDurationE(v any) (time.Duration, error) {
|
||||
if n := cast.ToInt(v); n > 0 {
|
||||
return time.Duration(n) * time.Millisecond, nil
|
||||
}
|
||||
@@ -44,14 +44,14 @@ func ToDurationE(v interface{}) (time.Duration, error) {
|
||||
|
||||
// ToStringSlicePreserveString is the same as ToStringSlicePreserveStringE,
|
||||
// but it never fails.
|
||||
func ToStringSlicePreserveString(v interface{}) []string {
|
||||
func ToStringSlicePreserveString(v any) []string {
|
||||
vv, _ := ToStringSlicePreserveStringE(v)
|
||||
return vv
|
||||
}
|
||||
|
||||
// ToStringSlicePreserveStringE converts v to a string slice.
|
||||
// If v is a string, it will be wrapped in a string slice.
|
||||
func ToStringSlicePreserveStringE(v interface{}) ([]string, error) {
|
||||
func ToStringSlicePreserveStringE(v any) ([]string, error) {
|
||||
if v == nil {
|
||||
return nil, nil
|
||||
}
|
||||
@@ -86,7 +86,7 @@ func ToStringSlicePreserveStringE(v interface{}) ([]string, error) {
|
||||
// TypeToString converts v to a string if it's a valid string type.
|
||||
// Note that this will not try to convert numeric values etc.,
|
||||
// use ToString for that.
|
||||
func TypeToString(v interface{}) (string, bool) {
|
||||
func TypeToString(v any) (string, bool) {
|
||||
switch s := v.(type) {
|
||||
case string:
|
||||
return s, true
|
||||
@@ -110,13 +110,13 @@ func TypeToString(v interface{}) (string, bool) {
|
||||
}
|
||||
|
||||
// ToString converts v to a string.
|
||||
func ToString(v interface{}) string {
|
||||
func ToString(v any) string {
|
||||
s, _ := ToStringE(v)
|
||||
return s
|
||||
}
|
||||
|
||||
// ToStringE converts v to a string.
|
||||
func ToStringE(v interface{}) (string, error) {
|
||||
func ToStringE(v any) (string, error) {
|
||||
if s, ok := TypeToString(v); ok {
|
||||
return s, nil
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ func TestToStringSlicePreserveString(t *testing.T) {
|
||||
|
||||
c.Assert(ToStringSlicePreserveString("Hugo"), qt.DeepEquals, []string{"Hugo"})
|
||||
c.Assert(ToStringSlicePreserveString(qt.Commentf("Hugo")), qt.DeepEquals, []string{"Hugo"})
|
||||
c.Assert(ToStringSlicePreserveString([]interface{}{"A", "B"}), qt.DeepEquals, []string{"A", "B"})
|
||||
c.Assert(ToStringSlicePreserveString([]any{"A", "B"}), qt.DeepEquals, []string{"A", "B"})
|
||||
c.Assert(ToStringSlicePreserveString([]int{1, 3}), qt.DeepEquals, []string{"1", "3"})
|
||||
c.Assert(ToStringSlicePreserveString(nil), qt.IsNil)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
// Copyright 2022 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 hstring
|
||||
|
||||
type RenderedString string
|
||||
|
||||
func (s RenderedString) String() string {
|
||||
return string(s)
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
// Copyright 2022 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 hstring
|
||||
|
||||
import (
|
||||
"html/template"
|
||||
"testing"
|
||||
|
||||
qt "github.com/frankban/quicktest"
|
||||
"github.com/spf13/cast"
|
||||
)
|
||||
|
||||
func TestStringTypes(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
|
||||
// Validate that it will behave like a string in Hugo settings.
|
||||
c.Assert(cast.ToString(RenderedString("Hugo")), qt.Equals, "Hugo")
|
||||
c.Assert(template.HTML(RenderedString("Hugo")), qt.Equals, template.HTML("Hugo"))
|
||||
}
|
||||
@@ -29,8 +29,8 @@ type RLocker interface {
|
||||
|
||||
// KeyValue is a interface{} tuple.
|
||||
type KeyValue struct {
|
||||
Key interface{}
|
||||
Value interface{}
|
||||
Key any
|
||||
Value any
|
||||
}
|
||||
|
||||
// KeyValueStr is a string tuple.
|
||||
@@ -41,8 +41,8 @@ type KeyValueStr struct {
|
||||
|
||||
// KeyValues holds an key and a slice of values.
|
||||
type KeyValues struct {
|
||||
Key interface{}
|
||||
Values []interface{}
|
||||
Key any
|
||||
Values []any
|
||||
}
|
||||
|
||||
// KeyString returns the key as a string, an empty string if conversion fails.
|
||||
@@ -57,7 +57,7 @@ func (k KeyValues) String() string {
|
||||
// NewKeyValuesStrings takes a given key and slice of values and returns a new
|
||||
// KeyValues struct.
|
||||
func NewKeyValuesStrings(key string, values ...string) KeyValues {
|
||||
iv := make([]interface{}, len(values))
|
||||
iv := make([]any, len(values))
|
||||
for i := 0; i < len(values); i++ {
|
||||
iv[i] = values[i]
|
||||
}
|
||||
@@ -71,7 +71,7 @@ type Zeroer interface {
|
||||
}
|
||||
|
||||
// IsNil reports whether v is nil.
|
||||
func IsNil(v interface{}) bool {
|
||||
func IsNil(v any) bool {
|
||||
if v == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -25,5 +25,5 @@ func TestKeyValues(t *testing.T) {
|
||||
kv := NewKeyValuesStrings("key", "a1", "a2")
|
||||
|
||||
c.Assert(kv.KeyString(), qt.Equals, "key")
|
||||
c.Assert(kv.Values, qt.DeepEquals, []interface{}{"a1", "a2"})
|
||||
c.Assert(kv.Values, qt.DeepEquals, []any{"a1", "a2"})
|
||||
}
|
||||
|
||||
+2
-2
@@ -17,6 +17,6 @@ package urls
|
||||
// args must contain a path, but can also point to the target
|
||||
// language or output format.
|
||||
type RefLinker interface {
|
||||
Ref(args map[string]interface{}) (string, error)
|
||||
RelRef(args map[string]interface{}) (string, error)
|
||||
Ref(args map[string]any) (string, error)
|
||||
RelRef(args map[string]any) (string, error)
|
||||
}
|
||||
|
||||
+3
-3
@@ -17,13 +17,13 @@ package compare
|
||||
// The semantics of equals is that the two value are interchangeable
|
||||
// in the Hugo templates.
|
||||
type Eqer interface {
|
||||
Eq(other interface{}) bool
|
||||
Eq(other any) bool
|
||||
}
|
||||
|
||||
// ProbablyEqer is an equal check that may return false positives, but never
|
||||
// a false negative.
|
||||
type ProbablyEqer interface {
|
||||
ProbablyEq(other interface{}) bool
|
||||
ProbablyEq(other any) bool
|
||||
}
|
||||
|
||||
// Comparer can be used to compare two values.
|
||||
@@ -31,5 +31,5 @@ type ProbablyEqer interface {
|
||||
// Compare returns -1 if the given version is less than, 0 if equal and 1 if greater than
|
||||
// the running version.
|
||||
type Comparer interface {
|
||||
Compare(other interface{}) int
|
||||
Compare(other any) int
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ type Sitemap struct {
|
||||
Filename string
|
||||
}
|
||||
|
||||
func DecodeSitemap(prototype Sitemap, input map[string]interface{}) Sitemap {
|
||||
func DecodeSitemap(prototype Sitemap, input map[string]any) Sitemap {
|
||||
for key, value := range input {
|
||||
switch key {
|
||||
case "changefreq":
|
||||
@@ -177,7 +177,7 @@ func (s *Server) MatchRedirect(pattern string) Redirect {
|
||||
|
||||
type Headers struct {
|
||||
For string
|
||||
Values map[string]interface{}
|
||||
Values map[string]any
|
||||
}
|
||||
|
||||
type Redirect struct {
|
||||
|
||||
@@ -27,7 +27,7 @@ func TestBuild(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
|
||||
v := New()
|
||||
v.Set("build", map[string]interface{}{
|
||||
v.Set("build", map[string]any{
|
||||
"useResourceCacheWhen": "always",
|
||||
})
|
||||
|
||||
@@ -35,7 +35,7 @@ func TestBuild(t *testing.T) {
|
||||
|
||||
c.Assert(b.UseResourceCacheWhen, qt.Equals, "always")
|
||||
|
||||
v.Set("build", map[string]interface{}{
|
||||
v.Set("build", map[string]any{
|
||||
"useResourceCacheWhen": "foo",
|
||||
})
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ func (c *compositeConfig) GetInt(key string) int {
|
||||
return c.base.GetInt(key)
|
||||
}
|
||||
|
||||
func (c *compositeConfig) Merge(key string, value interface{}) {
|
||||
func (c *compositeConfig) Merge(key string, value any) {
|
||||
c.layer.Merge(key, value)
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ func (c *compositeConfig) GetParams(key string) maps.Params {
|
||||
return c.base.GetParams(key)
|
||||
}
|
||||
|
||||
func (c *compositeConfig) GetStringMap(key string) map[string]interface{} {
|
||||
func (c *compositeConfig) GetStringMap(key string) map[string]any {
|
||||
if c.layer.IsSet(key) {
|
||||
return c.layer.GetStringMap(key)
|
||||
}
|
||||
@@ -79,7 +79,7 @@ func (c *compositeConfig) GetStringSlice(key string) []string {
|
||||
return c.base.GetStringSlice(key)
|
||||
}
|
||||
|
||||
func (c *compositeConfig) Get(key string) interface{} {
|
||||
func (c *compositeConfig) Get(key string) any {
|
||||
if c.layer.IsSet(key) {
|
||||
return c.layer.Get(key)
|
||||
}
|
||||
@@ -100,7 +100,7 @@ func (c *compositeConfig) GetString(key string) string {
|
||||
return c.base.GetString(key)
|
||||
}
|
||||
|
||||
func (c *compositeConfig) Set(key string, value interface{}) {
|
||||
func (c *compositeConfig) Set(key string, value any) {
|
||||
c.layer.Set(key, value)
|
||||
}
|
||||
|
||||
|
||||
@@ -67,11 +67,11 @@ func FromFile(fs afero.Fs, filename string) (Provider, error) {
|
||||
|
||||
// FromFileToMap is the same as FromFile, but it returns the config values
|
||||
// as a simple map.
|
||||
func FromFileToMap(fs afero.Fs, filename string) (map[string]interface{}, error) {
|
||||
func FromFileToMap(fs afero.Fs, filename string) (map[string]any, error) {
|
||||
return loadConfigFromFile(fs, filename)
|
||||
}
|
||||
|
||||
func readConfig(format metadecoders.Format, data []byte) (map[string]interface{}, error) {
|
||||
func readConfig(format metadecoders.Format, data []byte) (map[string]any, error) {
|
||||
m, err := metadecoders.Default.UnmarshalToMap(data, format)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -82,7 +82,7 @@ func readConfig(format metadecoders.Format, data []byte) (map[string]interface{}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func loadConfigFromFile(fs afero.Fs, filename string) (map[string]interface{}, error) {
|
||||
func loadConfigFromFile(fs afero.Fs, filename string) (map[string]any, error) {
|
||||
m, err := metadecoders.Default.UnmarshalFileToMap(fs, filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -156,13 +156,13 @@ func LoadConfigFromDir(sourceFs afero.Fs, configDir, environment string) (Provid
|
||||
|
||||
root := item
|
||||
if len(keyPath) > 0 {
|
||||
root = make(map[string]interface{})
|
||||
root = make(map[string]any)
|
||||
m := root
|
||||
for i, key := range keyPath {
|
||||
if i >= len(keyPath)-1 {
|
||||
m[key] = item
|
||||
} else {
|
||||
nm := make(map[string]interface{})
|
||||
nm := make(map[string]any)
|
||||
m[key] = nm
|
||||
m = nm
|
||||
}
|
||||
@@ -203,6 +203,6 @@ func init() {
|
||||
|
||||
// RenameKeys renames config keys in m recursively according to a global Hugo
|
||||
// alias definition.
|
||||
func RenameKeys(m map[string]interface{}) {
|
||||
func RenameKeys(m map[string]any) {
|
||||
keyAliases.Rename(m)
|
||||
}
|
||||
|
||||
@@ -24,12 +24,12 @@ type Provider interface {
|
||||
GetInt(key string) int
|
||||
GetBool(key string) bool
|
||||
GetParams(key string) maps.Params
|
||||
GetStringMap(key string) map[string]interface{}
|
||||
GetStringMap(key string) map[string]any
|
||||
GetStringMapString(key string) map[string]string
|
||||
GetStringSlice(key string) []string
|
||||
Get(key string) interface{}
|
||||
Set(key string, value interface{})
|
||||
Merge(key string, value interface{})
|
||||
Get(key string) any
|
||||
Set(key string, value any)
|
||||
Merge(key string, value any)
|
||||
SetDefaults(params maps.Params)
|
||||
SetDefaultMergeStrategy()
|
||||
WalkParams(walkFn func(params ...KeyParams) bool)
|
||||
|
||||
@@ -84,7 +84,7 @@ type defaultConfigProvider struct {
|
||||
keyCache sync.Map
|
||||
}
|
||||
|
||||
func (c *defaultConfigProvider) Get(k string) interface{} {
|
||||
func (c *defaultConfigProvider) Get(k string) any {
|
||||
if k == "" {
|
||||
return c.root
|
||||
}
|
||||
@@ -133,7 +133,7 @@ func (c *defaultConfigProvider) GetParams(k string) maps.Params {
|
||||
return v.(maps.Params)
|
||||
}
|
||||
|
||||
func (c *defaultConfigProvider) GetStringMap(k string) map[string]interface{} {
|
||||
func (c *defaultConfigProvider) GetStringMap(k string) map[string]any {
|
||||
v := c.Get(k)
|
||||
return maps.ToStringMap(v)
|
||||
}
|
||||
@@ -148,7 +148,7 @@ func (c *defaultConfigProvider) GetStringSlice(k string) []string {
|
||||
return cast.ToStringSlice(v)
|
||||
}
|
||||
|
||||
func (c *defaultConfigProvider) Set(k string, v interface{}) {
|
||||
func (c *defaultConfigProvider) Set(k string, v any) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
@@ -166,7 +166,7 @@ func (c *defaultConfigProvider) Set(k string, v interface{}) {
|
||||
}
|
||||
|
||||
switch vv := v.(type) {
|
||||
case map[string]interface{}, map[interface{}]interface{}, map[string]string:
|
||||
case map[string]any, map[any]any, map[string]string:
|
||||
p := maps.MustToParamsAndPrepare(vv)
|
||||
v = p
|
||||
}
|
||||
@@ -198,7 +198,7 @@ func (c *defaultConfigProvider) SetDefaults(params maps.Params) {
|
||||
}
|
||||
}
|
||||
|
||||
func (c *defaultConfigProvider) Merge(k string, v interface{}) {
|
||||
func (c *defaultConfigProvider) Merge(k string, v any) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
k = strings.ToLower(k)
|
||||
@@ -289,7 +289,7 @@ func (c *defaultConfigProvider) Merge(k string, v interface{}) {
|
||||
}
|
||||
|
||||
switch vv := v.(type) {
|
||||
case map[string]interface{}, map[interface{}]interface{}, map[string]string:
|
||||
case map[string]any, map[any]any, map[string]string:
|
||||
p := maps.MustToParamsAndPrepare(vv)
|
||||
v = p
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ func TestDefaultConfigProvider(t *testing.T) {
|
||||
c.Run("Set and get", func(c *qt.C) {
|
||||
cfg := New()
|
||||
var k string
|
||||
var v interface{}
|
||||
var v any
|
||||
|
||||
k, v = "foo", "bar"
|
||||
cfg.Set(k, v)
|
||||
@@ -55,7 +55,7 @@ func TestDefaultConfigProvider(t *testing.T) {
|
||||
c.Run("Set and get map", func(c *qt.C) {
|
||||
cfg := New()
|
||||
|
||||
cfg.Set("foo", map[string]interface{}{
|
||||
cfg.Set("foo", map[string]any{
|
||||
"bar": "baz",
|
||||
})
|
||||
|
||||
@@ -63,14 +63,14 @@ func TestDefaultConfigProvider(t *testing.T) {
|
||||
"bar": "baz",
|
||||
})
|
||||
|
||||
c.Assert(cfg.GetStringMap("foo"), qt.DeepEquals, map[string]interface{}{"bar": string("baz")})
|
||||
c.Assert(cfg.GetStringMap("foo"), qt.DeepEquals, map[string]any{"bar": string("baz")})
|
||||
c.Assert(cfg.GetStringMapString("foo"), qt.DeepEquals, map[string]string{"bar": string("baz")})
|
||||
})
|
||||
|
||||
c.Run("Set and get nested", func(c *qt.C) {
|
||||
cfg := New()
|
||||
|
||||
cfg.Set("a", map[string]interface{}{
|
||||
cfg.Set("a", map[string]any{
|
||||
"B": "bv",
|
||||
})
|
||||
cfg.Set("a.c", "cv")
|
||||
@@ -86,7 +86,7 @@ func TestDefaultConfigProvider(t *testing.T) {
|
||||
"a": "av",
|
||||
})
|
||||
|
||||
cfg.Set("b", map[string]interface{}{
|
||||
cfg.Set("b", map[string]any{
|
||||
"b": "bv",
|
||||
})
|
||||
|
||||
@@ -99,7 +99,7 @@ func TestDefaultConfigProvider(t *testing.T) {
|
||||
|
||||
cfg.Set("a", "av")
|
||||
|
||||
cfg.Set("", map[string]interface{}{
|
||||
cfg.Set("", map[string]any{
|
||||
"a": "av2",
|
||||
"b": "bv2",
|
||||
})
|
||||
@@ -113,7 +113,7 @@ func TestDefaultConfigProvider(t *testing.T) {
|
||||
|
||||
cfg.Set("a", "av")
|
||||
|
||||
cfg.Set("", map[string]interface{}{
|
||||
cfg.Set("", map[string]any{
|
||||
"b": "bv2",
|
||||
})
|
||||
|
||||
@@ -124,14 +124,14 @@ func TestDefaultConfigProvider(t *testing.T) {
|
||||
|
||||
cfg = New()
|
||||
|
||||
cfg.Set("", map[string]interface{}{
|
||||
"foo": map[string]interface{}{
|
||||
cfg.Set("", map[string]any{
|
||||
"foo": map[string]any{
|
||||
"a": "av",
|
||||
},
|
||||
})
|
||||
|
||||
cfg.Set("", map[string]interface{}{
|
||||
"foo": map[string]interface{}{
|
||||
cfg.Set("", map[string]any{
|
||||
"foo": map[string]any{
|
||||
"b": "bv2",
|
||||
},
|
||||
})
|
||||
@@ -145,11 +145,11 @@ func TestDefaultConfigProvider(t *testing.T) {
|
||||
c.Run("Merge default strategy", func(c *qt.C) {
|
||||
cfg := New()
|
||||
|
||||
cfg.Set("a", map[string]interface{}{
|
||||
cfg.Set("a", map[string]any{
|
||||
"B": "bv",
|
||||
})
|
||||
|
||||
cfg.Merge("a", map[string]interface{}{
|
||||
cfg.Merge("a", map[string]any{
|
||||
"B": "bv2",
|
||||
"c": "cv2",
|
||||
})
|
||||
@@ -163,7 +163,7 @@ func TestDefaultConfigProvider(t *testing.T) {
|
||||
|
||||
cfg.Set("a", "av")
|
||||
|
||||
cfg.Merge("", map[string]interface{}{
|
||||
cfg.Merge("", map[string]any{
|
||||
"a": "av2",
|
||||
"b": "bv2",
|
||||
})
|
||||
@@ -176,16 +176,16 @@ func TestDefaultConfigProvider(t *testing.T) {
|
||||
c.Run("Merge shallow", func(c *qt.C) {
|
||||
cfg := New()
|
||||
|
||||
cfg.Set("a", map[string]interface{}{
|
||||
cfg.Set("a", map[string]any{
|
||||
"_merge": "shallow",
|
||||
"B": "bv",
|
||||
"c": map[string]interface{}{
|
||||
"c": map[string]any{
|
||||
"b": "bv",
|
||||
},
|
||||
})
|
||||
|
||||
cfg.Merge("a", map[string]interface{}{
|
||||
"c": map[string]interface{}{
|
||||
cfg.Merge("a", map[string]any{
|
||||
"c": map[string]any{
|
||||
"d": "dv2",
|
||||
},
|
||||
"e": "ev2",
|
||||
@@ -203,20 +203,20 @@ func TestDefaultConfigProvider(t *testing.T) {
|
||||
|
||||
// Issue #8679
|
||||
c.Run("Merge typed maps", func(c *qt.C) {
|
||||
for _, left := range []interface{}{
|
||||
for _, left := range []any{
|
||||
map[string]string{
|
||||
"c": "cv1",
|
||||
},
|
||||
map[string]interface{}{
|
||||
map[string]any{
|
||||
"c": "cv1",
|
||||
},
|
||||
map[interface{}]interface{}{
|
||||
map[any]any{
|
||||
"c": "cv1",
|
||||
},
|
||||
} {
|
||||
cfg := New()
|
||||
|
||||
cfg.Set("", map[string]interface{}{
|
||||
cfg.Set("", map[string]any{
|
||||
"b": left,
|
||||
})
|
||||
|
||||
@@ -235,27 +235,27 @@ func TestDefaultConfigProvider(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
for _, left := range []interface{}{
|
||||
for _, left := range []any{
|
||||
map[string]string{
|
||||
"b": "bv1",
|
||||
},
|
||||
map[string]interface{}{
|
||||
map[string]any{
|
||||
"b": "bv1",
|
||||
},
|
||||
map[interface{}]interface{}{
|
||||
map[any]any{
|
||||
"b": "bv1",
|
||||
},
|
||||
} {
|
||||
for _, right := range []interface{}{
|
||||
for _, right := range []any{
|
||||
map[string]string{
|
||||
"b": "bv2",
|
||||
"c": "cv2",
|
||||
},
|
||||
map[string]interface{}{
|
||||
map[string]any{
|
||||
"b": "bv2",
|
||||
"c": "cv2",
|
||||
},
|
||||
map[interface{}]interface{}{
|
||||
map[any]any{
|
||||
"b": "bv2",
|
||||
"c": "cv2",
|
||||
},
|
||||
@@ -280,12 +280,12 @@ func TestDefaultConfigProvider(t *testing.T) {
|
||||
c.Run("Prevent _merge only maps", func(c *qt.C) {
|
||||
cfg := New()
|
||||
|
||||
cfg.Set("", map[string]interface{}{
|
||||
cfg.Set("", map[string]any{
|
||||
"B": "bv",
|
||||
})
|
||||
|
||||
cfg.Merge("", map[string]interface{}{
|
||||
"c": map[string]interface{}{
|
||||
cfg.Merge("", map[string]any{
|
||||
"c": map[string]any{
|
||||
"_merge": "shallow",
|
||||
"d": "dv2",
|
||||
},
|
||||
@@ -299,7 +299,7 @@ func TestDefaultConfigProvider(t *testing.T) {
|
||||
c.Run("IsSet", func(c *qt.C) {
|
||||
cfg := New()
|
||||
|
||||
cfg.Set("a", map[string]interface{}{
|
||||
cfg.Set("a", map[string]any{
|
||||
"B": "bv",
|
||||
})
|
||||
|
||||
@@ -357,15 +357,15 @@ func TestDefaultConfigProvider(t *testing.T) {
|
||||
|
||||
func BenchmarkDefaultConfigProvider(b *testing.B) {
|
||||
type cfger interface {
|
||||
Get(key string) interface{}
|
||||
Set(key string, value interface{})
|
||||
Get(key string) any
|
||||
Set(key string, value any)
|
||||
IsSet(key string) bool
|
||||
}
|
||||
|
||||
newMap := func() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"a": map[string]interface{}{
|
||||
"b": map[string]interface{}{
|
||||
newMap := func() map[string]any {
|
||||
return map[string]any{
|
||||
"a": map[string]any{
|
||||
"b": map[string]any{
|
||||
"c": 32,
|
||||
"d": 43,
|
||||
},
|
||||
|
||||
@@ -35,7 +35,7 @@ func init() {
|
||||
cfg.Set("languages", lang)
|
||||
cfg.SetDefaultMergeStrategy()
|
||||
|
||||
configHelpers := map[string]interface{}{
|
||||
configHelpers := map[string]any{
|
||||
"mergeStrategy": cfg.Get(""),
|
||||
}
|
||||
return docshelper.DocProvider{"config": configHelpers}
|
||||
|
||||
+2
-2
@@ -41,8 +41,8 @@ func SetEnvVars(oldVars *[]string, keyValues ...string) {
|
||||
}
|
||||
|
||||
func SplitEnvVar(v string) (string, string) {
|
||||
parts := strings.SplitN(v, "=", 2)
|
||||
return parts[0], parts[1]
|
||||
name, value, _ := strings.Cut(v, "=")
|
||||
return name, value
|
||||
}
|
||||
|
||||
func setEnvVar(vars *[]string, key, value string) {
|
||||
|
||||
@@ -147,15 +147,15 @@ func (c Config) CheckAllowedHTTPMethod(method string) error {
|
||||
}
|
||||
|
||||
// ToSecurityMap converts c to a map with 'security' as the root key.
|
||||
func (c Config) ToSecurityMap() map[string]interface{} {
|
||||
func (c Config) ToSecurityMap() map[string]any {
|
||||
// Take it to JSON and back to get proper casing etc.
|
||||
asJson, err := json.Marshal(c)
|
||||
herrors.Must(err)
|
||||
m := make(map[string]interface{})
|
||||
m := make(map[string]any)
|
||||
herrors.Must(json.Unmarshal(asJson, &m))
|
||||
|
||||
// Add the root
|
||||
sec := map[string]interface{}{
|
||||
sec := map[string]any{
|
||||
"security": m,
|
||||
}
|
||||
return sec
|
||||
@@ -196,7 +196,7 @@ func stringSliceToWhitelistHook() mapstructure.DecodeHookFuncType {
|
||||
return func(
|
||||
f reflect.Type,
|
||||
t reflect.Type,
|
||||
data interface{}) (interface{}, error) {
|
||||
data any) (any, error) {
|
||||
|
||||
if t != reflect.TypeOf(Whitelist{}) {
|
||||
return data, nil
|
||||
|
||||
@@ -18,7 +18,6 @@ import (
|
||||
|
||||
qt "github.com/frankban/quicktest"
|
||||
"github.com/gohugoio/hugo/config"
|
||||
|
||||
)
|
||||
|
||||
func TestDecodeConfigFromTOML(t *testing.T) {
|
||||
|
||||
+3
-3
@@ -283,10 +283,10 @@ func (b *contentBuilder) applyArcheType(contentFilename, archetypeFilename strin
|
||||
defer f.Close()
|
||||
|
||||
if archetypeFilename == "" {
|
||||
return b.cf.AppplyArchetypeTemplate(f, p, b.kind, DefaultArchetypeTemplateTemplate)
|
||||
return b.cf.ApplyArchetypeTemplate(f, p, b.kind, DefaultArchetypeTemplateTemplate)
|
||||
}
|
||||
|
||||
return b.cf.AppplyArchetypeFilename(f, p, b.kind, archetypeFilename)
|
||||
return b.cf.ApplyArchetypeFilename(f, p, b.kind, archetypeFilename)
|
||||
|
||||
}
|
||||
|
||||
@@ -346,7 +346,7 @@ func (b *contentBuilder) openInEditorIfConfigured(filename string) error {
|
||||
editorExec := strings.Fields(editor)[0]
|
||||
editorFlags := strings.Fields(editor)[1:]
|
||||
|
||||
var args []interface{}
|
||||
var args []any
|
||||
for _, editorFlag := range editorFlags {
|
||||
args = append(args, editorFlag)
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ func TestNewContentFromFile(t *testing.T) {
|
||||
name string
|
||||
kind string
|
||||
path string
|
||||
expected interface{}
|
||||
expected any
|
||||
}{
|
||||
{"Post", "post", "post/sample-1.md", []string{`title = "Post Arch title"`, `test = "test1"`, "date = \"2015-01-12T19:20:04-07:00\""}},
|
||||
{"Post org-mode", "post", "post/org-1.org", []string{`#+title: ORG-1`}},
|
||||
@@ -368,7 +368,7 @@ Some text.
|
||||
return nil
|
||||
}
|
||||
|
||||
func cContains(c *qt.C, v interface{}, matches ...string) {
|
||||
func cContains(c *qt.C, v any, matches ...string) {
|
||||
for _, m := range matches {
|
||||
c.Assert(v, qt.Contains, m)
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//go:build !nodeploy
|
||||
// +build !nodeploy
|
||||
|
||||
package deploy
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//go:build !nodeploy
|
||||
// +build !nodeploy
|
||||
|
||||
package deploy
|
||||
|
||||
@@ -115,7 +115,7 @@ func (m *matcher) Matches(path string) bool {
|
||||
// decode creates a config from a given Hugo configuration.
|
||||
func decodeConfig(cfg config.Provider) (deployConfig, error) {
|
||||
var (
|
||||
mediaTypesConfig []map[string]interface{}
|
||||
mediaTypesConfig []map[string]any
|
||||
dcfg deployConfig
|
||||
)
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//go:build !solaris && !nodeploy
|
||||
// +build !solaris,!nodeploy
|
||||
|
||||
package deploy
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//go:build !nodeploy
|
||||
// +build !nodeploy
|
||||
|
||||
package deploy
|
||||
@@ -252,7 +253,7 @@ func TestWalkLocal(t *testing.T) {
|
||||
if got, err := walkLocal(fs, nil, nil, nil, media.DefaultTypes); err != nil {
|
||||
t.Fatal(err)
|
||||
} else {
|
||||
expect := map[string]interface{}{}
|
||||
expect := map[string]any{}
|
||||
for _, path := range tc.Expect {
|
||||
if _, ok := got[path]; !ok {
|
||||
t.Errorf("expected %q in results, but was not found", path)
|
||||
@@ -290,7 +291,7 @@ func TestLocalFile(t *testing.T) {
|
||||
Description string
|
||||
Path string
|
||||
Matcher *matcher
|
||||
MediaTypesConfig []map[string]interface{}
|
||||
MediaTypesConfig []map[string]any
|
||||
WantContent []byte
|
||||
WantSize int64
|
||||
WantMD5 []byte
|
||||
@@ -351,9 +352,9 @@ func TestLocalFile(t *testing.T) {
|
||||
{
|
||||
Description: "Custom MediaType",
|
||||
Path: "foo.hugo",
|
||||
MediaTypesConfig: []map[string]interface{}{
|
||||
MediaTypesConfig: []map[string]any{
|
||||
{
|
||||
"hugo/custom": map[string]interface{}{
|
||||
"hugo/custom": map[string]any{
|
||||
"suffixes": []string{"hugo"},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//go:build !nodeploy
|
||||
// +build !nodeploy
|
||||
|
||||
package deploy
|
||||
|
||||
Vendored
+3
-3
@@ -68,7 +68,7 @@ type Deps struct {
|
||||
FileCaches filecache.Caches
|
||||
|
||||
// The translation func to use
|
||||
Translate func(translationID string, templateData interface{}) string `json:"-"`
|
||||
Translate func(translationID string, templateData any) string `json:"-"`
|
||||
|
||||
// The language in use. TODO(bep) consolidate with site
|
||||
Language *langs.Language
|
||||
@@ -83,7 +83,7 @@ type Deps struct {
|
||||
WithTemplate func(templ tpl.TemplateManager) error `json:"-"`
|
||||
|
||||
// Used in tests
|
||||
OverloadedTemplateFuncs map[string]interface{}
|
||||
OverloadedTemplateFuncs map[string]any
|
||||
|
||||
translationProvider ResourceProvider
|
||||
|
||||
@@ -392,7 +392,7 @@ type DepsCfg struct {
|
||||
TemplateProvider ResourceProvider
|
||||
WithTemplate func(templ tpl.TemplateManager) error
|
||||
// Used in tests
|
||||
OverloadedTemplateFuncs map[string]interface{}
|
||||
OverloadedTemplateFuncs map[string]any
|
||||
|
||||
// i18n handling.
|
||||
TranslationProvider ResourceProvider
|
||||
|
||||
@@ -0,0 +1,276 @@
|
||||
{
|
||||
"version": "0.2",
|
||||
"words": [
|
||||
"aaabaab",
|
||||
"aabb",
|
||||
"aabba",
|
||||
"aabbaa",
|
||||
"aabbaabb",
|
||||
"abourget",
|
||||
"absurl",
|
||||
"adoc",
|
||||
"algolia",
|
||||
"allowfullscreen",
|
||||
"ananke",
|
||||
"anchorize",
|
||||
"anthonyfok",
|
||||
"asciidoctor",
|
||||
"attrlink",
|
||||
"azblob",
|
||||
"baseof",
|
||||
"beevelop",
|
||||
"bibtex",
|
||||
"Bjørn",
|
||||
"blackfriday",
|
||||
"blogue",
|
||||
"bogem",
|
||||
"Bootcamp",
|
||||
"brlink",
|
||||
"Brotli",
|
||||
"Browsersync",
|
||||
"canonify",
|
||||
"Catmull",
|
||||
"Catwoman",
|
||||
"Cheatsheet",
|
||||
"choco",
|
||||
"chromastyles",
|
||||
"clockoon",
|
||||
"Cloudinary",
|
||||
"CNAME",
|
||||
"Codecademy's",
|
||||
"CODEOWNERS",
|
||||
"Coen",
|
||||
"Commento",
|
||||
"Cond",
|
||||
"Contentful",
|
||||
"copyrighthtml",
|
||||
"corejs",
|
||||
"countrunes",
|
||||
"countwords",
|
||||
"crossreferences",
|
||||
"datatable",
|
||||
"DATOCMS",
|
||||
"debugconfig",
|
||||
"DELIM",
|
||||
"dhersam",
|
||||
"digitalcraftsman",
|
||||
"Disqus",
|
||||
"Dmdh",
|
||||
"doas",
|
||||
"dokuwiki",
|
||||
"dpkg",
|
||||
"DRING",
|
||||
"Emojify",
|
||||
"Enwrite",
|
||||
"eopkg",
|
||||
"eparis",
|
||||
"errorf",
|
||||
"erroridf",
|
||||
"Evernote",
|
||||
"exitwp",
|
||||
"Feminella",
|
||||
"firstpost",
|
||||
"Formspree",
|
||||
"fpath",
|
||||
"Francia",
|
||||
"freenode",
|
||||
"frontmatter",
|
||||
"funcs",
|
||||
"funcsig",
|
||||
"Garen",
|
||||
"gcloud",
|
||||
"Getenv",
|
||||
"getjson",
|
||||
"getpage",
|
||||
"Gmfc",
|
||||
"Goel",
|
||||
"Gohugo",
|
||||
"gohugoio",
|
||||
"goldenbridge",
|
||||
"Goldmark",
|
||||
"gomodules",
|
||||
"GOPATH",
|
||||
"govendor",
|
||||
"Gowans",
|
||||
"Grayscale",
|
||||
"Gruber",
|
||||
"gtag",
|
||||
"hidecaption",
|
||||
"Hokus",
|
||||
"hola",
|
||||
"hügó",
|
||||
"hugodeps",
|
||||
"hugodoc",
|
||||
"Hugofy",
|
||||
"hugolang",
|
||||
"hugoversion",
|
||||
"Hyas",
|
||||
"Hyvor",
|
||||
"iframes",
|
||||
"ifttt",
|
||||
"iife",
|
||||
"imgproc",
|
||||
"importr",
|
||||
"IMWQ",
|
||||
"indice",
|
||||
"innershortcode",
|
||||
"Intelli",
|
||||
"interdoc",
|
||||
"IPTC",
|
||||
"ismenucurrent",
|
||||
"Isset",
|
||||
"Isso",
|
||||
"Jaco",
|
||||
"johnpatitucci",
|
||||
"Joomla",
|
||||
"JRBR",
|
||||
"jsonify",
|
||||
"katex",
|
||||
"keycdn",
|
||||
"KEYVALS",
|
||||
"kubernetes",
|
||||
"Lanczos",
|
||||
"langformatnumber",
|
||||
"lastmod",
|
||||
"libwebp",
|
||||
"linktitle",
|
||||
"Lipi",
|
||||
"lrwxr",
|
||||
"maingo",
|
||||
"markdownified",
|
||||
"markdownify",
|
||||
"mathjax",
|
||||
"mdhender",
|
||||
"mdshortcode",
|
||||
"mercredi",
|
||||
"Mittwoch",
|
||||
"mkdir",
|
||||
"mmark",
|
||||
"monokai",
|
||||
"Morling",
|
||||
"mspowerpoint",
|
||||
"Multihost",
|
||||
"Muut",
|
||||
"myclass",
|
||||
"mydeployment",
|
||||
"myindex",
|
||||
"mylayout",
|
||||
"mypage",
|
||||
"mypartials",
|
||||
"mypost",
|
||||
"mysite",
|
||||
"myspa",
|
||||
"mystyle",
|
||||
"mytheme",
|
||||
"NDJSON",
|
||||
"needsexample",
|
||||
"Netravali",
|
||||
"newparam",
|
||||
"Nikhil",
|
||||
"Njjy",
|
||||
"nlist",
|
||||
"nobr",
|
||||
"nocopy",
|
||||
"Norsk",
|
||||
"nosniff",
|
||||
"NOSQL",
|
||||
"notoc",
|
||||
"novembre",
|
||||
"NUMWORKERMULTIPLIER",
|
||||
"Obhu",
|
||||
"octohug",
|
||||
"Octopress",
|
||||
"oldparam",
|
||||
"onrender",
|
||||
"opengraph",
|
||||
"OWASP",
|
||||
"Pandoc",
|
||||
"partialcached",
|
||||
"Pastorius",
|
||||
"Patitucci",
|
||||
"PCRE",
|
||||
"peaceiris",
|
||||
"Pedersen",
|
||||
"permalinkable",
|
||||
"plainify",
|
||||
"POSIX",
|
||||
"postprocess",
|
||||
"println",
|
||||
"publishdate",
|
||||
"Pygments",
|
||||
"querify",
|
||||
"QVOMC",
|
||||
"rdwatters",
|
||||
"readfile",
|
||||
"rebinded",
|
||||
"REDIR",
|
||||
"reftext",
|
||||
"relatedfuncs",
|
||||
"relref",
|
||||
"relurl",
|
||||
"remarkjs",
|
||||
"rgba",
|
||||
"rlimit",
|
||||
"roboto",
|
||||
"rssxml",
|
||||
"rwxrwxrwx",
|
||||
"safehtml",
|
||||
"safejs",
|
||||
"Samsa",
|
||||
"Shekhar",
|
||||
"Shortcode",
|
||||
"Shortcodes",
|
||||
"Sindre",
|
||||
"sitemapindex",
|
||||
"sitemapxml",
|
||||
"Smartcrop",
|
||||
"Sprintf",
|
||||
"Startseite",
|
||||
"strconv",
|
||||
"stringifier",
|
||||
"struct",
|
||||
"structs",
|
||||
"subdir",
|
||||
"Talkyard",
|
||||
"taxo",
|
||||
"tbody",
|
||||
"tdewolff",
|
||||
"testshortcodes",
|
||||
"thead",
|
||||
"Thinkful",
|
||||
"TLDR",
|
||||
"TMPDIR",
|
||||
"tojson",
|
||||
"Torikian",
|
||||
"totoml",
|
||||
"toyaml",
|
||||
"twitteruser",
|
||||
"Unmarshal",
|
||||
"Unmarshal",
|
||||
"urlize",
|
||||
"urlset",
|
||||
"vimrc",
|
||||
"wanghc",
|
||||
"Wappalyzer",
|
||||
"warnf",
|
||||
"webp",
|
||||
"Wercker",
|
||||
"wibble",
|
||||
"wordcount",
|
||||
"workson",
|
||||
"xvzf",
|
||||
"yoyoyo",
|
||||
"Zgotmpl",
|
||||
"zzbbaabb"
|
||||
],
|
||||
"language": "en,en-GB,en-US,de,fr",
|
||||
"files": [
|
||||
"**/*.md"
|
||||
],
|
||||
"ignorePaths": [
|
||||
".cspell.json",
|
||||
"**/node_modules/**",
|
||||
"*.min.*"
|
||||
],
|
||||
"useGitignore": true
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
name: 'Check spelling'
|
||||
on: # rebuild any PRs and main branch changes
|
||||
push:
|
||||
branches-ignore:
|
||||
- "dependabot/**"
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
spellcheck:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: streetsidesoftware/cspell-action@3bc52c39528d0214a947ff7f8b5c23ad3273435b
|
||||
with:
|
||||
inline: warning
|
||||
strict: false
|
||||
incremental_files_only: true
|
||||
@@ -58,6 +58,7 @@
|
||||
</head>
|
||||
|
||||
<body class="ma0 sans-serif bg-primary-color-light{{ with getenv "HUGO_ENV" }} {{ . }}{{ end }}">
|
||||
{{ partial "hooks/after-body-start" . }}
|
||||
{{ block "nav" . }}{{ partial "site-nav.html" . }}{{ end }}
|
||||
{{ block "header" . }}{{ end }}
|
||||
<main role="main" class="content-with-sidebar min-vh-100 pb7 pb0-ns">
|
||||
@@ -65,6 +66,9 @@
|
||||
</main>
|
||||
|
||||
{{ block "footer" . }}{{ partialCached "site-footer.html" . }}{{ end }}
|
||||
|
||||
{{ partial "hooks/before-body-end" . }}
|
||||
|
||||
|
||||
{{ if .Page.Store.Get "hasMermaid" }}
|
||||
<script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
|
||||
|
||||
Generated
+1
@@ -0,0 +1 @@
|
||||
{{/* Deliberately empty */}}
|
||||
Generated
+1
@@ -0,0 +1 @@
|
||||
{{/* Deliberately empty */}}
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
HUGO
|
||||
</a>
|
||||
</h1>
|
||||
<ul class="list ma0 pa0 dn dib-l">
|
||||
<ul class="list ma0 pa0 dn dib-l" role="menu">
|
||||
{{ range .Site.Menus.global }}
|
||||
<li class="f5 dib mr4" role="menuitem">
|
||||
{{/* TODO: Create an "Global" active class to show which site one is currently at */}}
|
||||
|
||||
@@ -1 +1 @@
|
||||
# github.com/gohugoio/gohugoioTheme v0.0.0-20211211134334-0fe25799bb58
|
||||
# github.com/gohugoio/gohugoioTheme v0.0.0-20220228085601-7cfbda06d135
|
||||
|
||||
@@ -42,7 +42,7 @@ The default configuration is listed below. Any build using features not in the a
|
||||
Note that these and other config settings in Hugo can be overridden by the OS environment. If you want to block all remote HTTP fetching of data:
|
||||
|
||||
```
|
||||
HUGO_SECURITY_HTTP_URLS=none hugo
|
||||
HUGO_SECURITY_HTTP_URLS=none hugo
|
||||
```
|
||||
|
||||
## Dependency Security
|
||||
|
||||
@@ -14,7 +14,7 @@ hugo is the main command, used to build your Hugo site.
|
||||
Hugo is a Fast and Flexible Static Site Generator
|
||||
built with love by spf13 and friends in Go.
|
||||
|
||||
Complete documentation is available at http://gohugo.io/.
|
||||
Complete documentation is available at https://gohugo.io/.
|
||||
|
||||
```
|
||||
hugo [flags]
|
||||
@@ -23,7 +23,7 @@ hugo [flags]
|
||||
### Options
|
||||
|
||||
```
|
||||
-b, --baseURL string hostname (and path) to the root, e.g. http://spf13.com/
|
||||
-b, --baseURL string hostname (and path) to the root, e.g. https://spf13.com/
|
||||
-D, --buildDrafts include content marked as draft
|
||||
-E, --buildExpired include expired content
|
||||
-F, --buildFuture include content with publishdate in the future
|
||||
|
||||
@@ -12,7 +12,7 @@ Generate Markdown documentation for the Hugo CLI.
|
||||
Generate Markdown documentation for the Hugo CLI.
|
||||
|
||||
This command is, mostly, used to create up-to-date documentation
|
||||
of Hugo's command-line interface for http://gohugo.io/.
|
||||
of Hugo's command-line interface for https://gohugo.io/.
|
||||
|
||||
It creates one Markdown file per command with front matter suitable
|
||||
for rendering in Hugo.
|
||||
|
||||
@@ -26,7 +26,7 @@ See https://gohugo.io/hugo-modules/ for more information.
|
||||
### Options
|
||||
|
||||
```
|
||||
-b, --baseURL string hostname (and path) to the root, e.g. http://spf13.com/
|
||||
-b, --baseURL string hostname (and path) to the root, e.g. https://spf13.com/
|
||||
-D, --buildDrafts include content marked as draft
|
||||
-E, --buildExpired include expired content
|
||||
-F, --buildFuture include content with publishdate in the future
|
||||
|
||||
@@ -25,7 +25,7 @@ hugo new [path] [flags]
|
||||
### Options
|
||||
|
||||
```
|
||||
-b, --baseURL string hostname (and path) to the root, e.g. http://spf13.com/
|
||||
-b, --baseURL string hostname (and path) to the root, e.g. https://spf13.com/
|
||||
-D, --buildDrafts include content marked as draft
|
||||
-E, --buildExpired include expired content
|
||||
-F, --buildFuture include content with publishdate in the future
|
||||
|
||||
@@ -30,7 +30,7 @@ hugo server [flags]
|
||||
|
||||
```
|
||||
--appendPort append port to baseURL (default true)
|
||||
-b, --baseURL string hostname (and path) to the root, e.g. http://spf13.com/
|
||||
-b, --baseURL string hostname (and path) to the root, e.g. https://spf13.com/
|
||||
--bind string interface to which the server will bind (default "127.0.0.1")
|
||||
-D, --buildDrafts include content marked as draft
|
||||
-E, --buildExpired include expired content
|
||||
|
||||
@@ -18,12 +18,12 @@ toc: true
|
||||
|
||||
They are stored in a reserved Front Matter object named `_build` with the following defaults:
|
||||
|
||||
```yaml
|
||||
{{< code-toggle >}}
|
||||
_build:
|
||||
render: always
|
||||
list: always
|
||||
publishResources: true
|
||||
```
|
||||
{{< /code-toggle >}}
|
||||
|
||||
#### render
|
||||
If `always`, the page will be treated as a published page, holding its dedicated output files (`index.html`, etc...) and permalink.
|
||||
|
||||
@@ -30,7 +30,7 @@ Hugo comes with all the code you need to load Disqus into your templates. Before
|
||||
Disqus comments require you set a single value in your [site's configuration file][configuration] like so:
|
||||
|
||||
{{< code-toggle copy="false" >}}
|
||||
disqusShortname = "yourdiscussshortname"
|
||||
disqusShortname = "yourDisqusShortname"
|
||||
{{</ code-toggle >}}
|
||||
|
||||
For many websites, this is enough configuration. However, you also have the option to set the following in the [front matter][] of a single content file:
|
||||
|
||||
@@ -12,8 +12,68 @@ toc: true
|
||||
---
|
||||
|
||||
|
||||
{{< new-in "0.93.0" >}}
|
||||
|
||||
|
||||
## GoAT Diagrams (Ascii)
|
||||
|
||||
Hugo! supports [GoAT](https://github.com/bep/goat) natively. This means that this code block:
|
||||
|
||||
````
|
||||
```goat
|
||||
. . . .--- 1 .-- 1 / 1
|
||||
/ \ | | .---+ .-+ +
|
||||
/ \ .---+---. .--+--. | '--- 2 | '-- 2 / \ 2
|
||||
+ + | | | | ---+ ---+ +
|
||||
/ \ / \ .-+-. .-+-. .+. .+. | .--- 3 | .-- 3 \ / 3
|
||||
/ \ / \ | | | | | | | | '---+ '-+ +
|
||||
1 2 3 4 1 2 3 4 1 2 3 4 '--- 4 '-- 4 \ 4
|
||||
|
||||
```
|
||||
````
|
||||
|
||||
Will be rendered as:
|
||||
|
||||
```goat
|
||||
|
||||
. . . .--- 1 .-- 1 / 1
|
||||
/ \ | | .---+ .-+ +
|
||||
/ \ .---+---. .--+--. | '--- 2 | '-- 2 / \ 2
|
||||
+ + | | | | ---+ ---+ +
|
||||
/ \ / \ .-+-. .-+-. .+. .+. | .--- 3 | .-- 3 \ / 3
|
||||
/ \ / \ | | | | | | | | '---+ '-+ +
|
||||
1 2 3 4 1 2 3 4 1 2 3 4 '--- 4 '-- 4 \ 4
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Mermaid Diagrams
|
||||
|
||||
Hugo currently does not provide default templates for Mermaid diagrams. But you can easily add your own. One way to do it would be to create ` layouts/_default/_markup/render-codeblock-mermaid.html`:
|
||||
|
||||
|
||||
```go-html-template
|
||||
<div class="mermaid">
|
||||
{{- .Inner | safeHTML }}
|
||||
</div>
|
||||
{{ .Page.Store.Set "hasMermaid" true }}
|
||||
```
|
||||
|
||||
And then include this snippet at the bottom of the content template (below `.Content`):
|
||||
|
||||
```go-html-template
|
||||
{{ if .Page.Store.Get "hasMermaid" }}
|
||||
<script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
|
||||
<script>
|
||||
mermaid.initialize({ startOnLoad: true });
|
||||
</script>
|
||||
{{ end }}
|
||||
```
|
||||
|
||||
With that you can use the `mermaid` language in Markdown code blocks:
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Alice
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user