mirror of
https://github.com/gohugoio/hugo.git
synced 2026-09-02 03:32:38 +00:00
Compare commits
181 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 24afe2b822 | |||
| 9fd7d3957e | |||
| c45025cb90 | |||
| a5ebdf7d17 | |||
| 9bdedb251c | |||
| dce210ab56 | |||
| 0b96aba022 | |||
| fa520a2d98 | |||
| 82029c1ec9 | |||
| 4b670bc8cc | |||
| 7489a86459 | |||
| da54787cfa | |||
| c7975b48b6 | |||
| b2dcd53e3c | |||
| 36983e6189 | |||
| d73e37387c | |||
| aa3e183056 | |||
| 1b7acfe763 | |||
| 19e12caf8c | |||
| 20f2211fce | |||
| a21a9373e0 | |||
| 775c7c2474 | |||
| eada236f87 | |||
| e5329f13c0 | |||
| 5b145ddc4c | |||
| 3c568ad013 | |||
| 54bdcaacae | |||
| 1622510a5c | |||
| 56d0b65887 | |||
| 75c3787fc2 | |||
| 9babb1f0c4 | |||
| 8a5124d6b3 | |||
| 898a0a96af | |||
| 3b721110d5 | |||
| 40ba7e6d63 | |||
| 4f43c9022a | |||
| c327e75d05 | |||
| 8bd8d4fe9a | |||
| ad7c38cd66 | |||
| b78576fd38 | |||
| 18888e09bb | |||
| 1e5eb8679e | |||
| 3c0036805d | |||
| 7f0ebd4a3c | |||
| 23ea43180b | |||
| 6a74cbe916 | |||
| 241db8f78a | |||
| 7624ab0281 | |||
| 8490a0aa9d | |||
| bd731d27be | |||
| 80dd6ddde2 | |||
| 2997310124 | |||
| 2bbc865f7b | |||
| 0792cfa9fa | |||
| b3f0674b80 | |||
| ef78a0d18a | |||
| 5859586453 | |||
| 2d159e9cc7 | |||
| f45cb31728 | |||
| 49ef647203 | |||
| 8f08cdd0ac | |||
| 281abb18ee | |||
| d8e685154d | |||
| 934ee21fac | |||
| c7427a50ed | |||
| 49e2931eb2 | |||
| e8831a056b | |||
| 74b6c4e5ff | |||
| 8df5d76e70 | |||
| 8ae2c9c3d6 | |||
| ce9aceb749 | |||
| fd32849bfe | |||
| 417f9ddf55 | |||
| 0df7bd62df | |||
| f441f67512 | |||
| 7ed22e9fb6 | |||
| fb974ae87f | |||
| 745ddcbbab | |||
| 3b3f5a2596 | |||
| d10ed683c5 | |||
| 19e387d181 | |||
| cafb1d53c0 | |||
| 4f466db666 | |||
| 17af79a03e | |||
| 2fefc01606 | |||
| 0c251be66b | |||
| 836c24261f | |||
| c6d650c8c8 | |||
| 8585b388d2 | |||
| d61bee5e09 | |||
| 21ca2e9ce4 | |||
| 3efa1d8121 | |||
| 65ec8fe827 | |||
| d3e8ab2e39 | |||
| da81455656 | |||
| 0c0bb37285 | |||
| ddd75f2121 | |||
| 4ed6ebef4c | |||
| 94cfdf6bef | |||
| 4513801778 | |||
| 56354a63bb | |||
| b9b73a2f63 | |||
| aead8108b8 | |||
| 1cf235412f | |||
| df6e9efd8f | |||
| ea05c0e845 | |||
| 273047b5ba | |||
| 83e501849e | |||
| 12230b6897 | |||
| afdb180e23 | |||
| 196a9df585 | |||
| 9b6e61464b | |||
| d62ede8e9e | |||
| 81b7e48a55 | |||
| 16e7c11203 | |||
| 8f071fc159 | |||
| 469351d5b6 | |||
| 26f1458a2d | |||
| 5ee1f0876f | |||
| a82d2700fc | |||
| ae816452b1 | |||
| a1518704a7 | |||
| 3a21a1708d | |||
| 451746ddd7 | |||
| ff6253bc7c | |||
| aa4ccb8a1e | |||
| 5509954c7e | |||
| 6b59b64f02 | |||
| 6608f15570 | |||
| b361d9a462 | |||
| 592a7d104d | |||
| 93216fda72 | |||
| 8a4005cf2b | |||
| 740b72558b | |||
| 1fb17be9a0 | |||
| 51d89dab18 | |||
| c8bfe47c6a | |||
| 50cc7fe545 | |||
| 1773d71d5b | |||
| 8a58ebb311 | |||
| 0453683816 | |||
| 55c29d4de3 | |||
| ccb1bf1abb | |||
| a67d95fe1a | |||
| ad6504e6b5 | |||
| 158e7ec204 | |||
| eef934ae7e | |||
| 00954c5d1f | |||
| 1b785a7a6d | |||
| d20ca37005 | |||
| 3e316155c5 | |||
| e625088ef5 | |||
| 67f3aa72cf | |||
| 2e711a28c7 | |||
| 0947cf9583 | |||
| 3c24ae030f | |||
| 03d6960a15 | |||
| 92c7f7ab85 | |||
| a03c631c42 | |||
| 167c01530b | |||
| 4c804319f6 | |||
| 186a5ebfca | |||
| 9b445b9da2 | |||
| 3af783966d | |||
| 31f322a610 | |||
| 38c60f2be4 | |||
| 3cc217a650 | |||
| 5f8c2818f1 | |||
| c5f2f5837f | |||
| 0efb00c2a8 | |||
| 40a092b068 | |||
| d534ce9424 | |||
| a6b6b135a4 | |||
| 960667561f | |||
| 6c05563082 | |||
| f5250ec09d | |||
| 86a5b59f64 | |||
| bb80fff69a | |||
| 347cfb0c17 | |||
| b60ae35b97 | |||
| 003ba5b10f |
@@ -1,6 +1,6 @@
|
||||
defaults: &defaults
|
||||
docker:
|
||||
- image: bepsays/ci-goreleaser:1.13-4
|
||||
- image: bepsays/ci-goreleaser:1.13.7-1
|
||||
environment:
|
||||
CGO_ENABLED: "0"
|
||||
|
||||
@@ -17,6 +17,7 @@ jobs:
|
||||
cd hugo
|
||||
go mod download
|
||||
sleep 5
|
||||
go mod verify
|
||||
go test -p 1 ./...
|
||||
- persist_to_workspace:
|
||||
root: .
|
||||
|
||||
+2
-1
@@ -22,4 +22,5 @@ dist
|
||||
|
||||
resources/sunset.jpg
|
||||
|
||||
vendor
|
||||
vendor
|
||||
|
||||
|
||||
+4
-3
@@ -13,8 +13,8 @@ git:
|
||||
depth: false
|
||||
|
||||
go:
|
||||
- "1.12.13"
|
||||
- "1.13.4"
|
||||
- "1.12.16"
|
||||
- "1.13.7"
|
||||
- master
|
||||
|
||||
arch:
|
||||
@@ -64,7 +64,8 @@ install:
|
||||
- go get github.com/magefile/mage
|
||||
|
||||
script:
|
||||
- go mod download || true
|
||||
- go mod download
|
||||
- go mod verify
|
||||
- mage -v test
|
||||
- if [ "$TRAVIS_ARCH" = "amd64" ]; then
|
||||
mage -v check;
|
||||
|
||||
+7
-3
@@ -29,12 +29,16 @@ Please don't use the GitHub issue tracker to ask questions.
|
||||
## Reporting Issues
|
||||
|
||||
If you believe you have found a defect in Hugo or its documentation, use
|
||||
the GitHub [issue tracker](https://github.com/gohugoio/hugo/issues) to report
|
||||
the GitHub issue tracker to report
|
||||
the problem to the Hugo maintainers. If you're not sure if it's a bug or not,
|
||||
start by asking in the [discussion forum](https://discourse.gohugo.io).
|
||||
When reporting the issue, please provide the version of Hugo in use (`hugo
|
||||
version`) and your operating system.
|
||||
|
||||
- [Hugo Issues · gohugoio/hugo](https://github.com/gohugoio/hugo/issues)
|
||||
- [Hugo Documentation Issues · gohugoio/hugoDocs](https://github.com/gohugoio/hugoDocs/issues)
|
||||
- [Hugo Website Theme Issues · gohugoio/hugoThemesSite](https://github.com/gohugoio/hugoThemesSite/issues)
|
||||
|
||||
## Code Contribution
|
||||
|
||||
Hugo has become a fully featured static site generator, so any new functionality must:
|
||||
@@ -48,11 +52,11 @@ If it is of some complexity, the contributor is expected to maintain and support
|
||||
|
||||
It is recommended to open up a discussion on the [Hugo Forum](https://discourse.gohugo.io/) to get feedback on your idea before you begin. If you are submitting a complex feature, create a small design proposal on the [Hugo issue tracker](https://github.com/gohugoio/hugo/issues) before you start.
|
||||
|
||||
Note that we do not accept new features that require [CGO](https://github.com/golang/go/wiki/cgo).
|
||||
We have one exception to this rule which is LibSASS.
|
||||
|
||||
**Bug fixes are, of course, always welcome.**
|
||||
|
||||
|
||||
|
||||
## Submitting Patches
|
||||
|
||||
The Hugo project welcomes all contributors and contributions regardless of skill or experience level. If you are interested in helping with the project, we will help you with your contribution.
|
||||
|
||||
+2
-2
@@ -26,14 +26,14 @@ RUN mage hugo && mage install
|
||||
|
||||
# ---
|
||||
|
||||
FROM alpine:3.10
|
||||
FROM alpine:3.11
|
||||
|
||||
COPY --from=build /go/bin/hugo /usr/bin/hugo
|
||||
|
||||
# libc6-compat & libstdc++ are required for extended SASS libraries
|
||||
# ca-certificates are required to fetch outside resources (like Twitter oEmbeds)
|
||||
RUN apk update && \
|
||||
apk add --no-cache ca-certificates libc6-compat libstdc++
|
||||
apk add --no-cache ca-certificates libc6-compat libstdc++ git
|
||||
|
||||
VOLUME /site
|
||||
WORKDIR /site
|
||||
|
||||
@@ -54,7 +54,7 @@ Use the [installation instructions in the Hugo documentation](https://gohugo.io/
|
||||
#### Prerequisite Tools
|
||||
|
||||
* [Git](https://git-scm.com/)
|
||||
* [Go (at least Go 1.11)](https://golang.org/dl/)
|
||||
* [Go (we test it with the last 2 major versions)](https://golang.org/dl/)
|
||||
|
||||
#### Fetch from GitHub
|
||||
|
||||
|
||||
Vendored
+3
-13
@@ -17,6 +17,8 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/gohugoio/hugo/hugofs"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/afero"
|
||||
)
|
||||
@@ -121,18 +123,6 @@ func (c *Cache) pruneRootDir(force bool) (int, error) {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
counter := 0
|
||||
// Module cache has 0555 directories; make them writable in order to remove content.
|
||||
afero.Walk(c.Fs, c.pruneAllRootDir, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
if info.IsDir() {
|
||||
counter++
|
||||
c.Fs.Chmod(path, 0777)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return 1, c.Fs.RemoveAll(c.pruneAllRootDir)
|
||||
return hugofs.MakeReadableAndRemoveAllModulePkgDir(c.Fs, c.pruneAllRootDir)
|
||||
|
||||
}
|
||||
|
||||
+13
-20
@@ -20,8 +20,6 @@ import (
|
||||
|
||||
"golang.org/x/sync/semaphore"
|
||||
|
||||
"github.com/gohugoio/hugo/modules"
|
||||
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/gohugoio/hugo/common/herrors"
|
||||
@@ -74,7 +72,7 @@ type commandeer struct {
|
||||
|
||||
visitedURLs *types.EvictingStringQueue
|
||||
|
||||
doWithCommandeer func(c *commandeer) error
|
||||
cfgInit func(c *commandeer) error
|
||||
|
||||
// We watch these for changes.
|
||||
configFiles []string
|
||||
@@ -88,6 +86,7 @@ type commandeer struct {
|
||||
doLiveReload bool
|
||||
fastRenderMode bool
|
||||
showErrorInBrowser bool
|
||||
wasError bool
|
||||
|
||||
configured bool
|
||||
paused bool
|
||||
@@ -132,7 +131,7 @@ func (c *commandeer) getErrorWithContext() interface{} {
|
||||
|
||||
if c.h.verbose {
|
||||
var b bytes.Buffer
|
||||
herrors.FprintStackTrace(&b, c.buildErr)
|
||||
herrors.FprintStackTraceFromErr(&b, c.buildErr)
|
||||
m["StackTrace"] = b.String()
|
||||
}
|
||||
|
||||
@@ -153,7 +152,7 @@ func (c *commandeer) initFs(fs *hugofs.Fs) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func newCommandeer(mustHaveConfigFile, running bool, h *hugoBuilderCommon, f flagsToConfigHandler, doWithCommandeer func(c *commandeer) error, subCmdVs ...*cobra.Command) (*commandeer, error) {
|
||||
func newCommandeer(mustHaveConfigFile, running bool, h *hugoBuilderCommon, f flagsToConfigHandler, cfgInit func(c *commandeer) error, subCmdVs ...*cobra.Command) (*commandeer, error) {
|
||||
|
||||
var rebuildDebouncer func(f func())
|
||||
if running {
|
||||
@@ -172,7 +171,7 @@ func newCommandeer(mustHaveConfigFile, running bool, h *hugoBuilderCommon, f fla
|
||||
h: h,
|
||||
ftch: f,
|
||||
commandeerHugoState: newCommandeerHugoState(),
|
||||
doWithCommandeer: doWithCommandeer,
|
||||
cfgInit: cfgInit,
|
||||
visitedURLs: types.NewEvictingStringQueue(10),
|
||||
debounce: rebuildDebouncer,
|
||||
fullRebuildSem: semaphore.NewWeighted(1),
|
||||
@@ -285,12 +284,12 @@ func (c *commandeer) loadConfig(mustHaveConfigFile, running bool) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
doWithCommandeer := func(cfg config.Provider) error {
|
||||
cfgSetAndInit := func(cfg config.Provider) error {
|
||||
c.Cfg = cfg
|
||||
if c.doWithCommandeer == nil {
|
||||
if c.cfgInit == nil {
|
||||
return nil
|
||||
}
|
||||
err := c.doWithCommandeer(c)
|
||||
err := c.cfgInit(c)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -308,17 +307,11 @@ func (c *commandeer) loadConfig(mustHaveConfigFile, running bool) error {
|
||||
AbsConfigDir: c.h.getConfigDir(dir),
|
||||
Environ: os.Environ(),
|
||||
Environment: environment},
|
||||
doWithCommandeer,
|
||||
cfgSetAndInit,
|
||||
doWithConfig)
|
||||
|
||||
if err != nil {
|
||||
if mustHaveConfigFile {
|
||||
return err
|
||||
}
|
||||
if err != hugolib.ErrNoConfigFile && !modules.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
|
||||
if err != nil && mustHaveConfigFile {
|
||||
return err
|
||||
} else if mustHaveConfigFile && len(configFiles) == 0 {
|
||||
return hugolib.ErrNoConfigFile
|
||||
}
|
||||
@@ -337,8 +330,8 @@ func (c *commandeer) loadConfig(mustHaveConfigFile, running bool) error {
|
||||
|
||||
// This is potentially double work, but we need to do this one more time now
|
||||
// that all the languages have been configured.
|
||||
if c.doWithCommandeer != nil {
|
||||
if err := c.doWithCommandeer(c); err != nil {
|
||||
if c.cfgInit != nil {
|
||||
if err := c.cfgInit(c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
+10
-4
@@ -47,12 +47,12 @@ func (b *commandsBuilder) addAll() *commandsBuilder {
|
||||
b.newServerCmd(),
|
||||
newVersionCmd(),
|
||||
newEnvCmd(),
|
||||
newConfigCmd(),
|
||||
b.newConfigCmd(),
|
||||
newCheckCmd(),
|
||||
newDeployCmd(),
|
||||
newConvertCmd(),
|
||||
b.newDeployCmd(),
|
||||
b.newConvertCmd(),
|
||||
b.newNewCmd(),
|
||||
newListCmd(),
|
||||
b.newListCmd(),
|
||||
newImportCmd(),
|
||||
newGenCmd(),
|
||||
createReleaser(),
|
||||
@@ -111,6 +111,12 @@ func (b *commandsBuilder) newBuilderCmd(cmd *cobra.Command) *baseBuilderCmd {
|
||||
return bcmd
|
||||
}
|
||||
|
||||
func (b *commandsBuilder) newBuilderBasicCmd(cmd *cobra.Command) *baseBuilderCmd {
|
||||
bcmd := &baseBuilderCmd{commandsBuilder: b, baseCmd: &baseCmd{cmd: cmd}}
|
||||
bcmd.hugoBuilderCommon.handleCommonBuilderFlags(cmd)
|
||||
return bcmd
|
||||
}
|
||||
|
||||
func (c *baseCmd) flagsToConfig(cfg config.Provider) {
|
||||
initializeFlags(c.cmd, cfg)
|
||||
}
|
||||
|
||||
+136
-21
@@ -20,6 +20,12 @@ import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/gohugoio/hugo/htesting"
|
||||
|
||||
"github.com/spf13/afero"
|
||||
|
||||
"github.com/gohugoio/hugo/hugofs"
|
||||
|
||||
"github.com/gohugoio/hugo/common/types"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
@@ -32,18 +38,117 @@ func TestExecute(t *testing.T) {
|
||||
|
||||
c := qt.New(t)
|
||||
|
||||
dir, err := createSimpleTestSite(t, testSiteConfig{})
|
||||
createSite := func(c *qt.C) (string, func()) {
|
||||
dir, clean, err := createSimpleTestSite(t, testSiteConfig{})
|
||||
c.Assert(err, qt.IsNil)
|
||||
return dir, clean
|
||||
}
|
||||
|
||||
c.Run("hugo", func(c *qt.C) {
|
||||
dir, clean := createSite(c)
|
||||
defer clean()
|
||||
resp := Execute([]string{"-s=" + dir})
|
||||
c.Assert(resp.Err, qt.IsNil)
|
||||
result := resp.Result
|
||||
c.Assert(len(result.Sites) == 1, qt.Equals, true)
|
||||
c.Assert(len(result.Sites[0].RegularPages()) == 1, qt.Equals, true)
|
||||
c.Assert(result.Sites[0].Info.Params()["myparam"], qt.Equals, "paramproduction")
|
||||
})
|
||||
|
||||
c.Run("hugo, set environment", func(c *qt.C) {
|
||||
dir, clean := createSite(c)
|
||||
defer clean()
|
||||
resp := Execute([]string{"-s=" + dir, "-e=staging"})
|
||||
c.Assert(resp.Err, qt.IsNil)
|
||||
result := resp.Result
|
||||
c.Assert(result.Sites[0].Info.Params()["myparam"], qt.Equals, "paramstaging")
|
||||
})
|
||||
|
||||
c.Run("convert toJSON", func(c *qt.C) {
|
||||
dir, clean := createSite(c)
|
||||
output := filepath.Join(dir, "myjson")
|
||||
defer clean()
|
||||
resp := Execute([]string{"convert", "toJSON", "-s=" + dir, "-e=staging", "-o=" + output})
|
||||
c.Assert(resp.Err, qt.IsNil)
|
||||
converted := readFileFrom(c, filepath.Join(output, "content", "p1.md"))
|
||||
c.Assert(converted, qt.Equals, "{\n \"title\": \"P1\",\n \"weight\": 1\n}\n\nContent\n\n", qt.Commentf(converted))
|
||||
})
|
||||
|
||||
c.Run("config, set environment", func(c *qt.C) {
|
||||
dir, clean := createSite(c)
|
||||
defer clean()
|
||||
out, err := captureStdout(func() error {
|
||||
resp := Execute([]string{"config", "-s=" + dir, "-e=staging"})
|
||||
return resp.Err
|
||||
})
|
||||
c.Assert(err, qt.IsNil)
|
||||
c.Assert(out, qt.Contains, "params = map[myparam:paramstaging]", qt.Commentf(out))
|
||||
})
|
||||
|
||||
c.Run("deploy, environment set", func(c *qt.C) {
|
||||
dir, clean := createSite(c)
|
||||
defer clean()
|
||||
resp := Execute([]string{"deploy", "-s=" + dir, "-e=staging", "--target=mydeployment", "--dryRun"})
|
||||
c.Assert(resp.Err, qt.Not(qt.IsNil))
|
||||
c.Assert(resp.Err.Error(), qt.Contains, `no provider registered for "hugocloud"`)
|
||||
})
|
||||
|
||||
c.Run("list", func(c *qt.C) {
|
||||
dir, clean := createSite(c)
|
||||
defer clean()
|
||||
out, err := captureStdout(func() error {
|
||||
resp := Execute([]string{"list", "all", "-s=" + dir, "-e=staging"})
|
||||
return resp.Err
|
||||
})
|
||||
c.Assert(err, qt.IsNil)
|
||||
c.Assert(out, qt.Contains, "p1.md")
|
||||
})
|
||||
|
||||
c.Run("new theme", func(c *qt.C) {
|
||||
dir, clean := createSite(c)
|
||||
defer clean()
|
||||
themesDir := filepath.Join(dir, "mythemes")
|
||||
resp := Execute([]string{"new", "theme", "mytheme", "-s=" + dir, "-e=staging", "--themesDir=" + themesDir})
|
||||
c.Assert(resp.Err, qt.IsNil)
|
||||
themeTOML := readFileFrom(c, filepath.Join(themesDir, "mytheme", "theme.toml"))
|
||||
c.Assert(themeTOML, qt.Contains, "name = \"Mytheme\"")
|
||||
})
|
||||
|
||||
c.Run("new site", func(c *qt.C) {
|
||||
dir, clean := createSite(c)
|
||||
defer clean()
|
||||
siteDir := filepath.Join(dir, "mysite")
|
||||
resp := Execute([]string{"new", "site", siteDir, "-e=staging"})
|
||||
c.Assert(resp.Err, qt.IsNil)
|
||||
config := readFileFrom(c, filepath.Join(siteDir, "config.toml"))
|
||||
c.Assert(config, qt.Contains, "baseURL = \"http://example.org/\"")
|
||||
checkNewSiteInited(c, siteDir)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func checkNewSiteInited(c *qt.C, basepath string) {
|
||||
paths := []string{
|
||||
filepath.Join(basepath, "layouts"),
|
||||
filepath.Join(basepath, "content"),
|
||||
filepath.Join(basepath, "archetypes"),
|
||||
filepath.Join(basepath, "static"),
|
||||
filepath.Join(basepath, "data"),
|
||||
filepath.Join(basepath, "config.toml"),
|
||||
}
|
||||
|
||||
for _, path := range paths {
|
||||
_, err := os.Stat(path)
|
||||
c.Assert(err, qt.IsNil)
|
||||
}
|
||||
}
|
||||
|
||||
func readFileFrom(c *qt.C, filename string) string {
|
||||
c.Helper()
|
||||
filename = filepath.Clean(filename)
|
||||
b, err := afero.ReadFile(hugofs.Os, filename)
|
||||
c.Assert(err, qt.IsNil)
|
||||
|
||||
defer func() {
|
||||
os.RemoveAll(dir)
|
||||
}()
|
||||
|
||||
resp := Execute([]string{"-s=" + dir})
|
||||
c.Assert(resp.Err, qt.IsNil)
|
||||
result := resp.Result
|
||||
c.Assert(len(result.Sites) == 1, qt.Equals, true)
|
||||
c.Assert(len(result.Sites[0].RegularPages()) == 1, qt.Equals, true)
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func TestCommandsPersistentFlags(t *testing.T) {
|
||||
@@ -146,16 +251,14 @@ func TestCommandsExecute(t *testing.T) {
|
||||
|
||||
c := qt.New(t)
|
||||
|
||||
dir, err := createSimpleTestSite(t, testSiteConfig{})
|
||||
dir, clean, err := createSimpleTestSite(t, testSiteConfig{})
|
||||
c.Assert(err, qt.IsNil)
|
||||
|
||||
dirOut, err := ioutil.TempDir("", "hugo-cli-out")
|
||||
dirOut, clean2, err := htesting.CreateTempDir(hugofs.Os, "hugo-cli-out")
|
||||
c.Assert(err, qt.IsNil)
|
||||
|
||||
defer func() {
|
||||
os.RemoveAll(dir)
|
||||
os.RemoveAll(dirOut)
|
||||
}()
|
||||
defer clean()
|
||||
defer clean2()
|
||||
|
||||
sourceFlag := fmt.Sprintf("-s=%s", dir)
|
||||
|
||||
@@ -222,10 +325,10 @@ type testSiteConfig struct {
|
||||
contentDir string
|
||||
}
|
||||
|
||||
func createSimpleTestSite(t *testing.T, cfg testSiteConfig) (string, error) {
|
||||
d, e := ioutil.TempDir("", "hugo-cli")
|
||||
func createSimpleTestSite(t *testing.T, cfg testSiteConfig) (string, func(), error) {
|
||||
d, clean, e := htesting.CreateTempDir(hugofs.Os, "hugo-cli")
|
||||
if e != nil {
|
||||
return "", e
|
||||
return "", nil, e
|
||||
}
|
||||
|
||||
cfgStr := `
|
||||
@@ -233,6 +336,7 @@ func createSimpleTestSite(t *testing.T, cfg testSiteConfig) (string, error) {
|
||||
baseURL = "https://example.org"
|
||||
title = "Hugo Commands"
|
||||
|
||||
|
||||
`
|
||||
|
||||
contentDir := "content"
|
||||
@@ -244,8 +348,19 @@ title = "Hugo Commands"
|
||||
contentDir = cfg.contentDir
|
||||
}
|
||||
|
||||
os.MkdirAll(filepath.Join(d, "public"), 0777)
|
||||
|
||||
// Just the basic. These are for CLI tests, not site testing.
|
||||
writeFile(t, filepath.Join(d, "config.toml"), cfgStr)
|
||||
writeFile(t, filepath.Join(d, "config", "staging", "params.toml"), `myparam="paramstaging"`)
|
||||
writeFile(t, filepath.Join(d, "config", "staging", "deployment.toml"), `
|
||||
[[targets]]
|
||||
name = "mydeployment"
|
||||
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, contentDir, "p1.md"), `
|
||||
---
|
||||
@@ -270,7 +385,7 @@ Environment: {{ hugo.Environment }}
|
||||
|
||||
`)
|
||||
|
||||
return d, nil
|
||||
return d, clean, nil
|
||||
|
||||
}
|
||||
|
||||
|
||||
+10
-11
@@ -15,6 +15,7 @@ package commands
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"regexp"
|
||||
@@ -27,27 +28,23 @@ import (
|
||||
"github.com/gohugoio/hugo/modules"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
jww "github.com/spf13/jwalterweatherman"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
var _ cmder = (*configCmd)(nil)
|
||||
|
||||
type configCmd struct {
|
||||
hugoBuilderCommon
|
||||
*baseCmd
|
||||
*baseBuilderCmd
|
||||
}
|
||||
|
||||
func newConfigCmd() *configCmd {
|
||||
func (b *commandsBuilder) newConfigCmd() *configCmd {
|
||||
cc := &configCmd{}
|
||||
cc.baseCmd = newBaseCmd(&cobra.Command{
|
||||
cmd := &cobra.Command{
|
||||
Use: "config",
|
||||
Short: "Print the site configuration",
|
||||
Long: `Print the site configuration, both default and custom settings.`,
|
||||
RunE: cc.printConfig,
|
||||
})
|
||||
|
||||
cc.cmd.PersistentFlags().StringVarP(&cc.source, "source", "s", "", "filesystem path to read files relative from")
|
||||
}
|
||||
|
||||
printMountsCmd := &cobra.Command{
|
||||
Use: "mounts",
|
||||
@@ -55,7 +52,9 @@ func newConfigCmd() *configCmd {
|
||||
RunE: cc.printMounts,
|
||||
}
|
||||
|
||||
cc.cmd.AddCommand(printMountsCmd)
|
||||
cmd.AddCommand(printMountsCmd)
|
||||
|
||||
cc.baseBuilderCmd = b.newBuilderBasicCmd(cmd)
|
||||
|
||||
return cc
|
||||
}
|
||||
@@ -105,9 +104,9 @@ func (c *configCmd) printConfig(cmd *cobra.Command, args []string) error {
|
||||
for _, k := range keys {
|
||||
kv := reflect.ValueOf(allSettings[k])
|
||||
if kv.Kind() == reflect.String {
|
||||
jww.FEEDBACK.Printf("%s%s\"%+v\"\n", k, separator, allSettings[k])
|
||||
fmt.Printf("%s%s\"%+v\"\n", k, separator, allSettings[k])
|
||||
} else {
|
||||
jww.FEEDBACK.Printf("%s%s%+v\n", k, separator, allSettings[k])
|
||||
fmt.Printf("%s%s%+v\n", k, separator, allSettings[k])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+17
-55
@@ -16,10 +16,11 @@ package commands
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gohugoio/hugo/parser/pageparser"
|
||||
|
||||
"github.com/gohugoio/hugo/resources/page"
|
||||
|
||||
"github.com/gohugoio/hugo/hugofs"
|
||||
@@ -28,7 +29,6 @@ import (
|
||||
|
||||
"github.com/gohugoio/hugo/parser"
|
||||
"github.com/gohugoio/hugo/parser/metadecoders"
|
||||
"github.com/gohugoio/hugo/parser/pageparser"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
@@ -44,27 +44,25 @@ var (
|
||||
)
|
||||
|
||||
type convertCmd struct {
|
||||
hugoBuilderCommon
|
||||
|
||||
outputDir string
|
||||
unsafe bool
|
||||
|
||||
*baseCmd
|
||||
*baseBuilderCmd
|
||||
}
|
||||
|
||||
func newConvertCmd() *convertCmd {
|
||||
func (b *commandsBuilder) newConvertCmd() *convertCmd {
|
||||
cc := &convertCmd{}
|
||||
|
||||
cc.baseCmd = newBaseCmd(&cobra.Command{
|
||||
cmd := &cobra.Command{
|
||||
Use: "convert",
|
||||
Short: "Convert your content to different formats",
|
||||
Long: `Convert your content (e.g. front matter) to different formats.
|
||||
|
||||
See convert's subcommands toJSON, toTOML and toYAML for more information.`,
|
||||
RunE: nil,
|
||||
})
|
||||
}
|
||||
|
||||
cc.cmd.AddCommand(
|
||||
cmd.AddCommand(
|
||||
&cobra.Command{
|
||||
Use: "toJSON",
|
||||
Short: "Convert front matter to JSON",
|
||||
@@ -94,10 +92,10 @@ to use YAML for the front matter.`,
|
||||
},
|
||||
)
|
||||
|
||||
cc.cmd.PersistentFlags().StringVarP(&cc.outputDir, "output", "o", "", "filesystem path to write files to")
|
||||
cc.cmd.PersistentFlags().StringVarP(&cc.source, "source", "s", "", "filesystem path to read files relative from")
|
||||
cc.cmd.PersistentFlags().BoolVar(&cc.unsafe, "unsafe", false, "enable less safe operations, please backup first")
|
||||
cc.cmd.PersistentFlags().SetAnnotation("source", cobra.BashCompSubdirsInDir, []string{})
|
||||
cmd.PersistentFlags().StringVarP(&cc.outputDir, "output", "o", "", "filesystem path to write files to")
|
||||
cmd.PersistentFlags().BoolVar(&cc.unsafe, "unsafe", false, "enable less safe operations, please backup first")
|
||||
|
||||
cc.baseBuilderCmd = b.newBuilderBasicCmd(cmd)
|
||||
|
||||
return cc
|
||||
}
|
||||
@@ -159,7 +157,7 @@ func (cc *convertCmd) convertAndSavePage(p page.Page, site *hugolib.Site, target
|
||||
return nil
|
||||
}
|
||||
|
||||
pf, err := parseContentFile(file)
|
||||
pf, err := pageparser.ParseFrontMatterAndContent(file)
|
||||
if err != nil {
|
||||
site.Log.ERROR.Println(errMsg)
|
||||
file.Close()
|
||||
@@ -169,23 +167,23 @@ func (cc *convertCmd) convertAndSavePage(p page.Page, site *hugolib.Site, target
|
||||
file.Close()
|
||||
|
||||
// better handling of dates in formats that don't have support for them
|
||||
if pf.frontMatterFormat == metadecoders.JSON || pf.frontMatterFormat == metadecoders.YAML || pf.frontMatterFormat == metadecoders.TOML {
|
||||
for k, v := range pf.frontMatter {
|
||||
if pf.FrontMatterFormat == metadecoders.JSON || pf.FrontMatterFormat == metadecoders.YAML || pf.FrontMatterFormat == metadecoders.TOML {
|
||||
for k, v := range pf.FrontMatter {
|
||||
switch vv := v.(type) {
|
||||
case time.Time:
|
||||
pf.frontMatter[k] = vv.Format(time.RFC3339)
|
||||
pf.FrontMatter[k] = vv.Format(time.RFC3339)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var newContent bytes.Buffer
|
||||
err = parser.InterfaceToFrontMatter(pf.frontMatter, targetFormat, &newContent)
|
||||
err = parser.InterfaceToFrontMatter(pf.FrontMatter, targetFormat, &newContent)
|
||||
if err != nil {
|
||||
site.Log.ERROR.Println(errMsg)
|
||||
return err
|
||||
}
|
||||
|
||||
newContent.Write(pf.content)
|
||||
newContent.Write(pf.Content)
|
||||
|
||||
newFilename := p.File().Filename()
|
||||
|
||||
@@ -212,39 +210,3 @@ type parsedFile struct {
|
||||
// Everything after Front Matter
|
||||
content []byte
|
||||
}
|
||||
|
||||
func parseContentFile(r io.Reader) (parsedFile, error) {
|
||||
var pf parsedFile
|
||||
|
||||
psr, err := pageparser.Parse(r, pageparser.Config{})
|
||||
if err != nil {
|
||||
return pf, err
|
||||
}
|
||||
|
||||
iter := psr.Iterator()
|
||||
|
||||
walkFn := func(item pageparser.Item) bool {
|
||||
if pf.frontMatterSource != nil {
|
||||
// The rest is content.
|
||||
pf.content = psr.Input()[item.Pos:]
|
||||
// Done
|
||||
return false
|
||||
} else if item.IsFrontMatter() {
|
||||
pf.frontMatterFormat = metadecoders.FormatFromFrontMatterType(item.Type)
|
||||
pf.frontMatterSource = item.Val
|
||||
}
|
||||
return true
|
||||
|
||||
}
|
||||
|
||||
iter.PeekWalk(walkFn)
|
||||
|
||||
metadata, err := metadecoders.Default.UnmarshalToMap(pf.frontMatterSource, pf.frontMatterFormat)
|
||||
if err != nil {
|
||||
return pf, err
|
||||
}
|
||||
pf.frontMatter = metadata
|
||||
|
||||
return pf, nil
|
||||
|
||||
}
|
||||
|
||||
+12
-11
@@ -24,8 +24,7 @@ var _ cmder = (*deployCmd)(nil)
|
||||
|
||||
// deployCmd supports deploying sites to Cloud providers.
|
||||
type deployCmd struct {
|
||||
hugoBuilderCommon
|
||||
*baseCmd
|
||||
*baseBuilderCmd
|
||||
}
|
||||
|
||||
// TODO: In addition to the "deploy" command, consider adding a "--deploy"
|
||||
@@ -38,10 +37,10 @@ type deployCmd struct {
|
||||
// run "hugo && hugo deploy" again and again and upload new stuff every time. Is
|
||||
// this intended?
|
||||
|
||||
func newDeployCmd() *deployCmd {
|
||||
func (b *commandsBuilder) newDeployCmd() *deployCmd {
|
||||
cc := &deployCmd{}
|
||||
|
||||
cc.baseCmd = newBaseCmd(&cobra.Command{
|
||||
cmd := &cobra.Command{
|
||||
Use: "deploy",
|
||||
Short: "Deploy your site to a Cloud provider.",
|
||||
Long: `Deploy your site to a Cloud provider.
|
||||
@@ -64,14 +63,16 @@ documentation.
|
||||
}
|
||||
return deployer.Deploy(context.Background())
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
cc.cmd.Flags().String("target", "", "target deployment from deployments section in config file; defaults to the first one")
|
||||
cc.cmd.Flags().Bool("confirm", false, "ask for confirmation before making changes to the target")
|
||||
cc.cmd.Flags().Bool("dryRun", false, "dry run")
|
||||
cc.cmd.Flags().Bool("force", false, "force upload of all files")
|
||||
cc.cmd.Flags().Bool("invalidateCDN", true, "invalidate the CDN cache listed in the deployment target")
|
||||
cc.cmd.Flags().Int("maxDeletes", 256, "maximum # of files to delete, or -1 to disable")
|
||||
cmd.Flags().String("target", "", "target deployment from deployments section in config file; defaults to the first one")
|
||||
cmd.Flags().Bool("confirm", false, "ask for confirmation before making changes to the target")
|
||||
cmd.Flags().Bool("dryRun", false, "dry run")
|
||||
cmd.Flags().Bool("force", false, "force upload of all files")
|
||||
cmd.Flags().Bool("invalidateCDN", true, "invalidate the CDN cache listed in the deployment target")
|
||||
cmd.Flags().Int("maxDeletes", 256, "maximum # of files to delete, or -1 to disable")
|
||||
|
||||
cc.baseBuilderCmd = b.newBuilderBasicCmd(cmd)
|
||||
|
||||
return cc
|
||||
}
|
||||
|
||||
+22
-12
@@ -118,9 +118,9 @@ func Execute(args []string) Response {
|
||||
func initializeConfig(mustHaveConfigFile, running bool,
|
||||
h *hugoBuilderCommon,
|
||||
f flagsToConfigHandler,
|
||||
doWithCommandeer func(c *commandeer) error) (*commandeer, error) {
|
||||
cfgInit func(c *commandeer) error) (*commandeer, error) {
|
||||
|
||||
c, err := newCommandeer(mustHaveConfigFile, running, h, f, doWithCommandeer)
|
||||
c, err := newCommandeer(mustHaveConfigFile, running, h, f, cfgInit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -667,7 +667,7 @@ func (c *commandeer) timeTrack(start time.Time, name string) {
|
||||
|
||||
// getDirList provides NewWatcher() with a list of directories to watch for changes.
|
||||
func (c *commandeer) getDirList() ([]string, error) {
|
||||
var dirnames []string
|
||||
var filenames []string
|
||||
|
||||
walkFn := func(path string, fi hugofs.FileMetaInfo, err error) error {
|
||||
if err != nil {
|
||||
@@ -681,25 +681,29 @@ func (c *commandeer) getDirList() ([]string, error) {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
|
||||
dirnames = append(dirnames, fi.Meta().Filename())
|
||||
filenames = append(filenames, fi.Meta().Filename())
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
watchDirs := c.hugo().PathSpec.BaseFs.WatchDirs()
|
||||
for _, watchDir := range watchDirs {
|
||||
watchFiles := c.hugo().PathSpec.BaseFs.WatchDirs()
|
||||
for _, fi := range watchFiles {
|
||||
if !fi.IsDir() {
|
||||
filenames = append(filenames, fi.Meta().Filename())
|
||||
continue
|
||||
}
|
||||
|
||||
w := hugofs.NewWalkway(hugofs.WalkwayConfig{Logger: c.logger, Info: watchDir, WalkFn: walkFn})
|
||||
w := hugofs.NewWalkway(hugofs.WalkwayConfig{Logger: c.logger, Info: fi, WalkFn: walkFn})
|
||||
if err := w.Walk(); err != nil {
|
||||
c.logger.ERROR.Println("walker: ", err)
|
||||
}
|
||||
}
|
||||
|
||||
dirnames = helpers.UniqueStringsSorted(dirnames)
|
||||
filenames = helpers.UniqueStringsSorted(filenames)
|
||||
|
||||
return dirnames, nil
|
||||
return filenames, nil
|
||||
}
|
||||
|
||||
func (c *commandeer) buildSites() (err error) {
|
||||
@@ -712,12 +716,15 @@ func (c *commandeer) handleBuildErr(err error, msg string) {
|
||||
c.logger.ERROR.Print(msg + ":\n\n")
|
||||
c.logger.ERROR.Println(helpers.FirstUpper(err.Error()))
|
||||
if !c.h.quiet && c.h.verbose {
|
||||
herrors.PrintStackTrace(err)
|
||||
herrors.PrintStackTraceFromErr(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *commandeer) rebuildSites(events []fsnotify.Event) error {
|
||||
defer c.timeTrack(time.Now(), "Total")
|
||||
defer func() {
|
||||
c.wasError = false
|
||||
}()
|
||||
|
||||
c.buildErr = nil
|
||||
visited := c.visitedURLs.PeekAllSet()
|
||||
@@ -734,16 +741,19 @@ func (c *commandeer) rebuildSites(events []fsnotify.Event) error {
|
||||
}
|
||||
|
||||
}
|
||||
return c.hugo().Build(hugolib.BuildCfg{RecentlyVisited: visited}, events...)
|
||||
return c.hugo().Build(hugolib.BuildCfg{RecentlyVisited: visited, ErrRecovery: c.wasError}, events...)
|
||||
}
|
||||
|
||||
func (c *commandeer) partialReRender(urls ...string) error {
|
||||
defer func() {
|
||||
c.wasError = false
|
||||
}()
|
||||
c.buildErr = nil
|
||||
visited := make(map[string]bool)
|
||||
for _, url := range urls {
|
||||
visited[url] = true
|
||||
}
|
||||
return c.hugo().Build(hugolib.BuildCfg{RecentlyVisited: visited, PartialReRender: true})
|
||||
return c.hugo().Build(hugolib.BuildCfg{RecentlyVisited: visited, PartialReRender: true, ErrRecovery: c.wasError})
|
||||
}
|
||||
|
||||
func (c *commandeer) fullRebuild(changeType string) {
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
qt "github.com/frankban/quicktest"
|
||||
@@ -37,12 +36,9 @@ title = "Hugo Commands"
|
||||
contentDir = "thisdoesnotexist"
|
||||
|
||||
`
|
||||
dir, err := createSimpleTestSite(t, testSiteConfig{configTOML: cfgStr, contentDir: contentDir})
|
||||
dir, clean, err := createSimpleTestSite(t, testSiteConfig{configTOML: cfgStr, contentDir: contentDir})
|
||||
c.Assert(err, qt.IsNil)
|
||||
|
||||
defer func() {
|
||||
os.RemoveAll(dir)
|
||||
}()
|
||||
defer clean()
|
||||
|
||||
cmd.SetArgs([]string{"-s=" + dir, "-c=" + contentDir})
|
||||
|
||||
|
||||
@@ -26,6 +26,8 @@ import (
|
||||
"time"
|
||||
"unicode"
|
||||
|
||||
"github.com/gohugoio/hugo/parser/pageparser"
|
||||
|
||||
"github.com/gohugoio/hugo/common/hugio"
|
||||
|
||||
"github.com/gohugoio/hugo/parser/metadecoders"
|
||||
@@ -397,19 +399,19 @@ func convertJekyllPost(path, relPath, targetDir string, draft bool) error {
|
||||
return err
|
||||
}
|
||||
|
||||
pf, err := parseContentFile(bytes.NewReader(contentBytes))
|
||||
pf, err := pageparser.ParseFrontMatterAndContent(bytes.NewReader(contentBytes))
|
||||
if err != nil {
|
||||
jww.ERROR.Println("Parse file error:", path)
|
||||
return err
|
||||
}
|
||||
|
||||
newmetadata, err := convertJekyllMetaData(pf.frontMatter, postName, postDate, draft)
|
||||
newmetadata, err := convertJekyllMetaData(pf.FrontMatter, postName, postDate, draft)
|
||||
if err != nil {
|
||||
jww.ERROR.Println("Convert metadata error:", path)
|
||||
return err
|
||||
}
|
||||
|
||||
content, err := convertJekyllContent(newmetadata, string(pf.content))
|
||||
content, err := convertJekyllContent(newmetadata, string(pf.Content))
|
||||
if err != nil {
|
||||
jww.ERROR.Println("Converting Jekyll error:", path)
|
||||
return err
|
||||
|
||||
+6
-8
@@ -29,8 +29,7 @@ import (
|
||||
var _ cmder = (*listCmd)(nil)
|
||||
|
||||
type listCmd struct {
|
||||
hugoBuilderCommon
|
||||
*baseCmd
|
||||
*baseBuilderCmd
|
||||
}
|
||||
|
||||
func (lc *listCmd) buildSites(config map[string]interface{}) (*hugolib.HugoSites, error) {
|
||||
@@ -59,19 +58,19 @@ func (lc *listCmd) buildSites(config map[string]interface{}) (*hugolib.HugoSites
|
||||
return sites, nil
|
||||
}
|
||||
|
||||
func newListCmd() *listCmd {
|
||||
func (b *commandsBuilder) newListCmd() *listCmd {
|
||||
cc := &listCmd{}
|
||||
|
||||
cc.baseCmd = newBaseCmd(&cobra.Command{
|
||||
cmd := &cobra.Command{
|
||||
Use: "list",
|
||||
Short: "Listing out various types of content",
|
||||
Long: `Listing out various types of content.
|
||||
|
||||
List requires a subcommand, e.g. ` + "`hugo list drafts`.",
|
||||
RunE: nil,
|
||||
})
|
||||
}
|
||||
|
||||
cc.cmd.AddCommand(
|
||||
cmd.AddCommand(
|
||||
&cobra.Command{
|
||||
Use: "drafts",
|
||||
Short: "List all drafts",
|
||||
@@ -202,8 +201,7 @@ List requires a subcommand, e.g. ` + "`hugo list drafts`.",
|
||||
},
|
||||
)
|
||||
|
||||
cc.cmd.PersistentFlags().StringVarP(&cc.source, "source", "s", "", "filesystem path to read files relative from")
|
||||
cc.cmd.PersistentFlags().SetAnnotation("source", cobra.BashCompSubdirsInDir, []string{})
|
||||
cc.baseBuilderCmd = b.newBuilderBasicCmd(cmd)
|
||||
|
||||
return cc
|
||||
}
|
||||
|
||||
+9
-10
@@ -10,31 +10,27 @@ import (
|
||||
"testing"
|
||||
|
||||
qt "github.com/frankban/quicktest"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func captureStdout(f func() (*cobra.Command, error)) (string, error) {
|
||||
func captureStdout(f func() error) (string, error) {
|
||||
old := os.Stdout
|
||||
r, w, _ := os.Pipe()
|
||||
os.Stdout = w
|
||||
|
||||
_, err := f()
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
err := f()
|
||||
|
||||
w.Close()
|
||||
os.Stdout = old
|
||||
|
||||
var buf bytes.Buffer
|
||||
io.Copy(&buf, r)
|
||||
return buf.String(), nil
|
||||
return buf.String(), err
|
||||
}
|
||||
|
||||
func TestListAll(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
dir, err := createSimpleTestSite(t, testSiteConfig{})
|
||||
dir, clean, err := createSimpleTestSite(t, testSiteConfig{})
|
||||
defer clean()
|
||||
|
||||
c.Assert(err, qt.IsNil)
|
||||
|
||||
@@ -47,7 +43,10 @@ func TestListAll(t *testing.T) {
|
||||
|
||||
cmd.SetArgs([]string{"-s=" + dir, "list", "all"})
|
||||
|
||||
out, err := captureStdout(cmd.ExecuteC)
|
||||
out, err := captureStdout(func() error {
|
||||
_, err := cmd.ExecuteC()
|
||||
return err
|
||||
})
|
||||
c.Assert(err, qt.IsNil)
|
||||
|
||||
r := csv.NewReader(strings.NewReader(out))
|
||||
|
||||
+104
-26
@@ -14,7 +14,10 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/gohugoio/hugo/modules"
|
||||
"github.com/spf13/cobra"
|
||||
@@ -26,7 +29,52 @@ type modCmd struct {
|
||||
*baseBuilderCmd
|
||||
}
|
||||
|
||||
func (c *modCmd) newVerifyCmd() *cobra.Command {
|
||||
var clean bool
|
||||
|
||||
verifyCmd := &cobra.Command{
|
||||
Use: "verify",
|
||||
Short: "Verify dependencies.",
|
||||
Long: `Verify checks that the dependencies of the current module, which are stored in a local downloaded source cache, have not been modified since being downloaded.
|
||||
`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return c.withModsClient(true, func(c *modules.Client) error {
|
||||
return c.Verify(clean)
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
verifyCmd.Flags().BoolVarP(&clean, "clean", "", false, "delete module cache for dependencies that fail verification")
|
||||
|
||||
return verifyCmd
|
||||
}
|
||||
|
||||
func (c *modCmd) newCleanCmd() *cobra.Command {
|
||||
var pattern string
|
||||
cmd := &cobra.Command{
|
||||
Use: "clean",
|
||||
Short: "Delete the Hugo Module cache for the current project.",
|
||||
Long: `Delete the Hugo Module cache for the current project.
|
||||
|
||||
Note that after you run this command, all of your dependencies will be re-downloaded next time you run "hugo".
|
||||
|
||||
Also note that if you configure a positive maxAge for the "modules" file cache, it will also be cleaned as part of "hugo --gc".
|
||||
|
||||
`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return c.withModsClient(true, func(c *modules.Client) error {
|
||||
return c.Clean(pattern)
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().StringVarP(&pattern, "pattern", "", "", `pattern matching module paths to clean (all if not set), e.g. "**hugo*"`)
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (b *commandsBuilder) newModCmd() *modCmd {
|
||||
|
||||
c := &modCmd{}
|
||||
|
||||
const commonUsage = `
|
||||
@@ -72,16 +120,65 @@ Install a specific version:
|
||||
Install the latest versions of all module dependencies:
|
||||
|
||||
hugo mod get -u
|
||||
hugo mod get -u ./... (recursive)
|
||||
|
||||
Run "go help get" for more information. All flags available for "go get" is also relevant here.
|
||||
` + commonUsage,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return c.withModsClient(false, func(c *modules.Client) error {
|
||||
// We currently just pass on the flags we get to Go and
|
||||
// need to do the flag handling manually.
|
||||
if len(args) == 1 && args[0] == "-h" {
|
||||
return cmd.Help()
|
||||
// We currently just pass on the flags we get to Go and
|
||||
// need to do the flag handling manually.
|
||||
if len(args) == 1 && args[0] == "-h" {
|
||||
return cmd.Help()
|
||||
}
|
||||
|
||||
var lastArg string
|
||||
if len(args) != 0 {
|
||||
lastArg = args[len(args)-1]
|
||||
}
|
||||
|
||||
if lastArg == "./..." {
|
||||
args = args[:len(args)-1]
|
||||
// Do a recursive update.
|
||||
dirname, err := os.Getwd()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Sanity check. We do recursive walking and want to avoid
|
||||
// accidents.
|
||||
if len(dirname) < 5 {
|
||||
return errors.New("must not be run from the file system root")
|
||||
}
|
||||
|
||||
filepath.Walk(dirname, func(path string, info os.FileInfo, err error) error {
|
||||
if info.IsDir() {
|
||||
return nil
|
||||
}
|
||||
|
||||
if info.Name() == "go.mod" {
|
||||
// Found a module.
|
||||
dir := filepath.Dir(path)
|
||||
fmt.Println("Update module in", dir)
|
||||
c.source = dir
|
||||
err := c.withModsClient(false, func(c *modules.Client) error {
|
||||
if len(args) == 1 && args[0] == "-h" {
|
||||
return cmd.Help()
|
||||
}
|
||||
return c.Get(args...)
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
return c.withModsClient(false, func(c *modules.Client) error {
|
||||
return c.Get(args...)
|
||||
})
|
||||
},
|
||||
@@ -132,6 +229,7 @@ If a module is vendored, that is where Hugo will look for it's dependencies.
|
||||
})
|
||||
},
|
||||
},
|
||||
c.newVerifyCmd(),
|
||||
&cobra.Command{
|
||||
Use: "tidy",
|
||||
Short: "Remove unused entries in go.mod and go.sum.",
|
||||
@@ -141,27 +239,7 @@ If a module is vendored, that is where Hugo will look for it's dependencies.
|
||||
})
|
||||
},
|
||||
},
|
||||
&cobra.Command{
|
||||
Use: "clean",
|
||||
Short: "Delete the entire Hugo Module cache.",
|
||||
Long: `Delete the entire Hugo Module cache.
|
||||
|
||||
Note that after you run this command, all of your dependencies will be re-downloaded next time you run "hugo".
|
||||
|
||||
Also note that if you configure a positive maxAge for the "modules" file cache, it will also be cleaned as part of "hugo --gc".
|
||||
|
||||
`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
com, err := c.initConfig(true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = com.hugo().FileCaches.ModulesCache().Prune(true)
|
||||
return err
|
||||
|
||||
},
|
||||
},
|
||||
c.newCleanCmd(),
|
||||
)
|
||||
|
||||
c.baseBuilderCmd = b.newBuilderCmd(cmd)
|
||||
|
||||
+2
-2
@@ -55,8 +55,8 @@ Ensure you run this within the root directory of your site.`,
|
||||
cmd.Flags().StringVarP(&cc.contentType, "kind", "k", "", "content type to create")
|
||||
cmd.Flags().StringVar(&cc.contentEditor, "editor", "", "edit new content with this editor, if provided")
|
||||
|
||||
cmd.AddCommand(newNewSiteCmd().getCommand())
|
||||
cmd.AddCommand(newNewThemeCmd().getCommand())
|
||||
cmd.AddCommand(b.newNewSiteCmd().getCommand())
|
||||
cmd.AddCommand(b.newNewThemeCmd().getCommand())
|
||||
|
||||
cmd.RunE = cc.newContent
|
||||
|
||||
|
||||
@@ -17,9 +17,6 @@ import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/gohugoio/hugo/hugofs"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
qt "github.com/frankban/quicktest"
|
||||
)
|
||||
|
||||
@@ -30,105 +27,3 @@ func TestNewContentPathSectionWithForwardSlashes(t *testing.T) {
|
||||
c.Assert(p, qt.Equals, filepath.FromSlash("/post/new.md"))
|
||||
c.Assert(s, qt.Equals, "post")
|
||||
}
|
||||
|
||||
func checkNewSiteInited(fs *hugofs.Fs, basepath string, t *testing.T) {
|
||||
c := qt.New(t)
|
||||
paths := []string{
|
||||
filepath.Join(basepath, "layouts"),
|
||||
filepath.Join(basepath, "content"),
|
||||
filepath.Join(basepath, "archetypes"),
|
||||
filepath.Join(basepath, "static"),
|
||||
filepath.Join(basepath, "data"),
|
||||
filepath.Join(basepath, "config.toml"),
|
||||
}
|
||||
|
||||
for _, path := range paths {
|
||||
_, err := fs.Source.Stat(path)
|
||||
c.Assert(err, qt.IsNil)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDoNewSite(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
n := newNewSiteCmd()
|
||||
basepath := filepath.Join("base", "blog")
|
||||
_, fs := newTestCfg()
|
||||
|
||||
c.Assert(n.doNewSite(fs, basepath, false), qt.IsNil)
|
||||
|
||||
checkNewSiteInited(fs, basepath, t)
|
||||
}
|
||||
|
||||
func TestDoNewSite_noerror_base_exists_but_empty(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
basepath := filepath.Join("base", "blog")
|
||||
_, fs := newTestCfg()
|
||||
n := newNewSiteCmd()
|
||||
|
||||
c.Assert(fs.Source.MkdirAll(basepath, 0777), qt.IsNil)
|
||||
|
||||
c.Assert(n.doNewSite(fs, basepath, false), qt.IsNil)
|
||||
}
|
||||
|
||||
func TestDoNewSite_error_base_exists(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
basepath := filepath.Join("base", "blog")
|
||||
_, fs := newTestCfg()
|
||||
n := newNewSiteCmd()
|
||||
|
||||
c.Assert(fs.Source.MkdirAll(basepath, 0777), qt.IsNil)
|
||||
_, err := fs.Source.Create(filepath.Join(basepath, "foo"))
|
||||
c.Assert(err, qt.IsNil)
|
||||
// Since the directory already exists and isn't empty, expect an error
|
||||
c.Assert(n.doNewSite(fs, basepath, false), qt.Not(qt.IsNil))
|
||||
|
||||
}
|
||||
|
||||
func TestDoNewSite_force_empty_dir(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
basepath := filepath.Join("base", "blog")
|
||||
_, fs := newTestCfg()
|
||||
n := newNewSiteCmd()
|
||||
|
||||
c.Assert(fs.Source.MkdirAll(basepath, 0777), qt.IsNil)
|
||||
c.Assert(n.doNewSite(fs, basepath, true), qt.IsNil)
|
||||
|
||||
checkNewSiteInited(fs, basepath, t)
|
||||
}
|
||||
|
||||
func TestDoNewSite_error_force_dir_inside_exists(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
basepath := filepath.Join("base", "blog")
|
||||
_, fs := newTestCfg()
|
||||
n := newNewSiteCmd()
|
||||
|
||||
contentPath := filepath.Join(basepath, "content")
|
||||
|
||||
c.Assert(fs.Source.MkdirAll(contentPath, 0777), qt.IsNil)
|
||||
c.Assert(n.doNewSite(fs, basepath, true), qt.Not(qt.IsNil))
|
||||
}
|
||||
|
||||
func TestDoNewSite_error_force_config_inside_exists(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
basepath := filepath.Join("base", "blog")
|
||||
_, fs := newTestCfg()
|
||||
n := newNewSiteCmd()
|
||||
|
||||
configPath := filepath.Join(basepath, "config.toml")
|
||||
c.Assert(fs.Source.MkdirAll(basepath, 0777), qt.IsNil)
|
||||
_, err := fs.Source.Create(configPath)
|
||||
c.Assert(err, qt.IsNil)
|
||||
|
||||
c.Assert(n.doNewSite(fs, basepath, true), qt.Not(qt.IsNil))
|
||||
}
|
||||
|
||||
func newTestCfg() (*viper.Viper, *hugofs.Fs) {
|
||||
|
||||
v := viper.New()
|
||||
fs := hugofs.NewMem(v)
|
||||
|
||||
v.SetFs(fs.Source)
|
||||
|
||||
return v, fs
|
||||
|
||||
}
|
||||
|
||||
@@ -37,11 +37,11 @@ var _ cmder = (*newSiteCmd)(nil)
|
||||
type newSiteCmd struct {
|
||||
configFormat string
|
||||
|
||||
*baseCmd
|
||||
*baseBuilderCmd
|
||||
}
|
||||
|
||||
func newNewSiteCmd() *newSiteCmd {
|
||||
ccmd := &newSiteCmd{}
|
||||
func (b *commandsBuilder) newNewSiteCmd() *newSiteCmd {
|
||||
cc := &newSiteCmd{}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "site [path]",
|
||||
@@ -49,15 +49,15 @@ func newNewSiteCmd() *newSiteCmd {
|
||||
Long: `Create a new site in the provided directory.
|
||||
The new site will have the correct structure, but no content or theme yet.
|
||||
Use ` + "`hugo new [contentPath]`" + ` to create new content.`,
|
||||
RunE: ccmd.newSite,
|
||||
RunE: cc.newSite,
|
||||
}
|
||||
|
||||
cmd.Flags().StringVarP(&ccmd.configFormat, "format", "f", "toml", "config & frontmatter format")
|
||||
cmd.Flags().StringVarP(&cc.configFormat, "format", "f", "toml", "config & frontmatter format")
|
||||
cmd.Flags().Bool("force", false, "init inside non-empty directory")
|
||||
|
||||
ccmd.baseCmd = newBaseCmd(cmd)
|
||||
cc.baseBuilderCmd = b.newBuilderBasicCmd(cmd)
|
||||
|
||||
return ccmd
|
||||
return cc
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -29,12 +29,11 @@ import (
|
||||
var _ cmder = (*newThemeCmd)(nil)
|
||||
|
||||
type newThemeCmd struct {
|
||||
*baseCmd
|
||||
hugoBuilderCommon
|
||||
*baseBuilderCmd
|
||||
}
|
||||
|
||||
func newNewThemeCmd() *newThemeCmd {
|
||||
ccmd := &newThemeCmd{baseCmd: newBaseCmd(nil)}
|
||||
func (b *commandsBuilder) newNewThemeCmd() *newThemeCmd {
|
||||
cc := &newThemeCmd{}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "theme [name]",
|
||||
@@ -43,12 +42,12 @@ func newNewThemeCmd() *newThemeCmd {
|
||||
New theme is a skeleton. Please add content to the touched files. Add your
|
||||
name to the copyright line in the license and adjust the theme.toml file
|
||||
as you see fit.`,
|
||||
RunE: ccmd.newTheme,
|
||||
RunE: cc.newTheme,
|
||||
}
|
||||
|
||||
ccmd.cmd = cmd
|
||||
cc.baseBuilderCmd = b.newBuilderBasicCmd(cmd)
|
||||
|
||||
return ccmd
|
||||
return cc
|
||||
}
|
||||
|
||||
// newTheme creates a new Hugo theme template
|
||||
|
||||
+15
-11
@@ -16,6 +16,7 @@ package commands
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
@@ -33,7 +34,6 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/gohugoio/hugo/livereload"
|
||||
"github.com/gohugoio/hugo/tpl"
|
||||
|
||||
"github.com/gohugoio/hugo/config"
|
||||
"github.com/gohugoio/hugo/helpers"
|
||||
@@ -287,7 +287,7 @@ func getRootWatchDirsStr(baseDir string, watchDirs []string) string {
|
||||
type fileServer struct {
|
||||
baseURLs []string
|
||||
roots []string
|
||||
errorTemplate tpl.Template
|
||||
errorTemplate func(err interface{}) (io.Reader, error)
|
||||
c *commandeer
|
||||
s *serverCmd
|
||||
}
|
||||
@@ -334,9 +334,9 @@ func (f *fileServer) createEndpoint(i int) (*http.ServeMux, string, string, erro
|
||||
// First check the error state
|
||||
err := f.c.getErrorWithContext()
|
||||
if err != nil {
|
||||
f.c.wasError = true
|
||||
w.WriteHeader(500)
|
||||
var b bytes.Buffer
|
||||
err := f.errorTemplate.Execute(&b, err)
|
||||
r, err := f.errorTemplate(err)
|
||||
if err != nil {
|
||||
f.c.logger.ERROR.Println(err)
|
||||
}
|
||||
@@ -344,7 +344,7 @@ func (f *fileServer) createEndpoint(i int) (*http.ServeMux, string, string, erro
|
||||
if !f.c.paused {
|
||||
port = f.c.Cfg.GetInt("liveReloadPort")
|
||||
}
|
||||
fmt.Fprint(w, injectLiveReloadScript(&b, port))
|
||||
fmt.Fprint(w, injectLiveReloadScript(r, port))
|
||||
|
||||
return
|
||||
}
|
||||
@@ -416,17 +416,21 @@ func (c *commandeer) serve(s *serverCmd) error {
|
||||
roots = []string{""}
|
||||
}
|
||||
|
||||
templ, err := c.hugo().TextTmpl.Parse("__default_server_error", buildErrorTemplate)
|
||||
templ, err := c.hugo().TextTmpl().Parse("__default_server_error", buildErrorTemplate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
srv := &fileServer{
|
||||
baseURLs: baseURLs,
|
||||
roots: roots,
|
||||
c: c,
|
||||
s: s,
|
||||
errorTemplate: templ,
|
||||
baseURLs: baseURLs,
|
||||
roots: roots,
|
||||
c: c,
|
||||
s: s,
|
||||
errorTemplate: func(ctx interface{}) (io.Reader, error) {
|
||||
b := &bytes.Buffer{}
|
||||
err := c.hugo().Tmpl().Execute(templ, b, ctx)
|
||||
return b, err
|
||||
},
|
||||
}
|
||||
|
||||
doLiveReload := !c.Cfg.GetBool("disableLiveReload")
|
||||
|
||||
@@ -34,7 +34,8 @@ func TestServer(t *testing.T) {
|
||||
t.Skip("Skip server test on appveyor")
|
||||
}
|
||||
c := qt.New(t)
|
||||
dir, err := createSimpleTestSite(t, testSiteConfig{})
|
||||
dir, clean, err := createSimpleTestSite(t, testSiteConfig{})
|
||||
defer clean()
|
||||
c.Assert(err, qt.IsNil)
|
||||
|
||||
// Let us hope that this port is available on all systems ...
|
||||
|
||||
@@ -15,11 +15,14 @@
|
||||
package herrors
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"runtime"
|
||||
"runtime/debug"
|
||||
"strconv"
|
||||
|
||||
_errors "github.com/pkg/errors"
|
||||
)
|
||||
@@ -33,13 +36,13 @@ type stackTracer interface {
|
||||
StackTrace() _errors.StackTrace
|
||||
}
|
||||
|
||||
// PrintStackTrace prints the error's stack trace to stdoud.
|
||||
func PrintStackTrace(err error) {
|
||||
FprintStackTrace(os.Stdout, err)
|
||||
// PrintStackTraceFromErr prints the error's stack trace to stdoud.
|
||||
func PrintStackTraceFromErr(err error) {
|
||||
FprintStackTraceFromErr(os.Stdout, err)
|
||||
}
|
||||
|
||||
// FprintStackTrace prints the error's stack trace to w.
|
||||
func FprintStackTrace(w io.Writer, err error) {
|
||||
// FprintStackTraceFromErr prints the error's stack trace to w.
|
||||
func FprintStackTraceFromErr(w io.Writer, err error) {
|
||||
if err, ok := err.(stackTracer); ok {
|
||||
for _, f := range err.StackTrace() {
|
||||
fmt.Fprintf(w, "%+s:%d\n", f, f)
|
||||
@@ -47,6 +50,18 @@ func FprintStackTrace(w io.Writer, err error) {
|
||||
}
|
||||
}
|
||||
|
||||
// PrintStackTrace prints the current stacktrace to w.
|
||||
func PrintStackTrace(w io.Writer) {
|
||||
buf := make([]byte, 1<<16)
|
||||
runtime.Stack(buf, true)
|
||||
fmt.Fprintf(w, "%s", buf)
|
||||
}
|
||||
|
||||
// ErrorSender is a, typically, non-blocking error handler.
|
||||
type ErrorSender interface {
|
||||
SendError(err error)
|
||||
}
|
||||
|
||||
// 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()
|
||||
@@ -56,7 +71,16 @@ func Recover(args ...interface{}) {
|
||||
args = append(args, "stacktrace from panic: \n"+string(debug.Stack()), "\n")
|
||||
fmt.Println(args...)
|
||||
}
|
||||
}
|
||||
|
||||
// Get the current goroutine id. Used only for debugging.
|
||||
func GetGID() uint64 {
|
||||
b := make([]byte, 64)
|
||||
b = b[:runtime.Stack(b, false)]
|
||||
b = bytes.TrimPrefix(b, []byte("goroutine "))
|
||||
b = b[:bytes.IndexByte(b, ' ')]
|
||||
n, _ := strconv.ParseUint(string(b), 10, 64)
|
||||
return n
|
||||
}
|
||||
|
||||
// ErrFeatureNotAvailable denotes that a feature is unavailable.
|
||||
|
||||
+12
-4
@@ -15,7 +15,7 @@ package hugo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"io"
|
||||
|
||||
"runtime"
|
||||
"strings"
|
||||
@@ -245,7 +245,15 @@ func goMinorVersion(version string) int {
|
||||
if strings.HasPrefix(version, "devel") {
|
||||
return 9999 // magic
|
||||
}
|
||||
i, _ := strconv.Atoi(strings.Split(version, ".")[1])
|
||||
return i
|
||||
|
||||
var major, minor int
|
||||
var trailing string
|
||||
n, err := fmt.Sscanf(version, "go%d.%d%s", &major, &minor, &trailing)
|
||||
if n == 2 && err == io.EOF {
|
||||
// Means there were no trailing characters (i.e., not an alpha/beta)
|
||||
err = nil
|
||||
}
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return minor
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ package hugo
|
||||
// CurrentVersion represents the current build version.
|
||||
// This should be the only one.
|
||||
var CurrentVersion = Version{
|
||||
Number: 0.60,
|
||||
Number: 0.65,
|
||||
PatchLevel: 0,
|
||||
Suffix: "",
|
||||
}
|
||||
|
||||
@@ -84,5 +84,6 @@ func TestParseHugoVersion(t *testing.T) {
|
||||
func TestGoMinorVersion(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
c.Assert(goMinorVersion("go1.12.5"), qt.Equals, 12)
|
||||
c.Assert(goMinorVersion("go1.14rc1"), qt.Equals, 14)
|
||||
c.Assert(GoMinorVersion() >= 11, qt.Equals, true)
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ package para
|
||||
import (
|
||||
"context"
|
||||
"runtime"
|
||||
|
||||
"sort"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
// Copyright 2019 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 text
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"unicode"
|
||||
|
||||
"golang.org/x/text/runes"
|
||||
"golang.org/x/text/transform"
|
||||
"golang.org/x/text/unicode/norm"
|
||||
)
|
||||
|
||||
var accentTransformerPool = &sync.Pool{
|
||||
New: func() interface{} {
|
||||
return transform.Chain(norm.NFD, runes.Remove(runes.In(unicode.Mn)), norm.NFC)
|
||||
},
|
||||
}
|
||||
|
||||
// RemoveAccents removes all accents from b.
|
||||
func RemoveAccents(b []byte) []byte {
|
||||
t := accentTransformerPool.Get().(transform.Transformer)
|
||||
b, _, _ = transform.Bytes(t, b)
|
||||
t.Reset()
|
||||
accentTransformerPool.Put(t)
|
||||
return b
|
||||
}
|
||||
|
||||
// RemoveAccentsString removes all accents from s.
|
||||
func RemoveAccentsString(s string) string {
|
||||
t := accentTransformerPool.Get().(transform.Transformer)
|
||||
s, _, _ = transform.String(t, s)
|
||||
t.Reset()
|
||||
accentTransformerPool.Put(t)
|
||||
return s
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
// Copyright 2019 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 text
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
qt "github.com/frankban/quicktest"
|
||||
)
|
||||
|
||||
func TestRemoveAccents(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
|
||||
c.Assert(string(RemoveAccents([]byte("Resumé"))), qt.Equals, "Resume")
|
||||
c.Assert(string(RemoveAccents([]byte("Hugo Rocks!"))), qt.Equals, "Hugo Rocks!")
|
||||
c.Assert(string(RemoveAccentsString("Resumé")), qt.Equals, "Resume")
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
// Copyright 2019 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 types
|
||||
|
||||
import "github.com/spf13/cast"
|
||||
|
||||
// ToStringSlicePreserveString converts v to a string slice.
|
||||
// If v is a string, it will be wrapped in a string slice.
|
||||
func ToStringSlicePreserveString(v interface{}) []string {
|
||||
if v == nil {
|
||||
return nil
|
||||
}
|
||||
if sds, ok := v.(string); ok {
|
||||
return []string{sds}
|
||||
}
|
||||
return cast.ToStringSlice(v)
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
// Copyright 2019 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 types
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
qt "github.com/frankban/quicktest"
|
||||
)
|
||||
|
||||
func TestToStringSlicePreserveString(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
|
||||
c.Assert(ToStringSlicePreserveString("Hugo"), qt.DeepEquals, []string{"Hugo"})
|
||||
c.Assert(ToStringSlicePreserveString([]interface{}{"A", "B"}), qt.DeepEquals, []string{"A", "B"})
|
||||
c.Assert(ToStringSlicePreserveString(nil), qt.IsNil)
|
||||
|
||||
}
|
||||
@@ -21,6 +21,12 @@ import (
|
||||
"github.com/spf13/cast"
|
||||
)
|
||||
|
||||
// RLocker represents the read locks in sync.RWMutex.
|
||||
type RLocker interface {
|
||||
RLock()
|
||||
RUnlock()
|
||||
}
|
||||
|
||||
// KeyValueStr is a string tuple.
|
||||
type KeyValueStr struct {
|
||||
Key string
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"github.com/spf13/cast"
|
||||
"github.com/gohugoio/hugo/common/types"
|
||||
)
|
||||
|
||||
// Provider provides the configuration settings for Hugo.
|
||||
@@ -35,14 +35,7 @@ type Provider interface {
|
||||
// we do not attempt to split it into fields.
|
||||
func GetStringSlicePreserveString(cfg Provider, key string) []string {
|
||||
sd := cfg.Get(key)
|
||||
return toStringSlicePreserveString(sd)
|
||||
}
|
||||
|
||||
func toStringSlicePreserveString(v interface{}) []string {
|
||||
if sds, ok := v.(string); ok {
|
||||
return []string{sds}
|
||||
}
|
||||
return cast.ToStringSlice(v)
|
||||
return types.ToStringSlicePreserveString(sd)
|
||||
}
|
||||
|
||||
// SetBaseTestDefaults provides some common config defaults used in tests.
|
||||
|
||||
@@ -110,7 +110,7 @@ func executeArcheTypeAsTemplate(s *hugolib.Site, name, kind, targetPath, archety
|
||||
Date: time.Now().Format(time.RFC3339),
|
||||
Name: name,
|
||||
File: f,
|
||||
Site: &s.Info,
|
||||
Site: s.Info,
|
||||
}
|
||||
|
||||
if archetypeFilename == "" {
|
||||
@@ -129,16 +129,16 @@ func executeArcheTypeAsTemplate(s *hugolib.Site, name, kind, targetPath, archety
|
||||
archetypeTemplate = []byte(archetypeShortcodeReplacementsPre.Replace(string(archetypeTemplate)))
|
||||
|
||||
// Reuse the Hugo template setup to get the template funcs properly set up.
|
||||
templateHandler := s.Deps.Tmpl.(tpl.TemplateHandler)
|
||||
templateName := "_text/" + helpers.Filename(archetypeFilename)
|
||||
if err := templateHandler.AddTemplate(templateName, string(archetypeTemplate)); err != nil {
|
||||
templateHandler := s.Deps.Tmpl().(tpl.TemplateManager)
|
||||
templateName := helpers.Filename(archetypeFilename)
|
||||
if err := templateHandler.AddTemplate("_text/"+templateName, string(archetypeTemplate)); err != nil {
|
||||
return nil, errors.Wrapf(err, "Failed to parse archetype file %q:", archetypeFilename)
|
||||
}
|
||||
|
||||
templ, _ := templateHandler.Lookup(templateName)
|
||||
|
||||
var buff bytes.Buffer
|
||||
if err := templ.Execute(&buff, data); err != nil {
|
||||
if err := templateHandler.Execute(templ, &buff, data); err != nil {
|
||||
return nil, errors.Wrapf(err, "Failed to process archetype file %q:", archetypeFilename)
|
||||
}
|
||||
|
||||
|
||||
Vendored
+59
-26
@@ -5,6 +5,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"go.uber.org/atomic"
|
||||
|
||||
"github.com/gohugoio/hugo/cache/filecache"
|
||||
"github.com/gohugoio/hugo/common/loggers"
|
||||
@@ -37,11 +38,11 @@ type Deps struct {
|
||||
// Used to log warnings that may repeat itself many times.
|
||||
DistinctWarningLog *helpers.DistinctLogger
|
||||
|
||||
// The templates to use. This will usually implement the full tpl.TemplateHandler.
|
||||
Tmpl tpl.TemplateFinder `json:"-"`
|
||||
// The templates to use. This will usually implement the full tpl.TemplateManager.
|
||||
tmpl tpl.TemplateHandler
|
||||
|
||||
// We use this to parse and execute ad-hoc text templates.
|
||||
TextTmpl tpl.TemplateParseFinder `json:"-"`
|
||||
textTmpl tpl.TemplateParseFinder
|
||||
|
||||
// The file systems to use.
|
||||
Fs *hugofs.Fs `json:"-"`
|
||||
@@ -77,7 +78,10 @@ type Deps struct {
|
||||
OutputFormatsConfig output.Formats
|
||||
|
||||
templateProvider ResourceProvider
|
||||
WithTemplate func(templ tpl.TemplateHandler) error `json:"-"`
|
||||
WithTemplate func(templ tpl.TemplateManager) error `json:"-"`
|
||||
|
||||
// Used in tests
|
||||
OverloadedTemplateFuncs map[string]interface{}
|
||||
|
||||
translationProvider ResourceProvider
|
||||
|
||||
@@ -89,6 +93,9 @@ type Deps struct {
|
||||
// BuildStartListeners will be notified before a build starts.
|
||||
BuildStartListeners *Listeners
|
||||
|
||||
// Atomic flags set during a build.
|
||||
BuildFlags *BuildFlags
|
||||
|
||||
*globalErrHandler
|
||||
}
|
||||
|
||||
@@ -150,9 +157,20 @@ type ResourceProvider interface {
|
||||
Clone(deps *Deps) error
|
||||
}
|
||||
|
||||
// TemplateHandler returns the used tpl.TemplateFinder as tpl.TemplateHandler.
|
||||
func (d *Deps) TemplateHandler() tpl.TemplateHandler {
|
||||
return d.Tmpl.(tpl.TemplateHandler)
|
||||
func (d *Deps) Tmpl() tpl.TemplateHandler {
|
||||
return d.tmpl
|
||||
}
|
||||
|
||||
func (d *Deps) TextTmpl() tpl.TemplateParseFinder {
|
||||
return d.textTmpl
|
||||
}
|
||||
|
||||
func (d *Deps) SetTmpl(tmpl tpl.TemplateHandler) {
|
||||
d.tmpl = tmpl
|
||||
}
|
||||
|
||||
func (d *Deps) SetTextTmpl(tmpl tpl.TemplateParseFinder) {
|
||||
d.textTmpl = tmpl
|
||||
}
|
||||
|
||||
// LoadResources loads translations and templates.
|
||||
@@ -239,24 +257,26 @@ func New(cfg DepsCfg) (*Deps, error) {
|
||||
distinctWarnLogger := helpers.NewDistinctLogger(logger.WARN)
|
||||
|
||||
d := &Deps{
|
||||
Fs: fs,
|
||||
Log: logger,
|
||||
DistinctErrorLog: distinctErrorLogger,
|
||||
DistinctWarningLog: distinctWarnLogger,
|
||||
templateProvider: cfg.TemplateProvider,
|
||||
translationProvider: cfg.TranslationProvider,
|
||||
WithTemplate: cfg.WithTemplate,
|
||||
PathSpec: ps,
|
||||
ContentSpec: contentSpec,
|
||||
SourceSpec: sp,
|
||||
ResourceSpec: resourceSpec,
|
||||
Cfg: cfg.Language,
|
||||
Language: cfg.Language,
|
||||
Site: cfg.Site,
|
||||
FileCaches: fileCaches,
|
||||
BuildStartListeners: &Listeners{},
|
||||
Timeout: time.Duration(timeoutms) * time.Millisecond,
|
||||
globalErrHandler: &globalErrHandler{},
|
||||
Fs: fs,
|
||||
Log: logger,
|
||||
DistinctErrorLog: distinctErrorLogger,
|
||||
DistinctWarningLog: distinctWarnLogger,
|
||||
templateProvider: cfg.TemplateProvider,
|
||||
translationProvider: cfg.TranslationProvider,
|
||||
WithTemplate: cfg.WithTemplate,
|
||||
OverloadedTemplateFuncs: cfg.OverloadedTemplateFuncs,
|
||||
PathSpec: ps,
|
||||
ContentSpec: contentSpec,
|
||||
SourceSpec: sp,
|
||||
ResourceSpec: resourceSpec,
|
||||
Cfg: cfg.Language,
|
||||
Language: cfg.Language,
|
||||
Site: cfg.Site,
|
||||
FileCaches: fileCaches,
|
||||
BuildStartListeners: &Listeners{},
|
||||
BuildFlags: &BuildFlags{},
|
||||
Timeout: time.Duration(timeoutms) * time.Millisecond,
|
||||
globalErrHandler: &globalErrHandler{},
|
||||
}
|
||||
|
||||
if cfg.Cfg.GetBool("templateMetrics") {
|
||||
@@ -344,7 +364,9 @@ type DepsCfg struct {
|
||||
|
||||
// Template handling.
|
||||
TemplateProvider ResourceProvider
|
||||
WithTemplate func(templ tpl.TemplateHandler) error
|
||||
WithTemplate func(templ tpl.TemplateManager) error
|
||||
// Used in tests
|
||||
OverloadedTemplateFuncs map[string]interface{}
|
||||
|
||||
// i18n handling.
|
||||
TranslationProvider ResourceProvider
|
||||
@@ -352,3 +374,14 @@ type DepsCfg struct {
|
||||
// Whether we are in running (server) mode
|
||||
Running bool
|
||||
}
|
||||
|
||||
// BuildFlags are flags that may be turned on during a build.
|
||||
type BuildFlags struct {
|
||||
HasLateTemplate atomic.Bool
|
||||
}
|
||||
|
||||
func NewBuildFlags() BuildFlags {
|
||||
return BuildFlags{
|
||||
//HasLateTemplate: atomic.NewBool(false),
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+28
@@ -0,0 +1,28 @@
|
||||
// Copyright 2019 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 deps
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
qt "github.com/frankban/quicktest"
|
||||
)
|
||||
|
||||
func TestBuildFlags(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
var bf BuildFlags
|
||||
c.Assert(bf.HasLateTemplate.Load(), qt.Equals, false)
|
||||
bf.HasLateTemplate.Store(true)
|
||||
c.Assert(bf.HasLateTemplate.Load(), qt.Equals, true)
|
||||
}
|
||||
-2
@@ -1,2 +0,0 @@
|
||||
ignorePaths:
|
||||
- "resources/**"
|
||||
+4
-4
@@ -13,16 +13,16 @@ Note that this repository contains solely the documentation for Hugo. For contri
|
||||
|
||||
*Pull requests shall **only** contain changes to the actual documentation. However, changes on the code base of Hugo **and** the documentation shall be a single, atomic pull request in the [hugo](https://github.com/gohugoio/hugo) repository.*
|
||||
|
||||
Spelling fixes are most welcomed, and if you want to contribute longer sections to the documentation, it would be great if you had these in mind when writing:
|
||||
Spelling fixes are most welcomed, and if you want to contribute longer sections to the documentation, it would be great if you had the following criteria in mind when writing:
|
||||
|
||||
* Short is good. People go to the library to read novels. If there is more than one way to _do a thing_ in Hugo, describe the current _best practice_ (avoid "… but you can also do …" and "… in older versions of Hugo you had to …".
|
||||
* For examples, try to find short snippets that teaches people about the concept. If the example is also useful as-is (copy and paste), then great, but don't list long and similar examples just so people can use them on their sites.
|
||||
* Hugo has users from all over the world, so an easy to understand and [simple English](https://simple.wikipedia.org/wiki/Basic_English) is good.
|
||||
* For example, try to find short snippets that teaches people about the concept. If the example is also useful as-is (copy and paste), then great. Don't list long and similar examples just so people can use them on their sites.
|
||||
* Hugo has users from all over the world, so easy to understand and [simple English](https://simple.wikipedia.org/wiki/Basic_English) is good.
|
||||
|
||||
## Branches
|
||||
|
||||
* The `master` branch is where the site is automatically built from, and is the place to put changes relevant to the current Hugo version.
|
||||
* The `next` branch is where we store changes that is related to the next Hugo release. This can be previewed here: https://next--gohugoio.netlify.com/
|
||||
* The `next` branch is where we store changes that are related to the next Hugo release. This can be previewed here: https://next--gohugoio.netlify.com/
|
||||
|
||||
## Build
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
{{/* {{ define "header" }}{{ partial "page-header" . }}{{ end }} */}}
|
||||
{{ define "main" }}
|
||||
{{ $section_to_display := .Pages }}
|
||||
<div class="w-100 ph4 pb5 pb6-ns pt1 pt3-ns">
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
{{/* TODO: think about adding these tags back in, but they need to be limited to news
|
||||
{{ define "header" }}{{ partial "page-header" . }}{{ end }} */}}
|
||||
{{ define "main" }}
|
||||
<div class="w-100 ph4 ph5-ns pb5 pb6-ns pt1 pt3-ns ">
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
# github.com/gohugoio/gohugoioTheme v0.0.0-20191021162625-2e7250ca437d
|
||||
# github.com/gohugoio/gohugoioTheme v0.0.0-20200128164921-1d0bc5482051
|
||||
|
||||
@@ -58,33 +58,6 @@ pattern = "2006"
|
||||
[social]
|
||||
twitter = "GoHugoIO"
|
||||
|
||||
#CUSTOM PARAMS
|
||||
[params]
|
||||
description = "The world’s fastest framework for building websites"
|
||||
## Used for views in rendered HTML (i.e., rather than using the .Hugo variable)
|
||||
release = "0.55.0-DEV"
|
||||
## Setting this to true will add a "noindex" to *EVERY* page on the site
|
||||
removefromexternalsearch = false
|
||||
## Gh repo for site footer (include trailing slash)
|
||||
ghrepo = "https://github.com/gohugoio/hugoDocs/"
|
||||
## GH Repo for filing a new issue
|
||||
github_repo = "https://github.com/gohugoio/hugo/issues/new"
|
||||
### Edit content repo (set to automatically enter "edit" mode; this is good for "improve this page" links)
|
||||
ghdocsrepo = "https://github.com/gohugoio/hugoDocs/tree/master/docs"
|
||||
## Gitter URL
|
||||
gitter = "https://gitter.im/spf13/hugo"
|
||||
## Discuss Forum URL
|
||||
forum = "https://discourse.gohugo.io/"
|
||||
## Google Tag Manager
|
||||
gtmid = ""
|
||||
|
||||
# First one is picked as the Twitter card image if not set on page.
|
||||
images = ["images/gohugoio-card.png"]
|
||||
|
||||
flex_box_interior_classes = "flex-auto w-100 w-40-l mr3 mb3 bg-white ba b--moon-gray nested-copy-line-height"
|
||||
|
||||
#sidebar_direction = "sidebar_left"
|
||||
|
||||
# MARKDOWN
|
||||
## Configuration for BlackFriday markdown parser: https://github.com/russross/blackfriday
|
||||
[blackfriday]
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
|
||||
description = "The world’s fastest framework for building websites"
|
||||
## Used for views in rendered HTML (i.e., rather than using the .Hugo variable)
|
||||
release = "0.52"
|
||||
## Setting this to true will add a "noindex" to *EVERY* page on the site..
|
||||
removefromexternalsearch = false
|
||||
## Gh repo for site footer (include trailing slash)
|
||||
|
||||
@@ -43,7 +43,7 @@ sections:
|
||||
link: templates/
|
||||
color_classes: bg-primary-color-light black
|
||||
image: /images/home-page-templating-example.png
|
||||
copy: "Hugo's Go-based templating provides just the right amount of logic to build anything from the simple to complex. If you prefer Jade/Pug-like syntax, you can also use Amber, Ace, or any combination of the three."
|
||||
copy: "Hugo's Go-based templating provides just the right amount of logic to build anything from the simple to complex."
|
||||
---
|
||||
|
||||
Hugo is one of the most popular open-source static site generators. With its amazing speed and flexibility, Hugo makes building websites fun again.
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 83 KiB |
@@ -0,0 +1,54 @@
|
||||
---
|
||||
title: Hugo's Security Model
|
||||
description: A summary of Hugo's security model.
|
||||
date: 2019-10-01
|
||||
layout: single
|
||||
keywords: ["Security", "Privacy"]
|
||||
menu:
|
||||
docs:
|
||||
parent: "about"
|
||||
weight: 4
|
||||
weight: 5
|
||||
sections_weight: 5
|
||||
draft: false
|
||||
aliases: [/security/]
|
||||
toc: true
|
||||
---
|
||||
|
||||
## Runtime Security
|
||||
|
||||
Hugo produces static output, so once built, the runtime is the browser (assuming the output is HTML) and any server (API) that you integrate with.
|
||||
|
||||
But when developing and building your site, the runtime is the `hugo` executable. Securing a runtime can be [a real challenge](https://blog.logrocket.com/how-to-protect-your-node-js-applications-from-malicious-dependencies-5f2e60ea08f9/).
|
||||
|
||||
**Hugo's main approach is that of sandboxing:**
|
||||
|
||||
* Hugo has a virtual file system and only the main project (not third-party components) is allowed to mount directories or files outside the project root.
|
||||
* Only the main project can walk symbolic links.
|
||||
* User-defined components have only read-access to the filesystem.
|
||||
* We shell out to some external binaries to support [Asciidoctor](/content-management/formats/#list-of-content-formats) and simliar, but those binaries and their flags are predefined. General functions to run arbitrary external OS commands have been [discussed](https://github.com/gohugoio/hugo/issues/796), but not implemented because of security concerns.
|
||||
|
||||
Hugo will soon introduce a concept of _Content Source Plugins_ (AKA _Pages from Data_), but the above will still hold true.
|
||||
|
||||
## Dependency Security
|
||||
|
||||
Hugo builds as a static binary using [Go Modules](https://github.com/golang/go/wiki/Modules) to manage its dependencies. Go Modules have several safeguards, one of them being the `go.sum` file. This is a database of the expected cryptographic checksums of all of your dependencies, including any transitive.
|
||||
|
||||
[Hugo Modules](/hugo-modules/) is built on top of Go Modules functionality, and a Hugo project using Hugo Modules will have a `go.sum` file. We recommend that you commit this file to your version control system. The Hugo build will fail if there is a checksum mismatch, which would be an indication of [dependency tampering](https://julienrenaux.fr/2019/12/20/github-actions-security-risk/).
|
||||
|
||||
## Web Application Security
|
||||
|
||||
These are the security threats as defined by [OWASP](https://en.wikipedia.org/wiki/OWASP).
|
||||
|
||||
For HTML output, this is the core security model:
|
||||
|
||||
https://golang.org/pkg/html/template/#hdr-Security_Model
|
||||
|
||||
In short:
|
||||
|
||||
Templates authors (you) are trusted, but the data you send in is not.
|
||||
This is why you sometimes need to use the _safe_ functions, such as `safeHTML`, to avoid escaping of data you know is safe.
|
||||
There is one exception to the above, as noted in the documentation: If you enable inline shortcodes, you also say that the shortcodes and data handling in content files are trusted, as those macros are treated as pure text.
|
||||
It may be worth adding that Hugo is a static site generator with no concept of dynamic user input.
|
||||
|
||||
For content, the default Markdown renderer is [configured](/getting-started/configuration-markup) to remove or escape potentially unsafe content. This behavior can be reconfigured if you trust your content.
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-02-19
|
||||
title: "hugo"
|
||||
slug: hugo
|
||||
url: /commands/hugo/
|
||||
@@ -15,7 +15,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 https://gohugo.io/.
|
||||
Complete documentation is available at http://gohugo.io/.
|
||||
|
||||
```
|
||||
hugo [flags]
|
||||
@@ -24,7 +24,7 @@ hugo [flags]
|
||||
### Options
|
||||
|
||||
```
|
||||
-b, --baseURL string hostname (and path) to the root, e.g. https://spf13.com/
|
||||
-b, --baseURL string hostname (and path) to the root, e.g. http://spf13.com/
|
||||
-D, --buildDrafts include content marked as draft
|
||||
-E, --buildExpired include expired content
|
||||
-F, --buildFuture include content with publishdate in the future
|
||||
@@ -79,4 +79,4 @@ hugo [flags]
|
||||
* [hugo server](/commands/hugo_server/) - A high performance webserver
|
||||
* [hugo version](/commands/hugo_version/) - Print the version number of Hugo
|
||||
|
||||
###### Auto generated by spf13/cobra on 31-Jul-2019
|
||||
###### Auto generated by spf13/cobra on 19-Feb-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-02-19
|
||||
title: "hugo check"
|
||||
slug: hugo_check
|
||||
url: /commands/hugo_check/
|
||||
@@ -40,4 +40,4 @@ Contains some verification checks
|
||||
* [hugo](/commands/hugo/) - hugo builds your site
|
||||
* [hugo check ulimit](/commands/hugo_check_ulimit/) - Check system ulimit settings
|
||||
|
||||
###### Auto generated by spf13/cobra on 31-Jul-2019
|
||||
###### Auto generated by spf13/cobra on 19-Feb-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-02-19
|
||||
title: "hugo check ulimit"
|
||||
slug: hugo_check_ulimit
|
||||
url: /commands/hugo_check_ulimit/
|
||||
@@ -44,4 +44,4 @@ hugo check ulimit [flags]
|
||||
|
||||
* [hugo check](/commands/hugo_check/) - Contains some verification checks
|
||||
|
||||
###### Auto generated by spf13/cobra on 31-Jul-2019
|
||||
###### Auto generated by spf13/cobra on 19-Feb-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-02-19
|
||||
title: "hugo config"
|
||||
slug: hugo_config
|
||||
url: /commands/hugo_config/
|
||||
@@ -44,4 +44,4 @@ hugo config [flags]
|
||||
* [hugo](/commands/hugo/) - hugo builds your site
|
||||
* [hugo config mounts](/commands/hugo_config_mounts/) - Print the configured file mounts
|
||||
|
||||
###### Auto generated by spf13/cobra on 31-Jul-2019
|
||||
###### Auto generated by spf13/cobra on 19-Feb-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-02-19
|
||||
title: "hugo config mounts"
|
||||
slug: hugo_config_mounts
|
||||
url: /commands/hugo_config_mounts/
|
||||
@@ -43,4 +43,4 @@ hugo config mounts [flags]
|
||||
|
||||
* [hugo config](/commands/hugo_config/) - Print the site configuration
|
||||
|
||||
###### Auto generated by spf13/cobra on 31-Jul-2019
|
||||
###### Auto generated by spf13/cobra on 19-Feb-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-02-19
|
||||
title: "hugo convert"
|
||||
slug: hugo_convert
|
||||
url: /commands/hugo_convert/
|
||||
@@ -46,4 +46,4 @@ See convert's subcommands toJSON, toTOML and toYAML for more information.
|
||||
* [hugo convert toTOML](/commands/hugo_convert_totoml/) - Convert front matter to TOML
|
||||
* [hugo convert toYAML](/commands/hugo_convert_toyaml/) - Convert front matter to YAML
|
||||
|
||||
###### Auto generated by spf13/cobra on 31-Jul-2019
|
||||
###### Auto generated by spf13/cobra on 19-Feb-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-02-19
|
||||
title: "hugo convert toJSON"
|
||||
slug: hugo_convert_toJSON
|
||||
url: /commands/hugo_convert_tojson/
|
||||
@@ -46,4 +46,4 @@ hugo convert toJSON [flags]
|
||||
|
||||
* [hugo convert](/commands/hugo_convert/) - Convert your content to different formats
|
||||
|
||||
###### Auto generated by spf13/cobra on 31-Jul-2019
|
||||
###### Auto generated by spf13/cobra on 19-Feb-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-02-19
|
||||
title: "hugo convert toTOML"
|
||||
slug: hugo_convert_toTOML
|
||||
url: /commands/hugo_convert_totoml/
|
||||
@@ -46,4 +46,4 @@ hugo convert toTOML [flags]
|
||||
|
||||
* [hugo convert](/commands/hugo_convert/) - Convert your content to different formats
|
||||
|
||||
###### Auto generated by spf13/cobra on 31-Jul-2019
|
||||
###### Auto generated by spf13/cobra on 19-Feb-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-02-19
|
||||
title: "hugo convert toYAML"
|
||||
slug: hugo_convert_toYAML
|
||||
url: /commands/hugo_convert_toyaml/
|
||||
@@ -46,4 +46,4 @@ hugo convert toYAML [flags]
|
||||
|
||||
* [hugo convert](/commands/hugo_convert/) - Convert your content to different formats
|
||||
|
||||
###### Auto generated by spf13/cobra on 31-Jul-2019
|
||||
###### Auto generated by spf13/cobra on 19-Feb-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-02-19
|
||||
title: "hugo deploy"
|
||||
slug: hugo_deploy
|
||||
url: /commands/hugo_deploy/
|
||||
@@ -27,7 +27,7 @@ hugo deploy [flags]
|
||||
--dryRun dry run
|
||||
--force force upload of all files
|
||||
-h, --help help for deploy
|
||||
--invalidateCDN invalidate the CDN cache via the cloudFrontDistributionID listed in the deployment target (default true)
|
||||
--invalidateCDN invalidate the CDN cache listed in the deployment target (default true)
|
||||
--maxDeletes int maximum # of files to delete, or -1 to disable (default 256)
|
||||
--target string target deployment from deployments section in config file; defaults to the first one
|
||||
```
|
||||
@@ -53,4 +53,4 @@ hugo deploy [flags]
|
||||
|
||||
* [hugo](/commands/hugo/) - hugo builds your site
|
||||
|
||||
###### Auto generated by spf13/cobra on 31-Jul-2019
|
||||
###### Auto generated by spf13/cobra on 19-Feb-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-02-19
|
||||
title: "hugo env"
|
||||
slug: hugo_env
|
||||
url: /commands/hugo_env/
|
||||
@@ -43,4 +43,4 @@ hugo env [flags]
|
||||
|
||||
* [hugo](/commands/hugo/) - hugo builds your site
|
||||
|
||||
###### Auto generated by spf13/cobra on 31-Jul-2019
|
||||
###### Auto generated by spf13/cobra on 19-Feb-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-02-19
|
||||
title: "hugo gen"
|
||||
slug: hugo_gen
|
||||
url: /commands/hugo_gen/
|
||||
@@ -43,4 +43,4 @@ A collection of several useful generators.
|
||||
* [hugo gen doc](/commands/hugo_gen_doc/) - Generate Markdown documentation for the Hugo CLI.
|
||||
* [hugo gen man](/commands/hugo_gen_man/) - Generate man pages for the Hugo CLI
|
||||
|
||||
###### Auto generated by spf13/cobra on 31-Jul-2019
|
||||
###### Auto generated by spf13/cobra on 19-Feb-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-02-19
|
||||
title: "hugo gen autocomplete"
|
||||
slug: hugo_gen_autocomplete
|
||||
url: /commands/hugo_gen_autocomplete/
|
||||
@@ -61,4 +61,4 @@ hugo gen autocomplete [flags]
|
||||
|
||||
* [hugo gen](/commands/hugo_gen/) - A collection of several useful generators.
|
||||
|
||||
###### Auto generated by spf13/cobra on 31-Jul-2019
|
||||
###### Auto generated by spf13/cobra on 19-Feb-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-02-19
|
||||
title: "hugo gen chromastyles"
|
||||
slug: hugo_gen_chromastyles
|
||||
url: /commands/hugo_gen_chromastyles/
|
||||
@@ -48,4 +48,4 @@ hugo gen chromastyles [flags]
|
||||
|
||||
* [hugo gen](/commands/hugo_gen/) - A collection of several useful generators.
|
||||
|
||||
###### Auto generated by spf13/cobra on 31-Jul-2019
|
||||
###### Auto generated by spf13/cobra on 19-Feb-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-02-19
|
||||
title: "hugo gen doc"
|
||||
slug: hugo_gen_doc
|
||||
url: /commands/hugo_gen_doc/
|
||||
@@ -13,7 +13,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 https://gohugo.io/.
|
||||
of Hugo's command-line interface for http://gohugo.io/.
|
||||
|
||||
It creates one Markdown file per command with front matter suitable
|
||||
for rendering in Hugo.
|
||||
@@ -50,4 +50,4 @@ hugo gen doc [flags]
|
||||
|
||||
* [hugo gen](/commands/hugo_gen/) - A collection of several useful generators.
|
||||
|
||||
###### Auto generated by spf13/cobra on 31-Jul-2019
|
||||
###### Auto generated by spf13/cobra on 19-Feb-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-02-19
|
||||
title: "hugo gen man"
|
||||
slug: hugo_gen_man
|
||||
url: /commands/hugo_gen_man/
|
||||
@@ -46,4 +46,4 @@ hugo gen man [flags]
|
||||
|
||||
* [hugo gen](/commands/hugo_gen/) - A collection of several useful generators.
|
||||
|
||||
###### Auto generated by spf13/cobra on 31-Jul-2019
|
||||
###### Auto generated by spf13/cobra on 19-Feb-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-02-19
|
||||
title: "hugo import"
|
||||
slug: hugo_import
|
||||
url: /commands/hugo_import/
|
||||
@@ -42,4 +42,4 @@ Import requires a subcommand, e.g. `hugo import jekyll jekyll_root_path target_p
|
||||
* [hugo](/commands/hugo/) - hugo builds your site
|
||||
* [hugo import jekyll](/commands/hugo_import_jekyll/) - hugo import from Jekyll
|
||||
|
||||
###### Auto generated by spf13/cobra on 31-Jul-2019
|
||||
###### Auto generated by spf13/cobra on 19-Feb-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-02-19
|
||||
title: "hugo import jekyll"
|
||||
slug: hugo_import_jekyll
|
||||
url: /commands/hugo_import_jekyll/
|
||||
@@ -46,4 +46,4 @@ hugo import jekyll [flags]
|
||||
|
||||
* [hugo import](/commands/hugo_import/) - Import your site from others.
|
||||
|
||||
###### Auto generated by spf13/cobra on 31-Jul-2019
|
||||
###### Auto generated by spf13/cobra on 19-Feb-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-02-19
|
||||
title: "hugo list"
|
||||
slug: hugo_list
|
||||
url: /commands/hugo_list/
|
||||
@@ -45,4 +45,4 @@ List requires a subcommand, e.g. `hugo list drafts`.
|
||||
* [hugo list expired](/commands/hugo_list_expired/) - List all posts already expired
|
||||
* [hugo list future](/commands/hugo_list_future/) - List all posts dated in the future
|
||||
|
||||
###### Auto generated by spf13/cobra on 31-Jul-2019
|
||||
###### Auto generated by spf13/cobra on 19-Feb-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-02-19
|
||||
title: "hugo list all"
|
||||
slug: hugo_list_all
|
||||
url: /commands/hugo_list_all/
|
||||
@@ -43,4 +43,4 @@ hugo list all [flags]
|
||||
|
||||
* [hugo list](/commands/hugo_list/) - Listing out various types of content
|
||||
|
||||
###### Auto generated by spf13/cobra on 31-Jul-2019
|
||||
###### Auto generated by spf13/cobra on 19-Feb-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-02-19
|
||||
title: "hugo list drafts"
|
||||
slug: hugo_list_drafts
|
||||
url: /commands/hugo_list_drafts/
|
||||
@@ -43,4 +43,4 @@ hugo list drafts [flags]
|
||||
|
||||
* [hugo list](/commands/hugo_list/) - Listing out various types of content
|
||||
|
||||
###### Auto generated by spf13/cobra on 31-Jul-2019
|
||||
###### Auto generated by spf13/cobra on 19-Feb-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-02-19
|
||||
title: "hugo list expired"
|
||||
slug: hugo_list_expired
|
||||
url: /commands/hugo_list_expired/
|
||||
@@ -43,4 +43,4 @@ hugo list expired [flags]
|
||||
|
||||
* [hugo list](/commands/hugo_list/) - Listing out various types of content
|
||||
|
||||
###### Auto generated by spf13/cobra on 31-Jul-2019
|
||||
###### Auto generated by spf13/cobra on 19-Feb-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-02-19
|
||||
title: "hugo list future"
|
||||
slug: hugo_list_future
|
||||
url: /commands/hugo_list_future/
|
||||
@@ -43,4 +43,4 @@ hugo list future [flags]
|
||||
|
||||
* [hugo list](/commands/hugo_list/) - Listing out various types of content
|
||||
|
||||
###### Auto generated by spf13/cobra on 31-Jul-2019
|
||||
###### Auto generated by spf13/cobra on 19-Feb-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-02-19
|
||||
title: "hugo mod"
|
||||
slug: hugo_mod
|
||||
url: /commands/hugo_mod/
|
||||
@@ -27,7 +27,7 @@ See https://gohugo.io/hugo-modules/ for more information.
|
||||
### Options
|
||||
|
||||
```
|
||||
-b, --baseURL string hostname (and path) to the root, e.g. https://spf13.com/
|
||||
-b, --baseURL string hostname (and path) to the root, e.g. http://spf13.com/
|
||||
-D, --buildDrafts include content marked as draft
|
||||
-E, --buildExpired include expired content
|
||||
-F, --buildFuture include content with publishdate in the future
|
||||
@@ -73,11 +73,12 @@ See https://gohugo.io/hugo-modules/ for more information.
|
||||
### SEE ALSO
|
||||
|
||||
* [hugo](/commands/hugo/) - hugo builds your site
|
||||
* [hugo mod clean](/commands/hugo_mod_clean/) - Delete the entire Hugo Module cache.
|
||||
* [hugo mod clean](/commands/hugo_mod_clean/) - Delete the Hugo Module cache for the current project.
|
||||
* [hugo mod get](/commands/hugo_mod_get/) - Resolves dependencies in your current Hugo Project.
|
||||
* [hugo mod graph](/commands/hugo_mod_graph/) - Print a module dependency graph.
|
||||
* [hugo mod init](/commands/hugo_mod_init/) - Initialize this project as a Hugo Module.
|
||||
* [hugo mod tidy](/commands/hugo_mod_tidy/) - Remove unused entries in go.mod and go.sum.
|
||||
* [hugo mod vendor](/commands/hugo_mod_vendor/) - Vendor all module dependencies into the _vendor directory.
|
||||
* [hugo mod verify](/commands/hugo_mod_verify/) - Verify dependencies.
|
||||
|
||||
###### Auto generated by spf13/cobra on 31-Jul-2019
|
||||
###### Auto generated by spf13/cobra on 19-Feb-2020
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-02-19
|
||||
title: "hugo mod clean"
|
||||
slug: hugo_mod_clean
|
||||
url: /commands/hugo_mod_clean/
|
||||
---
|
||||
## hugo mod clean
|
||||
|
||||
Delete the entire Hugo Module cache.
|
||||
Delete the Hugo Module cache for the current project.
|
||||
|
||||
### Synopsis
|
||||
|
||||
Delete the entire Hugo Module cache.
|
||||
Delete the Hugo Module cache for the current project.
|
||||
|
||||
Note that after you run this command, all of your dependencies will be re-downloaded next time you run "hugo".
|
||||
|
||||
@@ -25,7 +25,8 @@ hugo mod clean [flags]
|
||||
### Options
|
||||
|
||||
```
|
||||
-h, --help help for clean
|
||||
-h, --help help for clean
|
||||
--pattern string pattern matching module paths to clean (all if not set), e.g. "**hugo*"
|
||||
```
|
||||
|
||||
### Options inherited from parent commands
|
||||
@@ -49,4 +50,4 @@ hugo mod clean [flags]
|
||||
|
||||
* [hugo mod](/commands/hugo_mod/) - Various Hugo Modules helpers.
|
||||
|
||||
###### Auto generated by spf13/cobra on 31-Jul-2019
|
||||
###### Auto generated by spf13/cobra on 19-Feb-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-02-19
|
||||
title: "hugo mod get"
|
||||
slug: hugo_mod_get
|
||||
url: /commands/hugo_mod_get/
|
||||
@@ -26,6 +26,7 @@ Install a specific version:
|
||||
Install the latest versions of all module dependencies:
|
||||
|
||||
hugo mod get -u
|
||||
hugo mod get -u ./... (recursive)
|
||||
|
||||
Run "go help get" for more information. All flags available for "go get" is also relevant here.
|
||||
|
||||
@@ -68,4 +69,4 @@ hugo mod get [flags]
|
||||
|
||||
* [hugo mod](/commands/hugo_mod/) - Various Hugo Modules helpers.
|
||||
|
||||
###### Auto generated by spf13/cobra on 31-Jul-2019
|
||||
###### Auto generated by spf13/cobra on 19-Feb-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-02-19
|
||||
title: "hugo mod graph"
|
||||
slug: hugo_mod_graph
|
||||
url: /commands/hugo_mod_graph/
|
||||
@@ -45,4 +45,4 @@ hugo mod graph [flags]
|
||||
|
||||
* [hugo mod](/commands/hugo_mod/) - Various Hugo Modules helpers.
|
||||
|
||||
###### Auto generated by spf13/cobra on 31-Jul-2019
|
||||
###### Auto generated by spf13/cobra on 19-Feb-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-02-19
|
||||
title: "hugo mod init"
|
||||
slug: hugo_mod_init
|
||||
url: /commands/hugo_mod_init/
|
||||
@@ -50,4 +50,4 @@ hugo mod init [flags]
|
||||
|
||||
* [hugo mod](/commands/hugo_mod/) - Various Hugo Modules helpers.
|
||||
|
||||
###### Auto generated by spf13/cobra on 31-Jul-2019
|
||||
###### Auto generated by spf13/cobra on 19-Feb-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-02-19
|
||||
title: "hugo mod tidy"
|
||||
slug: hugo_mod_tidy
|
||||
url: /commands/hugo_mod_tidy/
|
||||
@@ -43,4 +43,4 @@ hugo mod tidy [flags]
|
||||
|
||||
* [hugo mod](/commands/hugo_mod/) - Various Hugo Modules helpers.
|
||||
|
||||
###### Auto generated by spf13/cobra on 31-Jul-2019
|
||||
###### Auto generated by spf13/cobra on 19-Feb-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-02-19
|
||||
title: "hugo mod vendor"
|
||||
slug: hugo_mod_vendor
|
||||
url: /commands/hugo_mod_vendor/
|
||||
@@ -46,4 +46,4 @@ hugo mod vendor [flags]
|
||||
|
||||
* [hugo mod](/commands/hugo_mod/) - Various Hugo Modules helpers.
|
||||
|
||||
###### Auto generated by spf13/cobra on 31-Jul-2019
|
||||
###### Auto generated by spf13/cobra on 19-Feb-2020
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
---
|
||||
date: 2020-02-19
|
||||
title: "hugo mod verify"
|
||||
slug: hugo_mod_verify
|
||||
url: /commands/hugo_mod_verify/
|
||||
---
|
||||
## hugo mod verify
|
||||
|
||||
Verify dependencies.
|
||||
|
||||
### Synopsis
|
||||
|
||||
Verify checks that the dependencies of the current module, which are stored in a local downloaded source cache, have not been modified since being downloaded.
|
||||
|
||||
|
||||
```
|
||||
hugo mod verify [flags]
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
```
|
||||
--clean delete module cache for dependencies that fail verification
|
||||
-h, --help help for verify
|
||||
```
|
||||
|
||||
### Options inherited from parent commands
|
||||
|
||||
```
|
||||
--config string config file (default is path/config.yaml|json|toml)
|
||||
--configDir string config dir (default "config")
|
||||
--debug debug output
|
||||
-e, --environment string build environment
|
||||
--ignoreVendor ignores any _vendor directory
|
||||
--log enable Logging
|
||||
--logFile string log File path (if set, logging enabled automatically)
|
||||
--quiet build in quiet mode
|
||||
-s, --source string filesystem path to read files relative from
|
||||
--themesDir string filesystem path to themes directory
|
||||
-v, --verbose verbose output
|
||||
--verboseLog verbose logging
|
||||
```
|
||||
|
||||
### SEE ALSO
|
||||
|
||||
* [hugo mod](/commands/hugo_mod/) - Various Hugo Modules helpers.
|
||||
|
||||
###### Auto generated by spf13/cobra on 19-Feb-2020
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-02-19
|
||||
title: "hugo new"
|
||||
slug: hugo_new
|
||||
url: /commands/hugo_new/
|
||||
@@ -26,7 +26,7 @@ hugo new [path] [flags]
|
||||
### Options
|
||||
|
||||
```
|
||||
-b, --baseURL string hostname (and path) to the root, e.g. https://spf13.com/
|
||||
-b, --baseURL string hostname (and path) to the root, e.g. http://spf13.com/
|
||||
-D, --buildDrafts include content marked as draft
|
||||
-E, --buildExpired include expired content
|
||||
-F, --buildFuture include content with publishdate in the future
|
||||
@@ -77,4 +77,4 @@ hugo new [path] [flags]
|
||||
* [hugo new site](/commands/hugo_new_site/) - Create a new site (skeleton)
|
||||
* [hugo new theme](/commands/hugo_new_theme/) - Create a new theme
|
||||
|
||||
###### Auto generated by spf13/cobra on 31-Jul-2019
|
||||
###### Auto generated by spf13/cobra on 19-Feb-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-02-19
|
||||
title: "hugo new site"
|
||||
slug: hugo_new_site
|
||||
url: /commands/hugo_new_site/
|
||||
@@ -47,4 +47,4 @@ hugo new site [path] [flags]
|
||||
|
||||
* [hugo new](/commands/hugo_new/) - Create new content for your site
|
||||
|
||||
###### Auto generated by spf13/cobra on 31-Jul-2019
|
||||
###### Auto generated by spf13/cobra on 19-Feb-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-02-19
|
||||
title: "hugo new theme"
|
||||
slug: hugo_new_theme
|
||||
url: /commands/hugo_new_theme/
|
||||
@@ -46,4 +46,4 @@ hugo new theme [name] [flags]
|
||||
|
||||
* [hugo new](/commands/hugo_new/) - Create new content for your site
|
||||
|
||||
###### Auto generated by spf13/cobra on 31-Jul-2019
|
||||
###### Auto generated by spf13/cobra on 19-Feb-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-02-19
|
||||
title: "hugo server"
|
||||
slug: hugo_server
|
||||
url: /commands/hugo_server/
|
||||
@@ -31,7 +31,7 @@ hugo server [flags]
|
||||
|
||||
```
|
||||
--appendPort append port to baseURL (default true)
|
||||
-b, --baseURL string hostname (and path) to the root, e.g. https://spf13.com/
|
||||
-b, --baseURL string hostname (and path) to the root, e.g. http://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
|
||||
@@ -90,4 +90,4 @@ hugo server [flags]
|
||||
|
||||
* [hugo](/commands/hugo/) - hugo builds your site
|
||||
|
||||
###### Auto generated by spf13/cobra on 31-Jul-2019
|
||||
###### Auto generated by spf13/cobra on 19-Feb-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-02-19
|
||||
title: "hugo version"
|
||||
slug: hugo_version
|
||||
url: /commands/hugo_version/
|
||||
@@ -43,4 +43,4 @@ hugo version [flags]
|
||||
|
||||
* [hugo](/commands/hugo/) - hugo builds your site
|
||||
|
||||
###### Auto generated by spf13/cobra on 31-Jul-2019
|
||||
###### Auto generated by spf13/cobra on 19-Feb-2020
|
||||
|
||||
@@ -53,7 +53,6 @@ There are a few alternatives to commenting on static sites for those who do not
|
||||
|
||||
* [Static Man](https://staticman.net/)
|
||||
* [Talkyard](https://www.talkyard.io/blog-comments) (Open source, & serverless hosting)
|
||||
* [txtpen](https://txtpen.github.io/hn/)
|
||||
* [IntenseDebate](https://intensedebate.com/)
|
||||
* [Graph Comment][]
|
||||
* [Muut](https://muut.com/)
|
||||
@@ -64,16 +63,6 @@ There are a few alternatives to commenting on static sites for those who do not
|
||||
* [Commento](https://commento.io/) (Open Source, available as a service, local install, or docker image)
|
||||
* [JustComments](https://just-comments.com) (Open Source, available as a service, can be self-hosted)
|
||||
|
||||
<!-- I don't think this is worth including in the documentation since it seems that Steve is no longer supporting or developing this project. rdwatters - 2017-02-29.-->
|
||||
<!-- * [Kaiju](https://github.com/spf13/kaiju) -->
|
||||
|
||||
<!-- ## Kaiju
|
||||
|
||||
[Kaiju](https://github.com/spf13/kaiju) is an open-source project started by [spf13](https://spf13.com/) (Hugo’s author) to bring easy and fast real time discussions to the web.
|
||||
|
||||
Written using Go, Socket.io, and [MongoDB][], Kaiju is very fast and easy to deploy.
|
||||
|
||||
It is in early development but shows promise. If you have interest, please help by contributing via pull request, [opening an issue in the Kaiju GitHub repository][kaijuissue], or [Tweeting about it][tweet]. Every bit helps. -->
|
||||
|
||||
[configuration]: /getting-started/configuration/
|
||||
[disquspartial]: /templates/partials/#disqus
|
||||
|
||||
@@ -16,7 +16,7 @@ menu:
|
||||
|
||||
## The Image Page Resource
|
||||
|
||||
The `image` is a [Page Resource]({{< relref "/content-management/page-resources" >}}), and the processing methods listed below does not work on images inside your `/static` folder.
|
||||
The `image` is a [Page Resource]({{< relref "/content-management/page-resources" >}}), and the processing methods listed below do not work on images inside your `/static` folder.
|
||||
|
||||
To get all images in a [Page Bundle]({{< relref "/content-management/organization#page-bundles" >}}):
|
||||
|
||||
@@ -88,7 +88,7 @@ Sometimes it can be useful to create the filter chain once and then reuse it:
|
||||
|
||||
Provides an [Exif](https://en.wikipedia.org/wiki/Exif) object with metadata about the image.
|
||||
|
||||
Note that this is only suported for JPG and TIFF images, so it's recommended to wrap the access with a `with`, e.g.:
|
||||
Note that this is only suported for JPEG and TIFF images, so it's recommended to wrap the access with a `with`, e.g.:
|
||||
|
||||
```go-html-template
|
||||
{{ with $img.Exif }}
|
||||
@@ -98,11 +98,12 @@ Tags:
|
||||
{{ range $k, $v := .Tags }}
|
||||
TAG: {{ $k }}: {{ $v }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
```
|
||||
|
||||
#### Exif fields
|
||||
|
||||
Data
|
||||
Date
|
||||
: "photo taken" date/time
|
||||
|
||||
Lat
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 34 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 34 KiB |
@@ -173,7 +173,7 @@ When defined in the front matter, the `slug` can take the place of the filename
|
||||
|
||||
{{< code file="content/posts/old-post.md" >}}
|
||||
---
|
||||
title: New Post
|
||||
title: A new post with the filename old-post.md
|
||||
slug: "new-post"
|
||||
---
|
||||
{{< /code >}}
|
||||
|
||||
@@ -17,7 +17,7 @@ menu:
|
||||
## Properties
|
||||
|
||||
ResourceType
|
||||
: The main type of the resource. For example, a file of MIME type `image/jpg` has the ResourceType `image`.
|
||||
: The main type of the resource. For example, a file of MIME type `image/jpeg` has the ResourceType `image`.
|
||||
|
||||
Name
|
||||
: Default value is the filename (relative to the owning page). Can be set in front matter.
|
||||
@@ -35,7 +35,7 @@ Content
|
||||
: The content of the resource itself. For most resources, this returns a string with the contents of the file. This can be used to inline some resources, such as `<script>{{ (.Resources.GetMatch "myscript.js").Content | safeJS }}</script>` or `<img src="{{ (.Resources.GetMatch "mylogo.png").Content | base64Encode }}">`.
|
||||
|
||||
MediaType
|
||||
: The MIME type of the resource, such as `image/jpg`.
|
||||
: The MIME type of the resource, such as `image/jpeg`.
|
||||
|
||||
MediaType.MainType
|
||||
: The main type of the resource's MIME type. For example, a file of MIME type `application/pdf` has for MainType `application`.
|
||||
@@ -67,7 +67,7 @@ GetMatch
|
||||
```go
|
||||
// Using Match/GetMatch to find this images/sunset.jpg ?
|
||||
.Resources.Match "images/sun*" ✅
|
||||
.Resources.Match "**/Sunset.jpg" ✅
|
||||
.Resources.Match "**/sunset.jpg" ✅
|
||||
.Resources.Match "images/*.jpg" ✅
|
||||
.Resources.Match "**.jpg" ✅
|
||||
.Resources.Match "*" 🚫
|
||||
@@ -78,7 +78,7 @@ GetMatch
|
||||
|
||||
## Page Resources Metadata
|
||||
|
||||
Page Resources' metadata is managed from their page's front matter with an array/table parameter named `resources`. You can batch assign values using a [wildcards](http://tldp.org/LDP/GNU-Linux-Tools-Summary/html/x11655.htm).
|
||||
The page resources' metadata is managed from the corresponding page's front matter with an array/table parameter named `resources`. You can batch assign values using [wildcards](http://tldp.org/LDP/GNU-Linux-Tools-Summary/html/x11655.htm).
|
||||
|
||||
{{% note %}}
|
||||
Resources of type `page` get `Title` etc. from their own front matter.
|
||||
@@ -135,7 +135,7 @@ From the example above:
|
||||
- Every docx in the bundle will receive the `word` icon.
|
||||
|
||||
{{% warning %}}
|
||||
The __order matters__ --- Only the **first set** values of the `title`, `name` and `params`-**keys** will be used. Consecutive parameters will be set only for the ones not already set. For example, in the above example, `.Params.icon` is already first set to `"photo"` in `src = "documents/photo_specs.pdf"`. So that would not get overridden to `"pdf"` by the later set `src = "**.pdf"` rule.
|
||||
The __order matters__ --- Only the **first set** values of the `title`, `name` and `params`-**keys** will be used. Consecutive parameters will be set only for the ones not already set. In the above example, `.Params.icon` is first set to `"photo"` in `src = "documents/photo_specs.pdf"`. So that would not get overridden to `"pdf"` by the later set `src = "**.pdf"` rule.
|
||||
{{%/ warning %}}
|
||||
|
||||
### The `:counter` placeholder in `name` and `title`
|
||||
|
||||
@@ -51,6 +51,17 @@ Here are two examples of paired shortcodes:
|
||||
|
||||
The examples above use two different delimiters, the difference being the `%` character in the first and the `<>` characters in the second.
|
||||
|
||||
### Shortcodes with raw string parameters
|
||||
|
||||
{{< new-in "0.64.1" >}}
|
||||
|
||||
You can pass multiple lines as parameters to a shortcode by using raw string literals:
|
||||
|
||||
```
|
||||
{{</* myshortcode `This is some <b>HTML</b>,
|
||||
and a new line with a "quouted string".` */>}}
|
||||
```
|
||||
|
||||
### Shortcodes with Markdown
|
||||
|
||||
In Hugo `0.55` we changed how the `%` delimiter works. Shortcodes using the `%` as the outer-most delimiter will now be fully rendered when sent to the content renderer (e.g. Blackfriday for Markdown), meaning they can be part of the generated table of contents, footnotes, etc.
|
||||
|
||||
@@ -74,11 +74,9 @@ func GetTitleFunc(style string) func(s string) string {
|
||||
case "go":
|
||||
return strings.Title
|
||||
case "chicago":
|
||||
tc := transform.NewTitleConverter(transform.ChicagoStyle)
|
||||
return tc.Title
|
||||
return transform.NewTitleConverter(transform.ChicagoStyle)
|
||||
default:
|
||||
tc := transform.NewTitleConverter(transform.APStyle)
|
||||
return tc.Title
|
||||
return transform.NewTitleConverter(transform.APStyle)
|
||||
}
|
||||
}
|
||||
{{< / highlight >}}
|
||||
@@ -93,14 +91,10 @@ See [Highlight](/functions/highlight/).
|
||||
|
||||
Highlighting in code fences is enabled by default.{{< new-in "0.60.0" >}}
|
||||
|
||||
````
|
||||
```go-html-template{hl_lines=[3,"5-6"],linenos=true}
|
||||
```
|
||||
````
|
||||
|
||||
````
|
||||
```go {linenos=table,hl_lines=[8,"15-17"],linenostart=199}
|
||||
// ... code
|
||||
```
|
||||
````
|
||||
|
||||
|
||||
@@ -122,11 +116,9 @@ func GetTitleFunc(style string) func(s string) string {
|
||||
case "go":
|
||||
return strings.Title
|
||||
case "chicago":
|
||||
tc := transform.NewTitleConverter(transform.ChicagoStyle)
|
||||
return tc.Title
|
||||
return transform.NewTitleConverter(transform.ChicagoStyle)
|
||||
default:
|
||||
tc := transform.NewTitleConverter(transform.APStyle)
|
||||
return tc.Title
|
||||
return transform.NewTitleConverter(transform.APStyle)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -18,7 +18,11 @@ toc: true
|
||||
---
|
||||
|
||||
{{% note "TOC Heading Levels are Fixed" %}}
|
||||
Currently, the `{{.TableOfContents}}` [page variable](/variables/page/) does not allow you to specify which heading levels you want the TOC to render. [See the related GitHub discussion (#1778)](https://github.com/gohugoio/hugo/issues/1778). As such, the resulting `<nav id="TableOfContents"><ul></ul></nav>` is going to start at `<h1>` when pulling from `{{.Content}}`.
|
||||
|
||||
Previously, there was no out-of-the-box way to specify which heading levels you want the TOC to render. [See the related GitHub discussion (#1778)](https://github.com/gohugoio/hugo/issues/1778). As such, the resulting `<nav id="TableOfContents"><ul></ul></nav>` was going to start at `<h1>` when pulling from `{{.Content}}`.
|
||||
|
||||
Hugo [v0.60.0](https://github.com/gohugoio/hugo/releases/tag/v0.60.0) made a switch to [Goldmark](https://github.com/yuin/goldmark/) as the default library for Markdown which has improved and configurable implementation of TOC. Take a look at [how to configure TOC](/getting-started/configuration-markup/#table-of-contents) for Goldmark renderer.
|
||||
|
||||
{{% /note %}}
|
||||
|
||||
## Usage
|
||||
@@ -43,7 +47,7 @@ A collection of textile samples lay spread out on the table - Samsa was a travel
|
||||
|
||||
Hugo will take this Markdown and create a table of contents from `## Introduction`, `## My Heading`, and `### My Subheading` and then store it in the [page variable][pagevars]`.TableOfContents`.
|
||||
|
||||
The built-in `.TableOfContents` variables outputs a `<nav id="TableOfContents">` element with a child `<ul>`, whose child `<li>` elements begin with any `<h1>`'s (i.e., `#` in markdown) inside your content.'
|
||||
The built-in `.TableOfContents` variables outputs a `<nav id="TableOfContents">` element with a child `<ul>`, whose child `<li>` elements begin with appropriate HTML headings. See [the available settings](/getting-started/configuration-markup/#table-of-contents) to configure what heading levels you want to include in TOC.
|
||||
|
||||
{{% note "Table of contents not available for MMark" %}}
|
||||
Hugo documents created in the [MMark](/content-management/formats/#mmark) Markdown dialect do not currently display TOCs. TOCs are, however, compatible with all other supported Markdown formats.
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
---
|
||||
title: Content Types
|
||||
linktitle: Types
|
||||
description: Hugo supports sites with multiple content types and assumes your site will be organized into sections, where each section represents the corresponding type.
|
||||
description: Hugo is built around content organized in sections.
|
||||
date: 2017-02-01
|
||||
publishdate: 2017-02-01
|
||||
lastmod: 2017-02-01
|
||||
categories: [content management]
|
||||
keywords: [lists,sections,content types,types,organization]
|
||||
menu:
|
||||
@@ -17,83 +14,11 @@ aliases: [/content/types]
|
||||
toc: true
|
||||
---
|
||||
|
||||
A **content type** can have a unique set of metadata (i.e., [front matter][]) or customized [template][] and can be created by the `hugo new` command via [archetypes][].
|
||||
A **content type** is a way to organize your content. Hugo resolves the content type from either the `type` in front matter or, if not set, the first directory in the file path. E.g. `content/blog/my-first-event.md` will be of type `blog` if no `type` set.
|
||||
|
||||
## What is a Content Type
|
||||
A content type is used to
|
||||
|
||||
[Tumblr][] is a good example of a website with multiple content types. A piece of "content" could be a photo, quote, or a post, each with different sets of metadata and different visual rendering.
|
||||
|
||||
## Assign a Content Type
|
||||
|
||||
Hugo assumes that your site will be organized into [sections][] and each section represents a corresponding type. This is to reduce the amount of configuration necessary for new Hugo projects.
|
||||
|
||||
If you are taking advantage of this default behavior, each new piece of content you place into a section will automatically inherit the type. Therefore a new file created at `content/posts/new-post.md` will automatically be assigned the type `posts`. Alternatively, you can set the content type in a content file's [front matter][] in the field "`type`".
|
||||
|
||||
## Create New Content of a Specific Type
|
||||
|
||||
You can manually add files to your content directories, but Hugo can create and populate a new content file with preconfigured front matter via [archetypes][].
|
||||
|
||||
## Define a Content Type
|
||||
|
||||
Creating a new content type is easy. You simply define the templates and archetype unique to your new content type, or Hugo will use defaults.
|
||||
* Determine how the content is rendered. See [Template Lookup Order](/templates/lookup-order/) and [Content Views](https://gohugo.io/templates/views) for more.
|
||||
* Determine which [archetype](/content-management/archetypes/) template to use for new content.
|
||||
|
||||
|
||||
{{% note "Declaring Content Types" %}}
|
||||
Remember, all of the following are *optional*. If you do not specifically declare content types in your front matter or develop specific layouts for content types, Hugo is smart enough to assume the content type from the file path and section. (See [Content Sections](/content-management/sections/) for more information.)
|
||||
{{% /note %}}
|
||||
|
||||
The following examples take you stepwise through creating a new type layout for a content file that contains the following front matter:
|
||||
|
||||
{{< code file="content/events/my-first-event.md" copy="false" >}}
|
||||
+++
|
||||
title = My First Event
|
||||
date = "2016-06-24T19:20:04-07:00"
|
||||
description = "Today is my 36th birthday. How time flies."
|
||||
type = "event"
|
||||
layout = "birthday"
|
||||
+++
|
||||
{{< /code >}}
|
||||
|
||||
By default, Hugo assumes `*.md` under `events` is of the `events` content type. However, we have specified that this particular file at `content/events/my-first-event.md` is of type `event` and should render using the `birthday` layout.
|
||||
|
||||
### Create a Type Layout Directory
|
||||
|
||||
Create a directory with the name of the type in `/layouts`. For creating these custom layouts, **type is always singular**; e.g., `events => event` and `posts => post`.
|
||||
|
||||
For this example, you need to create `layouts/event/birthday.html`.
|
||||
|
||||
{{% note %}}
|
||||
If you have multiple content files in your `events` directory that are of the `special` type and you don't want to define the `layout` specifically for each piece of content, you can create a layout at `layouts/special/single.html` to observe the [single page template lookup order](/templates/single-page-templates/).
|
||||
{{% /note %}}
|
||||
|
||||
{{% warning %}}
|
||||
With the "everything is a page" data model introduced in v0.18 (see [Content Organization](/content-management/organization/)), you can use `_index.md` in content directories to add both content and front matter to [list pages](/templates/lists/).
|
||||
{{% /warning %}}
|
||||
|
||||
### Create Views
|
||||
|
||||
Many sites support rendering content in a few different ways; e.g., a single page view and a summary view to be used when displaying a [list of section contents][sectiontemplates].
|
||||
|
||||
Hugo limits assumptions about how you want to display your content to an intuitive set of sane defaults and will support as many different views of a content type as your site requires. All that is required for these additional views is that a template exists in each `/layouts/<TYPE>` directory with the same name.
|
||||
|
||||
### Custom Content Type Template Lookup Order
|
||||
|
||||
The lookup order for the `content/events/my-first-event.md` templates would be as follows:
|
||||
|
||||
* `layouts/event/birthday.html`
|
||||
* `layouts/event/single.html`
|
||||
* `layouts/events/single.html`
|
||||
* `layouts/_default/single.html`
|
||||
|
||||
### Create a Corresponding Archetype
|
||||
|
||||
We can then create a custom archetype with preconfigured front matter at `event.md` in the `/archetypes` directory; i.e. `archetypes/event.md`.
|
||||
|
||||
Read [Archetypes][archetypes] for more information on archetype usage with `hugo new`.
|
||||
|
||||
[archetypes]: /content-management/archetypes/
|
||||
[front matter]: /content-management/front-matter/
|
||||
[sectiontemplates]: /templates/section-templates/
|
||||
[sections]: /content-management/sections/
|
||||
[template]: /templates/
|
||||
[Tumblr]: https://www.tumblr.com/
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
---
|
||||
title: .RenderString
|
||||
description: "Renders markup to HTML."
|
||||
godocref:
|
||||
date: 2019-12-18
|
||||
categories: [functions]
|
||||
menu:
|
||||
docs:
|
||||
parent: "functions"
|
||||
keywords: [markdown,goldmark,render]
|
||||
signature: [".RenderString MARKUP"]
|
||||
---
|
||||
|
||||
{{< new-in "0.62.0" >}}
|
||||
|
||||
`.RenderString` is a method on `Page` that renders some markup to HTML using the content renderer defined for that page (if not set in the options).
|
||||
|
||||
*Note* that this method does not parse and render shortcodes.
|
||||
|
||||
The method takes an optional map argument with these options:
|
||||
|
||||
display ("inline")
|
||||
: `inline` or `block`. If `inline` (default), surrounding ´<p></p>` on short snippets will be trimmed.
|
||||
|
||||
markup (defaults to the Page's markup)
|
||||
: See identifiers in [List of content formats](/content-management/formats/#list-of-content-formats).
|
||||
|
||||
Some examples:
|
||||
|
||||
```go-html-template
|
||||
{{ $optBlock := dict "display" "block" }}
|
||||
{{ $optOrg := dict "markup" "org" }}
|
||||
{{ "**Bold Markdown**" | $p.RenderString }}
|
||||
{{ "**Bold Block Markdown**" | $p.RenderString $optBlock }}
|
||||
{{ "/italic org mode/" | $p.RenderString $optOrg }}
|
||||
```
|
||||
|
||||
|
||||
**Note** that this method is more powerful than the similar [markdownify](/functions/markdownify/) function as it also supports [Render Hooks](/getting-started/configuration-markup/#markdown-render-hooks) and it has options to render other markup formats.
|
||||
@@ -1,7 +1,6 @@
|
||||
---
|
||||
title: errorf
|
||||
linktitle: errorf
|
||||
description: Log ERROR and fail the build from the templates.
|
||||
title: errorf and warnf
|
||||
description: Log ERROR or WARNING from the templates.
|
||||
date: 2017-09-30
|
||||
publishdate: 2017-09-30
|
||||
lastmod: 2017-09-30
|
||||
@@ -15,15 +14,20 @@ workson: []
|
||||
hugoversion:
|
||||
relatedfuncs: [printf]
|
||||
deprecated: false
|
||||
aliases: []
|
||||
---
|
||||
|
||||
`errorf` will evaluate a format string, then output the result to the ERROR log (and only once per error message to avoid flooding the log).
|
||||
`errorf` or `warnf` will evaluate a format string, then output the result to the ERROR or WARNING log (and only once per error message to avoid flooding the log).
|
||||
|
||||
This will also cause the build to fail (the `hugo` command will `exit -1`).
|
||||
Any ERROR will also cause the build to fail (the `hugo` command will `exit -1`).
|
||||
|
||||
Both functions return an empty string, so the messages are only printed to the console.
|
||||
|
||||
```
|
||||
{{ errorf "Failed to handle page %q" .Path }}
|
||||
```
|
||||
|
||||
Note that `errorf` supports all the formatting verbs of the [fmt](https://golang.org/pkg/fmt/) package.
|
||||
```
|
||||
{{ warnf "You should update the shortcodes in %q" .Path }}
|
||||
```
|
||||
|
||||
Note that `errorf` and `warnf` support all the formatting verbs of the [fmt](https://golang.org/pkg/fmt/) package.
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
---
|
||||
title: hugo
|
||||
linktitle: hugo
|
||||
description: The `hugo` function provides easy access to Hugo-related data.
|
||||
godocref:
|
||||
date: 2019-01-31
|
||||
publishdate: 2019-01-31
|
||||
lastmod: 2019-01-31
|
||||
keywords: []
|
||||
categories: [functions]
|
||||
menu:
|
||||
docs:
|
||||
parent: "functions"
|
||||
toc:
|
||||
signature: ["hugo"]
|
||||
workson: []
|
||||
hugoversion:
|
||||
relatedfuncs: []
|
||||
deprecated: false
|
||||
draft: false
|
||||
aliases: []
|
||||
---
|
||||
|
||||
`hugo` returns an instance that contains the following functions:
|
||||
|
||||
hugo.Generator
|
||||
: `<meta>` tag for the version of Hugo that generated the site. `hugo.Generator` outputs a *complete* HTML tag; e.g. `<meta name="generator" content="Hugo 0.63.2" />`
|
||||
|
||||
hugo.Version
|
||||
: the current version of the Hugo binary you are using e.g. `0.63.2`
|
||||
|
||||
|
||||
`hugo` returns an instance that contains the following functions:
|
||||
|
||||
hugo.Environment
|
||||
: the current running environment as defined through the `--environment` cli tag.
|
||||
|
||||
hugo.CommitHash
|
||||
: the git commit hash of the current Hugo binary e.g. `0e8bed9ccffba0df554728b46c5bbf6d78ae5247`
|
||||
|
||||
hugo.BuildDate
|
||||
: the compile date of the current Hugo binary formatted with RFC 3339 e.g. `2002-10-02T10:00:00-05:00`
|
||||
|
||||
|
||||
|
||||
{{% note "Use the Hugo Generator Tag" %}}
|
||||
We highly recommend using `hugo.Generator` in your website's `<head>`. `hugo.Generator` is included by default in all themes hosted on [themes.gohugo.io](https://themes.gohugo.io). The generator tag allows the Hugo team to track the usage and popularity of Hugo.
|
||||
{{% /note %}}
|
||||
|
||||
@@ -37,7 +37,3 @@ A more practical example is to fill in the missing translations from the other l
|
||||
{{ $pages = $pages | lang.Merge .Site.RegularPages }}
|
||||
{{ end }}
|
||||
```
|
||||
|
||||
{{% note %}}
|
||||
Note that the slightly ugly `.Scratch` construct will not be needed once this is fixed: https://github.com/golang/go/issues/10608
|
||||
{{% /note %}}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user