mirror of
https://github.com/gohugoio/hugo.git
synced 2026-09-01 19:22:38 +00:00
Compare commits
256 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a301f6b2ae | |||
| 646bc85088 | |||
| 5c0d10045d | |||
| 81f5633245 | |||
| 9698b0dab1 | |||
| 32344fe3db | |||
| 4d7fa9f114 | |||
| a985efcecf | |||
| 6c3c6686f5 | |||
| c34bf48560 | |||
| 833d16d467 | |||
| 06150c87be | |||
| 330e52ebe6 | |||
| 9e78235374 | |||
| 7cd66c53b9 | |||
| 723ec555e7 | |||
| 518d149646 | |||
| e0e81b280f | |||
| c9403cbcea | |||
| 3cc41523be | |||
| 2fd0a5a678 | |||
| 6e051c053e | |||
| 423b8f2fb8 | |||
| 991934497e | |||
| 558c09305e | |||
| b69a36140f | |||
| a0103864ab | |||
| b342e8fbdb | |||
| 6205d56b85 | |||
| a5039dddaf | |||
| 7f47b99ea9 | |||
| b98e2f66b0 | |||
| 57ebab7c23 | |||
| 0e314925fb | |||
| e4621446ce | |||
| 89044b8f87 | |||
| 01befcce35 | |||
| 04b1a6d997 | |||
| dd31e80007 | |||
| 6add6d77b4 | |||
| 2a171ff1c5 | |||
| 67f920419a | |||
| c03ea2b660 | |||
| fe60b7d9e4 | |||
| c2d9fd1ebe | |||
| ec9dcf3048 | |||
| 03802ff3cb | |||
| 5e31198c98 | |||
| 8d5766d417 | |||
| 5c41f41ad4 | |||
| 27a4c4410c | |||
| ade27699e5 | |||
| 17661debb6 | |||
| 8549189e8e | |||
| c2c7a4ce5b | |||
| 49e6c8cb4e | |||
| f37e77f2d3 | |||
| 27af5a339a | |||
| b3c825756f | |||
| 5146dc614f | |||
| 736f84b2d5 | |||
| cd4d820201 | |||
| 2b28e5a9cb | |||
| 102ec2da7a | |||
| feaa582cbe | |||
| ee67dbeff5 | |||
| 4a3f2427ed | |||
| 4205844bce | |||
| 9b55d13589 | |||
| 6f56a636f6 | |||
| 5ec7fa343a | |||
| b7ff4dc23e | |||
| da3c3e5fbd | |||
| 30748decf1 | |||
| 095bf64c99 | |||
| 7791a804e2 | |||
| c774b230e9 | |||
| 2f721f8ec6 | |||
| 8568928aa8 | |||
| 1bc93021e3 | |||
| 7eba37ae9b | |||
| efc61d6f3b | |||
| d8d6a25b57 | |||
| 9f12be54ee | |||
| 4437e918cd | |||
| 4de3ecdc26 | |||
| 1123711b09 | |||
| 3d84ef9720 | |||
| c494c37a45 | |||
| 9c9987535f | |||
| 4a39564efe | |||
| b6e097cfe6 | |||
| 19a8accc9f | |||
| 157669a0e6 | |||
| 8f49df946a | |||
| 1a68ad4e31 | |||
| 523d51948f | |||
| 971b28904b | |||
| 63bbb40dfb | |||
| 73ae6d581d | |||
| e18a2ad3f4 | |||
| cfa73050a4 | |||
| 244e49c0ea | |||
| 98dc46e1a9 | |||
| 87dd5725de | |||
| 8c6a03a92b | |||
| 1ce3e7d521 | |||
| c9dc316ad1 | |||
| 1664a0e893 | |||
| 1e67854b1a | |||
| e1b609af9b | |||
| 8e5566af6e | |||
| 1005f754e0 | |||
| efde7078ed | |||
| 2ebb9f5484 | |||
| 7204b354a9 | |||
| 574c2959b8 | |||
| 99958f90fe | |||
| 1d91d8e14b | |||
| 95f492114e | |||
| c947351d7c | |||
| aa54803a84 | |||
| cc2a5d52a4 | |||
| 52c159c452 | |||
| c7b6d74e89 | |||
| 1a8af7d4f0 | |||
| 03b93bb988 | |||
| 94fb4dc3dd | |||
| 4f44227bd8 | |||
| 99d36237c0 | |||
| e371162c3f | |||
| 5eadc4c0a8 | |||
| 18cb21ff2e | |||
| df298558a5 | |||
| b1106f8715 | |||
| c0177fe2b2 | |||
| 5914f91b6c | |||
| 5b4659fa0b | |||
| 7f1da3efcd | |||
| f7d4b01c6d | |||
| b809b9680d | |||
| a9c91361c2 | |||
| 63393230c9 | |||
| 6b61f2a5bb | |||
| 14e369b961 | |||
| 6cceef65c2 | |||
| ffcb4aeb8e | |||
| 8279d2e227 | |||
| c4fa2f0799 | |||
| 108314444b | |||
| 51e178a6a2 | |||
| cb12f41a96 | |||
| 78c3c78fca | |||
| 713132cd4b | |||
| bbaefd7e3e | |||
| cc1a718860 | |||
| 6a34f88dcc | |||
| ae383f04c8 | |||
| ee31e61fb0 | |||
| 760a87a45a | |||
| 3d3fa5c3fe | |||
| ee3d02134d | |||
| 8947c3fa0b | |||
| d7798906d8 | |||
| 305ce1c9ec | |||
| 3e9db2ad95 | |||
| 449deb7f9c | |||
| 1746e8a9b2 | |||
| 6f48146e75 | |||
| b0d850321e | |||
| b66d38c419 | |||
| 05a74eaec0 | |||
| 33ae621083 | |||
| 1352bc880d | |||
| d184e5059c | |||
| 322c285ba2 | |||
| 211ba42a95 | |||
| 0ac528d746 | |||
| d8bde266c1 | |||
| 0bd6356c6d | |||
| ca68abf0bc | |||
| a524124beb | |||
| c1eb625124 | |||
| 1510f07780 | |||
| aa2ef45421 | |||
| 76b2afe642 | |||
| f460530347 | |||
| 4c2a0de412 | |||
| 6be6684cc5 | |||
| dbaa15d40f | |||
| a449e87da7 | |||
| 7ef5a4c83e | |||
| a70bbd0696 | |||
| 24afe2b822 | |||
| 9fd7d3957e | |||
| c45025cb90 | |||
| a5ebdf7d17 | |||
| 9bdedb251c | |||
| dce210ab56 | |||
| 0b96aba022 | |||
| fa520a2d98 | |||
| 4b670bc8cc | |||
| 82029c1ec9 | |||
| 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 |
@@ -1,6 +1,6 @@
|
||||
defaults: &defaults
|
||||
docker:
|
||||
- image: bepsays/ci-goreleaser:1.13-4
|
||||
- image: bepsays/ci-goreleaser:1.14.3
|
||||
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: .
|
||||
|
||||
@@ -20,6 +20,7 @@ dock.sh
|
||||
GoBuilds
|
||||
dist
|
||||
|
||||
hugolib/hugo_stats.json
|
||||
resources/sunset.jpg
|
||||
|
||||
vendor
|
||||
|
||||
+4
-4
@@ -11,10 +11,9 @@ env:
|
||||
|
||||
git:
|
||||
depth: false
|
||||
|
||||
go:
|
||||
- "1.12.13"
|
||||
- "1.13.4"
|
||||
- "1.13.11"
|
||||
- "1.14.3"
|
||||
- master
|
||||
|
||||
arch:
|
||||
@@ -64,7 +63,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;
|
||||
|
||||
+3
-3
@@ -48,15 +48,15 @@ Hugo has become a fully featured static site generator, so any new functionality
|
||||
* strive not to break existing sites.
|
||||
* close or update an open [Hugo issue](https://github.com/gohugoio/hugo/issues)
|
||||
|
||||
If it is of some complexity, the contributor is expected to maintain and support the new future (answer questions on the forum, fix any bugs etc.).
|
||||
If it is of some complexity, the contributor is expected to maintain and support the new feature in the future (answer questions on the forum, fix any bugs etc.).
|
||||
|
||||
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.
|
||||
|
||||
+1
-1
@@ -33,7 +33,7 @@ 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
|
||||
|
||||
@@ -124,64 +124,67 @@ Hugo stands on the shoulder of many great open source libraries, in lexical orde
|
||||
|
||||
| Dependency | License |
|
||||
| :------------- | :------------- |
|
||||
| [github.com/alecthomas/chroma](https://github.com/alecthomas/chroma) | MIT License |
|
||||
| [github.com/armon/go-radix](https://github.com/armon/go-radix) | MIT License |
|
||||
| [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) | Apache License 2.0 |
|
||||
| [github.com/bep/debounce](https://github.com/bep/debounce) | MIT License |
|
||||
| [github.com/bep/gitmap](https://github.com/bep/gitmap) | MIT License |
|
||||
| [github.com/bep/golibsass](https://github.com/bep/golibsass) | MIT License |
|
||||
| [github.com/bep/tmc](https://github.com/bep/tmc) | MIT License |
|
||||
| [github.com/BurntSushi/locker](https://github.com/BurntSushi/locker) | The Unlicense |
|
||||
| [github.com/BurntSushi/toml](https://github.com/BurntSushi/toml) | MIT License |
|
||||
| [github.com/PuerkitoBio/purell](https://github.com/PuerkitoBio/purell) | BSD 3-Clause "New" or "Revised" License |
|
||||
| [github.com/PuerkitoBio/urlesc](https://github.com/PuerkitoBio/urlesc) | BSD 3-Clause "New" or "Revised" License |
|
||||
| [github.com/alecthomas/chroma](https://github.com/alecthomas/chroma) | MIT License |
|
||||
| [github.com/bep/debounce](https://github.com/bep/debounce) | MIT License |
|
||||
| [github.com/bep/gitmap](https://github.com/bep/gitmap) | MIT License |
|
||||
| [github.com/bep/go-tocss](https://github.com/bep/go-tocss) | MIT License |
|
||||
| [github.com/niklasfasching/go-org](https://github.com/niklasfasching/go-org) | MIT License |
|
||||
| [github.com/cpuguy83/go-md2man](https://github.com/cpuguy83/go-md2man) | MIT License |
|
||||
| [github.com/danwakefield/fnmatch](https://github.com/danwakefield/fnmatch) | BSD 2-Clause "Simplified" License |
|
||||
| [github.com/disintegration/imaging](https://github.com/disintegration/imaging) | MIT License |
|
||||
| [github.com/dlclark/regexp2](https://github.com/dlclark/regexp2) | MIT License |
|
||||
| [github.com/eknkc/amber](https://github.com/eknkc/amber) | MIT License |
|
||||
| [github.com/fsnotify/fsnotify](https://github.com/fsnotify/fsnotify) | BSD 3-Clause "New" or "Revised" License |
|
||||
| [github.com/disintegration/gift](https://github.com/disintegration/gift) | MIT License |
|
||||
| [github.com/dustin/go-humanize](https://github.com/dustin/go-humanize) | MIT License |
|
||||
| [github.com/fsnotify/fsnotify](https://github.com/fsnotify/fsnotify) | BSD 3-Clause "New" or "Revised" License |
|
||||
| [github.com/gobwas/glob](https://github.com/gobwas/glob) | MIT License |
|
||||
| [github.com/gorilla/websocket](https://github.com/gorilla/websocket) | BSD 2-Clause "Simplified" License |
|
||||
| [github.com/hashicorp/go-immutable-radix](https://github.com/hashicorp/go-immutable-radix) | Mozilla Public License 2.0 |
|
||||
| [github.com/gorilla/websocket](https://github.com/gorilla/websocket) | BSD 2-Clause "Simplified" License |
|
||||
| [github.com/hashicorp/golang-lru](https://github.com/hashicorp/golang-lru) | Mozilla Public License 2.0 |
|
||||
| [github.com/hashicorp/hcl](https://github.com/hashicorp/hcl) | Mozilla Public License 2.0 |
|
||||
| [github.com/jdkato/prose](https://github.com/jdkato/prose) | MIT License |
|
||||
| [github.com/kyokomi/emoji](https://github.com/kyokomi/emoji) | MIT License |
|
||||
| [github.com/hashicorp/hcl](https://github.com/hashicorp/hcl) | Mozilla Public License 2.0 |
|
||||
| [github.com/jdkato/prose](https://github.com/jdkato/prose) | MIT License |
|
||||
| [github.com/kr/pretty](https://github.com/kr/pretty) | MIT License |
|
||||
| [github.com/kyokomi/emoji](https://github.com/kyokomi/emoji) | MIT License |
|
||||
| [github.com/magiconair/properties](https://github.com/magiconair/properties) | BSD 2-Clause "Simplified" License |
|
||||
| [github.com/markbates/inflect](https://github.com/markbates/inflect) | MIT License |
|
||||
| [github.com/markbates/inflect](https://github.com/markbates/inflect) | MIT License |
|
||||
| [github.com/mattn/go-isatty](https://github.com/mattn/go-isatty) | MIT License |
|
||||
| [github.com/mattn/go-runewidth](https://github.com/mattn/go-runewidth) | MIT License |
|
||||
| [github.com/miekg/mmark](https://github.com/miekg/mmark) | Simplified BSD License |
|
||||
| [github.com/mitchellh/hashstructure](https://github.com/mitchellh/hashstructure) | MIT License |
|
||||
| [github.com/mitchellh/mapstructure](https://github.com/mitchellh/mapstructure) | MIT License |
|
||||
| [github.com/muesli/smartcrop](https://github.com/muesli/smartcrop) | MIT License |
|
||||
| [github.com/muesli/smartcrop](https://github.com/muesli/smartcrop) | MIT License |
|
||||
| [github.com/nicksnyder/go-i18n](https://github.com/nicksnyder/go-i18n) | MIT License |
|
||||
| [github.com/niklasfasching/go-org](https://github.com/niklasfasching/go-org) | MIT License |
|
||||
| [github.com/olekukonko/tablewriter](https://github.com/olekukonko/tablewriter) | MIT License |
|
||||
| [github.com/pelletier/go-toml](https://github.com/pelletier/go-toml) | MIT License |
|
||||
| [github.com/pkg/errors](https://github.com/pkg/errors) | BSD 2-Clause "Simplified" License |
|
||||
| [github.com/pelletier/go-toml](https://github.com/pelletier/go-toml) | MIT License |
|
||||
| [github.com/pkg/errors](https://github.com/pkg/errors) | BSD 2-Clause "Simplified" License |
|
||||
| [github.com/PuerkitoBio/purell](https://github.com/PuerkitoBio/purell) | BSD 3-Clause "New" or "Revised" License |
|
||||
| [github.com/PuerkitoBio/urlesc](https://github.com/PuerkitoBio/urlesc) | BSD 3-Clause "New" or "Revised" License |
|
||||
| [github.com/rogpeppe/go-internal](https://github.com/rogpeppe/go-internal) | BSD 3-Clause "New" or "Revised" License |
|
||||
| [github.com/russross/blackfriday](https://github.com/russross/blackfriday) | Simplified BSD License |
|
||||
| [github.com/shurcooL/sanitized_anchor_name](https://github.com/shurcooL/sanitized_anchor_name) | MIT License |
|
||||
| [github.com/rwcarlsen/goexif](https://github.com/rwcarlsen/goexif) | BSD 2-Clause "Simplified" License |
|
||||
| [github.com/spf13/afero](https://github.com/spf13/afero) | Apache License 2.0 |
|
||||
| [github.com/spf13/cast](https://github.com/spf13/cast) | MIT License |
|
||||
| [github.com/spf13/cast](https://github.com/spf13/cast) | MIT License |
|
||||
| [github.com/spf13/cobra](https://github.com/spf13/cobra) | Apache License 2.0 |
|
||||
| [github.com/spf13/fsync](https://github.com/spf13/fsync) | MIT License |
|
||||
| [github.com/spf13/jwalterweatherman](https://github.com/spf13/jwalterweatherman) | MIT License |
|
||||
| [github.com/spf13/nitro](https://github.com/spf13/nitro) | Apache License 2.0 |
|
||||
| [github.com/spf13/pflag](https://github.com/spf13/pflag) | BSD 3-Clause "New" or "Revised" License |
|
||||
| [github.com/spf13/viper](https://github.com/spf13/viper) | MIT License |
|
||||
| [github.com/tdewolff/minify](https://github.com/tdewolff/minify) | MIT License |
|
||||
| [github.com/tdewolff/parse](https://github.com/tdewolff/parse) | MIT License |
|
||||
| [github.com/wellington/go-libsass](https://github.com/wellington/go-libsass) | Apache License 2.0 |
|
||||
| [github.com/yosssi/ace](https://github.com/yosssi/ace) | MIT License |
|
||||
| [github.com/yuin/goldmark](https://github.com/yuin/goldmark) | MIT License |
|
||||
| [github.com/yuin/goldmark-highlighting](https://github.com/yuin/goldmark-highlighting) | MIT License |
|
||||
| [go.opencensus.io](https://go.opencensus.io) | Apache License 2.0 |
|
||||
| [go.uber.org/atomic](https://go.uber.org/atomic) | MIT License |
|
||||
| [gocloud.dev](https://gocloud.dev) | Apache License 2.0 |
|
||||
| [golang.org/x/image](https://golang.org/x/image) | BSD 3-Clause "New" or "Revised" License |
|
||||
| [golang.org/x/net](https://golang.org/x/net) | BSD 3-Clause "New" or "Revised" License |
|
||||
| [golang.org/x/oauth2](https://golang.org/x/oauth2) | BSD 3-Clause "New" or "Revised" License |
|
||||
| [golang.org/x/sync](https://golang.org/x/sync) | BSD 3-Clause "New" or "Revised" License |
|
||||
| [golang.org/x/sys](https://golang.org/x/sys) | BSD 3-Clause "New" or "Revised" License |
|
||||
| [golang.org/x/text](https://golang.org/x/text) | BSD 3-Clause "New" or "Revised" License
|
||||
| [gopkg.in/yaml.v2](https://gopkg.in/yaml.v2) | Apache License 2.0 |
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
| [golang.org/x/text](https://golang.org/x/text) | BSD 3-Clause "New" or "Revised" License |
|
||||
| [golang.org/x/xerrors](https://golang.org/x/xerrors) | BSD 3-Clause "New" or "Revised" License |
|
||||
| [google.golang.org/api](https://google.golang.org/api) | BSD 3-Clause "New" or "Revised" License |
|
||||
| [google.golang.org/genproto](https://google.golang.org/genproto) | Apache License 2.0 |
|
||||
| [gopkg.in/ini.v1](https://gopkg.in/ini.v1) | Apache License 2.0 |
|
||||
| [gopkg.in/yaml.v2](https://gopkg.in/yaml.v2) | Apache License 2.0 |
|
||||
|
||||
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)
|
||||
|
||||
}
|
||||
|
||||
+17
-21
@@ -18,9 +18,9 @@ import (
|
||||
"errors"
|
||||
"sync"
|
||||
|
||||
"golang.org/x/sync/semaphore"
|
||||
hconfig "github.com/gohugoio/hugo/config"
|
||||
|
||||
"github.com/gohugoio/hugo/modules"
|
||||
"golang.org/x/sync/semaphore"
|
||||
|
||||
"io/ioutil"
|
||||
|
||||
@@ -60,7 +60,8 @@ type commandeerHugoState struct {
|
||||
type commandeer struct {
|
||||
*commandeerHugoState
|
||||
|
||||
logger *loggers.Logger
|
||||
logger *loggers.Logger
|
||||
serverConfig *config.Server
|
||||
|
||||
// Currently only set when in "fast render mode". But it seems to
|
||||
// be fast enough that we could maybe just add it for all server modes.
|
||||
@@ -74,7 +75,7 @@ type commandeer struct {
|
||||
|
||||
visitedURLs *types.EvictingStringQueue
|
||||
|
||||
doWithCommandeer func(c *commandeer) error
|
||||
cfgInit func(c *commandeer) error
|
||||
|
||||
// We watch these for changes.
|
||||
configFiles []string
|
||||
@@ -154,7 +155,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 {
|
||||
@@ -173,12 +174,12 @@ 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),
|
||||
// This will be replaced later, but we need something to log to before the configuration is read.
|
||||
logger: loggers.NewLogger(jww.LevelError, jww.LevelError, out, ioutil.Discard, running),
|
||||
logger: loggers.NewLogger(jww.LevelWarn, jww.LevelError, out, ioutil.Discard, running),
|
||||
}
|
||||
|
||||
return c, c.loadConfig(mustHaveConfigFile, running)
|
||||
@@ -286,12 +287,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
|
||||
}
|
||||
|
||||
@@ -309,17 +310,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
|
||||
}
|
||||
@@ -338,8 +333,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
|
||||
}
|
||||
}
|
||||
@@ -351,6 +346,7 @@ func (c *commandeer) loadConfig(mustHaveConfigFile, running bool) error {
|
||||
|
||||
cfg.Logger = logger
|
||||
c.logger = logger
|
||||
c.serverConfig = hconfig.DecodeServer(cfg.Cfg)
|
||||
|
||||
createMemFs := config.GetBool("renderToMemory")
|
||||
|
||||
|
||||
+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
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ func (g *genChromaStyles) generate() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
formatter := html.New(html.WithClasses(true))
|
||||
formatter := html.New(html.WithAllClasses(true))
|
||||
formatter.WriteCSS(os.Stdout, style)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ func (g *genDocsHelper) generate() error {
|
||||
enc := json.NewEncoder(f)
|
||||
enc.SetIndent("", " ")
|
||||
|
||||
if err := enc.Encode(docshelper.DocProviders); err != nil {
|
||||
if err := enc.Encode(docshelper.GetDocProvider()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
+13
-14
@@ -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
|
||||
}
|
||||
@@ -231,11 +231,6 @@ func initializeFlags(cmd *cobra.Command, cfg config.Provider) {
|
||||
"duplicateTargetPaths",
|
||||
}
|
||||
|
||||
// Will set a value even if it is the default.
|
||||
flagKeysForced := []string{
|
||||
"minify",
|
||||
}
|
||||
|
||||
for _, key := range persFlagKeys {
|
||||
setValueFromFlag(cmd.PersistentFlags(), key, cfg, "", false)
|
||||
}
|
||||
@@ -243,9 +238,7 @@ func initializeFlags(cmd *cobra.Command, cfg config.Provider) {
|
||||
setValueFromFlag(cmd.Flags(), key, cfg, "", false)
|
||||
}
|
||||
|
||||
for _, key := range flagKeysForced {
|
||||
setValueFromFlag(cmd.Flags(), key, cfg, "", true)
|
||||
}
|
||||
setValueFromFlag(cmd.Flags(), "minify", cfg, "minifyOutput", true)
|
||||
|
||||
// Set some "config aliases"
|
||||
setValueFromFlag(cmd.Flags(), "destination", cfg, "publishDir", false)
|
||||
@@ -722,9 +715,6 @@ func (c *commandeer) handleBuildErr(err error, msg string) {
|
||||
|
||||
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()
|
||||
@@ -886,6 +876,10 @@ func (c *commandeer) handleEvents(watcher *watcher.Batcher,
|
||||
evs []fsnotify.Event,
|
||||
configSet map[string]bool) {
|
||||
|
||||
defer func() {
|
||||
c.wasError = false
|
||||
}()
|
||||
|
||||
var isHandled bool
|
||||
|
||||
for _, ev := range evs {
|
||||
@@ -1080,10 +1074,11 @@ func (c *commandeer) handleEvents(watcher *watcher.Batcher,
|
||||
// Will block forever trying to write to a channel that nobody is reading if livereload isn't initialized
|
||||
|
||||
// force refresh when more than one file
|
||||
if len(staticEvents) == 1 {
|
||||
if !c.wasError && len(staticEvents) == 1 {
|
||||
ev := staticEvents[0]
|
||||
path := c.hugo().BaseFs.SourceFilesystems.MakeStaticPathRelative(ev.Name)
|
||||
path = c.firstPathSpec().RelURL(helpers.ToSlashTrimLeading(path), false)
|
||||
|
||||
livereload.RefreshPath(path)
|
||||
} else {
|
||||
livereload.ForceRefresh()
|
||||
@@ -1107,6 +1102,10 @@ func (c *commandeer) handleEvents(watcher *watcher.Batcher,
|
||||
|
||||
if doLiveReload {
|
||||
if len(partitionedEvents.ContentEvents) == 0 && len(partitionedEvents.AssetEvents) > 0 {
|
||||
if c.wasError {
|
||||
livereload.ForceRefresh()
|
||||
return
|
||||
}
|
||||
changed := c.changeDetector.changed()
|
||||
if c.changeDetector != nil && len(changed) == 0 {
|
||||
// Nothing has changed.
|
||||
|
||||
@@ -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))
|
||||
|
||||
+119
-26
@@ -14,7 +14,11 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
|
||||
"github.com/gohugoio/hugo/modules"
|
||||
"github.com/spf13/cobra"
|
||||
@@ -26,7 +30,66 @@ 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
|
||||
}
|
||||
|
||||
var moduleNotFoundRe = regexp.MustCompile("module.*not found")
|
||||
|
||||
func (c *modCmd) newCleanCmd() *cobra.Command {
|
||||
var pattern string
|
||||
var all bool
|
||||
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 {
|
||||
if all {
|
||||
com, err := c.initConfig(false)
|
||||
|
||||
if err != nil && !moduleNotFoundRe.MatchString(err.Error()) {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = com.hugo().FileCaches.ModulesCache().Prune(true)
|
||||
return err
|
||||
}
|
||||
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*"`)
|
||||
cmd.Flags().BoolVarP(&all, "all", "", false, "clean entire module cache")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (b *commandsBuilder) newModCmd() *modCmd {
|
||||
|
||||
c := &modCmd{}
|
||||
|
||||
const commonUsage = `
|
||||
@@ -72,16 +135,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 +244,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 +254,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
|
||||
@@ -157,7 +156,7 @@ description = ""
|
||||
homepage = "http://example.com/"
|
||||
tags = []
|
||||
features = []
|
||||
min_version = "0.41"
|
||||
min_version = "0.41.0"
|
||||
|
||||
[author]
|
||||
name = ""
|
||||
|
||||
+7
-1
@@ -340,6 +340,7 @@ func (f *fileServer) createEndpoint(i int) (*http.ServeMux, string, string, erro
|
||||
if err != nil {
|
||||
f.c.logger.ERROR.Println(err)
|
||||
}
|
||||
|
||||
port = 1313
|
||||
if !f.c.paused {
|
||||
port = f.c.Cfg.GetInt("liveReloadPort")
|
||||
@@ -355,8 +356,13 @@ func (f *fileServer) createEndpoint(i int) (*http.ServeMux, string, string, erro
|
||||
w.Header().Set("Pragma", "no-cache")
|
||||
}
|
||||
|
||||
for _, header := range f.c.serverConfig.Match(r.RequestURI) {
|
||||
w.Header().Set(header.Key, header.Value)
|
||||
}
|
||||
|
||||
if f.c.fastRenderMode && f.c.buildErr == nil {
|
||||
p := r.RequestURI
|
||||
|
||||
p := strings.TrimSuffix(r.RequestURI, "?"+r.URL.RawQuery)
|
||||
if strings.HasSuffix(p, "/") || strings.HasSuffix(p, "html") || strings.HasSuffix(p, "htm") {
|
||||
if !f.c.visitedURLs.Contains(p) {
|
||||
// If not already on stack, re-render that single page.
|
||||
|
||||
@@ -30,8 +30,7 @@ var buildErrorTemplate = `<!doctype html>
|
||||
body {
|
||||
font-family: "Muli",avenir, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
|
||||
font-size: 16px;
|
||||
background-color: black;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
background-color: #2f1e2e;
|
||||
}
|
||||
main {
|
||||
margin: auto;
|
||||
@@ -43,7 +42,7 @@ var buildErrorTemplate = `<!doctype html>
|
||||
padding: 1rem 0;
|
||||
}
|
||||
.stack {
|
||||
margin-top: 6rem;
|
||||
margin-top: 4rem;
|
||||
}
|
||||
pre {
|
||||
white-space: pre-wrap;
|
||||
@@ -54,10 +53,7 @@ var buildErrorTemplate = `<!doctype html>
|
||||
}
|
||||
.highlight {
|
||||
overflow-x: auto;
|
||||
padding: 0.75rem;
|
||||
margin-bottom: 1rem;
|
||||
background-color: #272822;
|
||||
border: 1px solid black;
|
||||
}
|
||||
a {
|
||||
color: #0594cb;
|
||||
@@ -70,14 +66,14 @@ var buildErrorTemplate = `<!doctype html>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
{{ highlight .Error "apl" "noclasses=true,style=monokai" }}
|
||||
{{ highlight .Error "apl" "linenos=false,noclasses=true,style=paraiso-dark" }}
|
||||
{{ with .File }}
|
||||
{{ $params := printf "noclasses=true,style=monokai,linenos=table,hl_lines=%d,linenostart=%d" (add .LinesPos 1) (sub .Position.LineNumber .LinesPos) }}
|
||||
{{ $params := printf "noclasses=true,style=paraiso-dark,linenos=table,hl_lines=%d,linenostart=%d" (add .LinesPos 1) (sub .Position.LineNumber .LinesPos) }}
|
||||
{{ $lexer := .ChromaLexer | default "go-html-template" }}
|
||||
{{ highlight (delimit .Lines "\n") $lexer $params }}
|
||||
{{ end }}
|
||||
{{ with .StackTrace }}
|
||||
{{ highlight . "apl" "noclasses=true,style=monokai" }}
|
||||
{{ highlight . "apl" "noclasses=true,style=paraiso-dark" }}
|
||||
{{ end }}
|
||||
<p class="version">{{ .Version }}</p>
|
||||
<a href="">Reload Page</a>
|
||||
|
||||
@@ -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 ...
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package errors contains common Hugo errors and error related utilities.
|
||||
// Package herrors contains common Hugo errors and error related utilities.
|
||||
package herrors
|
||||
|
||||
import (
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package errors contains common Hugo errors and error related utilities.
|
||||
// Package herrors contains common Hugo errors and error related utilities.
|
||||
package herrors
|
||||
|
||||
import (
|
||||
|
||||
@@ -57,6 +57,11 @@ func PrintStackTrace(w io.Writer) {
|
||||
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()
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
// 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
|
||||
// limitatio ns under the License.
|
||||
// limitations under the License.
|
||||
|
||||
package herrors
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
// 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
|
||||
// limitatio ns under the License.
|
||||
// limitations under the License.
|
||||
|
||||
package herrors
|
||||
|
||||
|
||||
@@ -16,6 +16,9 @@ package hugo
|
||||
import (
|
||||
"fmt"
|
||||
"html/template"
|
||||
"os"
|
||||
|
||||
"github.com/gohugoio/hugo/config"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -54,6 +57,10 @@ func (i Info) Generator() template.HTML {
|
||||
return template.HTML(fmt.Sprintf(`<meta name="generator" content="Hugo %s" />`, CurrentVersion.String()))
|
||||
}
|
||||
|
||||
func (i Info) IsProduction() bool {
|
||||
return i.Environment == EnvironmentProduction
|
||||
}
|
||||
|
||||
// NewInfo creates a new Hugo Info object.
|
||||
func NewInfo(environment string) Info {
|
||||
if environment == "" {
|
||||
@@ -65,3 +72,9 @@ func NewInfo(environment string) Info {
|
||||
Environment: environment,
|
||||
}
|
||||
}
|
||||
|
||||
func GetExecEnviron(cfg config.Provider) []string {
|
||||
env := os.Environ()
|
||||
config.SetEnvVars(&env, "HUGO_ENVIRONMENT", cfg.GetString("environment"))
|
||||
return env
|
||||
}
|
||||
|
||||
@@ -31,5 +31,9 @@ func TestHugoInfo(t *testing.T) {
|
||||
c.Assert(hugoInfo.BuildDate, qt.Equals, buildDate)
|
||||
c.Assert(hugoInfo.Environment, qt.Equals, "production")
|
||||
c.Assert(string(hugoInfo.Generator()), qt.Contains, fmt.Sprintf("Hugo %s", hugoInfo.Version()))
|
||||
c.Assert(hugoInfo.IsProduction(), qt.Equals, true)
|
||||
|
||||
devHugoInfo := NewInfo("development")
|
||||
c.Assert(devHugoInfo.IsProduction(), qt.Equals, false)
|
||||
|
||||
}
|
||||
|
||||
+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.63,
|
||||
PatchLevel: 2,
|
||||
Number: 0.71,
|
||||
PatchLevel: 1,
|
||||
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,68 @@
|
||||
// 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 (
|
||||
"html/template"
|
||||
|
||||
"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)
|
||||
}
|
||||
|
||||
// TypeToString converts v to a string if it's a valid string type.
|
||||
// Note that this will not try to convert numeric values etc.,
|
||||
// use ToString for that.
|
||||
func TypeToString(v interface{}) (string, bool) {
|
||||
switch s := v.(type) {
|
||||
case string:
|
||||
return s, true
|
||||
case template.HTML:
|
||||
return string(s), true
|
||||
case template.CSS:
|
||||
return string(s), true
|
||||
case template.HTMLAttr:
|
||||
return string(s), true
|
||||
case template.JS:
|
||||
return string(s), true
|
||||
case template.JSStr:
|
||||
return string(s), true
|
||||
case template.URL:
|
||||
return string(s), true
|
||||
case template.Srcset:
|
||||
return string(s), true
|
||||
}
|
||||
|
||||
return "", false
|
||||
}
|
||||
|
||||
// ToString converts v to a string.
|
||||
func ToString(v interface{}) string {
|
||||
if s, ok := TypeToString(v); ok {
|
||||
return s
|
||||
}
|
||||
|
||||
return cast.ToString(v)
|
||||
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2018 The Hugo Authors. All rights reserved.
|
||||
// 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.
|
||||
@@ -11,4 +11,19 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package publisher
|
||||
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)
|
||||
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
// 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 config
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/gohugoio/hugo/common/types"
|
||||
|
||||
"github.com/gobwas/glob"
|
||||
"github.com/gohugoio/hugo/common/herrors"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
"github.com/spf13/cast"
|
||||
jww "github.com/spf13/jwalterweatherman"
|
||||
)
|
||||
|
||||
var DefaultBuild = Build{
|
||||
UseResourceCacheWhen: "fallback",
|
||||
WriteStats: false,
|
||||
}
|
||||
|
||||
// Build holds some build related condfiguration.
|
||||
type Build struct {
|
||||
UseResourceCacheWhen string // never, fallback, always. Default is fallback
|
||||
|
||||
// When enabled, will collect and write a hugo_stats.json with some build
|
||||
// related aggregated data (e.g. CSS class names).
|
||||
WriteStats bool
|
||||
}
|
||||
|
||||
func (b Build) UseResourceCache(err error) bool {
|
||||
if b.UseResourceCacheWhen == "never" {
|
||||
return false
|
||||
}
|
||||
|
||||
if b.UseResourceCacheWhen == "fallback" {
|
||||
return err == herrors.ErrFeatureNotAvailable
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func DecodeBuild(cfg Provider) Build {
|
||||
m := cfg.GetStringMap("build")
|
||||
b := DefaultBuild
|
||||
if m == nil {
|
||||
return b
|
||||
}
|
||||
|
||||
err := mapstructure.WeakDecode(m, &b)
|
||||
if err != nil {
|
||||
return DefaultBuild
|
||||
}
|
||||
|
||||
b.UseResourceCacheWhen = strings.ToLower(b.UseResourceCacheWhen)
|
||||
when := b.UseResourceCacheWhen
|
||||
if when != "never" && when != "always" && when != "fallback" {
|
||||
b.UseResourceCacheWhen = "fallback"
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
// Sitemap configures the sitemap to be generated.
|
||||
type Sitemap struct {
|
||||
ChangeFreq string
|
||||
Priority float64
|
||||
Filename string
|
||||
}
|
||||
|
||||
func DecodeSitemap(prototype Sitemap, input map[string]interface{}) Sitemap {
|
||||
|
||||
for key, value := range input {
|
||||
switch key {
|
||||
case "changefreq":
|
||||
prototype.ChangeFreq = cast.ToString(value)
|
||||
case "priority":
|
||||
prototype.Priority = cast.ToFloat64(value)
|
||||
case "filename":
|
||||
prototype.Filename = cast.ToString(value)
|
||||
default:
|
||||
jww.WARN.Printf("Unknown Sitemap field: %s\n", key)
|
||||
}
|
||||
}
|
||||
|
||||
return prototype
|
||||
}
|
||||
|
||||
// Config for the dev server.
|
||||
type Server struct {
|
||||
Headers []Headers
|
||||
|
||||
compiledInit sync.Once
|
||||
compiled []glob.Glob
|
||||
}
|
||||
|
||||
func (s *Server) Match(pattern string) []types.KeyValueStr {
|
||||
s.compiledInit.Do(func() {
|
||||
for _, h := range s.Headers {
|
||||
s.compiled = append(s.compiled, glob.MustCompile(h.For))
|
||||
}
|
||||
})
|
||||
|
||||
if s.compiled == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var matches []types.KeyValueStr
|
||||
|
||||
for i, g := range s.compiled {
|
||||
if g.Match(pattern) {
|
||||
h := s.Headers[i]
|
||||
for k, v := range h.Values {
|
||||
matches = append(matches, types.KeyValueStr{Key: k, Value: cast.ToString(v)})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sort.Slice(matches, func(i, j int) bool {
|
||||
return matches[i].Key < matches[j].Key
|
||||
})
|
||||
|
||||
return matches
|
||||
|
||||
}
|
||||
|
||||
type Headers struct {
|
||||
For string
|
||||
Values map[string]interface{}
|
||||
}
|
||||
|
||||
func DecodeServer(cfg Provider) *Server {
|
||||
m := cfg.GetStringMap("server")
|
||||
s := &Server{}
|
||||
if m == nil {
|
||||
return s
|
||||
}
|
||||
|
||||
_ = mapstructure.WeakDecode(m, s)
|
||||
return s
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
// Copyright 2020 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 config
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/gohugoio/hugo/common/herrors"
|
||||
"github.com/gohugoio/hugo/common/types"
|
||||
|
||||
qt "github.com/frankban/quicktest"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
func TestBuild(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
|
||||
v := viper.New()
|
||||
v.Set("build", map[string]interface{}{
|
||||
"useResourceCacheWhen": "always",
|
||||
})
|
||||
|
||||
b := DecodeBuild(v)
|
||||
|
||||
c.Assert(b.UseResourceCacheWhen, qt.Equals, "always")
|
||||
|
||||
v.Set("build", map[string]interface{}{
|
||||
"useResourceCacheWhen": "foo",
|
||||
})
|
||||
|
||||
b = DecodeBuild(v)
|
||||
|
||||
c.Assert(b.UseResourceCacheWhen, qt.Equals, "fallback")
|
||||
|
||||
c.Assert(b.UseResourceCache(herrors.ErrFeatureNotAvailable), qt.Equals, true)
|
||||
c.Assert(b.UseResourceCache(errors.New("err")), qt.Equals, false)
|
||||
|
||||
b.UseResourceCacheWhen = "always"
|
||||
c.Assert(b.UseResourceCache(herrors.ErrFeatureNotAvailable), qt.Equals, true)
|
||||
c.Assert(b.UseResourceCache(errors.New("err")), qt.Equals, true)
|
||||
c.Assert(b.UseResourceCache(nil), qt.Equals, true)
|
||||
|
||||
b.UseResourceCacheWhen = "never"
|
||||
c.Assert(b.UseResourceCache(herrors.ErrFeatureNotAvailable), qt.Equals, false)
|
||||
c.Assert(b.UseResourceCache(errors.New("err")), qt.Equals, false)
|
||||
c.Assert(b.UseResourceCache(nil), qt.Equals, false)
|
||||
|
||||
}
|
||||
|
||||
func TestServer(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
|
||||
cfg, err := FromConfigString(`[[server.headers]]
|
||||
for = "/*.jpg"
|
||||
|
||||
[server.headers.values]
|
||||
X-Frame-Options = "DENY"
|
||||
X-XSS-Protection = "1; mode=block"
|
||||
X-Content-Type-Options = "nosniff"
|
||||
`, "toml")
|
||||
|
||||
c.Assert(err, qt.IsNil)
|
||||
|
||||
s := DecodeServer(cfg)
|
||||
|
||||
c.Assert(s.Match("/foo.jpg"), qt.DeepEquals, []types.KeyValueStr{
|
||||
{Key: "X-Content-Type-Options", Value: "nosniff"},
|
||||
{Key: "X-Frame-Options", Value: "DENY"},
|
||||
{Key: "X-XSS-Protection", Value: "1; mode=block"}})
|
||||
|
||||
}
|
||||
@@ -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.
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
// 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 config
|
||||
|
||||
import (
|
||||
"github.com/spf13/cast"
|
||||
jww "github.com/spf13/jwalterweatherman"
|
||||
)
|
||||
|
||||
// Sitemap configures the sitemap to be generated.
|
||||
type Sitemap struct {
|
||||
ChangeFreq string
|
||||
Priority float64
|
||||
Filename string
|
||||
}
|
||||
|
||||
func DecodeSitemap(prototype Sitemap, input map[string]interface{}) Sitemap {
|
||||
|
||||
for key, value := range input {
|
||||
switch key {
|
||||
case "changefreq":
|
||||
prototype.ChangeFreq = cast.ToString(value)
|
||||
case "priority":
|
||||
prototype.Priority = cast.ToFloat64(value)
|
||||
case "filename":
|
||||
prototype.Filename = cast.ToString(value)
|
||||
default:
|
||||
jww.WARN.Printf("Unknown Sitemap field: %s\n", key)
|
||||
}
|
||||
}
|
||||
|
||||
return prototype
|
||||
}
|
||||
@@ -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 == "" {
|
||||
|
||||
+48
-6
@@ -31,6 +31,7 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/dustin/go-humanize"
|
||||
"github.com/gobwas/glob"
|
||||
"github.com/gohugoio/hugo/config"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/afero"
|
||||
@@ -125,7 +126,11 @@ func (d *Deployer) Deploy(ctx context.Context) error {
|
||||
}
|
||||
|
||||
// Load local files from the source directory.
|
||||
local, err := walkLocal(d.localFs, d.matchers)
|
||||
var include, exclude glob.Glob
|
||||
if d.target != nil {
|
||||
include, exclude = d.target.includeGlob, d.target.excludeGlob
|
||||
}
|
||||
local, err := walkLocal(d.localFs, d.matchers, include, exclude)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -133,7 +138,7 @@ func (d *Deployer) Deploy(ctx context.Context) error {
|
||||
d.summary.NumLocal = len(local)
|
||||
|
||||
// Load remote files from the target.
|
||||
remote, err := walkRemote(ctx, bucket)
|
||||
remote, err := walkRemote(ctx, bucket, include, exclude)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -435,9 +440,24 @@ func (lf *localFile) MD5() []byte {
|
||||
return lf.md5
|
||||
}
|
||||
|
||||
// knownHiddenDirectory checks if the specified name is a well known
|
||||
// hidden directory.
|
||||
func knownHiddenDirectory(name string) bool {
|
||||
var knownDirectories = []string{
|
||||
".well-known",
|
||||
}
|
||||
|
||||
for _, dir := range knownDirectories {
|
||||
if name == dir {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// walkLocal walks the source directory and returns a flat list of files,
|
||||
// using localFile.SlashPath as the map keys.
|
||||
func walkLocal(fs afero.Fs, matchers []*matcher) (map[string]*localFile, error) {
|
||||
func walkLocal(fs afero.Fs, matchers []*matcher, include, exclude glob.Glob) (map[string]*localFile, error) {
|
||||
retval := map[string]*localFile{}
|
||||
err := afero.Walk(fs, "", func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
@@ -446,7 +466,10 @@ func walkLocal(fs afero.Fs, matchers []*matcher) (map[string]*localFile, error)
|
||||
if info.IsDir() {
|
||||
// Skip hidden directories.
|
||||
if path != "" && strings.HasPrefix(info.Name(), ".") {
|
||||
return filepath.SkipDir
|
||||
// Except for specific hidden directories
|
||||
if !knownHiddenDirectory(info.Name()) {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -461,8 +484,18 @@ func walkLocal(fs afero.Fs, matchers []*matcher) (map[string]*localFile, error)
|
||||
path = norm.NFC.String(path)
|
||||
}
|
||||
|
||||
// Find the first matching matcher (if any).
|
||||
// Check include/exclude matchers.
|
||||
slashpath := filepath.ToSlash(path)
|
||||
if include != nil && !include.Match(slashpath) {
|
||||
jww.INFO.Printf(" dropping %q due to include\n", slashpath)
|
||||
return nil
|
||||
}
|
||||
if exclude != nil && exclude.Match(slashpath) {
|
||||
jww.INFO.Printf(" dropping %q due to exclude\n", slashpath)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Find the first matching matcher (if any).
|
||||
var m *matcher
|
||||
for _, cur := range matchers {
|
||||
if cur.Matches(slashpath) {
|
||||
@@ -484,7 +517,7 @@ func walkLocal(fs afero.Fs, matchers []*matcher) (map[string]*localFile, error)
|
||||
}
|
||||
|
||||
// walkRemote walks the target bucket and returns a flat list.
|
||||
func walkRemote(ctx context.Context, bucket *blob.Bucket) (map[string]*blob.ListObject, error) {
|
||||
func walkRemote(ctx context.Context, bucket *blob.Bucket, include, exclude glob.Glob) (map[string]*blob.ListObject, error) {
|
||||
retval := map[string]*blob.ListObject{}
|
||||
iter := bucket.List(nil)
|
||||
for {
|
||||
@@ -495,6 +528,15 @@ func walkRemote(ctx context.Context, bucket *blob.Bucket) (map[string]*blob.List
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Check include/exclude matchers.
|
||||
if include != nil && !include.Match(obj.Key) {
|
||||
jww.INFO.Printf(" remote dropping %q due to include\n", obj.Key)
|
||||
continue
|
||||
}
|
||||
if exclude != nil && exclude.Match(obj.Key) {
|
||||
jww.INFO.Printf(" remote dropping %q due to exclude\n", obj.Key)
|
||||
continue
|
||||
}
|
||||
// If the remote didn't give us an MD5, compute one.
|
||||
// This can happen for some providers (e.g., fileblob, which uses the
|
||||
// local filesystem), but not for the most common Cloud providers
|
||||
|
||||
@@ -17,7 +17,9 @@ import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
|
||||
"github.com/gobwas/glob"
|
||||
"github.com/gohugoio/hugo/config"
|
||||
hglob "github.com/gohugoio/hugo/hugofs/glob"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
)
|
||||
|
||||
@@ -41,6 +43,32 @@ type target struct {
|
||||
// GoogleCloudCDNOrigin specifies the Google Cloud project and CDN origin to
|
||||
// invalidate when deploying this target. It is specified as <project>/<origin>.
|
||||
GoogleCloudCDNOrigin string
|
||||
|
||||
// Optional patterns of files to include/exclude for this target.
|
||||
// Parsed using github.com/gobwas/glob.
|
||||
Include string
|
||||
Exclude string
|
||||
|
||||
// Parsed versions of Include/Exclude.
|
||||
includeGlob glob.Glob
|
||||
excludeGlob glob.Glob
|
||||
}
|
||||
|
||||
func (tgt *target) parseIncludeExclude() error {
|
||||
var err error
|
||||
if tgt.Include != "" {
|
||||
tgt.includeGlob, err = hglob.GetGlob(tgt.Include)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid deployment.target.include %q: %v", tgt.Include, err)
|
||||
}
|
||||
}
|
||||
if tgt.Exclude != "" {
|
||||
tgt.excludeGlob, err = hglob.GetGlob(tgt.Exclude)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid deployment.target.exclude %q: %v", tgt.Exclude, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// matcher represents configuration to be applied to files whose paths match
|
||||
@@ -87,6 +115,11 @@ func decodeConfig(cfg config.Provider) (deployConfig, error) {
|
||||
if err := mapstructure.WeakDecode(cfg.GetStringMap(deploymentConfigKey), &dcfg); err != nil {
|
||||
return dcfg, err
|
||||
}
|
||||
for _, tgt := range dcfg.Targets {
|
||||
if err := tgt.parseIncludeExclude(); err != nil {
|
||||
return dcfg, err
|
||||
}
|
||||
}
|
||||
var err error
|
||||
for _, m := range dcfg.Matchers {
|
||||
m.re, err = regexp.Compile(m.Pattern)
|
||||
|
||||
@@ -38,18 +38,21 @@ order = ["o1", "o2"]
|
||||
name = "name0"
|
||||
url = "url0"
|
||||
cloudfrontdistributionid = "cdn0"
|
||||
include = "*.html"
|
||||
|
||||
# All uppercase.
|
||||
[[deployment.targets]]
|
||||
NAME = "name1"
|
||||
URL = "url1"
|
||||
CLOUDFRONTDISTRIBUTIONID = "cdn1"
|
||||
INCLUDE = "*.jpg"
|
||||
|
||||
# Camelcase.
|
||||
[[deployment.targets]]
|
||||
name = "name2"
|
||||
url = "url2"
|
||||
cloudFrontDistributionID = "cdn2"
|
||||
exclude = "*.png"
|
||||
|
||||
# All lowercase.
|
||||
[[deployment.matchers]]
|
||||
@@ -90,11 +93,21 @@ force = true
|
||||
|
||||
// Targets.
|
||||
c.Assert(len(dcfg.Targets), qt.Equals, 3)
|
||||
wantInclude := []string{"*.html", "*.jpg", ""}
|
||||
wantExclude := []string{"", "", "*.png"}
|
||||
for i := 0; i < 3; i++ {
|
||||
tgt := dcfg.Targets[i]
|
||||
c.Assert(tgt.Name, qt.Equals, fmt.Sprintf("name%d", i))
|
||||
c.Assert(tgt.URL, qt.Equals, fmt.Sprintf("url%d", i))
|
||||
c.Assert(tgt.CloudFrontDistributionID, qt.Equals, fmt.Sprintf("cdn%d", i))
|
||||
c.Assert(tgt.Include, qt.Equals, wantInclude[i])
|
||||
if wantInclude[i] != "" {
|
||||
c.Assert(tgt.includeGlob, qt.Not(qt.IsNil))
|
||||
}
|
||||
c.Assert(tgt.Exclude, qt.Equals, wantExclude[i])
|
||||
if wantExclude[i] != "" {
|
||||
c.Assert(tgt.excludeGlob, qt.Not(qt.IsNil))
|
||||
}
|
||||
}
|
||||
|
||||
// Matchers.
|
||||
|
||||
@@ -207,6 +207,65 @@ func TestFindDiffs(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestWalkLocal(t *testing.T) {
|
||||
tests := map[string]struct {
|
||||
Given []string
|
||||
Expect []string
|
||||
}{
|
||||
"Empty": {
|
||||
Given: []string{},
|
||||
Expect: []string{},
|
||||
},
|
||||
"Normal": {
|
||||
Given: []string{"file.txt", "normal_dir/file.txt"},
|
||||
Expect: []string{"file.txt", "normal_dir/file.txt"},
|
||||
},
|
||||
"Hidden": {
|
||||
Given: []string{"file.txt", ".hidden_dir/file.txt", "normal_dir/file.txt"},
|
||||
Expect: []string{"file.txt", "normal_dir/file.txt"},
|
||||
},
|
||||
"Well Known": {
|
||||
Given: []string{"file.txt", ".hidden_dir/file.txt", ".well-known/file.txt"},
|
||||
Expect: []string{"file.txt", ".well-known/file.txt"},
|
||||
},
|
||||
}
|
||||
|
||||
for desc, tc := range tests {
|
||||
t.Run(desc, func(t *testing.T) {
|
||||
fs := afero.NewMemMapFs()
|
||||
for _, name := range tc.Given {
|
||||
dir, _ := path.Split(name)
|
||||
if dir != "" {
|
||||
if err := fs.MkdirAll(dir, 0755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
if fd, err := fs.Create(name); err != nil {
|
||||
t.Fatal(err)
|
||||
} else {
|
||||
fd.Close()
|
||||
}
|
||||
}
|
||||
if got, err := walkLocal(fs, nil, nil, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
} else {
|
||||
expect := map[string]interface{}{}
|
||||
for _, path := range tc.Expect {
|
||||
if _, ok := got[path]; !ok {
|
||||
t.Errorf("expected %q in results, but was not found", path)
|
||||
}
|
||||
expect[path] = nil
|
||||
}
|
||||
for path := range got {
|
||||
if _, ok := expect[path]; !ok {
|
||||
t.Errorf("got %q in results unexpectedly", path)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLocalFile(t *testing.T) {
|
||||
const (
|
||||
content = "hello world!"
|
||||
@@ -640,6 +699,168 @@ func TestMaxDeletes(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestIncludeExclude verifies that the include/exclude options for targets work.
|
||||
func TestIncludeExclude(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
tests := []struct {
|
||||
Include string
|
||||
Exclude string
|
||||
Want deploySummary
|
||||
}{
|
||||
{
|
||||
Want: deploySummary{NumLocal: 5, NumUploads: 5},
|
||||
},
|
||||
{
|
||||
Include: "**aaa",
|
||||
Want: deploySummary{NumLocal: 3, NumUploads: 3},
|
||||
},
|
||||
{
|
||||
Include: "**bbb",
|
||||
Want: deploySummary{NumLocal: 2, NumUploads: 2},
|
||||
},
|
||||
{
|
||||
Include: "aaa",
|
||||
Want: deploySummary{NumLocal: 1, NumUploads: 1},
|
||||
},
|
||||
{
|
||||
Exclude: "**aaa",
|
||||
Want: deploySummary{NumLocal: 2, NumUploads: 2},
|
||||
},
|
||||
{
|
||||
Exclude: "**bbb",
|
||||
Want: deploySummary{NumLocal: 3, NumUploads: 3},
|
||||
},
|
||||
{
|
||||
Exclude: "aaa",
|
||||
Want: deploySummary{NumLocal: 4, NumUploads: 4},
|
||||
},
|
||||
{
|
||||
Include: "**aaa",
|
||||
Exclude: "**nested**",
|
||||
Want: deploySummary{NumLocal: 2, NumUploads: 2},
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run(fmt.Sprintf("include %q exclude %q", test.Include, test.Exclude), func(t *testing.T) {
|
||||
fsTests, cleanup, err := initFsTests()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer cleanup()
|
||||
fsTest := fsTests[1] // just do file-based test
|
||||
|
||||
_, err = initLocalFs(ctx, fsTest.fs)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
tgt := &target{
|
||||
Include: test.Include,
|
||||
Exclude: test.Exclude,
|
||||
}
|
||||
if err := tgt.parseIncludeExclude(); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
deployer := &Deployer{
|
||||
localFs: fsTest.fs,
|
||||
maxDeletes: -1,
|
||||
bucket: fsTest.bucket,
|
||||
target: tgt,
|
||||
}
|
||||
|
||||
// Sync remote with local.
|
||||
if err := deployer.Deploy(ctx); err != nil {
|
||||
t.Errorf("deploy: failed: %v", err)
|
||||
}
|
||||
if !cmp.Equal(deployer.summary, test.Want) {
|
||||
t.Errorf("deploy: got %v, want %v", deployer.summary, test.Want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestIncludeExcludeRemoteDelete verifies deleted local files that don't match include/exclude patterns
|
||||
// are not deleted on the remote.
|
||||
func TestIncludeExcludeRemoteDelete(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
tests := []struct {
|
||||
Include string
|
||||
Exclude string
|
||||
Want deploySummary
|
||||
}{
|
||||
{
|
||||
Want: deploySummary{NumLocal: 3, NumRemote: 5, NumUploads: 0, NumDeletes: 2},
|
||||
},
|
||||
{
|
||||
Include: "**aaa",
|
||||
Want: deploySummary{NumLocal: 2, NumRemote: 3, NumUploads: 0, NumDeletes: 1},
|
||||
},
|
||||
{
|
||||
Include: "subdir/**",
|
||||
Want: deploySummary{NumLocal: 1, NumRemote: 2, NumUploads: 0, NumDeletes: 1},
|
||||
},
|
||||
{
|
||||
Exclude: "**bbb",
|
||||
Want: deploySummary{NumLocal: 2, NumRemote: 3, NumUploads: 0, NumDeletes: 1},
|
||||
},
|
||||
{
|
||||
Exclude: "bbb",
|
||||
Want: deploySummary{NumLocal: 3, NumRemote: 4, NumUploads: 0, NumDeletes: 1},
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run(fmt.Sprintf("include %q exclude %q", test.Include, test.Exclude), func(t *testing.T) {
|
||||
fsTests, cleanup, err := initFsTests()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer cleanup()
|
||||
fsTest := fsTests[1] // just do file-based test
|
||||
|
||||
local, err := initLocalFs(ctx, fsTest.fs)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
deployer := &Deployer{
|
||||
localFs: fsTest.fs,
|
||||
maxDeletes: -1,
|
||||
bucket: fsTest.bucket,
|
||||
}
|
||||
|
||||
// Initial sync to get the files on the remote
|
||||
if err := deployer.Deploy(ctx); err != nil {
|
||||
t.Errorf("deploy: failed: %v", err)
|
||||
}
|
||||
|
||||
// Delete two files, [1] and [2].
|
||||
if err := fsTest.fs.Remove(local[1].Name); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := fsTest.fs.Remove(local[2].Name); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Second sync
|
||||
tgt := &target{
|
||||
Include: test.Include,
|
||||
Exclude: test.Exclude,
|
||||
}
|
||||
if err := tgt.parseIncludeExclude(); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
deployer.target = tgt
|
||||
if err := deployer.Deploy(ctx); err != nil {
|
||||
t.Errorf("deploy: failed: %v", err)
|
||||
}
|
||||
|
||||
if !cmp.Equal(deployer.summary, test.Want) {
|
||||
t.Errorf("deploy: got %v, want %v", deployer.summary, test.Want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestCompression verifies that gzip compression works correctly.
|
||||
// In particular, MD5 hashes must be of the compressed content.
|
||||
func TestCompression(t *testing.T) {
|
||||
|
||||
Vendored
+20
-14
@@ -2,10 +2,10 @@ package deps
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"go.uber.org/atomic"
|
||||
|
||||
"github.com/gohugoio/hugo/cache/filecache"
|
||||
"github.com/gohugoio/hugo/common/loggers"
|
||||
@@ -93,8 +93,9 @@ type Deps struct {
|
||||
// BuildStartListeners will be notified before a build starts.
|
||||
BuildStartListeners *Listeners
|
||||
|
||||
// Atomic flags set during a build.
|
||||
BuildFlags *BuildFlags
|
||||
// Atomic values set during a build.
|
||||
// This is common/global for all sites.
|
||||
BuildState *BuildState
|
||||
|
||||
*globalErrHandler
|
||||
}
|
||||
@@ -236,7 +237,10 @@ func New(cfg DepsCfg) (*Deps, error) {
|
||||
return nil, errors.WithMessage(err, "failed to create file caches from configuration")
|
||||
}
|
||||
|
||||
resourceSpec, err := resources.NewSpec(ps, fileCaches, logger, cfg.OutputFormats, cfg.MediaTypes)
|
||||
errorHandler := &globalErrHandler{}
|
||||
buildState := &BuildState{}
|
||||
|
||||
resourceSpec, err := resources.NewSpec(ps, fileCaches, buildState, logger, errorHandler, cfg.OutputFormats, cfg.MediaTypes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -274,9 +278,9 @@ func New(cfg DepsCfg) (*Deps, error) {
|
||||
Site: cfg.Site,
|
||||
FileCaches: fileCaches,
|
||||
BuildStartListeners: &Listeners{},
|
||||
BuildFlags: &BuildFlags{},
|
||||
BuildState: buildState,
|
||||
Timeout: time.Duration(timeoutms) * time.Millisecond,
|
||||
globalErrHandler: &globalErrHandler{},
|
||||
globalErrHandler: errorHandler,
|
||||
}
|
||||
|
||||
if cfg.Cfg.GetBool("templateMetrics") {
|
||||
@@ -307,7 +311,7 @@ func (d Deps) ForLanguage(cfg DepsCfg, onCreated func(d *Deps) error) (*Deps, er
|
||||
// The resource cache is global so reuse.
|
||||
// TODO(bep) clean up these inits.
|
||||
resourceCache := d.ResourceSpec.ResourceCache
|
||||
d.ResourceSpec, err = resources.NewSpec(d.PathSpec, d.ResourceSpec.FileCaches, d.Log, cfg.OutputFormats, cfg.MediaTypes)
|
||||
d.ResourceSpec, err = resources.NewSpec(d.PathSpec, d.ResourceSpec.FileCaches, d.BuildState, d.Log, d.globalErrHandler, cfg.OutputFormats, cfg.MediaTypes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -375,13 +379,15 @@ type DepsCfg struct {
|
||||
Running bool
|
||||
}
|
||||
|
||||
// BuildFlags are flags that may be turned on during a build.
|
||||
type BuildFlags struct {
|
||||
HasLateTemplate atomic.Bool
|
||||
// BuildState are flags that may be turned on during a build.
|
||||
type BuildState struct {
|
||||
counter uint64
|
||||
}
|
||||
|
||||
func NewBuildFlags() BuildFlags {
|
||||
return BuildFlags{
|
||||
//HasLateTemplate: atomic.NewBool(false),
|
||||
}
|
||||
func (b *BuildState) Incr() int {
|
||||
return int(atomic.AddUint64(&b.counter, uint64(1)))
|
||||
}
|
||||
|
||||
func NewBuildState() BuildState {
|
||||
return BuildState{}
|
||||
}
|
||||
|
||||
Vendored
+8
-4
@@ -20,9 +20,13 @@ import (
|
||||
)
|
||||
|
||||
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)
|
||||
var bf BuildState
|
||||
bf.Incr()
|
||||
bf.Incr()
|
||||
bf.Incr()
|
||||
|
||||
c.Assert(bf.Incr(), qt.Equals, 4)
|
||||
|
||||
}
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
name: Compress images
|
||||
on: pull_request
|
||||
jobs:
|
||||
build:
|
||||
name: calibreapp/image-actions
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
- name: calibreapp/image-actions
|
||||
uses: docker://calibreapp/github-image-actions
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
+59
-56
@@ -1,70 +1,73 @@
|
||||
<!DOCTYPE html>
|
||||
<html class="no-js" lang="{{ with $.Site.LanguageCode }}{{ . }}{{ else }}en-us{{ end }}">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
{{/* https://www.zachleat.com/web/preload/ */}}
|
||||
<link rel="preload" href="{{ "fonts/muli-latin-200.woff2" | absURL }}" as="font" type="font/woff2" crossorigin>
|
||||
<link rel="preload" href="{{ "fonts/muli-latin-400.woff2" | absURL }}" as="font" type="font/woff2" crossorigin>
|
||||
<link rel="preload" href="{{ "fonts/muli-latin-800.woff2" | absURL }}" as="font" type="font/woff2" crossorigin>
|
||||
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
{{/* NOTE: the Site's title, and if there is a page title, that is set too */}}
|
||||
<title>{{ block "title" . }}{{ with .Title }}{{ . }} | {{ end }}{{ .Site.Title }}{{ end }}</title>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
{{/* https://www.zachleat.com/web/preload/ */}}
|
||||
<link rel="preload" href="{{ "fonts/muli-latin-200.woff2" | absURL }}" as="font" type="font/woff2" crossorigin>
|
||||
<link rel="preload" href="{{ "fonts/muli-latin-400.woff2" | absURL }}" as="font" type="font/woff2" crossorigin>
|
||||
<link rel="preload" href="{{ "fonts/muli-latin-800.woff2" | absURL }}" as="font" type="font/woff2" crossorigin>
|
||||
|
||||
<meta name="viewport" content="width=device-width,minimum-scale=1">
|
||||
{{ hugo.Generator }}
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
{{/* NOTE: the Site's title, and if there is a page title, that is set too */}}
|
||||
<title>{{ block "title" . }}{{ with .Title }}{{ . }} | {{ end }}{{ .Site.Title }}{{ end }}</title>
|
||||
|
||||
{{ if eq (getenv "HUGO_ENV") "production" | or (eq .Site.Params.env "production") }}
|
||||
<meta name="robots" content="index, follow">
|
||||
{{ else }}
|
||||
<meta name="robots" content="noindex, nofollow">
|
||||
{{ end }}
|
||||
<meta name="viewport" content="width=device-width,minimum-scale=1">
|
||||
{{ hugo.Generator }}
|
||||
|
||||
{{ range .AlternativeOutputFormats -}}
|
||||
<link rel="{{ .Rel }}" type="{{ .MediaType.Type }}" href="{{ .Permalink | safeURL }}">
|
||||
{{ end -}}
|
||||
|
||||
{{ $isDev := eq hugo.Environment "development" }}
|
||||
{{ $stylesheet := resources.Get "output/css/app.css" }}
|
||||
{{ if not $isDev }}
|
||||
{{ $stylesheet = $stylesheet | minify | fingerprint }}
|
||||
{{ end }}
|
||||
{{ with $stylesheet }}
|
||||
{{ if $isDev }}
|
||||
<link rel="stylesheet" href="{{ .RelPermalink }}" crossorigin="anonymous">
|
||||
{{ else }}
|
||||
<link rel="stylesheet" href="{{ .RelPermalink }}" integrity="{{ .Data.Integrity }}" crossorigin="anonymous">
|
||||
{{ end }}
|
||||
{{ $.Scratch.Set "stylesheet" . }}
|
||||
{{end}}
|
||||
{{ if eq (getenv "HUGO_ENV") "production" | or (eq .Site.Params.env "production") }}
|
||||
<meta name="robots" content="index, follow">
|
||||
{{ else }}
|
||||
<meta name="robots" content="noindex, nofollow">
|
||||
{{ end }}
|
||||
|
||||
{{ range .AlternativeOutputFormats -}}
|
||||
<link rel="{{ .Rel }}" type="{{ .MediaType.Type }}" href="{{ .Permalink | safeURL }}">
|
||||
{{ end -}}
|
||||
|
||||
{{ $isDev := eq hugo.Environment "development" }}
|
||||
{{ $stylesheet := resources.Get "output/css/app.css" }}
|
||||
{{ if not $isDev }}
|
||||
{{ $stylesheet = $stylesheet | minify | fingerprint }}
|
||||
{{ end }}
|
||||
{{ with $stylesheet }}
|
||||
{{ if $isDev }}
|
||||
<link rel="stylesheet" href="{{ .RelPermalink }}" crossorigin="anonymous">
|
||||
{{ else }}
|
||||
<link rel="stylesheet" href="{{ .RelPermalink }}" integrity="{{ .Data.Integrity }}" crossorigin="anonymous">
|
||||
{{ end }}
|
||||
{{ $.Scratch.Set "stylesheet" . }}
|
||||
{{end}}
|
||||
|
||||
|
||||
{{ block "scripts" . }}
|
||||
{{- partial "site-scripts.html" . -}}
|
||||
{{ end }}
|
||||
{{ partial "site-manifest.html" . }}
|
||||
{{- partial "head-additions.html" . -}}
|
||||
{{- template "_internal/opengraph.html" . -}}
|
||||
{{- template "_internal/schema.html" . -}}
|
||||
{{- template "_internal/twitter_cards.html" . -}}
|
||||
{{ block "scripts" . }}
|
||||
{{- partial "site-scripts.html" . -}}
|
||||
{{ end }}
|
||||
{{ partial "site-manifest.html" . }}
|
||||
{{- partial "head-additions.html" . -}}
|
||||
{{- template "_internal/opengraph.html" . -}}
|
||||
{{- template "_internal/schema.html" . -}}
|
||||
{{- template "_internal/twitter_cards.html" . -}}
|
||||
|
||||
{{ if eq (getenv "HUGO_ENV") "production" | or (eq .Site.Params.env "production") }}
|
||||
{{ partial "gtag" . }}
|
||||
{{ end }}
|
||||
{{ if eq (getenv "HUGO_ENV") "production" | or (eq .Site.Params.env "production") }}
|
||||
{{ partial "gtag" . }}
|
||||
{{ end }}
|
||||
|
||||
|
||||
|
||||
|
||||
</head>
|
||||
<body class="ma0 sans-serif bg-primary-color-light{{ with getenv "HUGO_ENV" }} {{ . }}{{ end }}">
|
||||
{{ block "nav" . }}{{ partial "site-nav.html" . }}{{ end }}
|
||||
{{ block "header" . }}{{ end }}
|
||||
<main role="main" class="content-with-sidebar min-vh-100 pb7 pb0-ns">
|
||||
{{ block "main" . }}{{ end }}
|
||||
</main>
|
||||
|
||||
{{ block "footer" . }}{{ partialCached "site-footer.html" . }}{{ end }}
|
||||
|
||||
</head>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
<body class="ma0 sans-serif bg-primary-color-light{{ with getenv "HUGO_ENV" }} {{ . }}{{ end }}">
|
||||
{{ block "nav" . }}{{ partial "site-nav.html" . }}{{ end }}
|
||||
{{ block "header" . }}{{ end }}
|
||||
<main role="main" class="content-with-sidebar min-vh-100 pb7 pb0-ns">
|
||||
{{ block "main" . }}{{ end }}
|
||||
</main>
|
||||
|
||||
{{ block "footer" . }}{{ partialCached "site-footer.html" . }}{{ end }}
|
||||
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -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)
|
||||
|
||||
@@ -26,7 +26,7 @@ But when developing and building your site, the runtime is the `hugo` executable
|
||||
* 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.
|
||||
* We shell out to some external binaries to support [Asciidoctor](/content-management/formats/#list-of-content-formats) and similar, 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.
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-03-03
|
||||
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 3-Mar-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-03-03
|
||||
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 3-Mar-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-03-03
|
||||
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 3-Mar-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-03-03
|
||||
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 3-Mar-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-03-03
|
||||
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 3-Mar-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-03-03
|
||||
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 3-Mar-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-03-03
|
||||
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 3-Mar-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-03-03
|
||||
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 3-Mar-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-03-03
|
||||
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 3-Mar-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-03-03
|
||||
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 3-Mar-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-03-03
|
||||
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 3-Mar-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-03-03
|
||||
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 3-Mar-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-03-03
|
||||
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 3-Mar-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-03-03
|
||||
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 3-Mar-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-03-03
|
||||
title: "hugo gen doc"
|
||||
slug: hugo_gen_doc
|
||||
url: /commands/hugo_gen_doc/
|
||||
@@ -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 3-Mar-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-03-03
|
||||
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 3-Mar-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-03-03
|
||||
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 3-Mar-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-03-03
|
||||
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 3-Mar-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-03-03
|
||||
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 3-Mar-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-03-03
|
||||
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 3-Mar-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-03-03
|
||||
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 3-Mar-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-03-03
|
||||
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 3-Mar-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-03-03
|
||||
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 3-Mar-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-03-03
|
||||
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 3-Mar-2020
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-03-03
|
||||
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,9 @@ hugo mod clean [flags]
|
||||
### Options
|
||||
|
||||
```
|
||||
-h, --help help for clean
|
||||
--all clean entire module cache
|
||||
-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 +51,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 3-Mar-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-03-03
|
||||
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 3-Mar-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-03-03
|
||||
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 3-Mar-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-03-03
|
||||
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 3-Mar-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-03-03
|
||||
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 3-Mar-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-03-03
|
||||
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 3-Mar-2020
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
---
|
||||
date: 2020-03-03
|
||||
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 3-Mar-2020
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-03-03
|
||||
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 3-Mar-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-03-03
|
||||
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 3-Mar-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-03-03
|
||||
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 3-Mar-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-03-03
|
||||
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 3-Mar-2020
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-07-31
|
||||
date: 2020-03-03
|
||||
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 3-Mar-2020
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
---
|
||||
title: Build Options
|
||||
linktitle: Build Options
|
||||
description: Build options help define how Hugo must treat a given page when building the site.
|
||||
date: 2020-03-02
|
||||
publishdate: 2020-03-02
|
||||
keywords: [build,content,front matter, page resources]
|
||||
categories: ["content management"]
|
||||
menu:
|
||||
docs:
|
||||
parent: "content-management"
|
||||
weight: 31
|
||||
weight: 31 #rem
|
||||
draft: false
|
||||
aliases: [/content/build-options/]
|
||||
toc: true
|
||||
---
|
||||
|
||||
They are stored in a reserved Front Matter object named `_build` with the following defaults:
|
||||
|
||||
```yaml
|
||||
_build:
|
||||
render: true
|
||||
list: always
|
||||
publishResources: true
|
||||
```
|
||||
|
||||
#### render
|
||||
If true, the page will be treated as a published page, holding its dedicated output files (`index.html`, etc...) and permalink.
|
||||
|
||||
#### list
|
||||
|
||||
Note that we extended this property from a boolean to an enum in Hugo 0.68.0.
|
||||
|
||||
Valid values are:
|
||||
|
||||
never
|
||||
: The page will not be incldued in any page collection.
|
||||
|
||||
always (default)
|
||||
: The page will be included in all page collections, e.g. `site.RegularPages`, `$page.Pages`.
|
||||
|
||||
local
|
||||
: The page will be included in any _local_ page collection, e.g. `$page.RegularPages`, `$page.Pages`. One use case for this would be to create fully navigable, but headless content sections. {{< new-in "0.68.0" >}}
|
||||
|
||||
If true, the page will be treated as part of the project's collections and, when appropriate, returned by Hugo's listing methods (`.Pages`, `.RegularPages` etc...).
|
||||
|
||||
#### publishResources
|
||||
|
||||
If set to true the [Bundle's Resources]({{< relref "content-management/page-bundles" >}}) will be published.
|
||||
Setting this to false will still publish Resources on demand (when a resource's `.Permalink` or `.RelPermalink` is invoked from the templates) but will skip the others.
|
||||
|
||||
{{% note %}}
|
||||
Any page, regardless of their build options, will always be available using the [`.GetPage`]({{< relref "functions/GetPage" >}}) methods.
|
||||
{{% /note %}}
|
||||
|
||||
------
|
||||
|
||||
### Illustrative use cases
|
||||
|
||||
#### Not publishing a page
|
||||
Project needs a "Who We Are" content file for Front Matter and body to be used by the homepage but nowhere else.
|
||||
|
||||
```yaml
|
||||
# content/who-we-are.md`
|
||||
title: Who we are
|
||||
_build:
|
||||
list: false
|
||||
render: false
|
||||
```
|
||||
|
||||
```go-html-template
|
||||
{{/* layouts/index.html */}}
|
||||
<section id="who-we-are">
|
||||
{{ with site.GetPage "who-we-are" }}
|
||||
{{ .Content }}
|
||||
{{ end }}
|
||||
</section>
|
||||
```
|
||||
|
||||
#### Listing pages without publishing them
|
||||
|
||||
Website needs to showcase a few of the hundred "testimonials" available as content files without publishing any of them.
|
||||
|
||||
To avoid setting the build options on every testimonials, one can use [`cascade`]({{< relref "/content-management/front-matter#front-matter-cascade" >}}) on the testimonial section's content file.
|
||||
|
||||
```yaml
|
||||
#content/testimonials/_index.md
|
||||
title: Testimonials
|
||||
# section build options:
|
||||
_build:
|
||||
render: true
|
||||
# children build options with cascade
|
||||
cascade:
|
||||
_build:
|
||||
render: false
|
||||
list: true # default
|
||||
```
|
||||
|
||||
```go-html-template
|
||||
{{/* layouts/_defaults/testimonials.html */}}
|
||||
<section id="testimonials">
|
||||
{{ range first 5 .Pages }}
|
||||
<blockquote cite="{{ .Params.cite }}">
|
||||
{{ .Content }}
|
||||
</blockquote>
|
||||
{{ end }}
|
||||
</section>
|
||||
@@ -51,29 +51,18 @@ Disqus has its own [internal template](https://gohugo.io/templates/internal/#dis
|
||||
|
||||
There are a few alternatives to commenting on static sites for those who do not want to use Disqus:
|
||||
|
||||
* [Static Man](https://staticman.net/)
|
||||
* [Staticman](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/)
|
||||
* [isso](https://posativ.org/isso/) (Self-hosted, Python)
|
||||
* [Tutorial on Implementing Isso with Hugo][issotutorial]
|
||||
* [Utterances](https://utteranc.es/) (Open source, Github comments widget built on Github issues)
|
||||
* [Utterances](https://utteranc.es/) (Open source, GitHub comments widget built on GitHub issues)
|
||||
* [Remark](https://github.com/umputun/remark) (Open source, Golang, Easy to run docker)
|
||||
* [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
|
||||
|
||||
@@ -34,7 +34,7 @@ The current list of content formats in Hugo:
|
||||
|MMark|mmark|Mmark is deprecated and will be removed in a future release.|
|
||||
|Emacs Org-Mode|org|See [go-org](https://github.com/niklasfasching/go-org).|
|
||||
|Asciidoc|asciidoc, adoc, ad|Needs Asciidoc or [Asciidoctor][ascii] installed.|
|
||||
|RST|rst|Needs [RST](http://docutils.sourceforge.net/rst.html) installed.|
|
||||
|RST|rst|Needs [RST](https://docutils.sourceforge.io/rst.html) installed.|
|
||||
|Pandoc|pandoc, pdc|Needs [Pandoc](https://www.pandoc.org/) installed.|
|
||||
|HTML|html, htm|To be treated as a content file, with layout, shortcodes etc., it must have front matter. If not, it will be copied as-is.|
|
||||
|
||||
@@ -88,7 +88,7 @@ Markdown syntax is simple enough to learn in a single sitting. The following are
|
||||
[mmark]: https://github.com/mmarkdown/mmark
|
||||
[org]: https://orgmode.org/
|
||||
[pandoc]: https://www.pandoc.org/
|
||||
[Pygments]: http://pygments.org/
|
||||
[rest]: http://docutils.sourceforge.net/rst.html
|
||||
[Pygments]: https://pygments.org/
|
||||
[rest]: https://docutils.sourceforge.io/rst.html
|
||||
[sc]: /content-management/shortcodes/
|
||||
[sct]: /templates/shortcode-templates/
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user