Compare commits
112 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9f9695cf7b | |||
| 0831d8ccaf | |||
| 1d4ff024ca | |||
| 521e63ac7c | |||
| 47d38628ec | |||
| 0024dcfe3e | |||
| beec1fc98e | |||
| 306573def0 | |||
| 80c8f3b81a | |||
| 6b6dcb44a0 | |||
| d96f2a460f | |||
| ac53035030 | |||
| b874a1ba7a | |||
| 4108705934 | |||
| 9c1e82085e | |||
| 2b73e89d6d | |||
| febf0aec8b | |||
| a4fad5be6b | |||
| 6084f0433c | |||
| cbb7214b6c | |||
| e6136b36f3 | |||
| 659917a002 | |||
| 9d194ab904 | |||
| a305609e18 | |||
| 179de5f5bc | |||
| 5dc1f95b63 | |||
| 6bc892fc24 | |||
| 5f06dbf779 | |||
| 0850e97984 | |||
| a3b4b10f65 | |||
| e3df6478f0 | |||
| 626afc9825 | |||
| e1027c5846 | |||
| e1a052ecb8 | |||
| bfc3488b8e | |||
| ce84b524f4 | |||
| 3cea2932e1 | |||
| 0efd374805 | |||
| 98293eaa15 | |||
| 2b8d907ab7 | |||
| 43338c3a99 | |||
| dea71670c0 | |||
| a5d0a57e6b | |||
| f465571b33 | |||
| f8212d2000 | |||
| 78e8a744b3 | |||
| c790029e1d | |||
| 554553c09c | |||
| de37455ec7 | |||
| 282f6035e7 | |||
| 360fa12213 | |||
| 02aa320030 | |||
| d2640fbc19 | |||
| 1637d12e37 | |||
| 3a7706b069 | |||
| 2955f93fc6 | |||
| 1f0c4e1fb3 | |||
| 91ab455d84 | |||
| ca1e46efb9 | |||
| fd71fa89bd | |||
| b5a3aa7082 | |||
| 3d5928889a | |||
| dc7bc7b4d2 | |||
| 42ed602580 | |||
| 6a2968fd5c | |||
| 23d5fc82ee | |||
| 8531ec7ca3 | |||
| 9f27091e10 | |||
| 187621ae24 | |||
| 4172a835e5 | |||
| fc97388968 | |||
| d67e843c12 | |||
| 6e33c557b0 | |||
| 128f14efad | |||
| 34ee27a78b | |||
| 0f1fc01ef2 | |||
| f32ccd018f | |||
| ffb609f4ab | |||
| 19d91abc92 | |||
| f5c0a2b4b2 | |||
| 31828026a1 | |||
| c74b0f8f9b | |||
| 80949dc73f | |||
| e02629f81a | |||
| b239595af5 | |||
| ed4a345efe | |||
| 9717ac7dce | |||
| 692ec00872 | |||
| d3dd74fd65 | |||
| 80230f26a3 | |||
| 6464981adb | |||
| 2e6712e281 | |||
| 65deb72dc4 | |||
| dc4226a8b2 | |||
| bf5f10faa9 | |||
| 019bd5576b | |||
| c3115292a7 | |||
| 0c6c98e401 | |||
| 90c7749085 | |||
| 13435a6f60 | |||
| 07b96d16e8 | |||
| ceaff7cafc | |||
| b84389c5e0 | |||
| 8de5324479 | |||
| 20cbc2c785 | |||
| 2174525cec | |||
| 7a6192647a | |||
| d68367cbe7 | |||
| 5241f0baee | |||
| b5b36e3200 | |||
| 4f0665f476 | |||
| fc8c5ad824 |
@@ -0,0 +1,8 @@
|
||||
*.md
|
||||
*.log
|
||||
*.txt
|
||||
.git
|
||||
.github
|
||||
.circleci
|
||||
docs
|
||||
examples
|
||||
@@ -0,0 +1,8 @@
|
||||
# Text files have auto line endings
|
||||
* text=auto
|
||||
|
||||
# Go source files always have LF line endings
|
||||
*.go text eol=lf
|
||||
|
||||
# SVG files should not be modified
|
||||
*.svg -text
|
||||
@@ -15,5 +15,7 @@ vendor/*/
|
||||
*.debug
|
||||
coverage*.out
|
||||
|
||||
dock.sh
|
||||
|
||||
GoBuilds
|
||||
dist
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
language: go
|
||||
sudo: false
|
||||
dist: trusty
|
||||
env:
|
||||
HUGO_BUILD_TAGS="extended"
|
||||
git:
|
||||
depth: false
|
||||
go:
|
||||
- 1.9.5
|
||||
- "1.10.1"
|
||||
- 1.9.7
|
||||
- "1.10.3"
|
||||
- tip
|
||||
os:
|
||||
- linux
|
||||
@@ -18,8 +20,9 @@ install:
|
||||
- go get github.com/magefile/mage
|
||||
- mage -v vendor
|
||||
script:
|
||||
- mage -v hugoRace
|
||||
- mage -v test
|
||||
- mage -v check
|
||||
- mage -v hugo
|
||||
- ./hugo -s docs/
|
||||
- ./hugo --renderToMemory -s docs/
|
||||
before_install:
|
||||
|
||||
@@ -192,6 +192,12 @@ To list all available commands along with descriptions:
|
||||
mage -l
|
||||
```
|
||||
|
||||
**Note:** From Hugo 0.43 we have added a build tag, `extended` that adds **SCSS support**. This needs a C compiler installed to build. You can enable this when building by:
|
||||
|
||||
```bash
|
||||
HUGO_BUILD_TAGS=extended mage install
|
||||
````
|
||||
|
||||
### Updating the Hugo Sources
|
||||
|
||||
If you want to stay in sync with the Hugo repository, you can easily pull down
|
||||
|
||||
@@ -1,23 +1,27 @@
|
||||
FROM golang:1.9.0-alpine3.6 AS build
|
||||
# GitHub: https://github.com/gohugoio
|
||||
# Twitter: https://twitter.com/gohugoio
|
||||
# Website: https://gohugo.io/
|
||||
|
||||
RUN apk add --no-cache --virtual git musl-dev
|
||||
RUN go get github.com/golang/dep/cmd/dep
|
||||
FROM golang:1.10.3-alpine3.7 AS build
|
||||
|
||||
ENV CGO_ENABLED=0
|
||||
ENV GOOS=linux
|
||||
|
||||
WORKDIR /go/src/github.com/gohugoio/hugo
|
||||
ADD . /go/src/github.com/gohugoio/hugo/
|
||||
RUN dep ensure
|
||||
RUN go install -ldflags '-s -w'
|
||||
RUN apk add --no-cache \
|
||||
git \
|
||||
musl-dev && \
|
||||
go get github.com/golang/dep/cmd/dep
|
||||
COPY . /go/src/github.com/gohugoio/hugo/
|
||||
RUN dep ensure -vendor-only && \
|
||||
go install -ldflags '-s -w'
|
||||
|
||||
FROM alpine:3.6
|
||||
RUN \
|
||||
adduser -h /site -s /sbin/nologin -u 1000 -D hugo && \
|
||||
apk add --no-cache \
|
||||
dumb-init
|
||||
COPY --from=build /go/bin/hugo /bin/hugo
|
||||
USER hugo
|
||||
# ---
|
||||
|
||||
FROM scratch
|
||||
COPY --from=build /go/bin/hugo /hugo
|
||||
WORKDIR /site
|
||||
VOLUME /site
|
||||
EXPOSE 1313
|
||||
|
||||
ENTRYPOINT ["/usr/bin/dumb-init", "--", "hugo"]
|
||||
ENTRYPOINT [ "/hugo" ]
|
||||
CMD [ "--help" ]
|
||||
|
||||
@@ -3,24 +3,46 @@
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:f6a10073544cc0bd1eb9fd9f8d9bf4644971910a0f8393d51b5b4d286e554849"
|
||||
name = "github.com/BurntSushi/locker"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "a6e239ea1c69bff1cfdb20c4b73dadf52f784b6a"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:af3600b068c8dd0e004122f154de7ece06b0b13376f79e976701aab4834c860a"
|
||||
name = "github.com/BurntSushi/toml"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "a368813c5e648fee92e5f6c30e3944ff9d5e8895"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:1080c443bebc98b1c25665b46b321dc02f8a4d384fe544379dcba1e651f59321"
|
||||
name = "github.com/PuerkitoBio/purell"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "0bcb03f4b4d0a9428594752bd2a3b9aa0a9d4bd4"
|
||||
version = "v1.1.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:331a419049c2be691e5ba1d24342fc77c7e767a80c666a18fd8a9f7b82419c1c"
|
||||
name = "github.com/PuerkitoBio/urlesc"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "de5bf2ad457846296e2031421a34e2568e304e35"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:60d5ffa86fb76749180841154b3714cde4771723b7e52329fb97ec916a6a68a6"
|
||||
name = "github.com/alecthomas/assert"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "405dbfeb8e38effee6e723317226e93fff912d06"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:2d78d7ffff1988e613e4946d6a6914190db0b38d533e392208797d2f557c92b6"
|
||||
name = "github.com/alecthomas/chroma"
|
||||
packages = [
|
||||
".",
|
||||
@@ -53,83 +75,135 @@
|
||||
"lexers/w",
|
||||
"lexers/x",
|
||||
"lexers/y",
|
||||
"styles"
|
||||
"styles",
|
||||
]
|
||||
revision = "6b1131c0069211a7729895c26f8c51765a4baf25"
|
||||
pruneopts = ""
|
||||
revision = "1b755a90bd109f170385cb3964f0abdfd3451145"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:ba0a389824c3c3d378f5f334370524b7d04b5a5ccedce7dd2da05ae8d3868609"
|
||||
name = "github.com/alecthomas/colour"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "60882d9e27213e8552dcff6328914fe4c2b44bc9"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:5723237c9114bb92b4571532d9580dd0ed885ec3eb371d58085c074895c04a51"
|
||||
name = "github.com/alecthomas/repr"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "f49988b46e025398b9f834f7c726afe001ec481f"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:05d0e4ae6b8d0273647964fe26762e3345d5d196aaeb858838e75336703451ba"
|
||||
name = "github.com/bep/debounce"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "844797fa1dd9ba969d71b62797ff19d1e49d4eac"
|
||||
version = "v1.1.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:88b2a2ccfbcf8aa697ec140e196c524f40bbdc8e6f6d03ff79354bc694cb677d"
|
||||
name = "github.com/bep/gitmap"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "012701e8669671499fc43e9792335a1dcbfe2afb"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:7337271448975bc9cf3deae77bb2d7f7fc937c60c59b606ffcd25bfc754dd2ec"
|
||||
name = "github.com/bep/go-tocss"
|
||||
packages = [
|
||||
"scss",
|
||||
"scss/libsass",
|
||||
"tocss",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "2abb118dc8688b6c7df44e12f4152c2bded9b19c"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:e5ad472b763adca2591568384b8f07974d2da4a98b55ffb360e2cecc2a216bae"
|
||||
name = "github.com/chaseadamsio/goorgeous"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "dcf1ef873b8987bf12596fe6951c48347986eb2f"
|
||||
version = "v1.1.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:f30036d9c6eb2b9262edac69b5f6b59e25b25310ffee3035ab0e7c4b722a8552"
|
||||
name = "github.com/cpuguy83/go-md2man"
|
||||
packages = ["md2man"]
|
||||
revision = "20f5889cbdc3c73dbd2862796665e7c465ade7d1"
|
||||
version = "v1.0.8"
|
||||
pruneopts = ""
|
||||
revision = "a65d4d2de4d5f7c74868dfa9b202a3c8be315aaa"
|
||||
version = "v1.0.6"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:8f6c36ee73ded871996ada894e20dfecde56557d08b4d1849d5489076679971f"
|
||||
name = "github.com/danwakefield/fnmatch"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "cbb64ac3d964b81592e64f957ad53df015803288"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:0a39ec8bf5629610a4bc7873a92039ee509246da3cef1a0ea60f1ed7e5f9cea5"
|
||||
name = "github.com/davecgh/go-spew"
|
||||
packages = ["spew"]
|
||||
pruneopts = ""
|
||||
revision = "346938d642f2ec3594ed81d874461961cd0faa76"
|
||||
version = "v1.1.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:8dc164acd41f84c9f704362d061f90cf45014c3b7eb3fead126efb7d152e2efc"
|
||||
name = "github.com/disintegration/imaging"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "dd50a3ee9985ccd313a2f03c398fcaedc96dc707"
|
||||
version = "v1.2.4"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:536d2bdf1cdef7ec49e1cb4a8a083ae639159f0fd11a5829fe4d35ecb8cc3a1a"
|
||||
name = "github.com/dlclark/regexp2"
|
||||
packages = [
|
||||
".",
|
||||
"syntax"
|
||||
"syntax",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "487489b64fb796de2e55f4e8a4ad1e145f80e957"
|
||||
version = "v1.1.6"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:fbbae68d476d61afb78178dd4c5532dbfff154e2fea72d1312138bf35c613ec1"
|
||||
name = "github.com/eknkc/amber"
|
||||
packages = [
|
||||
".",
|
||||
"parser"
|
||||
"parser",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "cdade1c073850f4ffc70a829e31235ea6892853b"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:e5c807ac3b60699ccec9263f6eec756251b17e78582eb149f90ac345d9e58327"
|
||||
name = "github.com/fortytw2/leaktest"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "a5ef70473c97b71626b9abeda80ee92ba2a7de9e"
|
||||
version = "v1.2.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:b2106f1668ea5efc1ecc480f7e922a093adb9563fd9ce58585292871f0d0f229"
|
||||
name = "github.com/fsnotify/fsnotify"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "c2828203cd70a50dcccfb2761f8b1f8ceef9a8e9"
|
||||
version = "v1.4.7"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:b7a7e17513aeee6492d93015c7bf29c86a0c1c91210ea56b21e36c1a40958cba"
|
||||
name = "github.com/gobwas/glob"
|
||||
packages = [
|
||||
".",
|
||||
@@ -139,31 +213,39 @@
|
||||
"syntax/ast",
|
||||
"syntax/lexer",
|
||||
"util/runes",
|
||||
"util/strings"
|
||||
"util/strings",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "5ccd90ef52e1e632236f7326478d4faa74f99438"
|
||||
version = "v0.2.3"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:fe1b4d4cbe48c0d55507c55f8663aa4185576cc58fa0c8be03bb8f19dfe17a9c"
|
||||
name = "github.com/gorilla/websocket"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "ea4d1f681babbce9545c9c5f3d5194a789c89f5b"
|
||||
version = "v1.2.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:4423ee95d6ee30bb22f680445c58889bb5b91e1b955405bf34374a053784a8a2"
|
||||
name = "github.com/hashicorp/go-immutable-radix"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "7f3cd4390caab3250a57f30efdb2a65dd7649ecf"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:9c776d7d9c54b7ed89f119e449983c3f24c0023e75001d6092442412ebca6b94"
|
||||
name = "github.com/hashicorp/golang-lru"
|
||||
packages = ["simplelru"]
|
||||
pruneopts = ""
|
||||
revision = "0fb14efe8c47ae851c0034ed7a448854d3d34cf3"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:ccfc44438ba7fc24effffbe9c7b75bbbb51e7a275e361e62a4dbffbc9e8e43d9"
|
||||
name = "github.com/hashicorp/hcl"
|
||||
packages = [
|
||||
".",
|
||||
@@ -175,195 +257,317 @@
|
||||
"hcl/token",
|
||||
"json/parser",
|
||||
"json/scanner",
|
||||
"json/token"
|
||||
"json/token",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "ef8a98b0bbce4a65b5aa4c368430a80ddc533168"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:870d441fe217b8e689d7949fef6e43efbc787e50f200cb1e70dbca9204a1d6be"
|
||||
name = "github.com/inconshreveable/mousetrap"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75"
|
||||
version = "v1.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:3b82a4308adc7319d0c7efbad106e966cbbf70e47f16fb5f7aca131b01f6f9b1"
|
||||
name = "github.com/jdkato/prose"
|
||||
packages = [
|
||||
"internal/util",
|
||||
"transform"
|
||||
"transform",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "20d3663d4bc9dd10d75abcde9d92e04b4861c674"
|
||||
version = "v1.1.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:f72872791669f287262777a6a635c7aaebbdd9919cffacea802f8f9c1dc2e6f6"
|
||||
name = "github.com/kyokomi/emoji"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "7e06b236c489543f53868841f188a294e3383eab"
|
||||
version = "v1.5"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:3ee69edc976a8e66debd179073163cbbef426faa7c0ef2d8ff8e3be159699d2e"
|
||||
name = "github.com/magefile/mage"
|
||||
packages = [
|
||||
"mg",
|
||||
"sh"
|
||||
"sh",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "2f974307b636f59c13b88704cf350a4772fef271"
|
||||
version = "v1.0.2"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:093cd7ebfdecf5692c66f0b0f7a1877d796c89d9940f5769439c53dc65264036"
|
||||
name = "github.com/magiconair/properties"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "c3beff4c2358b44d0493c7dda585e7db7ff28ae6"
|
||||
version = "v1.7.6"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:fd46423a2fe75d52968baf37471b99e6f05cea3ac29c756128ead26af34e1c35"
|
||||
name = "github.com/markbates/inflect"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "a12c3aec81a6a938bf584a4bac567afed9256586"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:78229b46ddb7434f881390029bd1af7661294af31f6802e0e1bedaad4ab0af3c"
|
||||
name = "github.com/mattn/go-isatty"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39"
|
||||
version = "v0.0.3"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:81e673df85e765593a863f67cba4544cf40e8919590f04d67664940786c2b61a"
|
||||
name = "github.com/mattn/go-runewidth"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "9e777a8366cce605130a531d2cd6363d07ad7317"
|
||||
version = "v0.0.2"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:6066f4c384723dd468c96adc13bfe4d977f182c2305e1a82c94bb50e1507d528"
|
||||
name = "github.com/miekg/mmark"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "fd2f6c1403b37925bd7fe13af05853b8ae58ee5f"
|
||||
version = "v1.3.6"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:0de0f377aeccd41384e883c59c6f184c9db01c96db33a2724a1eaadd60f92629"
|
||||
name = "github.com/mitchellh/hashstructure"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "2bca23e0e452137f789efbc8610126fd8b94f73b"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:59fa50d593e5673a0dfffa1852b66fd700c05b35e368680b4b89a68fdb2c1379"
|
||||
name = "github.com/mitchellh/mapstructure"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "00c29f56e2386353d58c599509e8dc3801b0d716"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:08b8db6381176e5472815f67f29b2b8b21d5bf3adaba4de3e5416faaf26f3689"
|
||||
name = "github.com/muesli/smartcrop"
|
||||
packages = [
|
||||
".",
|
||||
"options"
|
||||
"options",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "f6ebaa786a12a0fdb2d7c6dee72808e68c296464"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:34afc91b88b56c71639e275ff3ea8179a8f094ddc86df96e26074000cade42fe"
|
||||
name = "github.com/nicksnyder/go-i18n"
|
||||
packages = [
|
||||
"i18n/bundle",
|
||||
"i18n/language",
|
||||
"i18n/translation"
|
||||
"i18n/translation",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "0dc1626d56435e9d605a29875701721c54bc9bbd"
|
||||
version = "v1.10.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:2656200f82783893859c77903afc794d97c1f5054e2b57f7021e33a6047e7b1e"
|
||||
name = "github.com/olekukonko/tablewriter"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "b8a9be070da40449e501c3c4730a889e42d87a9e"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:fef37519c971ab3c464318a0c9da6a7fb9c21439aa587e61bf10af651e6119b9"
|
||||
name = "github.com/pelletier/go-toml"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "acdc4509485b587f5e675510c4f2c63e90ff68a8"
|
||||
version = "v1.1.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:256484dbbcd271f9ecebc6795b2df8cad4c458dd0f5fd82a8c2fa0c29f233411"
|
||||
name = "github.com/pmezard/go-difflib"
|
||||
packages = ["difflib"]
|
||||
pruneopts = ""
|
||||
revision = "792786c7400a136282c1664665ae0a8db921c6c2"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:10bc894f31df5ca3366a50122ee2ade6b56f3f5531c523a8a551748a0663aa1b"
|
||||
name = "github.com/russross/blackfriday"
|
||||
packages = ["."]
|
||||
revision = "55d61fa8aa702f59229e6cff85793c22e580eaf5"
|
||||
version = "v1.5.1"
|
||||
pruneopts = ""
|
||||
revision = "11635eb403ff09dbc3a6b5a007ab5ab09151c229"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:afa9b7bb3d9e633ef32e46ab4b6a87b5376271e3d86b09a379029bbb10e26fa0"
|
||||
name = "github.com/sanity-io/litter"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "ae543b7ba8fd6af63e4976198f146e1348ae53c1"
|
||||
version = "v1.1.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:1ebe873a8dc99e3316c30fea2e211038c4d1fcb605eee17e00a5e91b8817925e"
|
||||
name = "github.com/sergi/go-diff"
|
||||
packages = ["diffmatchpatch"]
|
||||
pruneopts = ""
|
||||
revision = "1744e2970ca51c86172c8190fadad617561ed6e7"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:606fa779c7a80ab6a9ec5836cd12759f86cd6e1d82d5d60cf7ec5133e78c6cf8"
|
||||
name = "github.com/shurcooL/sanitized_anchor_name"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "86672fcb3f950f35f2e675df2240550f2a50762f"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:3d6c88f060fdaac3291f3d18f58eb542fe3a2b330609b269962d26d0c99104be"
|
||||
name = "github.com/spf13/afero"
|
||||
packages = [
|
||||
".",
|
||||
"mem"
|
||||
"mem",
|
||||
]
|
||||
revision = "63644898a8da0bc22138abf860edaf5277b6102e"
|
||||
version = "v1.1.0"
|
||||
pruneopts = ""
|
||||
revision = "787d034dfe70e44075ccc060d346146ef53270ad"
|
||||
version = "v1.1.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:d0b38ba6da419a6d4380700218eeec8623841d44a856bb57369c172fbf692ab4"
|
||||
name = "github.com/spf13/cast"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "8965335b8c7107321228e3e3702cab9832751bac"
|
||||
version = "v1.2.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:9e14345bfb9aa30952b41ffceaa2acd559933cfe3d17bd87b7f6e54b6c618492"
|
||||
name = "github.com/spf13/cobra"
|
||||
packages = [
|
||||
".",
|
||||
"doc"
|
||||
"doc",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "a1f051bc3eba734da4772d60e2d677f47cf93ef4"
|
||||
version = "v0.0.2"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:7c00f445c89f468abd5ab86546ba1fa11bac66e63325ade8ca05aa7220791fc7"
|
||||
name = "github.com/spf13/fsync"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "12a01e648f05a938100a26858d2d59a120307a18"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:104517520aab91164020ab6524a5d6b7cafc641b2e42ac6236f6ac1deac4f66a"
|
||||
name = "github.com/spf13/jwalterweatherman"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "7c0cea34c8ece3fbeb2b27ab9b59511d360fb394"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:5082c0d57a199dabc0868010784039249af0932fad2990b51ad9404c9a6b6e5d"
|
||||
name = "github.com/spf13/nitro"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "24d7ef30a12da0bdc5e2eb370a79c659ddccf0e8"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:261bc565833ef4f02121450d74eb88d5ae4bd74bfe5d0e862cddb8550ec35000"
|
||||
name = "github.com/spf13/pflag"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "e57e3eeb33f795204c1ca35f56c44f83227c6e66"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:79af66c513727a0ed32fb4137ad7d0613b01e8e2f5ce9479724e26e2c9068011"
|
||||
name = "github.com/spf13/viper"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "b5e8006cbee93ec955a89ab31e0e3ce3204f3736"
|
||||
version = "v1.0.2"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:a70d585d45f695f2e8e6782569bdf181419667a35e6035ceb086706b495aa21a"
|
||||
name = "github.com/stretchr/testify"
|
||||
packages = [
|
||||
"assert",
|
||||
"require"
|
||||
"require",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "12b6f73e6084dad08a7c6e575284b177ecafbc71"
|
||||
version = "v1.2.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:54b1c3f97e0d74b571055cc17af4a978b6160e6ccfda73608aba048e404319c1"
|
||||
name = "github.com/tdewolff/minify"
|
||||
packages = [
|
||||
".",
|
||||
"css",
|
||||
"html",
|
||||
"js",
|
||||
"json",
|
||||
"svg",
|
||||
"xml",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "8d72a4127ae33b755e95bffede9b92e396267ce2"
|
||||
version = "v2.3.5"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:33d327ae34260328b00ed15f89961446d805797a96de8643a983020825bb51ae"
|
||||
name = "github.com/tdewolff/parse"
|
||||
packages = [
|
||||
".",
|
||||
"buffer",
|
||||
"css",
|
||||
"html",
|
||||
"js",
|
||||
"json",
|
||||
"strconv",
|
||||
"svg",
|
||||
"xml",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "d739d6fccb0971177e06352fea02d3552625efb1"
|
||||
version = "v2.3.3"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:12e69a2969bdcdf2928607e51966a868482c2a450f1c97c5dde004257c8369ff"
|
||||
name = "github.com/wellington/go-libsass"
|
||||
packages = ["libs"]
|
||||
pruneopts = ""
|
||||
revision = "615eaa47ef794d037c1906a0eb7bf85375a5decf"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:b1e5dc66cd8ad9712eb8fd4dfaecac6ae45cbcde94476c5b64d905c5d789eef7"
|
||||
name = "github.com/yosssi/ace"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "ea038f4770b6746c3f8f84f14fa60d9fe1205b56"
|
||||
version = "v0.0.5"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:4525c51a65e4974007814da8e2621343840d769d80b2b2ab79e6958342726587"
|
||||
name = "golang.org/x/image"
|
||||
packages = [
|
||||
"bmp",
|
||||
@@ -374,33 +578,41 @@
|
||||
"tiff/lzw",
|
||||
"vp8",
|
||||
"vp8l",
|
||||
"webp"
|
||||
"webp",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "f315e440302883054d0c2bd85486878cb4f8572c"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:8bb19e8d6e1321626d3f58ffee75699e86940c79d959b30fcf632883d7c4d303"
|
||||
name = "golang.org/x/net"
|
||||
packages = [
|
||||
"context",
|
||||
"idna"
|
||||
"idna",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "61147c48b25b599e5b561d2e9c4f3e1ef489ca41"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:d84d0f563cc649de4c9a8272a0395f75b11952202d18d4d927e933cc91493062"
|
||||
name = "golang.org/x/sync"
|
||||
packages = ["errgroup"]
|
||||
pruneopts = ""
|
||||
revision = "1d60e4601c6fd243af51cc01ddf169918a5407ca"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:137a530894d869c2fb09e135e6bb7a5d701347ba273471eaa2483053f8fbeb35"
|
||||
name = "golang.org/x/sys"
|
||||
packages = ["unix"]
|
||||
pruneopts = ""
|
||||
revision = "3b87a42e500a6dc65dae1a55d0b641295971163e"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:4cf01dae652ef4428cf9d354bdec79467e436ecfa92d943b1ada8184e1a938b6"
|
||||
name = "golang.org/x/text"
|
||||
packages = [
|
||||
"collate",
|
||||
@@ -419,19 +631,84 @@
|
||||
"unicode/cldr",
|
||||
"unicode/norm",
|
||||
"unicode/rangetable",
|
||||
"width"
|
||||
"width",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "2cb43934f0eece38629746959acc633cba083fe4"
|
||||
|
||||
[[projects]]
|
||||
branch = "v2"
|
||||
digest = "1:f0620375dd1f6251d9973b5f2596228cc8042e887cd7f827e4220bc1ce8c30e2"
|
||||
name = "gopkg.in/yaml.v2"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183"
|
||||
version = "v2.2.1"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "b9b38ece73fd6c0d0b20eb2ff85dfcc15a82841223b4403566712fd7b7ae7d59"
|
||||
input-imports = [
|
||||
"github.com/BurntSushi/locker",
|
||||
"github.com/BurntSushi/toml",
|
||||
"github.com/PuerkitoBio/purell",
|
||||
"github.com/alecthomas/assert",
|
||||
"github.com/alecthomas/chroma",
|
||||
"github.com/alecthomas/chroma/formatters",
|
||||
"github.com/alecthomas/chroma/formatters/html",
|
||||
"github.com/alecthomas/chroma/lexers",
|
||||
"github.com/alecthomas/chroma/styles",
|
||||
"github.com/bep/debounce",
|
||||
"github.com/bep/gitmap",
|
||||
"github.com/bep/go-tocss/scss",
|
||||
"github.com/bep/go-tocss/scss/libsass",
|
||||
"github.com/bep/go-tocss/tocss",
|
||||
"github.com/chaseadamsio/goorgeous",
|
||||
"github.com/disintegration/imaging",
|
||||
"github.com/eknkc/amber",
|
||||
"github.com/fortytw2/leaktest",
|
||||
"github.com/fsnotify/fsnotify",
|
||||
"github.com/gobwas/glob",
|
||||
"github.com/gorilla/websocket",
|
||||
"github.com/hashicorp/go-immutable-radix",
|
||||
"github.com/jdkato/prose/transform",
|
||||
"github.com/kyokomi/emoji",
|
||||
"github.com/magefile/mage/mg",
|
||||
"github.com/magefile/mage/sh",
|
||||
"github.com/markbates/inflect",
|
||||
"github.com/miekg/mmark",
|
||||
"github.com/mitchellh/hashstructure",
|
||||
"github.com/mitchellh/mapstructure",
|
||||
"github.com/muesli/smartcrop",
|
||||
"github.com/nicksnyder/go-i18n/i18n/bundle",
|
||||
"github.com/nicksnyder/go-i18n/i18n/language",
|
||||
"github.com/olekukonko/tablewriter",
|
||||
"github.com/russross/blackfriday",
|
||||
"github.com/sanity-io/litter",
|
||||
"github.com/spf13/afero",
|
||||
"github.com/spf13/cast",
|
||||
"github.com/spf13/cobra",
|
||||
"github.com/spf13/cobra/doc",
|
||||
"github.com/spf13/fsync",
|
||||
"github.com/spf13/jwalterweatherman",
|
||||
"github.com/spf13/nitro",
|
||||
"github.com/spf13/pflag",
|
||||
"github.com/spf13/viper",
|
||||
"github.com/stretchr/testify/assert",
|
||||
"github.com/stretchr/testify/require",
|
||||
"github.com/tdewolff/minify",
|
||||
"github.com/tdewolff/minify/css",
|
||||
"github.com/tdewolff/minify/html",
|
||||
"github.com/tdewolff/minify/js",
|
||||
"github.com/tdewolff/minify/json",
|
||||
"github.com/tdewolff/minify/svg",
|
||||
"github.com/tdewolff/minify/xml",
|
||||
"github.com/yosssi/ace",
|
||||
"golang.org/x/image/webp",
|
||||
"golang.org/x/net/context",
|
||||
"golang.org/x/sync/errgroup",
|
||||
"golang.org/x/text/transform",
|
||||
"golang.org/x/text/unicode/norm",
|
||||
"gopkg.in/yaml.v2",
|
||||
]
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
|
||||
@@ -10,12 +10,20 @@
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/alecthomas/chroma"
|
||||
branch = "master"
|
||||
revision = "1b755a90bd109f170385cb3964f0abdfd3451145"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/bep/gitmap"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/bep/go-tocss"
|
||||
|
||||
[[override]]
|
||||
branch = "master"
|
||||
name = "github.com/wellington/go-libsass"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/chaseadamsio/goorgeous"
|
||||
version = "^1.1.0"
|
||||
@@ -149,3 +157,15 @@
|
||||
[[constraint]]
|
||||
name = "github.com/bep/debounce"
|
||||
version = "^1.1.0"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/tdewolff/minify"
|
||||
version = "^2.3.5"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/BurntSushi/locker"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/mitchellh/hashstructure"
|
||||
|
||||
@@ -1,13 +1,19 @@
|
||||
image: Visual Studio 2015
|
||||
|
||||
init:
|
||||
- set PATH=%PATH%;C:\MinGW\bin;%GOPATH%\bin
|
||||
- set PATH=%PATH%;C:\mingw-w64\x86_64-7.3.0-posix-seh-rt_v5-rev0\mingw64\bin;%GOPATH%\bin
|
||||
- go version
|
||||
- go env
|
||||
|
||||
environment:
|
||||
GOPATH: C:\GOPATH\
|
||||
HUGO_BUILD_TAGS: extended
|
||||
|
||||
# clones and cd's to path
|
||||
clone_folder: C:\GOPATH\src\github.com\gohugoio\hugo
|
||||
|
||||
install:
|
||||
- gem install asciidoctor
|
||||
# - gem install asciidoctor
|
||||
- pip install docutils
|
||||
- go get github.com/magefile/mage
|
||||
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
# Temp script used to test new builds.
|
||||
docker run --rm --mount type=bind,source="$(pwd)",target=/go/src/github.com/gohugoio/hugo -w /go/src/github.com/gohugoio/hugo -i -t bepsays/ci-goreleaser:latest /bin/bash
|
||||
@@ -56,7 +56,7 @@ func (c *benchmarkCmd) benchmark(cmd *cobra.Command, args []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
comm, err := initializeConfig(false, &c.hugoBuilderCommon, c, cfgInit)
|
||||
comm, err := initializeConfig(true, false, &c.hugoBuilderCommon, c, cfgInit)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ package commands
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -34,36 +35,41 @@ import (
|
||||
"github.com/gohugoio/hugo/deps"
|
||||
"github.com/gohugoio/hugo/helpers"
|
||||
"github.com/gohugoio/hugo/hugofs"
|
||||
src "github.com/gohugoio/hugo/source"
|
||||
"github.com/gohugoio/hugo/langs"
|
||||
)
|
||||
|
||||
type commandeer struct {
|
||||
type commandeerHugoState struct {
|
||||
*deps.DepsCfg
|
||||
hugo *hugolib.HugoSites
|
||||
fsCreate sync.Once
|
||||
}
|
||||
|
||||
hugo *hugolib.HugoSites
|
||||
type commandeer struct {
|
||||
*commandeerHugoState
|
||||
|
||||
// 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.
|
||||
changeDetector *fileChangeDetector
|
||||
|
||||
// We need to reuse this on server rebuilds.
|
||||
destinationFs afero.Fs
|
||||
|
||||
h *hugoBuilderCommon
|
||||
ftch flagsToConfigHandler
|
||||
|
||||
pathSpec *helpers.PathSpec
|
||||
visitedURLs *types.EvictingStringQueue
|
||||
|
||||
staticDirsConfig []*src.Dirs
|
||||
|
||||
// We watch these for changes.
|
||||
configFiles []string
|
||||
|
||||
doWithCommandeer func(c *commandeer) error
|
||||
|
||||
// We can do this only once.
|
||||
fsCreate sync.Once
|
||||
// We watch these for changes.
|
||||
configFiles []string
|
||||
|
||||
// Used in cases where we get flooded with events in server mode.
|
||||
debounce func(f func())
|
||||
|
||||
serverPorts []int
|
||||
languagesConfigured bool
|
||||
languages helpers.Languages
|
||||
languages langs.Languages
|
||||
|
||||
configured bool
|
||||
}
|
||||
@@ -75,31 +81,14 @@ func (c *commandeer) Set(key string, value interface{}) {
|
||||
c.Cfg.Set(key, value)
|
||||
}
|
||||
|
||||
// PathSpec lazily creates a new PathSpec, as all the paths must
|
||||
// be configured before it is created.
|
||||
func (c *commandeer) PathSpec() *helpers.PathSpec {
|
||||
c.configured = true
|
||||
return c.pathSpec
|
||||
}
|
||||
|
||||
func (c *commandeer) initFs(fs *hugofs.Fs) error {
|
||||
c.destinationFs = fs.Destination
|
||||
c.DepsCfg.Fs = fs
|
||||
ps, err := helpers.NewPathSpec(fs, c.Cfg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.pathSpec = ps
|
||||
|
||||
dirsConfig, err := c.createStaticDirsConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.staticDirsConfig = dirsConfig
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func newCommandeer(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, doWithCommandeer func(c *commandeer) error, subCmdVs ...*cobra.Command) (*commandeer, error) {
|
||||
|
||||
var rebuildDebouncer func(f func())
|
||||
if running {
|
||||
@@ -110,17 +99,80 @@ func newCommandeer(running bool, h *hugoBuilderCommon, f flagsToConfigHandler, d
|
||||
}
|
||||
|
||||
c := &commandeer{
|
||||
h: h,
|
||||
ftch: f,
|
||||
doWithCommandeer: doWithCommandeer,
|
||||
visitedURLs: types.NewEvictingStringQueue(10),
|
||||
debounce: rebuildDebouncer,
|
||||
h: h,
|
||||
ftch: f,
|
||||
commandeerHugoState: &commandeerHugoState{},
|
||||
doWithCommandeer: doWithCommandeer,
|
||||
visitedURLs: types.NewEvictingStringQueue(10),
|
||||
debounce: rebuildDebouncer,
|
||||
}
|
||||
|
||||
return c, c.loadConfig(running)
|
||||
return c, c.loadConfig(mustHaveConfigFile, running)
|
||||
}
|
||||
|
||||
func (c *commandeer) loadConfig(running bool) error {
|
||||
type fileChangeDetector struct {
|
||||
sync.Mutex
|
||||
current map[string]string
|
||||
prev map[string]string
|
||||
|
||||
irrelevantRe *regexp.Regexp
|
||||
}
|
||||
|
||||
func (f *fileChangeDetector) OnFileClose(name, md5sum string) {
|
||||
f.Lock()
|
||||
defer f.Unlock()
|
||||
f.current[name] = md5sum
|
||||
}
|
||||
|
||||
func (f *fileChangeDetector) changed() []string {
|
||||
if f == nil {
|
||||
return nil
|
||||
}
|
||||
f.Lock()
|
||||
defer f.Unlock()
|
||||
var c []string
|
||||
for k, v := range f.current {
|
||||
vv, found := f.prev[k]
|
||||
if !found || v != vv {
|
||||
c = append(c, k)
|
||||
}
|
||||
}
|
||||
|
||||
return f.filterIrrelevant(c)
|
||||
}
|
||||
|
||||
func (f *fileChangeDetector) filterIrrelevant(in []string) []string {
|
||||
var filtered []string
|
||||
for _, v := range in {
|
||||
if !f.irrelevantRe.MatchString(v) {
|
||||
filtered = append(filtered, v)
|
||||
}
|
||||
}
|
||||
return filtered
|
||||
}
|
||||
|
||||
func (f *fileChangeDetector) PrepareNew() {
|
||||
if f == nil {
|
||||
return
|
||||
}
|
||||
|
||||
f.Lock()
|
||||
defer f.Unlock()
|
||||
|
||||
if f.current == nil {
|
||||
f.current = make(map[string]string)
|
||||
f.prev = make(map[string]string)
|
||||
return
|
||||
}
|
||||
|
||||
f.prev = make(map[string]string)
|
||||
for k, v := range f.current {
|
||||
f.prev[k] = v
|
||||
}
|
||||
f.current = make(map[string]string)
|
||||
}
|
||||
|
||||
func (c *commandeer) loadConfig(mustHaveConfigFile, running bool) error {
|
||||
|
||||
if c.DepsCfg == nil {
|
||||
c.DepsCfg = &deps.DepsCfg{}
|
||||
@@ -168,12 +220,18 @@ func (c *commandeer) loadConfig(running bool) error {
|
||||
doWithConfig)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
if mustHaveConfigFile {
|
||||
return err
|
||||
}
|
||||
if err != hugolib.ErrNoConfigFile {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
c.configFiles = configFiles
|
||||
|
||||
if l, ok := c.Cfg.Get("languagesSorted").(helpers.Languages); ok {
|
||||
if l, ok := c.Cfg.Get("languagesSorted").(langs.Languages); ok {
|
||||
c.languagesConfigured = true
|
||||
c.languages = l
|
||||
}
|
||||
@@ -203,12 +261,41 @@ func (c *commandeer) loadConfig(running bool) error {
|
||||
c.fsCreate.Do(func() {
|
||||
fs := hugofs.NewFrom(sourceFs, config)
|
||||
|
||||
// Hugo writes the output to memory instead of the disk.
|
||||
if createMemFs {
|
||||
if c.destinationFs != nil {
|
||||
// Need to reuse the destination on server rebuilds.
|
||||
fs.Destination = c.destinationFs
|
||||
} else if createMemFs {
|
||||
// Hugo writes the output to memory instead of the disk.
|
||||
fs.Destination = new(afero.MemMapFs)
|
||||
}
|
||||
|
||||
doLiveReload := !c.h.buildWatch && !config.GetBool("disableLiveReload")
|
||||
fastRenderMode := doLiveReload && !config.GetBool("disableFastRender")
|
||||
|
||||
if fastRenderMode {
|
||||
// For now, fast render mode only. It should, however, be fast enough
|
||||
// for the full variant, too.
|
||||
changeDetector := &fileChangeDetector{
|
||||
// We use this detector to decide to do a Hot reload of a single path or not.
|
||||
// We need to filter out source maps and possibly some other to be able
|
||||
// to make that decision.
|
||||
irrelevantRe: regexp.MustCompile(`\.map$`),
|
||||
}
|
||||
changeDetector.PrepareNew()
|
||||
fs.Destination = hugofs.NewHashingFs(fs.Destination, changeDetector)
|
||||
c.changeDetector = changeDetector
|
||||
}
|
||||
|
||||
err = c.initFs(fs)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var h *hugolib.HugoSites
|
||||
|
||||
h, err = hugolib.NewHugoSites(*c.DepsCfg)
|
||||
c.hugo = h
|
||||
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
@@ -232,7 +319,7 @@ func (c *commandeer) loadConfig(running bool) error {
|
||||
|
||||
cfg.Logger.INFO.Println("Using config file:", config.ConfigFileUsed())
|
||||
|
||||
themeDir := c.PathSpec().GetThemeDir()
|
||||
themeDir := c.hugo.PathSpec.GetFirstThemeDir()
|
||||
if themeDir != "" {
|
||||
if _, err := sourceFs.Stat(themeDir); os.IsNotExist(err) {
|
||||
return newSystemError("Unable to find theme Directory:", themeDir)
|
||||
|
||||
@@ -148,7 +148,7 @@ Complete documentation is available at http://gohugo.io/.`,
|
||||
return nil
|
||||
}
|
||||
|
||||
c, err := initializeConfig(cc.buildWatch, &cc.hugoBuilderCommon, cc, cfgInit)
|
||||
c, err := initializeConfig(true, cc.buildWatch, &cc.hugoBuilderCommon, cc, cfgInit)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ func newConfigCmd() *configCmd {
|
||||
}
|
||||
|
||||
func (c *configCmd) printConfig(cmd *cobra.Command, args []string) error {
|
||||
cfg, err := initializeConfig(false, &c.hugoBuilderCommon, c, nil)
|
||||
cfg, err := initializeConfig(true, false, &c.hugoBuilderCommon, c, nil)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -96,7 +96,7 @@ func (cc *convertCmd) convertContents(mark rune) error {
|
||||
return newUserError("Unsafe operation not allowed, use --unsafe or set a different output path")
|
||||
}
|
||||
|
||||
c, err := initializeConfig(false, &cc.hugoBuilderCommon, cc, nil)
|
||||
c, err := initializeConfig(true, false, &cc.hugoBuilderCommon, cc, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -23,6 +23,8 @@ import (
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
|
||||
"github.com/gohugoio/hugo/hugolib/filesystems"
|
||||
|
||||
"golang.org/x/sync/errgroup"
|
||||
|
||||
"log"
|
||||
@@ -32,8 +34,6 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
src "github.com/gohugoio/hugo/source"
|
||||
|
||||
"github.com/gohugoio/hugo/config"
|
||||
|
||||
"github.com/gohugoio/hugo/parser"
|
||||
@@ -103,12 +103,12 @@ func Execute(args []string) Response {
|
||||
}
|
||||
|
||||
// InitializeConfig initializes a config file with sensible default configuration flags.
|
||||
func initializeConfig(running bool,
|
||||
func initializeConfig(mustHaveConfigFile, running bool,
|
||||
h *hugoBuilderCommon,
|
||||
f flagsToConfigHandler,
|
||||
doWithCommandeer func(c *commandeer) error) (*commandeer, error) {
|
||||
|
||||
c, err := newCommandeer(running, h, f, doWithCommandeer)
|
||||
c, err := newCommandeer(mustHaveConfigFile, running, h, f, doWithCommandeer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -277,9 +277,13 @@ func (c *commandeer) fullBuild() error {
|
||||
copyStaticFunc := func() error {
|
||||
cnt, err := c.copyStatic()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error copying static files: %s", err)
|
||||
if !os.IsNotExist(err) {
|
||||
return fmt.Errorf("Error copying static files: %s", err)
|
||||
}
|
||||
c.Logger.WARN.Println("No Static directory found")
|
||||
}
|
||||
langCount = cnt
|
||||
langCount = cnt
|
||||
return nil
|
||||
}
|
||||
buildSitesFunc := func() error {
|
||||
@@ -344,7 +348,7 @@ func (c *commandeer) build() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.Logger.FEEDBACK.Println("Watching for changes in", c.PathSpec().AbsPathify(c.Cfg.GetString("contentDir")))
|
||||
c.Logger.FEEDBACK.Println("Watching for changes in", c.hugo.PathSpec.AbsPathify(c.Cfg.GetString("contentDir")))
|
||||
c.Logger.FEEDBACK.Println("Press Ctrl+C to stop")
|
||||
watcher, err := c.newWatcher(watchDirs...)
|
||||
utils.CheckErr(c.Logger, err)
|
||||
@@ -380,49 +384,30 @@ func (c *commandeer) copyStatic() (map[string]uint64, error) {
|
||||
return c.doWithPublishDirs(c.copyStaticTo)
|
||||
}
|
||||
|
||||
func (c *commandeer) createStaticDirsConfig() ([]*src.Dirs, error) {
|
||||
var dirsConfig []*src.Dirs
|
||||
|
||||
if !c.languages.IsMultihost() {
|
||||
dirs, err := src.NewDirs(c.Fs, c.Cfg, c.DepsCfg.Logger)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dirsConfig = append(dirsConfig, dirs)
|
||||
} else {
|
||||
for _, l := range c.languages {
|
||||
dirs, err := src.NewDirs(c.Fs, l, c.DepsCfg.Logger)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dirsConfig = append(dirsConfig, dirs)
|
||||
}
|
||||
}
|
||||
|
||||
return dirsConfig, nil
|
||||
|
||||
}
|
||||
|
||||
func (c *commandeer) doWithPublishDirs(f func(dirs *src.Dirs, publishDir string) (uint64, error)) (map[string]uint64, error) {
|
||||
func (c *commandeer) doWithPublishDirs(f func(sourceFs *filesystems.SourceFilesystem) (uint64, error)) (map[string]uint64, error) {
|
||||
|
||||
langCount := make(map[string]uint64)
|
||||
|
||||
for _, dirs := range c.staticDirsConfig {
|
||||
staticFilesystems := c.hugo.BaseFs.SourceFilesystems.Static
|
||||
|
||||
cnt, err := f(dirs, c.pathSpec.PublishDir)
|
||||
if len(staticFilesystems) == 0 {
|
||||
c.Logger.WARN.Println("No static directories found to sync")
|
||||
return langCount, nil
|
||||
}
|
||||
|
||||
for lang, fs := range staticFilesystems {
|
||||
cnt, err := f(fs)
|
||||
if err != nil {
|
||||
return langCount, err
|
||||
}
|
||||
|
||||
if dirs.Language == nil {
|
||||
if lang == "" {
|
||||
// Not multihost
|
||||
for _, l := range c.languages {
|
||||
langCount[l.Lang] = cnt
|
||||
}
|
||||
} else {
|
||||
langCount[dirs.Language.Lang] = cnt
|
||||
langCount[lang] = cnt
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return langCount, nil
|
||||
@@ -443,29 +428,18 @@ func (fs *countingStatFs) Stat(name string) (os.FileInfo, error) {
|
||||
return f, err
|
||||
}
|
||||
|
||||
func (c *commandeer) copyStaticTo(dirs *src.Dirs, publishDir string) (uint64, error) {
|
||||
|
||||
func (c *commandeer) copyStaticTo(sourceFs *filesystems.SourceFilesystem) (uint64, error) {
|
||||
publishDir := c.hugo.PathSpec.PublishDir
|
||||
// If root, remove the second '/'
|
||||
if publishDir == "//" {
|
||||
publishDir = helpers.FilePathSeparator
|
||||
}
|
||||
|
||||
if dirs.Language != nil {
|
||||
// Multihost setup.
|
||||
publishDir = filepath.Join(publishDir, dirs.Language.Lang)
|
||||
if sourceFs.PublishFolder != "" {
|
||||
publishDir = filepath.Join(publishDir, sourceFs.PublishFolder)
|
||||
}
|
||||
|
||||
staticSourceFs, err := dirs.CreateStaticFs()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if staticSourceFs == nil {
|
||||
c.Logger.WARN.Println("No static directories found to sync")
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
fs := &countingStatFs{Fs: staticSourceFs}
|
||||
fs := &countingStatFs{Fs: sourceFs.Fs}
|
||||
|
||||
syncer := fsync.NewSyncer()
|
||||
syncer.NoTimes = c.Cfg.GetBool("noTimes")
|
||||
@@ -485,6 +459,8 @@ func (c *commandeer) copyStaticTo(dirs *src.Dirs, publishDir string) (uint64, er
|
||||
}
|
||||
c.Logger.INFO.Println("syncing static files to", publishDir)
|
||||
|
||||
var err error
|
||||
|
||||
// because we are using a baseFs (to get the union right).
|
||||
// set sync src to root
|
||||
err = syncer.Sync(publishDir, helpers.FilePathSeparator)
|
||||
@@ -498,6 +474,10 @@ func (c *commandeer) copyStaticTo(dirs *src.Dirs, publishDir string) (uint64, er
|
||||
return numFiles, err
|
||||
}
|
||||
|
||||
func (c *commandeer) firstPathSpec() *helpers.PathSpec {
|
||||
return c.hugo.Sites[0].PathSpec
|
||||
}
|
||||
|
||||
func (c *commandeer) timeTrack(start time.Time, name string) {
|
||||
if c.h.quiet {
|
||||
return
|
||||
@@ -514,41 +494,10 @@ func (c *commandeer) getDirList() ([]string, error) {
|
||||
var seen = make(map[string]bool)
|
||||
var nested []string
|
||||
|
||||
dataDir := c.PathSpec().AbsPathify(c.Cfg.GetString("dataDir"))
|
||||
i18nDir := c.PathSpec().AbsPathify(c.Cfg.GetString("i18nDir"))
|
||||
staticSyncer, err := newStaticSyncer(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
layoutDir := c.PathSpec().GetLayoutDirPath()
|
||||
staticDirs := staticSyncer.d.AbsStaticDirs
|
||||
|
||||
newWalker := func(allowSymbolicDirs bool) func(path string, fi os.FileInfo, err error) error {
|
||||
return func(path string, fi os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
if path == dataDir && os.IsNotExist(err) {
|
||||
c.Logger.WARN.Println("Skip dataDir:", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
if path == i18nDir && os.IsNotExist(err) {
|
||||
c.Logger.WARN.Println("Skip i18nDir:", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
if path == layoutDir && os.IsNotExist(err) {
|
||||
c.Logger.WARN.Println("Skip layoutDir:", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
if os.IsNotExist(err) {
|
||||
for _, staticDir := range staticDirs {
|
||||
if path == staticDir && os.IsNotExist(err) {
|
||||
c.Logger.WARN.Println("Skip staticDir:", err)
|
||||
}
|
||||
}
|
||||
// Ignore.
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -605,23 +554,32 @@ func (c *commandeer) getDirList() ([]string, error) {
|
||||
regularWalker := newWalker(false)
|
||||
|
||||
// SymbolicWalk will log anny ERRORs
|
||||
_ = helpers.SymbolicWalk(c.Fs.Source, dataDir, regularWalker)
|
||||
_ = helpers.SymbolicWalk(c.Fs.Source, i18nDir, regularWalker)
|
||||
_ = helpers.SymbolicWalk(c.Fs.Source, layoutDir, regularWalker)
|
||||
|
||||
for _, contentDir := range c.PathSpec().ContentDirs() {
|
||||
_ = helpers.SymbolicWalk(c.Fs.Source, contentDir.Value, symLinkWalker)
|
||||
// Also note that the Dirnames fetched below will contain any relevant theme
|
||||
// directories.
|
||||
for _, contentDir := range c.hugo.PathSpec.BaseFs.Content.Dirnames {
|
||||
_ = helpers.SymbolicWalk(c.Fs.Source, contentDir, symLinkWalker)
|
||||
}
|
||||
|
||||
for _, staticDir := range staticDirs {
|
||||
for _, staticDir := range c.hugo.PathSpec.BaseFs.Data.Dirnames {
|
||||
_ = helpers.SymbolicWalk(c.Fs.Source, staticDir, regularWalker)
|
||||
}
|
||||
|
||||
if c.PathSpec().ThemeSet() {
|
||||
themesDir := c.PathSpec().GetThemeDir()
|
||||
_ = helpers.SymbolicWalk(c.Fs.Source, filepath.Join(themesDir, "layouts"), regularWalker)
|
||||
_ = helpers.SymbolicWalk(c.Fs.Source, filepath.Join(themesDir, "i18n"), regularWalker)
|
||||
_ = helpers.SymbolicWalk(c.Fs.Source, filepath.Join(themesDir, "data"), regularWalker)
|
||||
for _, staticDir := range c.hugo.PathSpec.BaseFs.I18n.Dirnames {
|
||||
_ = helpers.SymbolicWalk(c.Fs.Source, staticDir, regularWalker)
|
||||
}
|
||||
|
||||
for _, staticDir := range c.hugo.PathSpec.BaseFs.Layouts.Dirnames {
|
||||
_ = helpers.SymbolicWalk(c.Fs.Source, staticDir, regularWalker)
|
||||
}
|
||||
|
||||
for _, staticFilesystem := range c.hugo.PathSpec.BaseFs.Static {
|
||||
for _, staticDir := range staticFilesystem.Dirnames {
|
||||
_ = helpers.SymbolicWalk(c.Fs.Source, staticDir, regularWalker)
|
||||
}
|
||||
}
|
||||
|
||||
for _, assetDir := range c.hugo.PathSpec.BaseFs.Assets.Dirnames {
|
||||
_ = helpers.SymbolicWalk(c.Fs.Source, assetDir, regularWalker)
|
||||
}
|
||||
|
||||
if len(nested) > 0 {
|
||||
@@ -646,69 +604,31 @@ func (c *commandeer) getDirList() ([]string, error) {
|
||||
return a, nil
|
||||
}
|
||||
|
||||
func (c *commandeer) recreateAndBuildSites(watching bool) (err error) {
|
||||
defer c.timeTrack(time.Now(), "Total")
|
||||
if err := c.initSites(); err != nil {
|
||||
return err
|
||||
}
|
||||
if !c.h.quiet {
|
||||
c.Logger.FEEDBACK.Println("Started building sites ...")
|
||||
}
|
||||
return c.hugo.Build(hugolib.BuildCfg{CreateSitesFromConfig: true})
|
||||
}
|
||||
|
||||
func (c *commandeer) resetAndBuildSites() (err error) {
|
||||
if err = c.initSites(); err != nil {
|
||||
return
|
||||
}
|
||||
if !c.h.quiet {
|
||||
c.Logger.FEEDBACK.Println("Started building sites ...")
|
||||
}
|
||||
return c.hugo.Build(hugolib.BuildCfg{ResetState: true})
|
||||
}
|
||||
|
||||
func (c *commandeer) initSites() error {
|
||||
if c.hugo != nil {
|
||||
c.hugo.Cfg = c.Cfg
|
||||
c.hugo.Log.ResetLogCounters()
|
||||
return nil
|
||||
}
|
||||
|
||||
h, err := hugolib.NewHugoSites(*c.DepsCfg)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.hugo = h
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *commandeer) buildSites() (err error) {
|
||||
if err := c.initSites(); err != nil {
|
||||
return err
|
||||
}
|
||||
return c.hugo.Build(hugolib.BuildCfg{})
|
||||
}
|
||||
|
||||
func (c *commandeer) rebuildSites(events []fsnotify.Event) error {
|
||||
defer c.timeTrack(time.Now(), "Total")
|
||||
|
||||
if err := c.initSites(); err != nil {
|
||||
return err
|
||||
}
|
||||
visited := c.visitedURLs.PeekAllSet()
|
||||
doLiveReload := !c.h.buildWatch && !c.Cfg.GetBool("disableLiveReload")
|
||||
if doLiveReload && !c.Cfg.GetBool("disableFastRender") {
|
||||
|
||||
// Make sure we always render the home pages
|
||||
for _, l := range c.languages {
|
||||
langPath := c.PathSpec().GetLangSubDir(l.Lang)
|
||||
langPath := c.hugo.PathSpec.GetLangSubDir(l.Lang)
|
||||
if langPath != "" {
|
||||
langPath = langPath + "/"
|
||||
}
|
||||
home := c.pathSpec.PrependBasePath("/" + langPath)
|
||||
home := c.hugo.PathSpec.PrependBasePath("/" + langPath)
|
||||
visited[home] = true
|
||||
}
|
||||
|
||||
@@ -717,9 +637,10 @@ func (c *commandeer) rebuildSites(events []fsnotify.Event) error {
|
||||
}
|
||||
|
||||
func (c *commandeer) fullRebuild() {
|
||||
if err := c.loadConfig(true); err != nil {
|
||||
c.commandeerHugoState = &commandeerHugoState{}
|
||||
if err := c.loadConfig(true, true); err != nil {
|
||||
jww.ERROR.Println("Failed to reload config:", err)
|
||||
} else if err := c.recreateAndBuildSites(true); err != nil {
|
||||
} else if err := c.buildSites(); err != nil {
|
||||
jww.ERROR.Println(err)
|
||||
} else if !c.h.buildWatch && !c.Cfg.GetBool("disableLiveReload") {
|
||||
livereload.ForceRefresh()
|
||||
@@ -905,12 +826,11 @@ func (c *commandeer) newWatcher(dirList ...string) (*watcher.Batcher, error) {
|
||||
// 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) > 0 {
|
||||
for _, ev := range staticEvents {
|
||||
path := staticSyncer.d.MakeStaticPathRelative(ev.Name)
|
||||
livereload.RefreshPath(path)
|
||||
}
|
||||
|
||||
if 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()
|
||||
}
|
||||
@@ -918,34 +838,54 @@ func (c *commandeer) newWatcher(dirList ...string) (*watcher.Batcher, error) {
|
||||
}
|
||||
|
||||
if len(dynamicEvents) > 0 {
|
||||
partitionedEvents := partitionDynamicEvents(
|
||||
c.firstPathSpec().BaseFs.SourceFilesystems,
|
||||
dynamicEvents)
|
||||
|
||||
doLiveReload := !c.h.buildWatch && !c.Cfg.GetBool("disableLiveReload")
|
||||
onePageName := pickOneWriteOrCreatePath(dynamicEvents)
|
||||
onePageName := pickOneWriteOrCreatePath(partitionedEvents.ContentEvents)
|
||||
|
||||
c.Logger.FEEDBACK.Println("\nChange detected, rebuilding site")
|
||||
const layout = "2006-01-02 15:04:05.000 -0700"
|
||||
c.Logger.FEEDBACK.Println(time.Now().Format(layout))
|
||||
|
||||
c.changeDetector.PrepareNew()
|
||||
if err := c.rebuildSites(dynamicEvents); err != nil {
|
||||
c.Logger.ERROR.Println("Failed to rebuild site:", err)
|
||||
}
|
||||
|
||||
if doLiveReload {
|
||||
navigate := c.Cfg.GetBool("navigateToChanged")
|
||||
// We have fetched the same page above, but it may have
|
||||
// changed.
|
||||
var p *hugolib.Page
|
||||
|
||||
if navigate {
|
||||
if onePageName != "" {
|
||||
p = c.hugo.GetContentPage(onePageName)
|
||||
if len(partitionedEvents.ContentEvents) == 0 && len(partitionedEvents.AssetEvents) > 0 {
|
||||
changed := c.changeDetector.changed()
|
||||
if c.changeDetector != nil && len(changed) == 0 {
|
||||
// Nothing has changed.
|
||||
continue
|
||||
} else if len(changed) == 1 {
|
||||
pathToRefresh := c.firstPathSpec().RelURL(helpers.ToSlashTrimLeading(changed[0]), false)
|
||||
livereload.RefreshPath(pathToRefresh)
|
||||
} else {
|
||||
livereload.ForceRefresh()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if p != nil {
|
||||
livereload.NavigateToPathForPort(p.RelPermalink(), p.Site.ServerPort())
|
||||
} else {
|
||||
livereload.ForceRefresh()
|
||||
if len(partitionedEvents.ContentEvents) > 0 {
|
||||
|
||||
navigate := c.Cfg.GetBool("navigateToChanged")
|
||||
// We have fetched the same page above, but it may have
|
||||
// changed.
|
||||
var p *hugolib.Page
|
||||
|
||||
if navigate {
|
||||
if onePageName != "" {
|
||||
p = c.hugo.GetContentPage(onePageName)
|
||||
}
|
||||
}
|
||||
|
||||
if p != nil {
|
||||
livereload.NavigateToPathForPort(p.RelPermalink(), p.Site.ServerPort())
|
||||
} else {
|
||||
livereload.ForceRefresh()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -960,6 +900,26 @@ func (c *commandeer) newWatcher(dirList ...string) (*watcher.Batcher, error) {
|
||||
return watcher, nil
|
||||
}
|
||||
|
||||
// dynamicEvents contains events that is considered dynamic, as in "not static".
|
||||
// Both of these categories will trigger a new build, but the asset events
|
||||
// does not fit into the "navigate to changed" logic.
|
||||
type dynamicEvents struct {
|
||||
ContentEvents []fsnotify.Event
|
||||
AssetEvents []fsnotify.Event
|
||||
}
|
||||
|
||||
func partitionDynamicEvents(sourceFs *filesystems.SourceFilesystems, events []fsnotify.Event) (de dynamicEvents) {
|
||||
for _, e := range events {
|
||||
if sourceFs.IsAsset(e.Name) {
|
||||
de.AssetEvents = append(de.AssetEvents, e)
|
||||
} else {
|
||||
de.ContentEvents = append(de.ContentEvents, e)
|
||||
}
|
||||
}
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
func pickOneWriteOrCreatePath(events []fsnotify.Event) string {
|
||||
name := ""
|
||||
|
||||
@@ -976,32 +936,36 @@ func pickOneWriteOrCreatePath(events []fsnotify.Event) string {
|
||||
}
|
||||
|
||||
// isThemeVsHugoVersionMismatch returns whether the current Hugo version is
|
||||
// less than the theme's min_version.
|
||||
// less than any of the themes' min_version.
|
||||
func (c *commandeer) isThemeVsHugoVersionMismatch(fs afero.Fs) (mismatch bool, requiredMinVersion string) {
|
||||
if !c.PathSpec().ThemeSet() {
|
||||
if !c.hugo.PathSpec.ThemeSet() {
|
||||
return
|
||||
}
|
||||
|
||||
themeDir := c.PathSpec().GetThemeDir()
|
||||
for _, absThemeDir := range c.hugo.BaseFs.AbsThemeDirs {
|
||||
|
||||
path := filepath.Join(themeDir, "theme.toml")
|
||||
path := filepath.Join(absThemeDir, "theme.toml")
|
||||
|
||||
exists, err := helpers.Exists(path, fs)
|
||||
exists, err := helpers.Exists(path, fs)
|
||||
|
||||
if err != nil || !exists {
|
||||
return
|
||||
}
|
||||
if err != nil || !exists {
|
||||
continue
|
||||
}
|
||||
|
||||
b, err := afero.ReadFile(fs, path)
|
||||
b, err := afero.ReadFile(fs, path)
|
||||
|
||||
tomlMeta, err := parser.HandleTOMLMetaData(b)
|
||||
tomlMeta, err := parser.HandleTOMLMetaData(b)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if minVersion, ok := tomlMeta["min_version"]; ok {
|
||||
if helpers.CompareVersion(minVersion) > 0 {
|
||||
return true, fmt.Sprint(minVersion)
|
||||
}
|
||||
}
|
||||
|
||||
if minVersion, ok := tomlMeta["min_version"]; ok {
|
||||
return helpers.CompareVersion(minVersion) > 0, fmt.Sprint(minVersion)
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
@@ -50,7 +50,7 @@ List requires a subcommand, e.g. ` + "`hugo list drafts`.",
|
||||
c.Set("buildDrafts", true)
|
||||
return nil
|
||||
}
|
||||
c, err := initializeConfig(false, &cc.hugoBuilderCommon, cc, cfgInit)
|
||||
c, err := initializeConfig(true, false, &cc.hugoBuilderCommon, cc, cfgInit)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -86,7 +86,7 @@ posted in the future.`,
|
||||
c.Set("buildFuture", true)
|
||||
return nil
|
||||
}
|
||||
c, err := initializeConfig(false, &cc.hugoBuilderCommon, cc, cfgInit)
|
||||
c, err := initializeConfig(true, false, &cc.hugoBuilderCommon, cc, cfgInit)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -122,7 +122,7 @@ expired.`,
|
||||
c.Set("buildExpired", true)
|
||||
return nil
|
||||
}
|
||||
c, err := initializeConfig(false, &cc.hugoBuilderCommon, cc, cfgInit)
|
||||
c, err := initializeConfig(true, false, &cc.hugoBuilderCommon, cc, cfgInit)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ func (n *newCmd) newContent(cmd *cobra.Command, args []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
c, err := initializeConfig(false, &n.hugoBuilderCommon, n, cfgInit)
|
||||
c, err := initializeConfig(true, false, &n.hugoBuilderCommon, n, cfgInit)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -104,9 +104,6 @@ func (n *newCmd) newContent(cmd *cobra.Command, args []string) error {
|
||||
return hugolib.NewSite(*cfg)
|
||||
}
|
||||
var s *hugolib.Site
|
||||
if err := c.initSites(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := c.hugo.Build(hugolib.BuildCfg{SkipRender: true}); err != nil {
|
||||
return nil, err
|
||||
@@ -129,27 +126,6 @@ func (n *newCmd) newContent(cmd *cobra.Command, args []string) error {
|
||||
return create.NewContent(ps, siteFactory, kind, createPath)
|
||||
}
|
||||
|
||||
func nextStepsText() string {
|
||||
var nextStepsText bytes.Buffer
|
||||
|
||||
nextStepsText.WriteString(`Just a few more steps and you're ready to go:
|
||||
|
||||
1. Download a theme into the same-named folder.
|
||||
Choose a theme from https://themes.gohugo.io/, or
|
||||
create your own with the "hugo new theme <THEMENAME>" command.
|
||||
2. Perhaps you want to add some content. You can add single files
|
||||
with "hugo new `)
|
||||
|
||||
nextStepsText.WriteString(filepath.Join("<SECTIONNAME>", "<FILENAME>.<FORMAT>"))
|
||||
|
||||
nextStepsText.WriteString(`".
|
||||
3. Start the built-in live server via "hugo server".
|
||||
|
||||
Visit https://gohugo.io/ for quickstart guide and full documentation.`)
|
||||
|
||||
return nextStepsText.String()
|
||||
}
|
||||
|
||||
func mkdir(x ...string) {
|
||||
p := filepath.Join(x...)
|
||||
|
||||
|
||||
@@ -15,24 +15,18 @@ package commands
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"errors"
|
||||
|
||||
"github.com/gohugoio/hugo/create"
|
||||
|
||||
"fmt"
|
||||
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/gohugoio/hugo/parser"
|
||||
|
||||
"github.com/gohugoio/hugo/create"
|
||||
"github.com/gohugoio/hugo/helpers"
|
||||
"github.com/gohugoio/hugo/hugofs"
|
||||
"github.com/gohugoio/hugo/parser"
|
||||
"github.com/spf13/cobra"
|
||||
jww "github.com/spf13/jwalterweatherman"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
var _ cmder = (*newSiteCmd)(nil)
|
||||
@@ -104,7 +98,7 @@ func (n *newSiteCmd) doNewSite(fs *hugofs.Fs, basepath string, force bool) error
|
||||
|
||||
createConfig(fs, basepath, n.configFormat)
|
||||
|
||||
// Create a defaul archetype file.
|
||||
// Create a default archetype file.
|
||||
helpers.SafeWriteToDisk(filepath.Join(archeTypePath, "default.md"),
|
||||
strings.NewReader(create.ArchetypeTemplateTemplate), fs.Source)
|
||||
|
||||
@@ -146,3 +140,24 @@ func createConfig(fs *hugofs.Fs, inpath string, kind string) (err error) {
|
||||
|
||||
return helpers.WriteToDisk(filepath.Join(inpath, "config."+kind), &buf, fs.Source)
|
||||
}
|
||||
|
||||
func nextStepsText() string {
|
||||
var nextStepsText bytes.Buffer
|
||||
|
||||
nextStepsText.WriteString(`Just a few more steps and you're ready to go:
|
||||
|
||||
1. Download a theme into the same-named folder.
|
||||
Choose a theme from https://themes.gohugo.io/, or
|
||||
create your own with the "hugo new theme <THEMENAME>" command.
|
||||
2. Perhaps you want to add some content. You can add single files
|
||||
with "hugo new `)
|
||||
|
||||
nextStepsText.WriteString(filepath.Join("<SECTIONNAME>", "<FILENAME>.<FORMAT>"))
|
||||
|
||||
nextStepsText.WriteString(`".
|
||||
3. Start the built-in live server via "hugo server".
|
||||
|
||||
Visit https://gohugo.io/ for quickstart guide and full documentation.`)
|
||||
|
||||
return nextStepsText.String()
|
||||
}
|
||||
|
||||
@@ -14,16 +14,14 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
|
||||
"bytes"
|
||||
|
||||
"errors"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gohugoio/hugo/hugofs"
|
||||
|
||||
"github.com/gohugoio/hugo/helpers"
|
||||
"github.com/gohugoio/hugo/hugofs"
|
||||
"github.com/spf13/cobra"
|
||||
jww "github.com/spf13/jwalterweatherman"
|
||||
)
|
||||
@@ -53,8 +51,9 @@ as you see fit.`,
|
||||
return ccmd
|
||||
}
|
||||
|
||||
// newTheme creates a new Hugo theme template
|
||||
func (n *newThemeCmd) newTheme(cmd *cobra.Command, args []string) error {
|
||||
c, err := initializeConfig(false, &n.hugoBuilderCommon, n, nil)
|
||||
c, err := initializeConfig(false, false, &n.hugoBuilderCommon, n, nil)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -64,13 +63,13 @@ func (n *newThemeCmd) newTheme(cmd *cobra.Command, args []string) error {
|
||||
return newUserError("theme name needs to be provided")
|
||||
}
|
||||
|
||||
createpath := c.PathSpec().AbsPathify(filepath.Join(c.Cfg.GetString("themesDir"), args[0]))
|
||||
jww.INFO.Println("creating theme at", createpath)
|
||||
createpath := c.hugo.PathSpec.AbsPathify(filepath.Join(c.Cfg.GetString("themesDir"), args[0]))
|
||||
jww.FEEDBACK.Println("Creating theme at", createpath)
|
||||
|
||||
cfg := c.DepsCfg
|
||||
|
||||
if x, _ := helpers.Exists(createpath, cfg.Fs.Source); x {
|
||||
return newUserError(createpath, "already exists")
|
||||
return errors.New(createpath + " already exists")
|
||||
}
|
||||
|
||||
mkdir(createpath, "layouts", "_default")
|
||||
@@ -81,6 +80,24 @@ func (n *newThemeCmd) newTheme(cmd *cobra.Command, args []string) error {
|
||||
touchFile(cfg.Fs.Source, createpath, "layouts", "_default", "list.html")
|
||||
touchFile(cfg.Fs.Source, createpath, "layouts", "_default", "single.html")
|
||||
|
||||
baseofDefault := []byte(`<!DOCTYPE html>
|
||||
<html>
|
||||
{{- partial "head.html" . -}}
|
||||
<body>
|
||||
{{- partial "header.html" . -}}
|
||||
<div id="content">
|
||||
{{- block "main" . }}{{- end }}
|
||||
</div>
|
||||
{{- partial "footer.html" . -}}
|
||||
</body>
|
||||
</html>
|
||||
`)
|
||||
err = helpers.WriteToDisk(filepath.Join(createpath, "layouts", "_default", "baseof.html"), bytes.NewReader(baseofDefault), cfg.Fs.Source)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
touchFile(cfg.Fs.Source, createpath, "layouts", "partials", "head.html")
|
||||
touchFile(cfg.Fs.Source, createpath, "layouts", "partials", "header.html")
|
||||
touchFile(cfg.Fs.Source, createpath, "layouts", "partials", "footer.html")
|
||||
|
||||
@@ -118,7 +135,7 @@ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
`)
|
||||
|
||||
err = helpers.WriteToDisk(filepath.Join(createpath, "LICENSE.md"), bytes.NewReader(by), cfg.Fs.Source)
|
||||
err = helpers.WriteToDisk(filepath.Join(createpath, "LICENSE"), bytes.NewReader(by), cfg.Fs.Source)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -135,12 +152,12 @@ func (n *newThemeCmd) createThemeMD(fs *hugofs.Fs, inpath string) (err error) {
|
||||
|
||||
name = "` + strings.Title(helpers.MakeTitle(filepath.Base(inpath))) + `"
|
||||
license = "MIT"
|
||||
licenselink = "https://github.com/yourname/yourtheme/blob/master/LICENSE.md"
|
||||
licenselink = "https://github.com/yourname/yourtheme/blob/master/LICENSE"
|
||||
description = ""
|
||||
homepage = "http://example.com/"
|
||||
tags = []
|
||||
features = []
|
||||
min_version = "0.38"
|
||||
min_version = "0.41"
|
||||
|
||||
[author]
|
||||
name = ""
|
||||
|
||||
@@ -226,7 +226,7 @@ func (s *serverCmd) server(cmd *cobra.Command, args []string) error {
|
||||
jww.ERROR.Println("memstats error:", err)
|
||||
}
|
||||
|
||||
c, err := initializeConfig(true, &s.hugoBuilderCommon, s, cfgInit)
|
||||
c, err := initializeConfig(true, true, &s.hugoBuilderCommon, s, cfgInit)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -288,7 +288,7 @@ func (f *fileServer) createEndpoint(i int) (*http.ServeMux, string, string, erro
|
||||
publishDir = filepath.Join(publishDir, root)
|
||||
}
|
||||
|
||||
absPublishDir := f.c.PathSpec().AbsPathify(publishDir)
|
||||
absPublishDir := f.c.hugo.PathSpec.AbsPathify(publishDir)
|
||||
|
||||
if i == 0 {
|
||||
if f.s.renderToDisk {
|
||||
@@ -298,7 +298,7 @@ func (f *fileServer) createEndpoint(i int) (*http.ServeMux, string, string, erro
|
||||
}
|
||||
}
|
||||
|
||||
httpFs := afero.NewHttpFs(f.c.Fs.Destination)
|
||||
httpFs := afero.NewHttpFs(f.c.destinationFs)
|
||||
fs := filesOnlyFs{httpFs.Dir(absPublishDir)}
|
||||
|
||||
doLiveReload := !f.s.buildWatch && !f.c.Cfg.GetBool("disableLiveReload")
|
||||
|
||||
@@ -17,53 +17,43 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/gohugoio/hugo/hugolib/filesystems"
|
||||
|
||||
"github.com/fsnotify/fsnotify"
|
||||
"github.com/gohugoio/hugo/helpers"
|
||||
src "github.com/gohugoio/hugo/source"
|
||||
"github.com/spf13/fsync"
|
||||
)
|
||||
|
||||
type staticSyncer struct {
|
||||
c *commandeer
|
||||
d *src.Dirs
|
||||
}
|
||||
|
||||
func newStaticSyncer(c *commandeer) (*staticSyncer, error) {
|
||||
dirs, err := src.NewDirs(c.Fs, c.Cfg, c.DepsCfg.Logger)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &staticSyncer{c: c, d: dirs}, nil
|
||||
return &staticSyncer{c: c}, nil
|
||||
}
|
||||
|
||||
func (s *staticSyncer) isStatic(path string) bool {
|
||||
return s.d.IsStatic(path)
|
||||
func (s *staticSyncer) isStatic(filename string) bool {
|
||||
return s.c.hugo.BaseFs.SourceFilesystems.IsStatic(filename)
|
||||
}
|
||||
|
||||
func (s *staticSyncer) syncsStaticEvents(staticEvents []fsnotify.Event) error {
|
||||
c := s.c
|
||||
|
||||
syncFn := func(dirs *src.Dirs, publishDir string) (uint64, error) {
|
||||
staticSourceFs, err := dirs.CreateStaticFs()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
syncFn := func(sourceFs *filesystems.SourceFilesystem) (uint64, error) {
|
||||
publishDir := c.hugo.PathSpec.PublishDir
|
||||
// If root, remove the second '/'
|
||||
if publishDir == "//" {
|
||||
publishDir = helpers.FilePathSeparator
|
||||
}
|
||||
|
||||
if dirs.Language != nil {
|
||||
// Multihost setup
|
||||
publishDir = filepath.Join(publishDir, dirs.Language.Lang)
|
||||
}
|
||||
|
||||
if staticSourceFs == nil {
|
||||
c.Logger.WARN.Println("No static directories found to sync")
|
||||
return 0, nil
|
||||
if sourceFs.PublishFolder != "" {
|
||||
publishDir = filepath.Join(publishDir, sourceFs.PublishFolder)
|
||||
}
|
||||
|
||||
syncer := fsync.NewSyncer()
|
||||
syncer.NoTimes = c.Cfg.GetBool("noTimes")
|
||||
syncer.NoChmod = c.Cfg.GetBool("noChmod")
|
||||
syncer.SrcFs = staticSourceFs
|
||||
syncer.SrcFs = sourceFs.Fs
|
||||
syncer.DestFs = c.Fs.Destination
|
||||
|
||||
// prevent spamming the log on changes
|
||||
@@ -88,8 +78,7 @@ func (s *staticSyncer) syncsStaticEvents(staticEvents []fsnotify.Event) error {
|
||||
|
||||
fromPath := ev.Name
|
||||
|
||||
// If we are here we already know the event took place in a static dir
|
||||
relPath := dirs.MakeStaticPathRelative(fromPath)
|
||||
relPath := sourceFs.MakePathRelative(fromPath)
|
||||
if relPath == "" {
|
||||
// Not member of this virtual host.
|
||||
continue
|
||||
@@ -105,7 +94,7 @@ func (s *staticSyncer) syncsStaticEvents(staticEvents []fsnotify.Event) error {
|
||||
// the source of that static file. In this case Hugo will incorrectly remove that file
|
||||
// from the published directory.
|
||||
if ev.Op&fsnotify.Rename == fsnotify.Rename || ev.Op&fsnotify.Remove == fsnotify.Remove {
|
||||
if _, err := staticSourceFs.Stat(relPath); os.IsNotExist(err) {
|
||||
if _, err := sourceFs.Fs.Stat(relPath); os.IsNotExist(err) {
|
||||
// If file doesn't exist in any static dir, remove it
|
||||
toRemove := filepath.Join(publishDir, relPath)
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
|
||||
"github.com/gohugoio/hugo/helpers"
|
||||
"github.com/gohugoio/hugo/hugolib"
|
||||
"github.com/gohugoio/hugo/resource/tocss/scss"
|
||||
"github.com/spf13/cobra"
|
||||
jww "github.com/spf13/jwalterweatherman"
|
||||
)
|
||||
@@ -44,13 +45,24 @@ func newVersionCmd() *versionCmd {
|
||||
}
|
||||
|
||||
func printHugoVersion() {
|
||||
if hugolib.CommitHash == "" {
|
||||
if hugolib.BuildDate == "" {
|
||||
jww.FEEDBACK.Printf("Hugo Static Site Generator v%s %s/%s\n", helpers.CurrentHugoVersion, runtime.GOOS, runtime.GOARCH)
|
||||
} else {
|
||||
jww.FEEDBACK.Printf("Hugo Static Site Generator v%s %s/%s BuildDate: %s\n", helpers.CurrentHugoVersion, runtime.GOOS, runtime.GOARCH, hugolib.BuildDate)
|
||||
}
|
||||
} else {
|
||||
jww.FEEDBACK.Printf("Hugo Static Site Generator v%s-%s %s/%s BuildDate: %s\n", helpers.CurrentHugoVersion, strings.ToUpper(hugolib.CommitHash), runtime.GOOS, runtime.GOARCH, hugolib.BuildDate)
|
||||
program := "Hugo Static Site Generator"
|
||||
|
||||
version := "v" + helpers.CurrentHugoVersion.String()
|
||||
if hugolib.CommitHash != "" {
|
||||
version += "-" + strings.ToUpper(hugolib.CommitHash)
|
||||
}
|
||||
if scss.Supports() {
|
||||
version += "/extended"
|
||||
}
|
||||
|
||||
osArch := runtime.GOOS + "/" + runtime.GOARCH
|
||||
|
||||
var buildDate string
|
||||
if hugolib.BuildDate != "" {
|
||||
buildDate = hugolib.BuildDate
|
||||
} else {
|
||||
buildDate = "unknown"
|
||||
}
|
||||
|
||||
jww.FEEDBACK.Println(program, version, osArch, "BuildDate:", buildDate)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
// Copyright 2018 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 errors contains common Hugo errors and error related utilities.
|
||||
package errors
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
// We will, at least to begin with, make some Hugo features (SCSS with libsass) optional,
|
||||
// and this error is used to signal those situations.
|
||||
var FeatureNotAvailableErr = errors.New("this feature is not available in your current Hugo version")
|
||||
@@ -0,0 +1,37 @@
|
||||
// Copyright 2018 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 loggers
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
jww "github.com/spf13/jwalterweatherman"
|
||||
)
|
||||
|
||||
// NewDebugLogger is a convenience function to create a debug logger.
|
||||
func NewDebugLogger() *jww.Notepad {
|
||||
return jww.NewNotepad(jww.LevelDebug, jww.LevelError, os.Stdout, ioutil.Discard, "", log.Ldate|log.Ltime)
|
||||
}
|
||||
|
||||
// NewWarningLogger is a convenience function to create a warning logger.
|
||||
func NewWarningLogger() *jww.Notepad {
|
||||
return jww.NewNotepad(jww.LevelWarn, jww.LevelError, os.Stdout, ioutil.Discard, "", log.Ldate|log.Ltime)
|
||||
}
|
||||
|
||||
// NewErrorLogger is a convenience function to create an error logger.
|
||||
func NewErrorLogger() *jww.Notepad {
|
||||
return jww.NewNotepad(jww.LevelError, jww.LevelError, os.Stdout, ioutil.Discard, "", log.Ldate|log.Ltime)
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
// Copyright 2018 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 maps
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cast"
|
||||
)
|
||||
|
||||
// ToLower makes all the keys in the given map lower cased and will do so
|
||||
// recursively.
|
||||
// Notes:
|
||||
// * This will modify the map given.
|
||||
// * Any nested map[interface{}]interface{} will be converted to map[string]interface{}.
|
||||
func ToLower(m map[string]interface{}) {
|
||||
for k, v := range m {
|
||||
switch v.(type) {
|
||||
case map[interface{}]interface{}:
|
||||
v = cast.ToStringMap(v)
|
||||
ToLower(v.(map[string]interface{}))
|
||||
case map[string]interface{}:
|
||||
ToLower(v.(map[string]interface{}))
|
||||
}
|
||||
|
||||
lKey := strings.ToLower(k)
|
||||
if k != lKey {
|
||||
delete(m, k)
|
||||
m[lKey] = v
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
// Copyright 2018 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 maps
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestToLower(t *testing.T) {
|
||||
|
||||
tests := []struct {
|
||||
input map[string]interface{}
|
||||
expected map[string]interface{}
|
||||
}{
|
||||
{
|
||||
map[string]interface{}{
|
||||
"abC": 32,
|
||||
},
|
||||
map[string]interface{}{
|
||||
"abc": 32,
|
||||
},
|
||||
},
|
||||
{
|
||||
map[string]interface{}{
|
||||
"abC": 32,
|
||||
"deF": map[interface{}]interface{}{
|
||||
23: "A value",
|
||||
24: map[string]interface{}{
|
||||
"AbCDe": "A value",
|
||||
"eFgHi": "Another value",
|
||||
},
|
||||
},
|
||||
"gHi": map[string]interface{}{
|
||||
"J": 25,
|
||||
},
|
||||
},
|
||||
map[string]interface{}{
|
||||
"abc": 32,
|
||||
"def": map[string]interface{}{
|
||||
"23": "A value",
|
||||
"24": map[string]interface{}{
|
||||
"abcde": "A value",
|
||||
"efghi": "Another value",
|
||||
},
|
||||
},
|
||||
"ghi": map[string]interface{}{
|
||||
"j": 25,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for i, test := range tests {
|
||||
// ToLower modifies input.
|
||||
ToLower(test.input)
|
||||
if !reflect.DeepEqual(test.expected, test.input) {
|
||||
t.Errorf("[%d] Expected\n%#v, got\n%#v\n", i, test.expected, test.input)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2015 The Hugo Authors. All rights reserved.
|
||||
// Copyright 2018 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,14 +11,14 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package hugolib
|
||||
package maps
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"sort"
|
||||
"sync"
|
||||
|
||||
"github.com/gohugoio/hugo/tpl/math"
|
||||
"github.com/gohugoio/hugo/common/math"
|
||||
)
|
||||
|
||||
// Scratch is a writable context used for stateful operations in Page/Node rendering.
|
||||
@@ -130,6 +130,6 @@ func (c *Scratch) GetSortedMapValues(key string) interface{} {
|
||||
return sortedArray
|
||||
}
|
||||
|
||||
func newScratch() *Scratch {
|
||||
func NewScratch() *Scratch {
|
||||
return &Scratch{values: make(map[string]interface{})}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2015 The Hugo Authors. All rights reserved.
|
||||
// Copyright 2018 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,7 +11,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package hugolib
|
||||
package maps
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
@@ -23,7 +23,7 @@ import (
|
||||
|
||||
func TestScratchAdd(t *testing.T) {
|
||||
t.Parallel()
|
||||
scratch := newScratch()
|
||||
scratch := NewScratch()
|
||||
scratch.Add("int1", 10)
|
||||
scratch.Add("int1", 20)
|
||||
scratch.Add("int2", 20)
|
||||
@@ -53,7 +53,7 @@ func TestScratchAdd(t *testing.T) {
|
||||
|
||||
func TestScratchAddSlice(t *testing.T) {
|
||||
t.Parallel()
|
||||
scratch := newScratch()
|
||||
scratch := NewScratch()
|
||||
|
||||
_, err := scratch.Add("intSlice", []int{1, 2})
|
||||
assert.Nil(t, err)
|
||||
@@ -82,14 +82,14 @@ func TestScratchAddSlice(t *testing.T) {
|
||||
|
||||
func TestScratchSet(t *testing.T) {
|
||||
t.Parallel()
|
||||
scratch := newScratch()
|
||||
scratch := NewScratch()
|
||||
scratch.Set("key", "val")
|
||||
assert.Equal(t, "val", scratch.Get("key"))
|
||||
}
|
||||
|
||||
func TestScratchDelete(t *testing.T) {
|
||||
t.Parallel()
|
||||
scratch := newScratch()
|
||||
scratch := NewScratch()
|
||||
scratch.Set("key", "val")
|
||||
scratch.Delete("key")
|
||||
scratch.Add("key", "Lucy Parsons")
|
||||
@@ -99,7 +99,7 @@ func TestScratchDelete(t *testing.T) {
|
||||
// Issue #2005
|
||||
func TestScratchInParallel(t *testing.T) {
|
||||
var wg sync.WaitGroup
|
||||
scratch := newScratch()
|
||||
scratch := NewScratch()
|
||||
key := "counter"
|
||||
scratch.Set(key, int64(1))
|
||||
for i := 1; i <= 10; i++ {
|
||||
@@ -133,7 +133,7 @@ func TestScratchInParallel(t *testing.T) {
|
||||
|
||||
func TestScratchGet(t *testing.T) {
|
||||
t.Parallel()
|
||||
scratch := newScratch()
|
||||
scratch := NewScratch()
|
||||
nothing := scratch.Get("nothing")
|
||||
if nothing != nil {
|
||||
t.Errorf("Should not return anything, but got %v", nothing)
|
||||
@@ -142,7 +142,7 @@ func TestScratchGet(t *testing.T) {
|
||||
|
||||
func TestScratchSetInMap(t *testing.T) {
|
||||
t.Parallel()
|
||||
scratch := newScratch()
|
||||
scratch := NewScratch()
|
||||
scratch.SetInMap("key", "lux", "Lux")
|
||||
scratch.SetInMap("key", "abc", "Abc")
|
||||
scratch.SetInMap("key", "zyx", "Zyx")
|
||||
@@ -153,7 +153,7 @@ func TestScratchSetInMap(t *testing.T) {
|
||||
|
||||
func TestScratchGetSortedMapValues(t *testing.T) {
|
||||
t.Parallel()
|
||||
scratch := newScratch()
|
||||
scratch := NewScratch()
|
||||
nothing := scratch.GetSortedMapValues("nothing")
|
||||
if nothing != nil {
|
||||
t.Errorf("Should not return anything, but got %v", nothing)
|
||||
@@ -161,7 +161,7 @@ func TestScratchGetSortedMapValues(t *testing.T) {
|
||||
}
|
||||
|
||||
func BenchmarkScratchGet(b *testing.B) {
|
||||
scratch := newScratch()
|
||||
scratch := NewScratch()
|
||||
scratch.Add("A", 1)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
@@ -0,0 +1,135 @@
|
||||
// Copyright 2018 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 math
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// DoArithmetic performs arithmetic operations (+,-,*,/) using reflection to
|
||||
// determine the type of the two terms.
|
||||
func DoArithmetic(a, b interface{}, op rune) (interface{}, error) {
|
||||
av := reflect.ValueOf(a)
|
||||
bv := reflect.ValueOf(b)
|
||||
var ai, bi int64
|
||||
var af, bf float64
|
||||
var au, bu uint64
|
||||
switch av.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
ai = av.Int()
|
||||
switch bv.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
bi = bv.Int()
|
||||
case reflect.Float32, reflect.Float64:
|
||||
af = float64(ai) // may overflow
|
||||
ai = 0
|
||||
bf = bv.Float()
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
bu = bv.Uint()
|
||||
if ai >= 0 {
|
||||
au = uint64(ai)
|
||||
ai = 0
|
||||
} else {
|
||||
bi = int64(bu) // may overflow
|
||||
bu = 0
|
||||
}
|
||||
default:
|
||||
return nil, errors.New("Can't apply the operator to the values")
|
||||
}
|
||||
case reflect.Float32, reflect.Float64:
|
||||
af = av.Float()
|
||||
switch bv.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
bf = float64(bv.Int()) // may overflow
|
||||
case reflect.Float32, reflect.Float64:
|
||||
bf = bv.Float()
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
bf = float64(bv.Uint()) // may overflow
|
||||
default:
|
||||
return nil, errors.New("Can't apply the operator to the values")
|
||||
}
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
au = av.Uint()
|
||||
switch bv.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
bi = bv.Int()
|
||||
if bi >= 0 {
|
||||
bu = uint64(bi)
|
||||
bi = 0
|
||||
} else {
|
||||
ai = int64(au) // may overflow
|
||||
au = 0
|
||||
}
|
||||
case reflect.Float32, reflect.Float64:
|
||||
af = float64(au) // may overflow
|
||||
au = 0
|
||||
bf = bv.Float()
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
bu = bv.Uint()
|
||||
default:
|
||||
return nil, errors.New("Can't apply the operator to the values")
|
||||
}
|
||||
case reflect.String:
|
||||
as := av.String()
|
||||
if bv.Kind() == reflect.String && op == '+' {
|
||||
bs := bv.String()
|
||||
return as + bs, nil
|
||||
}
|
||||
return nil, errors.New("Can't apply the operator to the values")
|
||||
default:
|
||||
return nil, errors.New("Can't apply the operator to the values")
|
||||
}
|
||||
|
||||
switch op {
|
||||
case '+':
|
||||
if ai != 0 || bi != 0 {
|
||||
return ai + bi, nil
|
||||
} else if af != 0 || bf != 0 {
|
||||
return af + bf, nil
|
||||
} else if au != 0 || bu != 0 {
|
||||
return au + bu, nil
|
||||
}
|
||||
return 0, nil
|
||||
case '-':
|
||||
if ai != 0 || bi != 0 {
|
||||
return ai - bi, nil
|
||||
} else if af != 0 || bf != 0 {
|
||||
return af - bf, nil
|
||||
} else if au != 0 || bu != 0 {
|
||||
return au - bu, nil
|
||||
}
|
||||
return 0, nil
|
||||
case '*':
|
||||
if ai != 0 || bi != 0 {
|
||||
return ai * bi, nil
|
||||
} else if af != 0 || bf != 0 {
|
||||
return af * bf, nil
|
||||
} else if au != 0 || bu != 0 {
|
||||
return au * bu, nil
|
||||
}
|
||||
return 0, nil
|
||||
case '/':
|
||||
if bi != 0 {
|
||||
return ai / bi, nil
|
||||
} else if bf != 0 {
|
||||
return af / bf, nil
|
||||
} else if bu != 0 {
|
||||
return au / bu, nil
|
||||
}
|
||||
return nil, errors.New("Can't divide the value by 0")
|
||||
default:
|
||||
return nil, errors.New("There is no such an operation")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
// Copyright 2018 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 math
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/alecthomas/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestDoArithmetic(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for i, test := range []struct {
|
||||
a interface{}
|
||||
b interface{}
|
||||
op rune
|
||||
expect interface{}
|
||||
}{
|
||||
{3, 2, '+', int64(5)},
|
||||
{3, 2, '-', int64(1)},
|
||||
{3, 2, '*', int64(6)},
|
||||
{3, 2, '/', int64(1)},
|
||||
{3.0, 2, '+', float64(5)},
|
||||
{3.0, 2, '-', float64(1)},
|
||||
{3.0, 2, '*', float64(6)},
|
||||
{3.0, 2, '/', float64(1.5)},
|
||||
{3, 2.0, '+', float64(5)},
|
||||
{3, 2.0, '-', float64(1)},
|
||||
{3, 2.0, '*', float64(6)},
|
||||
{3, 2.0, '/', float64(1.5)},
|
||||
{3.0, 2.0, '+', float64(5)},
|
||||
{3.0, 2.0, '-', float64(1)},
|
||||
{3.0, 2.0, '*', float64(6)},
|
||||
{3.0, 2.0, '/', float64(1.5)},
|
||||
{uint(3), uint(2), '+', uint64(5)},
|
||||
{uint(3), uint(2), '-', uint64(1)},
|
||||
{uint(3), uint(2), '*', uint64(6)},
|
||||
{uint(3), uint(2), '/', uint64(1)},
|
||||
{uint(3), 2, '+', uint64(5)},
|
||||
{uint(3), 2, '-', uint64(1)},
|
||||
{uint(3), 2, '*', uint64(6)},
|
||||
{uint(3), 2, '/', uint64(1)},
|
||||
{3, uint(2), '+', uint64(5)},
|
||||
{3, uint(2), '-', uint64(1)},
|
||||
{3, uint(2), '*', uint64(6)},
|
||||
{3, uint(2), '/', uint64(1)},
|
||||
{uint(3), -2, '+', int64(1)},
|
||||
{uint(3), -2, '-', int64(5)},
|
||||
{uint(3), -2, '*', int64(-6)},
|
||||
{uint(3), -2, '/', int64(-1)},
|
||||
{-3, uint(2), '+', int64(-1)},
|
||||
{-3, uint(2), '-', int64(-5)},
|
||||
{-3, uint(2), '*', int64(-6)},
|
||||
{-3, uint(2), '/', int64(-1)},
|
||||
{uint(3), 2.0, '+', float64(5)},
|
||||
{uint(3), 2.0, '-', float64(1)},
|
||||
{uint(3), 2.0, '*', float64(6)},
|
||||
{uint(3), 2.0, '/', float64(1.5)},
|
||||
{3.0, uint(2), '+', float64(5)},
|
||||
{3.0, uint(2), '-', float64(1)},
|
||||
{3.0, uint(2), '*', float64(6)},
|
||||
{3.0, uint(2), '/', float64(1.5)},
|
||||
{0, 0, '+', 0},
|
||||
{0, 0, '-', 0},
|
||||
{0, 0, '*', 0},
|
||||
{"foo", "bar", '+', "foobar"},
|
||||
{3, 0, '/', false},
|
||||
{3.0, 0, '/', false},
|
||||
{3, 0.0, '/', false},
|
||||
{uint(3), uint(0), '/', false},
|
||||
{3, uint(0), '/', false},
|
||||
{-3, uint(0), '/', false},
|
||||
{uint(3), 0, '/', false},
|
||||
{3.0, uint(0), '/', false},
|
||||
{uint(3), 0.0, '/', false},
|
||||
{3, "foo", '+', false},
|
||||
{3.0, "foo", '+', false},
|
||||
{uint(3), "foo", '+', false},
|
||||
{"foo", 3, '+', false},
|
||||
{"foo", "bar", '-', false},
|
||||
{3, 2, '%', false},
|
||||
} {
|
||||
errMsg := fmt.Sprintf("[%d] %v", i, test)
|
||||
|
||||
result, err := DoArithmetic(test.a, test.b, test.op)
|
||||
|
||||
if b, ok := test.expect.(bool); ok && !b {
|
||||
require.Error(t, err, errMsg)
|
||||
continue
|
||||
}
|
||||
|
||||
require.NoError(t, err, errMsg)
|
||||
assert.Equal(t, test.expect, result, errMsg)
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,8 @@ package config
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cast"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
@@ -40,5 +42,16 @@ func FromConfigString(config, configType string) (Provider, error) {
|
||||
return nil, err
|
||||
}
|
||||
return v, nil
|
||||
|
||||
}
|
||||
|
||||
// GetStringSlicePreserveString returns a string slice from the given config and key.
|
||||
// It differs from the GetStringSlice method in that if the config value is a string,
|
||||
// we do not attempt to split it into fields.
|
||||
func GetStringSlicePreserveString(cfg Provider, key string) []string {
|
||||
sd := cfg.Get(key)
|
||||
if sds, ok := sd.(string); ok {
|
||||
return []string{sds}
|
||||
} else {
|
||||
return cast.ToStringSlice(sd)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
// Copyright 2018 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 (
|
||||
"testing"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestGetStringSlicePreserveString(t *testing.T) {
|
||||
assert := require.New(t)
|
||||
cfg := viper.New()
|
||||
|
||||
s := "This is a string"
|
||||
sSlice := []string{"This", "is", "a", "slice"}
|
||||
|
||||
cfg.Set("s1", s)
|
||||
cfg.Set("s2", sSlice)
|
||||
|
||||
assert.Equal([]string{s}, GetStringSlicePreserveString(cfg, "s1"))
|
||||
assert.Equal(sSlice, GetStringSlicePreserveString(cfg, "s2"))
|
||||
assert.Nil(GetStringSlicePreserveString(cfg, "s3"))
|
||||
}
|
||||
@@ -30,7 +30,6 @@ type Config struct {
|
||||
Disqus Disqus
|
||||
GoogleAnalytics GoogleAnalytics
|
||||
Instagram Instagram
|
||||
SpeakerDeck SpeakerDeck
|
||||
Twitter Twitter
|
||||
Vimeo Vimeo
|
||||
YouTube YouTube
|
||||
@@ -65,11 +64,6 @@ type Instagram struct {
|
||||
Simple bool
|
||||
}
|
||||
|
||||
// SpeakerDeck holds the privacy configuration settings related to the SpeakerDeck shortcode.
|
||||
type SpeakerDeck struct {
|
||||
Service `mapstructure:",squash"`
|
||||
}
|
||||
|
||||
// Twitter holds the privacy configuration settingsrelated to the Twitter shortcode.
|
||||
type Twitter struct {
|
||||
Service `mapstructure:",squash"`
|
||||
@@ -77,11 +71,19 @@ type Twitter struct {
|
||||
// When set to true, the Tweet and its embedded page on your site are not used
|
||||
// for purposes that include personalized suggestions and personalized ads.
|
||||
EnableDNT bool
|
||||
|
||||
// If simple mode is enabled, a static and no-JS version of the Tweet will be built.
|
||||
Simple bool
|
||||
}
|
||||
|
||||
// Vimeo holds the privacy configuration settingsrelated to the Vimeo shortcode.
|
||||
type Vimeo struct {
|
||||
Service `mapstructure:",squash"`
|
||||
|
||||
// If simple mode is enabled, only a thumbnail is fetched from i.vimeocdn.com and
|
||||
// shown with a play button overlaid. If a user clicks the button, he/she will
|
||||
// be taken to the video page on vimeo.com in a new browser tab.
|
||||
Simple bool
|
||||
}
|
||||
|
||||
// YouTube holds the privacy configuration settingsrelated to the YouTube shortcode.
|
||||
|
||||
@@ -39,13 +39,13 @@ useSessionStorage = true
|
||||
[privacy.instagram]
|
||||
disable = true
|
||||
simple = true
|
||||
[privacy.speakerDeck]
|
||||
disable = true
|
||||
[privacy.twitter]
|
||||
disable = true
|
||||
enableDNT = true
|
||||
simple = true
|
||||
[privacy.vimeo]
|
||||
disable = true
|
||||
simple = true
|
||||
[privacy.youtube]
|
||||
disable = true
|
||||
privacyEnhanced = true
|
||||
@@ -65,11 +65,11 @@ simple = true
|
||||
assert.True(pc.GoogleAnalytics.UseSessionStorage)
|
||||
assert.True(pc.Instagram.Disable)
|
||||
assert.True(pc.Instagram.Simple)
|
||||
assert.True(pc.SpeakerDeck.Disable)
|
||||
assert.True(pc.Twitter.Disable)
|
||||
assert.True(pc.Twitter.EnableDNT)
|
||||
assert.True(pc.Twitter.Simple)
|
||||
assert.True(pc.Vimeo.Disable)
|
||||
|
||||
assert.True(pc.Vimeo.Simple)
|
||||
assert.True(pc.YouTube.PrivacyEnhanced)
|
||||
assert.True(pc.YouTube.Disable)
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ type Config struct {
|
||||
Disqus Disqus
|
||||
GoogleAnalytics GoogleAnalytics
|
||||
Instagram Instagram
|
||||
Twitter Twitter
|
||||
}
|
||||
|
||||
// Disqus holds the functional configuration settings related to the Disqus template.
|
||||
@@ -52,12 +53,20 @@ type Instagram struct {
|
||||
DisableInlineCSS bool
|
||||
}
|
||||
|
||||
// Twitter holds the functional configuration settings related to the Twitter shortcodes.
|
||||
type Twitter struct {
|
||||
// The Simple variant of Twitter is decorated with a basic set of inline styles.
|
||||
// This means that if you want to provide your own CSS, you want
|
||||
// to disable the inline CSS provided by Hugo.
|
||||
DisableInlineCSS bool
|
||||
}
|
||||
|
||||
func DecodeConfig(cfg config.Provider) (c Config, err error) {
|
||||
m := cfg.GetStringMap(servicesConfigKey)
|
||||
|
||||
err = mapstructure.WeakDecode(m, &c)
|
||||
|
||||
// Keep backwards compability.
|
||||
// Keep backwards compatibility.
|
||||
if c.GoogleAnalytics.ID == "" {
|
||||
// Try the global config
|
||||
c.GoogleAnalytics.ID = cfg.GetString(googleAnalyticsKey)
|
||||
|
||||
@@ -35,6 +35,8 @@ shortname = "DS"
|
||||
id = "ga_id"
|
||||
[services.instagram]
|
||||
disableInlineCSS = true
|
||||
[services.twitter]
|
||||
disableInlineCSS = true
|
||||
`
|
||||
cfg, err := config.FromConfigString(tomlConfig, "toml")
|
||||
assert.NoError(err)
|
||||
|
||||
@@ -16,6 +16,7 @@ package create
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
@@ -31,6 +32,7 @@ func NewContent(
|
||||
ps *helpers.PathSpec,
|
||||
siteFactory func(filename string, siteUsed bool) (*hugolib.Site, error), kind, targetPath string) error {
|
||||
ext := helpers.Ext(targetPath)
|
||||
fs := ps.BaseFs.SourceFilesystems.Archetypes.Fs
|
||||
|
||||
jww.INFO.Printf("attempting to create %q of %q of ext %q", targetPath, kind, ext)
|
||||
|
||||
@@ -40,9 +42,9 @@ func NewContent(
|
||||
siteUsed := false
|
||||
|
||||
if archetypeFilename != "" {
|
||||
f, err := ps.Fs.Source.Open(archetypeFilename)
|
||||
f, err := fs.Open(archetypeFilename)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("failed to open archetype file: %s", err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
@@ -71,7 +73,7 @@ func NewContent(
|
||||
targetDir := filepath.Dir(targetPath)
|
||||
|
||||
if targetDir != "" && targetDir != "." {
|
||||
exists, _ = helpers.Exists(targetDir, ps.Fs.Source)
|
||||
exists, _ = helpers.Exists(targetDir, fs)
|
||||
}
|
||||
|
||||
if exists {
|
||||
@@ -101,42 +103,27 @@ func NewContent(
|
||||
return nil
|
||||
}
|
||||
|
||||
// FindArchetype takes a given kind/archetype of content and returns an output
|
||||
// path for that archetype. If no archetype is found, an empty string is
|
||||
// returned.
|
||||
// FindArchetype takes a given kind/archetype of content and returns the path
|
||||
// to the archetype in the archetype filesystem, blank if none found.
|
||||
func findArchetype(ps *helpers.PathSpec, kind, ext string) (outpath string) {
|
||||
search := []string{ps.AbsPathify(ps.Cfg.GetString("archetypeDir"))}
|
||||
fs := ps.BaseFs.Archetypes.Fs
|
||||
|
||||
if ps.Cfg.GetString("theme") != "" {
|
||||
themeDir := filepath.Join(ps.AbsPathify(ps.Cfg.GetString("themesDir")+"/"+ps.Cfg.GetString("theme")), "/archetypes/")
|
||||
if _, err := ps.Fs.Source.Stat(themeDir); os.IsNotExist(err) {
|
||||
jww.ERROR.Printf("Unable to find archetypes directory for theme %q at %q", ps.Cfg.GetString("theme"), themeDir)
|
||||
// If the new content isn't in a subdirectory, kind == "".
|
||||
// Therefore it should be excluded otherwise `is a directory`
|
||||
// error will occur. github.com/gohugoio/hugo/issues/411
|
||||
var pathsToCheck = []string{"default"}
|
||||
|
||||
if ext != "" {
|
||||
if kind != "" {
|
||||
pathsToCheck = append([]string{kind + ext, "default" + ext}, pathsToCheck...)
|
||||
} else {
|
||||
search = append(search, themeDir)
|
||||
pathsToCheck = append([]string{"default" + ext}, pathsToCheck...)
|
||||
}
|
||||
}
|
||||
|
||||
for _, x := range search {
|
||||
// If the new content isn't in a subdirectory, kind == "".
|
||||
// Therefore it should be excluded otherwise `is a directory`
|
||||
// error will occur. github.com/gohugoio/hugo/issues/411
|
||||
var pathsToCheck = []string{"default"}
|
||||
|
||||
if ext != "" {
|
||||
if kind != "" {
|
||||
pathsToCheck = append([]string{kind + ext, "default" + ext}, pathsToCheck...)
|
||||
} else {
|
||||
pathsToCheck = append([]string{"default" + ext}, pathsToCheck...)
|
||||
}
|
||||
}
|
||||
|
||||
for _, p := range pathsToCheck {
|
||||
curpath := filepath.Join(x, p)
|
||||
jww.DEBUG.Println("checking", curpath, "for archetypes")
|
||||
if exists, _ := helpers.Exists(curpath, ps.Fs.Source); exists {
|
||||
jww.INFO.Println("curpath: " + curpath)
|
||||
return curpath
|
||||
}
|
||||
for _, p := range pathsToCheck {
|
||||
if exists, _ := helpers.Exists(p, fs); exists {
|
||||
return p
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -89,10 +89,11 @@ func executeArcheTypeAsTemplate(s *hugolib.Site, kind, targetPath, archetypeFile
|
||||
)
|
||||
|
||||
ps, err := helpers.NewPathSpec(s.Deps.Fs, s.Deps.Cfg)
|
||||
sp := source.NewSourceSpec(ps, ps.Fs.Source)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sp := source.NewSourceSpec(ps, ps.Fs.Source)
|
||||
|
||||
f := sp.NewFileInfo("", targetPath, false, nil)
|
||||
|
||||
name := f.TranslationBaseName()
|
||||
@@ -115,9 +116,9 @@ func executeArcheTypeAsTemplate(s *hugolib.Site, kind, targetPath, archetypeFile
|
||||
// TODO(bep) archetype revive the issue about wrong tpl funcs arg order
|
||||
archetypeTemplate = []byte(ArchetypeTemplateTemplate)
|
||||
} else {
|
||||
archetypeTemplate, err = afero.ReadFile(s.Fs.Source, archetypeFilename)
|
||||
archetypeTemplate, err = afero.ReadFile(s.BaseFs.Archetypes.Fs, archetypeFilename)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to read archetype file %q: %s", archetypeFilename, err)
|
||||
return nil, fmt.Errorf("failed to read archetype file %s", err)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -133,7 +134,7 @@ func executeArcheTypeAsTemplate(s *hugolib.Site, kind, targetPath, archetypeFile
|
||||
return nil, fmt.Errorf("Failed to parse archetype file %q: %s", archetypeFilename, err)
|
||||
}
|
||||
|
||||
templ := templateHandler.Lookup(templateName)
|
||||
templ, _ := templateHandler.Lookup(templateName)
|
||||
|
||||
var buff bytes.Buffer
|
||||
if err := templ.Execute(&buff, data); err != nil {
|
||||
|
||||
@@ -58,17 +58,15 @@ func TestNewContent(t *testing.T) {
|
||||
|
||||
for _, c := range cases {
|
||||
cfg, fs := newTestCfg()
|
||||
ps, err := helpers.NewPathSpec(fs, cfg)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, initFs(fs))
|
||||
h, err := hugolib.NewHugoSites(deps.DepsCfg{Cfg: cfg, Fs: fs})
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, initFs(fs))
|
||||
|
||||
siteFactory := func(filename string, siteUsed bool) (*hugolib.Site, error) {
|
||||
return h.Sites[0], nil
|
||||
}
|
||||
|
||||
require.NoError(t, create.NewContent(ps, siteFactory, c.kind, c.path))
|
||||
require.NoError(t, create.NewContent(h.PathSpec, siteFactory, c.kind, c.path))
|
||||
|
||||
fname := filepath.Join("content", filepath.FromSlash(c.path))
|
||||
content := readFileFromFs(t, fs.Source, fname)
|
||||
@@ -89,6 +87,9 @@ func initViper(v *viper.Viper) {
|
||||
v.Set("layoutDir", "layouts")
|
||||
v.Set("i18nDir", "i18n")
|
||||
v.Set("theme", "sample")
|
||||
v.Set("archetypeDir", "archetypes")
|
||||
v.Set("resourceDir", "resources")
|
||||
v.Set("publishDir", "public")
|
||||
}
|
||||
|
||||
func initFs(fs *hugofs.Fs) error {
|
||||
@@ -187,6 +188,13 @@ func readFileFromFs(t *testing.T, fs afero.Fs, filename string) string {
|
||||
func newTestCfg() (*viper.Viper, *hugofs.Fs) {
|
||||
|
||||
v := viper.New()
|
||||
v.Set("contentDir", "content")
|
||||
v.Set("dataDir", "data")
|
||||
v.Set("i18nDir", "i18n")
|
||||
v.Set("layoutDir", "layouts")
|
||||
v.Set("archetypeDir", "archetypes")
|
||||
v.Set("assetDir", "assets")
|
||||
|
||||
fs := hugofs.NewMem(v)
|
||||
|
||||
v.SetFs(fs.Source)
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
package deps
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/gohugoio/hugo/common/loggers"
|
||||
|
||||
"github.com/gohugoio/hugo/config"
|
||||
"github.com/gohugoio/hugo/helpers"
|
||||
"github.com/gohugoio/hugo/hugofs"
|
||||
"github.com/gohugoio/hugo/langs"
|
||||
"github.com/gohugoio/hugo/media"
|
||||
"github.com/gohugoio/hugo/metrics"
|
||||
"github.com/gohugoio/hugo/output"
|
||||
"github.com/gohugoio/hugo/resource"
|
||||
"github.com/gohugoio/hugo/source"
|
||||
"github.com/gohugoio/hugo/tpl"
|
||||
jww "github.com/spf13/jwalterweatherman"
|
||||
@@ -20,6 +23,7 @@ import (
|
||||
// There will be normally only one instance of deps in play
|
||||
// at a given time, i.e. one per Site built.
|
||||
type Deps struct {
|
||||
|
||||
// The logger to use.
|
||||
Log *jww.Notepad `json:"-"`
|
||||
|
||||
@@ -29,6 +33,9 @@ type Deps struct {
|
||||
// The templates to use. This will usually implement the full tpl.TemplateHandler.
|
||||
Tmpl tpl.TemplateFinder `json:"-"`
|
||||
|
||||
// We use this to parse and execute ad-hoc text templates.
|
||||
TextTmpl tpl.TemplateParseFinder `json:"-"`
|
||||
|
||||
// The file systems to use.
|
||||
Fs *hugofs.Fs `json:"-"`
|
||||
|
||||
@@ -41,13 +48,16 @@ type Deps struct {
|
||||
// The SourceSpec to use
|
||||
SourceSpec *source.SourceSpec `json:"-"`
|
||||
|
||||
// The Resource Spec to use
|
||||
ResourceSpec *resource.Spec
|
||||
|
||||
// The configuration to use
|
||||
Cfg config.Provider `json:"-"`
|
||||
|
||||
// The translation func to use
|
||||
Translate func(translationID string, args ...interface{}) string `json:"-"`
|
||||
|
||||
Language *helpers.Language
|
||||
Language *langs.Language
|
||||
|
||||
// All the output formats available for the current site.
|
||||
OutputFormatsConfig output.Formats
|
||||
@@ -61,6 +71,30 @@ type Deps struct {
|
||||
|
||||
// Timeout is configurable in site config.
|
||||
Timeout time.Duration
|
||||
|
||||
// BuildStartListeners will be notified before a build starts.
|
||||
BuildStartListeners *Listeners
|
||||
}
|
||||
|
||||
type Listeners struct {
|
||||
sync.Mutex
|
||||
|
||||
// A list of funcs to be notified about an event.
|
||||
listeners []func()
|
||||
}
|
||||
|
||||
func (b *Listeners) Add(f func()) {
|
||||
b.Lock()
|
||||
defer b.Unlock()
|
||||
b.listeners = append(b.listeners, f)
|
||||
}
|
||||
|
||||
func (b *Listeners) Notify() {
|
||||
b.Lock()
|
||||
defer b.Unlock()
|
||||
for _, notify := range b.listeners {
|
||||
notify()
|
||||
}
|
||||
}
|
||||
|
||||
// ResourceProvider is used to create and refresh, and clone resources needed.
|
||||
@@ -114,7 +148,7 @@ func New(cfg DepsCfg) (*Deps, error) {
|
||||
}
|
||||
|
||||
if logger == nil {
|
||||
logger = jww.NewNotepad(jww.LevelError, jww.LevelError, os.Stdout, ioutil.Discard, "", log.Ldate|log.Ltime)
|
||||
logger = loggers.NewErrorLogger()
|
||||
}
|
||||
|
||||
if fs == nil {
|
||||
@@ -128,6 +162,11 @@ func New(cfg DepsCfg) (*Deps, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resourceSpec, err := resource.NewSpec(ps, logger, cfg.MediaTypes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
contentSpec, err := helpers.NewContentSpec(cfg.Language)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -152,8 +191,10 @@ func New(cfg DepsCfg) (*Deps, error) {
|
||||
PathSpec: ps,
|
||||
ContentSpec: contentSpec,
|
||||
SourceSpec: sp,
|
||||
ResourceSpec: resourceSpec,
|
||||
Cfg: cfg.Language,
|
||||
Language: cfg.Language,
|
||||
BuildStartListeners: &Listeners{},
|
||||
Timeout: time.Duration(timeoutms) * time.Millisecond,
|
||||
}
|
||||
|
||||
@@ -166,10 +207,11 @@ func New(cfg DepsCfg) (*Deps, error) {
|
||||
|
||||
// ForLanguage creates a copy of the Deps with the language dependent
|
||||
// parts switched out.
|
||||
func (d Deps) ForLanguage(l *helpers.Language) (*Deps, error) {
|
||||
func (d Deps) ForLanguage(cfg DepsCfg) (*Deps, error) {
|
||||
l := cfg.Language
|
||||
var err error
|
||||
|
||||
d.PathSpec, err = helpers.NewPathSpec(d.Fs, l)
|
||||
d.PathSpec, err = helpers.NewPathSpecWithBaseBaseFsProvided(d.Fs, l, d.BaseFs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -179,6 +221,11 @@ func (d Deps) ForLanguage(l *helpers.Language) (*Deps, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
d.ResourceSpec, err = resource.NewSpec(d.PathSpec, d.Log, cfg.MediaTypes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
d.Cfg = l
|
||||
d.Language = l
|
||||
|
||||
@@ -190,6 +237,8 @@ func (d Deps) ForLanguage(l *helpers.Language) (*Deps, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
d.BuildStartListeners = &Listeners{}
|
||||
|
||||
return &d, nil
|
||||
|
||||
}
|
||||
@@ -206,11 +255,14 @@ type DepsCfg struct {
|
||||
Fs *hugofs.Fs
|
||||
|
||||
// The language to use.
|
||||
Language *helpers.Language
|
||||
Language *langs.Language
|
||||
|
||||
// The configuration to use.
|
||||
Cfg config.Provider
|
||||
|
||||
// The media types configured.
|
||||
MediaTypes media.Types
|
||||
|
||||
// Template handling.
|
||||
TemplateProvider ResourceProvider
|
||||
WithTemplate func(templ tpl.TemplateHandler) error
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Hugo Docs
|
||||
|
||||
Documentation site for [Hugo](https://github.com/gohugoio/hugo), the very fast and flexible static site generator built with love in GoLang.
|
||||
Documentation site for [Hugo](https://github.com/gohugoio/hugo), the very fast and flexible static site generator built with love in Go.
|
||||
|
||||
## Contributing
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ twitter = "GoHugoIO"
|
||||
[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.41"
|
||||
release = "0.44"
|
||||
## Setting this to true will add a "noindex" to *EVERY* page on the site
|
||||
removefromexternalsearch = false
|
||||
## Gh repo for site footer (include trailing slash)
|
||||
|
||||
@@ -23,7 +23,7 @@ toc: true
|
||||
|
||||
**Hugo is a static site generator. By using Hugo you are already standing on very solid ground. Static HTML files on disk are much easier to reason about compared to server and database driven web sites.**
|
||||
|
||||
But even static websites can integrate with external services, so from version `0.41`, Hugo provides a `Privacy Config` that covers the relevant built-in templates.
|
||||
But even static websites can integrate with external services, so from version `0.41`, Hugo provides a **Privacy Config** that covers the relevant built-in templates.
|
||||
|
||||
Note that:
|
||||
|
||||
@@ -46,13 +46,13 @@ useSessionStorage = false
|
||||
[privacy.instagram]
|
||||
disable = false
|
||||
simple = false
|
||||
[privacy.speakerDeck]
|
||||
disable = false
|
||||
[privacy.twitter]
|
||||
disable = false
|
||||
enableDNT = false
|
||||
simple = false
|
||||
[privacy.vimeo]
|
||||
disable = false
|
||||
simple = false
|
||||
[privacy.youtube]
|
||||
disable = false
|
||||
privacyEnhanced = false
|
||||
@@ -71,8 +71,6 @@ disable = true
|
||||
disable = true
|
||||
[privacy.instagram]
|
||||
disable = true
|
||||
[privacy.speakerDeck]
|
||||
disable = true
|
||||
[privacy.twitter]
|
||||
disable = true
|
||||
[privacy.vimeo]
|
||||
@@ -112,8 +110,25 @@ disableInlineCSS = true
|
||||
enableDNT
|
||||
: Enabling this for the twitter/tweet shortcode, the tweet and its embedded page on your site are not used for purposes that include personalized suggestions and personalized ads.
|
||||
|
||||
simple
|
||||
: If simple mode is enabled, a static and no-JS version of a tweet will be built.
|
||||
|
||||
|
||||
**Note:** If you use the _simple mode_ for Twitter, you may want to disable the inlines styles provided by Hugo:
|
||||
|
||||
{{< code-toggle file="config">}}
|
||||
[services]
|
||||
[services.twitter]
|
||||
disableInlineCSS = true
|
||||
{{< /code-toggle >}}
|
||||
|
||||
### YouTube
|
||||
|
||||
privacyEnhanced
|
||||
: When you turn on privacy-enhanced mode, YouTube won’t store information about visitors on your website unless the user plays the embedded video.
|
||||
|
||||
### Vimeo
|
||||
|
||||
simple
|
||||
: If simple mode is enabled, the video thumbnail is fetched from Vimeo's servers and it is overlayed with a play button. If the user clicks to play the video, it will open in a new tab directly on Vimeo's website.
|
||||
|
||||
|
||||
@@ -35,14 +35,13 @@ help = "Help"
|
||||
title = "My blog"
|
||||
weight = 1
|
||||
[languages.en.params]
|
||||
linkedin = "english-link"
|
||||
linkedin = "https://linkedin.com/whoever"
|
||||
|
||||
[languages.fr]
|
||||
copyright = "Tout est à moi"
|
||||
title = "Mon blog"
|
||||
title = "Mon blogue"
|
||||
weight = 2
|
||||
[languages.fr.params]
|
||||
linkedin = "lien-francais"
|
||||
linkedin = "https://linkedin.com/fr/whoever"
|
||||
[languages.fr.params.navigation]
|
||||
help = "Aide"
|
||||
{{< /code-toggle >}}
|
||||
@@ -55,11 +54,13 @@ and taxonomy pages will be rendered below `/` in English (your default content l
|
||||
|
||||
When working with front matter `Params` in [single page templates][singles], omit the `params` in the key for the translation.
|
||||
|
||||
If you want all of the languages to be put below their respective language code, enable `defaultContentLanguageInSubdir: true`.
|
||||
`defaultContentLanguage` sets the project's default language. If not set, the default language will be `en`.
|
||||
|
||||
If the default language needs to be rendererd below its own language code (`/en`) like the others, set `defaultContentLanguageInSubdir: true`.
|
||||
|
||||
Only the obvious non-global options can be overridden per language. Examples of global options are `baseURL`, `buildDrafts`, etc.
|
||||
|
||||
## Disable a Language
|
||||
### Disable a Language
|
||||
|
||||
You can disable one or more languages. This can be useful when working on a new translation.
|
||||
|
||||
@@ -81,7 +82,7 @@ HUGO_DISABLELANGUAGES=" " hugo server
|
||||
```
|
||||
|
||||
|
||||
## Configure Multilingual Multihost
|
||||
### Configure Multilingual Multihost
|
||||
|
||||
From **Hugo 0.31** we support multiple languages in a multihost configuration. See [this issue](https://github.com/gohugoio/hugo/issues/4027) for details.
|
||||
|
||||
@@ -94,11 +95,11 @@ Example:
|
||||
|
||||
{{< code-toggle file="config" >}}
|
||||
[languages]
|
||||
[languages.no]
|
||||
baseURL = "https://example.no"
|
||||
languageName = "Norsk"
|
||||
[languages.fr]
|
||||
baseURL = "https://example.fr"
|
||||
languageName = "Français"
|
||||
weight = 1
|
||||
title = "På norsk"
|
||||
title = "En Français"
|
||||
|
||||
[languages.en]
|
||||
baseURL = "https://example.com"
|
||||
@@ -127,7 +128,7 @@ Press Ctrl+C to stop
|
||||
|
||||
Live reload and `--navigateToChanged` between the servers work as expected.
|
||||
|
||||
## Taxonomies and Blackfriday
|
||||
### Taxonomies and Blackfriday
|
||||
|
||||
Taxonomies and [Blackfriday configuration][config] can also be set per language:
|
||||
|
||||
@@ -156,40 +157,113 @@ plaque = "plaques"
|
||||
|
||||
## Translate Your Content
|
||||
|
||||
Translated articles are identified by the name of the content file.
|
||||
There are two ways to manage your content translation, both ensures each page is assigned a language and linked to its translations.
|
||||
|
||||
### Examples of Translated Articles
|
||||
### Translation by filename
|
||||
|
||||
Considering the following example:
|
||||
|
||||
1. `/content/about.en.md`
|
||||
2. `/content/about.fr.md`
|
||||
|
||||
In this example, the `about.md` will be assigned the configured `defaultContentLanguage`.
|
||||
The first file is assigned the english language and linked to the second.
|
||||
The second file is assigned the french language and linked to the first.
|
||||
|
||||
1. `/content/about.md`
|
||||
2. `/content/about.fr.md`
|
||||
Their language is __assigned__ according to the language code added as __suffix to the filename__.
|
||||
|
||||
This way, you can slowly start to translate your current content without having to rename everything. If left unspecified, the default value for `defaultContentLanguage` is `en`.
|
||||
By having the same **path and base filename**, the content pieces are __linked__ together as translated pages.
|
||||
{{< note >}}
|
||||
|
||||
By having the same **directory and base filename**, the content pieces are linked together as translated pieces.
|
||||
If a file is missing any language code, it will be assigned the default language.
|
||||
|
||||
You can also set the key used to link the translations explicitly in front matter:
|
||||
{{</ note >}}
|
||||
### Translation by content directory
|
||||
|
||||
This system uses different content directories for each of the languages. Each language's content directory is set using the `contentDir` param.
|
||||
|
||||
{{< code-toggle file="config" >}}
|
||||
|
||||
languages:
|
||||
en:
|
||||
weight: 10
|
||||
languageName: "English"
|
||||
contentDir: "content/english"
|
||||
nn:
|
||||
weight: 20
|
||||
languageName: "Français"
|
||||
contentDir: "content/french"
|
||||
|
||||
{{< /code-toggle >}}
|
||||
|
||||
The value of `contentDir` can be any valid path, even absolute path references. The only restriction is that the content directories cannot overlap.
|
||||
|
||||
Considering the following example in conjunction with the configuration above:
|
||||
|
||||
1. `/content/english/about.md`
|
||||
2. `/content/french/about.md`
|
||||
|
||||
The first file is assigned the english language and is linked to the second.
|
||||
<br>The second file is assigned the french language and is linked to the first.
|
||||
|
||||
Their language is __assigned__ according to the content directory they are __placed__ in.
|
||||
|
||||
By having the same **path and basename** (relative to their language content directory), the content pieces are __linked__ together as translated pages.
|
||||
|
||||
### Bypassing default linking.
|
||||
|
||||
Any pages sharing the same `translationKey` set in front matter will be linked as translated pages regardless of basename or location.
|
||||
|
||||
Considering the following example:
|
||||
|
||||
1. `/content/about-us.en.md`
|
||||
2. `/content/om.nn.md`
|
||||
3. `/content/presentation/a-propos.fr.md`
|
||||
|
||||
```yaml
|
||||
translationKey: "my-story"
|
||||
# set in all three pages
|
||||
translationKey: "about"
|
||||
```
|
||||
|
||||
If you need distinct URLs per language, you can set the slug in the non-default language file. For example, you can define a custom slug for a French translation in the front matter of `content/about.fr.md` as follows:
|
||||
By setting the `translationKey` front matter param to `about` in all three pages, they will be __linked__ as translated pages.
|
||||
|
||||
```yaml
|
||||
|
||||
### Localizing permalinks
|
||||
|
||||
Because paths and filenames are used to handle linking, all translated pages, except for the language part, will be sharing the same url.
|
||||
|
||||
To localize the URLs, the [`slug`]({{< ref "content-management/organization/index.md#slug" >}}) or [`url`]({{< ref "content-management/organization/index.md#url" >}}) front matter param can be set in any of the non-default language file.
|
||||
|
||||
For example, a french translation (`content/about.fr.md`) can have its own localized slug.
|
||||
|
||||
{{< code-toggle >}}
|
||||
Title: A Propos
|
||||
slug: "a-propos"
|
||||
{{< /code-toggle >}}
|
||||
|
||||
```
|
||||
|
||||
At render, Hugo will build both `/about/` and `/a-propos/` as properly linked translated pages.
|
||||
At render, Hugo will build both `/about/` and `fr/a-propos/` while maintaning their translation linking.
|
||||
{{% note %}}
|
||||
If using `url`, remember to include the language part as well: `fr/compagnie/a-propos/`.
|
||||
{{%/ note %}}
|
||||
|
||||
For merging of content from other languages (i.e. missing content translations), see [lang.Merge](/functions/lang.merge/).
|
||||
### Page Bundles
|
||||
|
||||
## Link to Translated Content
|
||||
To avoid the burden of having to duplicate files, each Page Bundle inherits the resources of its linked translated pages' bundles except for the content files (markdown files, html files etc...).
|
||||
|
||||
Therefore, from within a template, the page will have access to the files from all linked pages' bundles.
|
||||
|
||||
If, across the linked bundles, two or more files share the same basenname, only one will be included and chosen as follows:
|
||||
|
||||
* File from current language Bundle, if present.
|
||||
* First file found across bundles by order of language `Weight`.
|
||||
|
||||
{{% note %}}
|
||||
|
||||
Page Bundle's resources follow the same language assignement logic as content files, be it by filename (`image.jpg`, `image.fr.jpg`) or by directory (`english/about/header.jpg`, `french/about/header.jpg`).
|
||||
|
||||
{{%/ note %}}
|
||||
|
||||
## Reference the Translated Content
|
||||
|
||||
To create a list of links to translated content, use a template similar to the following:
|
||||
|
||||
@@ -210,7 +284,7 @@ The above can be put in a `partial` (i.e., inside `layouts/partials/`) and inclu
|
||||
|
||||
The above also uses the [`i18n` function][i18func] described in the next section.
|
||||
|
||||
## List All Available Languages
|
||||
### List All Available Languages
|
||||
|
||||
`.AllTranslations` on a `Page` can be used to list all translations, including itself. Called on the home page it can be used to build a language navigator:
|
||||
|
||||
@@ -282,7 +356,7 @@ i18n|MISSING_TRANSLATION|en|wordCount
|
||||
|
||||
## Customize Dates
|
||||
|
||||
At the time of this writing, Golang does not yet have support for internationalized locales, but if you do some work, you can simulate it. For example, if you want to use French month names, you can add a data file like ``data/mois.yaml`` with this content:
|
||||
At the time of this writing, Go does not yet have support for internationalized locales, but if you do some work, you can simulate it. For example, if you want to use French month names, you can add a data file like ``data/mois.yaml`` with this content:
|
||||
|
||||
~~~yaml
|
||||
1: "janvier"
|
||||
@@ -366,7 +440,7 @@ For merging of content from other languages (i.e. missing content translations),
|
||||
|
||||
To support Multilingual mode in your themes, some considerations must be taken for the URLs in the templates. If there is more than one language, URLs must meet the following criteria:
|
||||
|
||||
* Come from the built-in `.Permalink` or `.URL`
|
||||
* Come from the built-in `.Permalink` or `.RelPermalink`
|
||||
* Be constructed with
|
||||
* The [`relLangURL` template function][rellangurl] or the [`absLangURL` template function][abslangurl] **OR**
|
||||
* Prefixed with `{{ .LanguagePrefix }}`
|
||||
|
||||
@@ -268,34 +268,6 @@ Assuming that standard Hugo pretty URLs are turned on.
|
||||
<a href="/about/#who:c28654c202e73453784cfd2c5ab356c0">Who</a>
|
||||
```
|
||||
|
||||
### `speakerdeck`
|
||||
|
||||
To embed slides from [Speaker Deck][], click on "< /> Embed" (under Share right next to the template on Speaker Deck) and copy the URL:
|
||||
|
||||
```
|
||||
<script async class="speakerdeck-embed" data-id="4e8126e72d853c0060001f97" data-ratio="1.33333333333333" src="//speakerdeck.com/assets/embed.js"></script>
|
||||
```
|
||||
|
||||
#### `speakerdeck` Example Input
|
||||
|
||||
Extract the value from the field `data-id` and pass it to the shortcode:
|
||||
|
||||
{{< code file="speakerdeck-example-input.md" >}}
|
||||
{{</* speakerdeck 4e8126e72d853c0060001f97 */>}}
|
||||
{{< /code >}}
|
||||
|
||||
#### `speakerdeck` Example Output
|
||||
|
||||
{{< output file="speakerdeck-example-input.md" >}}
|
||||
{{< speakerdeck 4e8126e72d853c0060001f97 >}}
|
||||
{{< /output >}}
|
||||
|
||||
#### `speakerdeck` Example Display
|
||||
|
||||
For the preceding `speakerdeck` example, the following simulates the displayed experience for visitors to your website. Naturally, the final display will be contingent on your stylesheets and surrounding markup.
|
||||
|
||||
{{< speakerdeck 4e8126e72d853c0060001f97 >}}
|
||||
|
||||
### `tweet`
|
||||
|
||||
You want to include a single tweet into your blog post? Everything you need is the URL of the tweet:
|
||||
@@ -402,6 +374,10 @@ Using the preceding `youtube` example (without `autoplay="true"`), the following
|
||||
|
||||
{{< youtube w7Ft2ymGmfc >}}
|
||||
|
||||
## Privacy Config
|
||||
|
||||
To learn how to configure your Hugo site to meet the new EU privacy regulation, see [Hugo and the GDPR][].
|
||||
|
||||
## Create Custom Shortcodes
|
||||
|
||||
To learn more about creating custom shortcodes, see the [shortcode template documentation][].
|
||||
@@ -410,6 +386,7 @@ To learn more about creating custom shortcodes, see the [shortcode template docu
|
||||
[contentmanagementsection]: /content-management/formats/
|
||||
[examplegist]: https://gist.github.com/spf13/7896402
|
||||
[figureelement]: http://html5doctor.com/the-figure-figcaption-elements/ "An article from HTML5 doctor discussing the fig and figcaption elements."
|
||||
[Hugo and the GDPR]: /about/hugo-and-gdpr/
|
||||
[Instagram]: https://www.instagram.com/
|
||||
[pagevariables]: /variables/page/
|
||||
[partials]: /templates/partials/
|
||||
@@ -418,7 +395,6 @@ To learn more about creating custom shortcodes, see the [shortcode template docu
|
||||
[sctemps]: /templates/shortcode-templates/
|
||||
[scvars]: /variables/shortcodes/
|
||||
[shortcode template documentation]: /templates/shortcode-templates/
|
||||
[Speaker Deck]: https://speakerdeck.com/
|
||||
[templatessection]: /templates/
|
||||
[Vimeo]: https://vimeo.com/
|
||||
[YouTube Videos]: https://www.youtube.com/
|
||||
|
||||
@@ -72,7 +72,13 @@ pygmentsCodefences
|
||||
: Set to true to enable syntax highlighting in code fences with a language tag in markdown (see below for an example).
|
||||
|
||||
pygmentsStyle
|
||||
: The style of code highlighting. See https://help.farbox.com/pygments.html for a gallery. Note that this option is not relevant when `pygmentsUseClasses` is set.
|
||||
: The style of code highlighting. Note that this option is not
|
||||
relevant when `pygmentsUseClasses` is set.
|
||||
|
||||
Syntax highlighting galleries:
|
||||
**Chroma** ([short snippets](https://xyproto.github.io/splash/docs/all.html),
|
||||
[long snippets](https://xyproto.github.io/splash/docs/longer/all.html)),
|
||||
[Pygments](https://help.farbox.com/pygments.html)
|
||||
|
||||
pygmentsUseClasses
|
||||
: Set to `true` to use CSS classes to format your highlighted code. See [Generate Syntax Highlighter CSS](#generate-syntax-highlighter-css).
|
||||
|
||||
@@ -88,7 +88,7 @@ Luckily, redirects can be handled easily with **aliases** in Hugo.
|
||||
|
||||
### Example: Aliases
|
||||
|
||||
Let's assume you create a new piece of content at `content/posts/my-awesome-blog-post.md`. The content is a revision of your previous post at `content/posts/my-original-url.md`. You can create an `aliases` field in the front matter of your new `my-awesome-blog-post.md` where you can add previous paths. The following examples show how to create this filed in TOML and YAML front matter, respectively.
|
||||
Let's assume you create a new piece of content at `content/posts/my-awesome-blog-post.md`. The content is a revision of your previous post at `content/posts/my-original-url.md`. You can create an `aliases` field in the front matter of your new `my-awesome-blog-post.md` where you can add previous paths. The following examples show how to create this field in TOML and YAML front matter, respectively.
|
||||
|
||||
#### TOML Front Matter
|
||||
|
||||
@@ -188,7 +188,7 @@ content/posts/post-1.md
|
||||
|
||||
## Ugly URLs
|
||||
|
||||
If you would like to have what are often referred to as "ugly URLs" (e.g., example.com/urls.html), set `uglyurls = true` or `uglyurls: true` in your site's `config.toml` or `config.yaml`, respectively. You can also use the `--uglyURLs=true` [flag from the command line][usage] with `hugo` or `hugo server`..
|
||||
If you would like to have what are often referred to as "ugly URLs" (e.g., example.com/urls.html), set `uglyurls = true` or `uglyurls: true` in your site's `config.toml` or `config.yaml`, respectively. You can also use the `--uglyURLs=true` [flag from the command line][usage] with `hugo` or `hugo server`.
|
||||
|
||||
If you want a specific piece of content to have an exact URL, you can specify this in the [front matter][] under the `url` key. The following are examples of the same content directory and what the eventual URL structure will be when Hugo runs with its default behavior.
|
||||
|
||||
@@ -253,7 +253,7 @@ Or, if you are on Windows and do not have `grep` installed:
|
||||
hugo config | FINDSTR /I canon
|
||||
```
|
||||
|
||||
## Override URLS with Front Matter
|
||||
## Override URLs with Front Matter
|
||||
|
||||
In addition to specifying permalink values in your site configuration for different content sections, Hugo provides even more granular control for individual pieces of content.
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ If you are having trouble following the installation guides for Go, check out [G
|
||||
|
||||
### Install Go From Source
|
||||
|
||||
[Download the latest stable version of Go][godl] and follow the official [Golang installation guide][goinstall].
|
||||
[Download the latest stable version of Go][godl] and follow the official [Go installation guide][goinstall].
|
||||
|
||||
Once you're finished installing Go, let's confirm everything is working correctly. Open a terminal---or command line under Windows--and type the following:
|
||||
|
||||
@@ -390,7 +390,7 @@ Thank you for reading through this contribution guide. Hopefully, we will see yo
|
||||
|
||||
Feel free to [open an issue][newissue] if you think you found a bug or you have a new idea to improve Hugo. We are happy to hear from you.
|
||||
|
||||
## Additional References for Learning Git and Golang
|
||||
## Additional References for Learning Git and Go
|
||||
|
||||
* [Codecademy's Free "Learn Git" Course][codecademy] (Free)
|
||||
* [Code School and GitHub's "Try Git" Tutorial][trygit] (Free)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
title: errorf
|
||||
linktitle: errorf
|
||||
description: Evaluates a format string and logs it to ERROR.
|
||||
description: Log ERROR and fail the build from the templates.
|
||||
date: 2017-09-30
|
||||
publishdate: 2017-09-30
|
||||
lastmod: 2017-09-30
|
||||
@@ -18,9 +18,12 @@ deprecated: false
|
||||
aliases: []
|
||||
---
|
||||
|
||||
`errorf` will evaluate a format string, then output the result to the ERROR log.
|
||||
This will also cause the build to fail.
|
||||
`errorf` will evaluate a format string, then output the result to the ERROR log (and only once per error message to avoid flooding the log).
|
||||
|
||||
This will also cause the build to fail (the `hugo` command will `exit -1`).
|
||||
|
||||
```
|
||||
{{ errorf "Something went horribly wrong! %s" err }}
|
||||
{{ errorf "Failed to handle page %q" .Path }}
|
||||
```
|
||||
|
||||
Note that `errorf` supports all the formatting verbs of the [fmt](https://golang.org/pkg/fmt/) package.
|
||||
|
||||
@@ -35,9 +35,9 @@ You can limit the number of matches in the list with a third parameter. The foll
|
||||
```
|
||||
|
||||
{{% note %}}
|
||||
Hugo uses Golang's [Regular Expression package](https://golang.org/pkg/regexp/), which is the same general syntax used by Perl, Python, and other languages but with a few minor differences for those coming from a background in PCRE. For a full syntax listing, see the [GitHub wiki for re2](https://github.com/google/re2/wiki/Syntax).
|
||||
Hugo uses Go's [Regular Expression package](https://golang.org/pkg/regexp/), which is the same general syntax used by Perl, Python, and other languages but with a few minor differences for those coming from a background in PCRE. For a full syntax listing, see the [GitHub wiki for re2](https://github.com/google/re2/wiki/Syntax).
|
||||
|
||||
If you are just learning RegEx, or at least Golang's flavor, you can practice pattern matching in the browser at <https://regex101.com/>.
|
||||
If you are just learning RegEx, or at least Go's flavor, you can practice pattern matching in the browser at <https://regex101.com/>.
|
||||
{{% /note %}}
|
||||
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ Assuming a key-value of `date: 2017-03-03` in a content file's front matter, you
|
||||
{{ .PublishDate.Format "January 2, 2006" }} => March 3, 2017
|
||||
```
|
||||
|
||||
For formatting *any* string representations of dates defined in your front matter, see the [`dateFormat` function][dateFormat], which will still leverage the Golang layout string explained below but uses a slightly different syntax.
|
||||
For formatting *any* string representations of dates defined in your front matter, see the [`dateFormat` function][dateFormat], which will still leverage the Go layout string explained below but uses a slightly different syntax.
|
||||
|
||||
## Go's Layout String
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ toc: false
|
||||
aliases: []
|
||||
---
|
||||
|
||||
`len` is a built-in function in Golang that returns the length of a variable according to its type. From the Golang documentation:
|
||||
`len` is a built-in function in Go that returns the length of a variable according to its type. From the Go documentation:
|
||||
|
||||
> Array: the number of elements in v.
|
||||
>
|
||||
@@ -57,4 +57,4 @@ Note the use of `.RegularPages`, a [site variable][] that counts all regular con
|
||||
[list templates]: /templates/lists/
|
||||
[section]: /content-management/sections/
|
||||
[site variable]: /variables/site/
|
||||
[`where`]: /functions/where/
|
||||
[`where`]: /functions/where/
|
||||
|
||||
@@ -37,7 +37,7 @@ would produce the following:
|
||||
</div>
|
||||
```
|
||||
|
||||
The above example uses the [`.Format` function](/functions/format), which page includes a full listing of date formatting using Golang's layout string.
|
||||
The above example uses the [`.Format` function](/functions/format), which page includes a full listing of date formatting using Go's layout string.
|
||||
|
||||
{{% note %}}
|
||||
Older Hugo themes may still be using the obsolete Page’s `.Now` (uppercase with leading dot), which causes build error that looks like the following:
|
||||
|
||||
@@ -25,7 +25,7 @@ aliases: []
|
||||
```
|
||||
|
||||
{{% note %}}
|
||||
Hugo uses Golang's [Regular Expression package](https://golang.org/pkg/regexp/), which is the same general syntax used by Perl, Python, and other languages but with a few minor differences for those coming from a background in PCRE. For a full syntax listing, see the [GitHub wiki for re2](https://github.com/google/re2/wiki/Syntax).
|
||||
Hugo uses Go's [Regular Expression package](https://golang.org/pkg/regexp/), which is the same general syntax used by Perl, Python, and other languages but with a few minor differences for those coming from a background in PCRE. For a full syntax listing, see the [GitHub wiki for re2](https://github.com/google/re2/wiki/Syntax).
|
||||
|
||||
If you are just learning RegEx, or at least Golang's flavor, you can practice pattern matching in the browser at <https://regex101.com/>.
|
||||
If you are just learning RegEx, or at least Go's flavor, you can practice pattern matching in the browser at <https://regex101.com/>.
|
||||
{{% /note %}}
|
||||
|
||||
@@ -22,6 +22,9 @@ aliases: [/extras/scratch/,/doc/scratch/]
|
||||
|
||||
In most cases you can do okay without `Scratch`, but due to scoping issues, there are many use cases that aren't solvable in Go Templates without `Scratch`'s help.
|
||||
|
||||
`.Scratch` is available as methods on `Page` and `Shortcode`. Since Hugo 0.43 you can also create a locally scoped `Scratch` using the template func `newScratch`.
|
||||
|
||||
|
||||
{{% note %}}
|
||||
See [this Go issue](https://github.com/golang/go/issues/10608) for the main motivation behind Scratch.
|
||||
{{% /note %}}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
---
|
||||
title: strings.Repeat
|
||||
# linktitle:
|
||||
description: Returns a string consisting of count copies of the string s.
|
||||
godocref:
|
||||
date: 2018-05-31
|
||||
publishdate: 2018-05-31
|
||||
lastmod: 2018-05-31
|
||||
categories: [functions]
|
||||
menu:
|
||||
docs:
|
||||
parent: "functions"
|
||||
keywords: [strings]
|
||||
signature: ["strings.Repeat INPUT COUNT"]
|
||||
workson: []
|
||||
hugoversion:
|
||||
relatedfuncs: []
|
||||
deprecated: false
|
||||
---
|
||||
|
||||
`strings.Repeat` provides the Go [`strings.Repeat`](https://golang.org/pkg/strings/#Repeat) function for Hugo templates. It takes a string and a count, and returns a string with consisting of count copies of the string argument.
|
||||
|
||||
```
|
||||
{{ strings.Repeat "yo" 3 }} → "yoyoyo"
|
||||
```
|
||||
|
||||
`strings.Repeat` *requires* the second argument, which tells the function how many times to repeat the first argument; there is no default. However, it can be used as a pipeline:
|
||||
|
||||
```
|
||||
{{ "yo" | strings.Repeat 3 }} → "yoyoyo"
|
||||
```
|
||||
@@ -0,0 +1,28 @@
|
||||
---
|
||||
title: strings.RuneCount
|
||||
description: Determines the number of runes in a string.
|
||||
godocref:
|
||||
date: 2018-06-01
|
||||
publishdate: 2018-06-01
|
||||
lastmod: 2018-06-01
|
||||
categories: [functions]
|
||||
menu:
|
||||
docs:
|
||||
parent: "functions"
|
||||
keywords: [counting, character count, length, rune length, rune count]
|
||||
signature: ["strings.RuneCount INPUT"]
|
||||
workson: []
|
||||
hugoversion:
|
||||
relatedfuncs: ["len", "countrunes"]
|
||||
deprecated: false
|
||||
aliases: []
|
||||
---
|
||||
|
||||
In contrast with `strings.CountRunes` function, which strips HTML and whitespace before counting runes, `strings.RuneCount` simply counts all the runes in a string. It relies on the Go [`utf8.RuneCountInString`] function.
|
||||
|
||||
```
|
||||
{{ "Hello, 世界" | strings.RuneCount }}
|
||||
<!-- outputs a content length of 9 runes. -->
|
||||
```
|
||||
|
||||
[`utf8.RuneCount`]: https://golang.org/pkg/unicode/utf8/#RuneCount
|
||||
@@ -12,7 +12,7 @@ toc: true
|
||||
|
||||
## The Config Toggler!
|
||||
|
||||
This is an exemple for the Config Toggle shortcode.
|
||||
This is an example for the Config Toggle shortcode.
|
||||
Its purpose is to let users choose a Config language by clicking on its corresponding tab. Upon doing so, every Code toggler on the page will be switched to the target language. Also, target language will be saved in user's `localStorage` so when they go to a different pages, Code Toggler display their last "toggled" config language.
|
||||
|
||||
## That Config Toggler
|
||||
|
||||
@@ -210,6 +210,9 @@ theme ("")
|
||||
themesDir ("themes")
|
||||
: The directory where Hugo reads the themes from.
|
||||
|
||||
timeout (10000)
|
||||
: Timeout for generating page contents, in milliseconds (defaults to 10 seconds). *Note:* this is used to bail out of recursive content generation, if your pages are slow to generate (e.g., because they require large image processing or depend on remote contents) you might need to raise this limit.
|
||||
|
||||
title ("")
|
||||
: Site title.
|
||||
|
||||
|
||||
@@ -104,7 +104,7 @@ The most common usage is probably to run `hugo` with your current directory bein
|
||||
|
||||
This generates your website to the `public/` directory by default, although you can customize the output directory in your [site configuration][config] by changing the `publishDir` field.
|
||||
|
||||
The site Hugo renders into `public/` is ready to be deployed to your web server:
|
||||
The command `hugo` renders your site into `public/` dir and is ready to be deployed to your web server:
|
||||
|
||||
```
|
||||
hugo
|
||||
|
||||
@@ -30,7 +30,7 @@ If you're already using Nanobox and just need deployment instructions, you can s
|
||||
|
||||
## What You'll Need
|
||||
|
||||
With Nanobox you don't need to worry about having Golang or Hugo installed. They'll be installed as part of the development environment created for you.
|
||||
With Nanobox you don't need to worry about having Go or Hugo installed. They'll be installed as part of the development environment created for you.
|
||||
|
||||
To get started you'll just need the following three items:
|
||||
|
||||
@@ -133,7 +133,7 @@ Make sure to check the version of Hugo you have installed and update the install
|
||||
|
||||
### Generating a New Hugo App
|
||||
|
||||
You'll generate your new application from inside the Nanobox VM (this is why you don't need to worry about having Golang or Hugo installed).
|
||||
You'll generate your new application from inside the Nanobox VM (this is why you don't need to worry about having Go or Hugo installed).
|
||||
|
||||
Run the following command to drop into a Nanobox console (inside the VM) where your codebase is mounted:
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ The following examples use GitHub, but other git providers will follow a similar
|
||||
|
||||

|
||||
|
||||
Selecting GitHub will bring up a typical modal you've seen through other application that use GitHub for authentication. Select "Authorize application."
|
||||
Selecting GitHub will bring up an authorization modal for authentication. Select "Authorize application."
|
||||
|
||||

|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ Hugo now has:
|
||||
* Add a `GetPage` to the site benchmarks [a1956391](https://github.com/gohugoio/hugo/commit/a19563910eec5fed08f3b02563b9a7b38026183d) [@bep](https://github.com/bep)
|
||||
* Add headless bundle support [0432c64d](https://github.com/gohugoio/hugo/commit/0432c64dd22e4610302162678bb93661ba68d758) [@bep](https://github.com/bep) [#4311](https://github.com/gohugoio/hugo/issues/4311)
|
||||
* Merge matching resources params maps [5a0819b9](https://github.com/gohugoio/hugo/commit/5a0819b9b5eb9e79826cfa0a65f235d9821b1ac4) [@bep](https://github.com/bep) [#4315](https://github.com/gohugoio/hugo/issues/4315)
|
||||
* Add some general code contribution criterias [78c86330](https://github.com/gohugoio/hugo/commit/78c863305f337ed4faf3cf0a23675f28b0ae5641) [@bep](https://github.com/bep)
|
||||
* Add some general code contribution criteria [78c86330](https://github.com/gohugoio/hugo/commit/78c863305f337ed4faf3cf0a23675f28b0ae5641) [@bep](https://github.com/bep)
|
||||
* Tighten page kind logic, introduce tests [8125b4b0](https://github.com/gohugoio/hugo/commit/8125b4b03d10eb73f8aea3f9ea41172aba8df082) [@vassudanagunta](https://github.com/vassudanagunta)
|
||||
|
||||
## Fixes
|
||||
|
||||
@@ -25,7 +25,7 @@ You would experience errors of type:
|
||||
png: invalid format: not enough pixel data
|
||||
```
|
||||
|
||||
This commit fixes that by adding a mutex per image. This should also improve the performance, sligthly, as it avoids duplicate work.
|
||||
This commit fixes that by adding a mutex per image. This should also improve the performance, slightly, as it avoids duplicate work.
|
||||
|
||||
The current workaround before this fix is to always operate on the original:
|
||||
|
||||
|
||||
|
After Width: | Height: | Size: 66 KiB |
@@ -1,13 +1,13 @@
|
||||
|
||||
---
|
||||
date: 2018-05-25
|
||||
title: "0.41"
|
||||
description: "0.41"
|
||||
title: "Hugo 0.41: Privacy Configuration for GDPR"
|
||||
description: "Hugo 0.41 adds a new site configuration section to meet the new General Data Protection Regulation (GDPR)."
|
||||
categories: ["Releases"]
|
||||
---
|
||||
|
||||
|
||||
In Hugo `0.41` we add a new **Privacy Configuration** section to meet the new regulations in the new **General Data Protection Regulation ([GDPR](https://en.wikipedia.org/wiki/General_Data_Protection_Regulation))**. Many have contributed in the discussion about this, but a special thanks to [@onedrawingperday](https://github.com/onedrawingperday), [@jhabdas](https://github.com/jhabdas), and [@it-gro](https://github.com/it-gro).
|
||||
In Hugo `0.41` we add a new **Privacy Configuration** section to meet the new regulations in the new **General Data Protection Regulation ([GDPR](https://en.wikipedia.org/wiki/General_Data_Protection_Regulation))**. Many have contributed work on this project, but a special thanks to [@onedrawingperday](https://github.com/onedrawingperday), [@jhabdas](https://github.com/jhabdas), and [@it-gro](https://github.com/it-gro).
|
||||
|
||||
> You can read more about the new Privacy Config [here](https://gohugo.io/about/hugo-and-gdpr/).
|
||||
|
||||
|
||||
|
After Width: | Height: | Size: 73 KiB |
@@ -0,0 +1,66 @@
|
||||
|
||||
---
|
||||
date: 2018-06-12
|
||||
title: "Hugo 0.42: Theme Composition and Inheritance!"
|
||||
description: "Hugo 0.42 adds Theme Components support, a new and powerful way of composing your Hugo sites."
|
||||
categories: ["Releases"]
|
||||
---
|
||||
|
||||
Hugo `0.42` adds **Theme Components**. This is a really powerful new way of building your Hugo sites with reusable components. This is both **Theme Composition** and **Theme Inheritance**.
|
||||
|
||||
>Read more about Theme Components in the [Hugo Documentation](https://gohugo.io/themes/theme-components/).
|
||||
|
||||
The feature above was implemented by [@bep](https://github.com/bep), the funny Norwegian, with great design help from the Hugo community. But that implementation would not have been possible without [Afero](https://github.com/spf13/afero), [Steve Francia's](https://github.com/spf13) virtual file system. Hugo is built on top of Afero and many other fast and solid Go projects, and if you look at the combined contribution log of the Hugo project and its many open source dependencies, the total amount of contributions is staggering. A big thank you to them all!
|
||||
|
||||
This release represents **27 contributions by 7 contributors** to the main Hugo code base. [@bep](https://github.com/bep) leads the Hugo development with a significant amount of contributions, but also a big shoutout to [@onedrawingperday](https://github.com/onedrawingperday), [@anthonyfok](https://github.com/anthonyfok), and [@stefanneuhaus](https://github.com/stefanneuhaus) for their ongoing contributions.
|
||||
|
||||
And a big thanks to [@digitalcraftsman](https://github.com/digitalcraftsman) for his relentless work on keeping the themes site in pristine condition and to [@kaushalmodi](https://github.com/kaushalmodi) for his great work on the documentation site.
|
||||
|
||||
Many have also been busy writing and fixing the documentation in [hugoDocs](https://github.com/gohugoio/hugoDocs),
|
||||
which has received **8 contributions by 5 contributors**. A special thanks to [@bep](https://github.com/bep), [@LorenzCK](https://github.com/LorenzCK), [@gavinwray](https://github.com/gavinwray), and [@deyton](https://github.com/deyton) for their work on the documentation site.
|
||||
|
||||
|
||||
Hugo now has:
|
||||
|
||||
* 26286+ [stars](https://github.com/gohugoio/hugo/stargazers)
|
||||
* 444+ [contributors](https://github.com/gohugoio/hugo/graphs/contributors)
|
||||
* 235+ [themes](http://themes.gohugo.io/)
|
||||
|
||||
## Notes
|
||||
* The `speakerdeck` shortcode is removed. It didn't work properly, so is isn't expected to be in wide use. If you use it, you will get a build error. You will either have to remove its usage or add a `speakerdeck` shortcode to your own project or theme.
|
||||
* We have now virtualized the filesystems for project and theme files. This makes everything simpler, faster and more powerful. But it also means that template lookups on the form `{{ template “theme/partials/pagination.html” . }}` will not work anymore. That syntax has never been documented, so it's not expected to be in wide use. `{{ partial "pagination.html" . }}` will give you the most specific version of that partial.
|
||||
|
||||
## Enhancements
|
||||
|
||||
|
||||
* Always load GA script over HTTPS [2e6712e2](https://github.com/gohugoio/hugo/commit/2e6712e2814f333caa807888c1d8a9a5a3c03709) [@coliff](https://github.com/coliff)
|
||||
* Remove speakerdeck shortcode [65deb72d](https://github.com/gohugoio/hugo/commit/65deb72dc4c9299416cf2d9defddb96dba4101fd) [@onedrawingperday](https://github.com/onedrawingperday) [#4830](https://github.com/gohugoio/hugo/issues/4830)
|
||||
* Add `strings.RuneCount` [019bd557](https://github.com/gohugoio/hugo/commit/019bd5576be87c9f06b6a928ede1a5e78677f7b3) [@theory](https://github.com/theory)
|
||||
* Add `strings.Repeat` [13435a6f](https://github.com/gohugoio/hugo/commit/13435a6f608306c5094fdcd72a1d9538727f91b2) [@theory](https://github.com/theory)
|
||||
* Reset Page's main output on server rebuilds [dc4226a8](https://github.com/gohugoio/hugo/commit/dc4226a8b27e03e31068fc945daab885d3819d04) [@bep](https://github.com/bep) [#4819](https://github.com/gohugoio/hugo/issues/4819)
|
||||
* Create LICENSE rather than LICENSE.md in "new theme" [ed4a345e](https://github.com/gohugoio/hugo/commit/ed4a345efeaa19eef2c1c6360d22f75c24abc31a) [@anthonyfok](https://github.com/anthonyfok) [#4623](https://github.com/gohugoio/hugo/issues/4623)
|
||||
* Create `_default/baseof.html` in "new theme" [9717ac7d](https://github.com/gohugoio/hugo/commit/9717ac7dce84d004afde4edb32ad81319c7dd8a7) [@anthonyfok](https://github.com/anthonyfok) [#3576](https://github.com/gohugoio/hugo/issues/3576)
|
||||
* Add `tweet_simple`shortcode [07b96d16](https://github.com/gohugoio/hugo/commit/07b96d16e8679c40e289c9076ef4414ed6eb7f81) [@onedrawingperday](https://github.com/onedrawingperday)
|
||||
* Make "new theme" feedback more intuitive [692ec008](https://github.com/gohugoio/hugo/commit/692ec008726b570c9b30ac3391774cbb622730cb) [@anthonyfok](https://github.com/anthonyfok)
|
||||
* Move nextStepsText() to new_site.go [d3dd74fd](https://github.com/gohugoio/hugo/commit/d3dd74fd655c22f21e91e38edb1d377a1357e3be) [@anthonyfok](https://github.com/anthonyfok)
|
||||
* Add support for theme composition and inheritance [80230f26](https://github.com/gohugoio/hugo/commit/80230f26a3020ff33bac2bef01b2c0e314b89f86) [@bep](https://github.com/bep) [#4460](https://github.com/gohugoio/hugo/issues/4460)[#4450](https://github.com/gohugoio/hugo/issues/4450)
|
||||
* Add vimeo_simple [8de53244](https://github.com/gohugoio/hugo/commit/8de53244799f0d2d0343056d348d810343cf7aa5) [@onedrawingperday](https://github.com/onedrawingperday) [#4749](https://github.com/gohugoio/hugo/issues/4749)
|
||||
* Add a BlackFriday option for rel="noreferrer" on external links [20cbc2c7](https://github.com/gohugoio/hugo/commit/20cbc2c7856a9b07d45648d940276374db35e425) [@stefanneuhaus](https://github.com/stefanneuhaus) [#4722](https://github.com/gohugoio/hugo/issues/4722)
|
||||
* Add a BlackFriday option for rel="nofollow" on external links [7a619264](https://github.com/gohugoio/hugo/commit/7a6192647a4b383cd539df2063388ea380371de6) [@stefanneuhaus](https://github.com/stefanneuhaus) [#4722](https://github.com/gohugoio/hugo/issues/4722)
|
||||
* Update Chroma [b5b36e32](https://github.com/gohugoio/hugo/commit/b5b36e32008bc8ea779ae06bf249b537f6d5c336) [@bep](https://github.com/bep) [#4779](https://github.com/gohugoio/hugo/issues/4779)
|
||||
* Enhance Page and Resource String() [4f0665f4](https://github.com/gohugoio/hugo/commit/4f0665f476e06e9707621c18f7422fdeb776e0d1) [@vassudanagunta](https://github.com/vassudanagunta)
|
||||
* Update theme documentation [c74b0f8f](https://github.com/gohugoio/hugo/commit/c74b0f8f9b30866e09efac8235cc5e0093ab3d50) [@bep](https://github.com/bep) [#4460](https://github.com/gohugoio/hugo/issues/4460)
|
||||
|
||||
## Fixes
|
||||
|
||||
* Make sure that `.Site.Taxonomies` is always set on rebuilds [6464981a](https://github.com/gohugoio/hugo/commit/6464981adb4d7d0f41e8e2c987342082982210a1) [@bep](https://github.com/bep) [#4838](https://github.com/gohugoio/hugo/issues/4838)
|
||||
* Reset the "distinct error logger" on rebuilds [bf5f10fa](https://github.com/gohugoio/hugo/commit/bf5f10faa9fd445c4dd21839aa7d73cd2acbfb85) [@bep](https://github.com/bep) [#4818](https://github.com/gohugoio/hugo/issues/4818)
|
||||
* Remove frameborder attr YT iframe + CSS fixes [ceaff7ca](https://github.com/gohugoio/hugo/commit/ceaff7cafc5357274e546984ae02a4cbdf305f81) [@onedrawingperday](https://github.com/onedrawingperday)
|
||||
* Fix vimeo_simple thumb scaling [b84389c5](https://github.com/gohugoio/hugo/commit/b84389c5e0e1ef15449b24d488bbbcbc41245c59) [@onedrawingperday](https://github.com/onedrawingperday)
|
||||
* Fix typo instagram_simple [d68367cb](https://github.com/gohugoio/hugo/commit/d68367cbe76cbc02adb5b778e8be98bed6319368) [@onedrawingperday](https://github.com/onedrawingperday)
|
||||
* Prevent isBaseTemplate() from matching "baseof" in dir [c3115292](https://github.com/gohugoio/hugo/commit/c3115292a7f2d2623cb45054a361e997ad9330c9) [@anthonyfok](https://github.com/anthonyfok) [#4809](https://github.com/gohugoio/hugo/issues/4809)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
|
||||
---
|
||||
date: 2018-06-13
|
||||
title: "Hugo 0.42.1: Two Bug Fixes"
|
||||
description: "Hugo 0.42.1 fixes two issues."
|
||||
categories: ["Releases"]
|
||||
images:
|
||||
- images/blog/hugo-bug-poster.png
|
||||
|
||||
---
|
||||
|
||||
|
||||
|
||||
This is a bug-fix release with two fixes:
|
||||
|
||||
* Reset the global pages cache on server rebuilds [128f14ef](https://github.com/gohugoio/hugo/commit/128f14efad90886ffef37c01ac1e20436a732f97) [@bep](https://github.com/bep) [#4845](https://github.com/gohugoio/hugo/issues/4845)
|
||||
* Do not fail server build when /static is missing [34ee27a7](https://github.com/gohugoio/hugo/commit/34ee27a78b9e2b5f475d44253ae234067b76cc6e) [@bep](https://github.com/bep) [#4846](https://github.com/gohugoio/hugo/issues/4846)
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
|
||||
---
|
||||
date: 2018-06-28
|
||||
title: "Hugo 0.42.2: One Bug Fix"
|
||||
description: "Hugo 0.42.2 fixes server reload on config changes."
|
||||
categories: ["Releases"]
|
||||
images:
|
||||
- images/blog/hugo-bug-poster.png
|
||||
|
||||
---
|
||||
|
||||
|
||||
This release fixes broken server-reload on config changes. This is a regression from Hugo `0.42`. [3a7706b0](https://github.com/gohugoio/hugo/commit/3a7706b069107e5fa6112b3f7ce006f16867cb38) [@bep](https://github.com/bep) [#4878](https://github.com/gohugoio/hugo/issues/4878)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
|
||||
---
|
||||
date: 2018-07-09
|
||||
title: "0.43"
|
||||
description: "0.43"
|
||||
categories: ["Releases"]
|
||||
---
|
||||
|
||||
Hugo `0.43` adds a powerful and very simple to use **Assets Pipeline** with **SASS and SCSS** with source map support, **PostCSS** and **minification** and **fingerprinting** and **Subresource Integrity** and ... much more. Oh, did we mention that you can now do **ad-hoc image processing** and execute text resources as Go templates?
|
||||
|
||||
An example pipeline:
|
||||
|
||||
```go-html-template
|
||||
{{ $styles := resources.Get "scss/main.scss" | toCSS | postCSS | minify | fingerprint }}
|
||||
<link rel="stylesheet" href="{{ $styles.Permalink }}" integrity="{{ $styles.Data.Integrity }}" media="screen">
|
||||
```
|
||||
|
||||
To me, the above is beautiful in its speed and simplicity. It could be printed on a t-shirt. I wrote in the [Hugo Birthday Post](https://gohugo.io/news/lets-celebrate-hugos-5th-birthday/) some days ago about the value of a single binary with native and fast implementations. I should have added _simplicity_ as a keyword. There seem to be a misconception that all of this needs to be hard and painful.
|
||||
|
||||
New functions to create `Resource` objects:
|
||||
|
||||
* `resources.Get`
|
||||
* `resources.FromString`: Create a Resource from a string.
|
||||
|
||||
New `Resource` transformation funcs:
|
||||
|
||||
* `resources.ToCSS`: Compile `SCSS` or `SASS` into `CSS`.
|
||||
* `resources.PostCSS`: Process your CSS with PostCSS. Config file support (project or theme or passed as an option).
|
||||
* `resources.Minify`: Currently supports `css`, `js`, `json`, `html`, `svg`, `xml`.
|
||||
* `resources.Fingerprint`: Creates a fingerprinted version of the given Resource with Subresource Integrity.
|
||||
* `resources.Concat`: Concatenates a list of Resource objects. Think of this as a poor man's bundler.
|
||||
* `resources.ExecuteAsTemplate`: Parses and executes the given Resource and data context (e.g. .Site) as a Go template.
|
||||
|
||||
|
||||
I, [@bep](https://github.com/bep), implemented this in [dea71670](https://github.com/gohugoio/hugo/commit/dea71670c059ab4d5a42bd22503f18c087dd22d4). We will work hard to get the documentation up to date, but follow the links above for details, and also see this [demo project](https://github.com/bep/hugo-sass-test).
|
||||
|
||||
|
||||
This release represents **35 contributions by 7 contributors** to the main Hugo code base.
|
||||
[@bep](https://github.com/bep) leads the Hugo development with a significant amount of contributions, but also a big shoutout to [@anthonyfok](https://github.com/anthonyfok), [@openscript](https://github.com/openscript), and [@caarlos0](https://github.com/caarlos0) for their ongoing contributions.
|
||||
And a big thanks to [@digitalcraftsman](https://github.com/digitalcraftsman) for his relentless work on keeping the themes site in pristine condition and to [@kaushalmodi](https://github.com/kaushalmodi) for his great work on the documentation site.
|
||||
|
||||
Many have also been busy writing and fixing the documentation in [hugoDocs](https://github.com/gohugoio/hugoDocs),
|
||||
which has received **11 contributions by 5 contributors**. A special thanks to [@bep](https://github.com/bep), [@danrl](https://github.com/danrl), [@regisphilibert](https://github.com/regisphilibert), and [@digitalcraftsman](https://github.com/digitalcraftsman) for their work on the documentation site.
|
||||
|
||||
Hugo now has:
|
||||
|
||||
* 26968+ [stars](https://github.com/gohugoio/hugo/stargazers)
|
||||
* 443+ [contributors](https://github.com/gohugoio/hugo/graphs/contributors)
|
||||
* 238+ [themes](http://themes.gohugo.io/)
|
||||
|
||||
## Notes
|
||||
|
||||
* Replace deprecated {Get,}ByPrefix with {Get,}Match [42ed6025](https://github.com/gohugoio/hugo/commit/42ed602580a672e420e1d860384e812f4871ff67) [@anthonyfok](https://github.com/anthonyfok)
|
||||
* Hugo is now released with two binary version: One with and one without SCSS/SASS support. At the time of writing, this is only available in the binaries on the GitHub release page. Brew, Snap builds etc. will come. But note that you **only need the extended version if you want to edit SCSS**. For your CI server, or if you don't use SCSS, you will most likely want the non-extended version.
|
||||
|
||||
## Enhancements
|
||||
|
||||
### Templates
|
||||
|
||||
* Return en empty slice in `after` instead of error [f8212d20](https://github.com/gohugoio/hugo/commit/f8212d20009c4b5cc6e1ec733d09531eb6525d9f) [@bep](https://github.com/bep) [#4894](https://github.com/gohugoio/hugo/issues/4894)
|
||||
* Update internal pagination template to support Bootstrap 4 [ca1e46ef](https://github.com/gohugoio/hugo/commit/ca1e46efb94e3f3d2c8482cb9434d2f38ffd2683) [@bep](https://github.com/bep) [#4881](https://github.com/gohugoio/hugo/issues/4881)
|
||||
* Support text/template/parse API change in go1.11 [9f27091e](https://github.com/gohugoio/hugo/commit/9f27091e1067875e2577c331acc60adaef5bb234) [@anthonyfok](https://github.com/anthonyfok) [#4784](https://github.com/gohugoio/hugo/issues/4784)
|
||||
|
||||
### Core
|
||||
|
||||
* Allow forward slash in shortcode names [de37455e](https://github.com/gohugoio/hugo/commit/de37455ec73cffd039b44e8f6c62d2884b1d6bbd) [@bep](https://github.com/bep) [#4886](https://github.com/gohugoio/hugo/issues/4886)
|
||||
* Reset the global pages cache on server rebuilds [128f14ef](https://github.com/gohugoio/hugo/commit/128f14efad90886ffef37c01ac1e20436a732f97) [@bep](https://github.com/bep) [#4845](https://github.com/gohugoio/hugo/issues/4845)
|
||||
|
||||
### Other
|
||||
|
||||
* Bump CircleCI image [e3df6478](https://github.com/gohugoio/hugo/commit/e3df6478f09a7a5fed96aced791fa94fd2c35d1a) [@bep](https://github.com/bep)
|
||||
* Add Goreleaser extended config [626afc98](https://github.com/gohugoio/hugo/commit/626afc98254421f5a5edc97c541b10bd81d5bbbb) [@bep](https://github.com/bep) [#4908](https://github.com/gohugoio/hugo/issues/4908)
|
||||
* Build both hugo and hugo.extended for 0.43 [e1027c58](https://github.com/gohugoio/hugo/commit/e1027c5846b48c4ad450f6cc27e2654c9e0dae39) [@anthonyfok](https://github.com/anthonyfok) [#4908](https://github.com/gohugoio/hugo/issues/4908)
|
||||
* Add temporary build script [bfc3488b](https://github.com/gohugoio/hugo/commit/bfc3488b8e8b3dc1ffc6a339ee2dac8dcbdb55a9) [@bep](https://github.com/bep)
|
||||
* Add "extended" to "hugo version" [ce84b524](https://github.com/gohugoio/hugo/commit/ce84b524f4e94299b5b66afe7ce1a9bd4a9959fc) [@anthonyfok](https://github.com/anthonyfok) [#4913](https://github.com/gohugoio/hugo/issues/4913)
|
||||
* Add a newScratch template func [2b8d907a](https://github.com/gohugoio/hugo/commit/2b8d907ab731627f4e2a30442cd729064516c8bb) [@bep](https://github.com/bep) [#4685](https://github.com/gohugoio/hugo/issues/4685)
|
||||
* Add Hugo Piper with SCSS support and much more [dea71670](https://github.com/gohugoio/hugo/commit/dea71670c059ab4d5a42bd22503f18c087dd22d4) [@bep](https://github.com/bep) [#4381](https://github.com/gohugoio/hugo/issues/4381)[#4903](https://github.com/gohugoio/hugo/issues/4903)[#4858](https://github.com/gohugoio/hugo/issues/4858)
|
||||
* Consider root and current section's content type if set in front matter [c790029e](https://github.com/gohugoio/hugo/commit/c790029e1dbb0b66af18d05764bd6045deb2e180) [@bep](https://github.com/bep) [#4891](https://github.com/gohugoio/hugo/issues/4891)
|
||||
* Update docker image [554553c0](https://github.com/gohugoio/hugo/commit/554553c09c7657d28681e1fa0638806a452737a0) [@bep](https://github.com/bep)
|
||||
* Merge branch 'release-0.42.2' [282f6035](https://github.com/gohugoio/hugo/commit/282f6035e7c36f8550d91033e3a66718468c6c8b) [@bep](https://github.com/bep)
|
||||
* Release 0.42.2 [1637d12e](https://github.com/gohugoio/hugo/commit/1637d12e3762fc1ebab4cd675f75afaf25f59cdb) [@bep](https://github.com/bep)
|
||||
* Update GoReleaser config [1f0c4e1f](https://github.com/gohugoio/hugo/commit/1f0c4e1fb347bb233f3312c424fbf5a013c03604) [@caarlos0](https://github.com/caarlos0)
|
||||
* Create missing head.html partial on new theme generation [fd71fa89](https://github.com/gohugoio/hugo/commit/fd71fa89bd6c197402582c87b2b76d4b96d562bf) [@openscript](https://github.com/openscript)
|
||||
* Add html doctype to baseof.html template for new themes [b5a3aa70](https://github.com/gohugoio/hugo/commit/b5a3aa7082135d0a573f4fbb00f798e26b67b902) [@openscript](https://github.com/openscript)
|
||||
* Adds .gitattributes to force Go files to LF [6a2968fd](https://github.com/gohugoio/hugo/commit/6a2968fd5c0116d93de0f379ac615e9076821899) [@neurocline](https://github.com/neurocline)
|
||||
* Update to Go 1.9.7 and Go 1.10.3 [23d5fc82](https://github.com/gohugoio/hugo/commit/23d5fc82ee01d56440d0991c899acd31e9b63e27) [@anthonyfok](https://github.com/anthonyfok)
|
||||
* Update Dockerfile to a multi-stage build [8531ec7c](https://github.com/gohugoio/hugo/commit/8531ec7ca36fd35a57fba06bbb06a65c94dfd3ed) [@skoblenick](https://github.com/skoblenick) [#4154](https://github.com/gohugoio/hugo/issues/4154)
|
||||
* Release 0.42.1 [d67e843c](https://github.com/gohugoio/hugo/commit/d67e843c1212e1f53933556b5f946c8541188d9a) [@bep](https://github.com/bep)
|
||||
* Do not fail server build when /static is missing [34ee27a7](https://github.com/gohugoio/hugo/commit/34ee27a78b9e2b5f475d44253ae234067b76cc6e) [@bep](https://github.com/bep) [#4846](https://github.com/gohugoio/hugo/issues/4846)
|
||||
|
||||
## Fixes
|
||||
|
||||
* Do not create paginator pages for the other output formats [43338c3a](https://github.com/gohugoio/hugo/commit/43338c3a99769eb7d0df0c12559b8b3d42b67dba) [@bep](https://github.com/bep) [#4890](https://github.com/gohugoio/hugo/issues/4890)
|
||||
* Fix the shortcodes/partials vs base template detection [a5d0a57e](https://github.com/gohugoio/hugo/commit/a5d0a57e6bdab583134a68c035aac9b3007f006a) [@bep](https://github.com/bep) [#4897](https://github.com/gohugoio/hugo/issues/4897)
|
||||
* nfpm replacements [e1a052ec](https://github.com/gohugoio/hugo/commit/e1a052ecb823c688406a8af97dfaaf52a75231da) [@caarlos0](https://github.com/caarlos0)
|
||||
* Fix typos [3cea2932](https://github.com/gohugoio/hugo/commit/3cea2932e17a08ebc19cd05f3079d9379bc8fba5) [@idealhack](https://github.com/idealhack)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
|
||||
---
|
||||
date: 2018-07-13
|
||||
title: "0.44"
|
||||
description: "0.44"
|
||||
categories: ["Releases"]
|
||||
---
|
||||
|
||||
|
||||
Hugo `0.44` is the follow-up release, or **The Sequel**, of the very well received `0.43` only days ago. That release added **Hugo Pipes**, with SCSS/SASS support, assets bundling and minification, ad-hoc image processing and much more.
|
||||
|
||||
This is mostly a bug-fix release, but it also includes several important improvements.
|
||||
|
||||
Many complained that their SVG images vanished when browsed from the `hugo server`. With **Hugo Pipes** MIME types suddenly got really important, but Hugo's use of `Suffix` was ambiguous. This became visible when we redefined the `image/svg+xml` to work with **Hugo Pipes**. We have now added a `Suffixes` field on the MIME type definition in Hugo, which is a list of one or more filename suffixes the MIME type is identified with. If you need to add a custom MIME type definition, this means that you also need to specify the full MIME type as the key, e.g. `image/svg+xml`.
|
||||
|
||||
Hugo now has:
|
||||
|
||||
* 27120+ [stars](https://github.com/gohugoio/hugo/stargazers)
|
||||
* 443+ [contributors](https://github.com/gohugoio/hugo/graphs/contributors)
|
||||
* 239+ [themes](http://themes.gohugo.io/)
|
||||
|
||||
## Notes
|
||||
* `MediaType.Suffix` is deprecated and replaced with a plural version, `MediaType.Suffixes`, with a more specific definition. You will get a detailed WARNING in the console if you need to do anything.
|
||||
|
||||
## Enhancements
|
||||
* Allow multiple file suffixes per media type [b874a1ba](https://github.com/gohugoio/hugo/commit/b874a1ba7ab8394dc741c8c70303a30a35b63e43) [@bep](https://github.com/bep) [#4920](https://github.com/gohugoio/hugo/issues/4920)
|
||||
* Clean up the in-memory Resource reader usage [47d38628](https://github.com/gohugoio/hugo/commit/47d38628ec0f4e72ff17661f13456b2a1511fe13) [@bep](https://github.com/bep) [#4936](https://github.com/gohugoio/hugo/issues/4936)
|
||||
* Move opening of the transformed resources after cache check [0024dcfe](https://github.com/gohugoio/hugo/commit/0024dcfe3e016c67046de06d1dac5e7f5235f9e1) [@bep](https://github.com/bep)
|
||||
* Improve type support in `resources.Concat` [306573de](https://github.com/gohugoio/hugo/commit/306573def0e20ec16ee5c447981cc09ed8bb7ec7) [@bep](https://github.com/bep) [#4934](https://github.com/gohugoio/hugo/issues/4934)
|
||||
* Flush `partialCached` cache on rebuilds [6b6dcb44](https://github.com/gohugoio/hugo/commit/6b6dcb44a014699c289bf32fe57d4c4216777be0) [@bep](https://github.com/bep) [#4931](https://github.com/gohugoio/hugo/issues/4931)
|
||||
* Include the transformation step in the error message [d96f2a46](https://github.com/gohugoio/hugo/commit/d96f2a460f58e91d8f6253a489d4879acfec6916) [@bep](https://github.com/bep) [#4924](https://github.com/gohugoio/hugo/issues/4924)
|
||||
* Exclude *.svg from CRLF/LF conversion [9c1e8208](https://github.com/gohugoio/hugo/commit/9c1e82085eb07d5b4dcdacbe82d5bafd26e08631) [@anthonyfok](https://github.com/anthonyfok)
|
||||
|
||||
## Fixes
|
||||
|
||||
* Fix `resources.Concat` for transformed resources [beec1fc9](https://github.com/gohugoio/hugo/commit/beec1fc98e5d37bba742d6bc2a0ff7c344b469f8) [@bep](https://github.com/bep) [#4936](https://github.com/gohugoio/hugo/issues/4936)
|
||||
* Fix static filesystem for themed multihost sites [80c8f3b8](https://github.com/gohugoio/hugo/commit/80c8f3b81a9849080e64bf877288ede28d960d3f) [@bep](https://github.com/bep) [#4929](https://github.com/gohugoio/hugo/issues/4929)
|
||||
* Set permission of embedded templates to 0644 [2b73e89d](https://github.com/gohugoio/hugo/commit/2b73e89d6d2822e86360a6c92c87f539677c119b) [@anthonyfok](https://github.com/anthonyfok)
|
||||
|
||||
|
After Width: | Height: | Size: 175 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 17 KiB |
@@ -0,0 +1,108 @@
|
||||
---
|
||||
date: 2018-07-04
|
||||
title: "Let’s celebrate Hugo’s 5th birthday"
|
||||
description: "How a side project became one of the most popular frameworks for building websites."
|
||||
categories: [blog]
|
||||
author: bep
|
||||
---
|
||||
|
||||
_By Bjørn Erik Pedersen ([@bepsays](https://twitter.com/bepsays) / [@bep](https://github.com/bep)), Hugo Lead_
|
||||
|
||||
**Five years ago today, [Steve Francia](https://github.com/spf13/) made his [first commit](https://github.com/gohugoio/hugo/commit/50a1d6f3f155ab837310e00ffb309a9199773c73
|
||||
) on the Hugo project: "Hugo: A Fast and Flexible Static Site Generator built with love by spf13 in GoLang".**
|
||||
|
||||
Steve was writing that on a train commute to New York. I'm writing this article running Hugo `v0.43-DEV`, the preview version of the next Hugo release. The release is scheduled for Monday and adds a powerful [assets pipeline](https://github.com/gohugoio/hugo/issues/4854#issue-333062459), with SCSS/SASS support, assets minification, fingerprinting/subresource integrity, ad-hoc image processing and much more.
|
||||
|
||||
**I cannot remember the last time I was this excited about a Hugo release. "Game changer" may be too strong, but it makes for a really nice integrated website design-workflow that, with Hugo's build speed, is hard to beat.**
|
||||
|
||||
{{< imgproc sunset Fill "600x300" >}}
|
||||
Fetch and scale an image in the upcoming Hugo 0.43.
|
||||
{{< /imgproc >}}
|
||||
|
||||
But that is a release for Monday. Now is a time to look at the current status of Hugo after the first five years.
|
||||
|
||||
## Hugo in Numbers
|
||||
|
||||
According to [BuiltWith](https://trends.builtwith.com/cms/Hugo), more than 29 000 live websites are built with Hugo. Of those, 390 are in the top 1 million. Wappalyzer [reports](https://www.wappalyzer.com/categories/static-site-generator) that Hugo serves almost 50% of the static sites.
|
||||
|
||||
Hugo is big in the [public sector](https://discourse.gohugo.io/t/hugo-in-public-administration/8792), with the US Government as a prominent user. Some examples are [vote.gov](https://vote.gov/) and [digital.gov](https://digital.gov/).
|
||||
|
||||
[Smashing Magazine](https://www.smashingmagazine.com/) is a big and very popular Hugo site. It is [reported](https://discourse.gohugo.io/t/smashing-magazine-s-redesign-powered-by-hugo-jamstack/5826/7) that they build their complex site with 7500 content pages in 13 seconds.
|
||||
|
||||
Some other example sites are [kubernetes.io](https://kubernetes.io/), [letsencrypt.org](https://gohugo.io/showcase/letsencrypt/), [support.1password.com](http://gohugo.io/showcase/1password-support/), [netlify.com](https://www.netlify.com), [litecoin.org](https://litecoin.org/), and [forestry.io](https://forestry.io/).
|
||||
|
||||
|
||||
{{< imgproc graph-stars Fit "600x400" >}}
|
||||
Number of GitHub stars in relation to the Hugo release dates.
|
||||
{{< /imgproc >}}
|
||||
|
||||
More numbers:
|
||||
|
||||
* 26800+ [stars](https://github.com/gohugoio/hugo/stargazers) on GitHub.
|
||||
* 444+ [contributors](https://github.com/gohugoio/hugo/graphs/contributors) to the Hugo source repository, 654+ to [Hugo Docs](https://github.com/gohugoio/hugoDocs/graphs/contributors). [@bep](https://github.com/bep) is the most active with around 70% of the current code base (line count).
|
||||
* 235+ [themes](https://themes.gohugo.io/)
|
||||
* 50% increase in the number of user sessions on the [gohugo.io](https://gohugo.io/) web sites the last 12 months.[^2]
|
||||
* Hugo build release binaries for [a myriad](https://github.com/gohugoio/hugo/releases/tag/v0.42.2) of platforms. And since it can also be installed from Chocolatey on Windows, Brew on MacOs, Snap on Linux and `apt-get` on Debian/Ubuntu, it is impossible to give accurate download numbers. But the number is not small.
|
||||
|
||||
## Hugo Next
|
||||
|
||||
We're not finished with Hugo, but Hugo `0.43` very nicely wraps up the first five years. It started out as a small and fast static site generator. It is now [even faster](https://forestry.io/blog/hugo-vs-jekyll-benchmark/), and now so loaded with features that it has grown out of being just a "static site generator". It is a _framework for building websites_.
|
||||
|
||||
My interest in Hugo started on the Sunday when I moved my blog, [bepsays.com](https://bepsays.com/en/), twice. The second static generator choice of that day, Hugo, was a good match. I remember Steve being very enthusiastic about getting patches with fixes and enhancements, and I was eventually taken over by the simplicity and power of Go, the programming language, and started to implement lots of new features.
|
||||
|
||||
My goal with all of this, if there is one, is to get a single binary with native and really fast implementations of the complete stack I need for web development and content editing. The single binary takes most of the pain out of installation and upgrades (if you stick with the same binary, it will continue to just work for decades).
|
||||
|
||||
**With 0.43, we are almost there.** With that release, it should be possible to set up a Hugo-only project without any additional tools (Gulp, WebPack) for all aspects of website building. There will still be situations where those tools will still be needed, of course, but we will continue to fill the gaps in the feature set.
|
||||
|
||||
Hugo has stuck with the sub-zero versions to signal active development, with a new main release every 5-6 weeks. But we take stability very seriously (breaking things add lots of support work, we don't like that) and most site upgrades are [smooth](https://twitter.com/tmmx/status/1006288444459503616). But we are closing in on the first major stable version.
|
||||
|
||||
|
||||
### The Road to 1.0
|
||||
|
||||
We have some more technical tasks that needs to be done (there is ongoing work to get the page quries into a more consistent state, also a simpler `.GetPage` method), but also some cool new functionality. The following roadmap is taken from memory, and may not be complete, but should be a good indication of what's ahead.
|
||||
|
||||
Pages from "other data sources"
|
||||
: Currently, in addition to Hugo's list pages, every URL must be backed by a content file (Markdown, HTML etc.). This covers most use cases, but we need a flexible way to generate pages from other data sources. Think product catalogues and similar.
|
||||
|
||||
Upgrade Blackfriday to v2
|
||||
: [Blackfriday](https://github.com/russross/blackfriday) is the main content renderer in Hugo. It has been rewritten to a more flexible architecture, which should allow us to fix some of the current shortcomings.
|
||||
|
||||
We should be able to create a better and easier-to-use data structure from the rendered content: Summary, the content after the summary, being able to range over the footnotes and the ToC. Having ToC as a proper data structure also open up a few other potential uses; using it as an index in [Related Content](https://gohugo.io/content-management/related/) would be one example.
|
||||
|
||||
This should also enable us to _do more_ with [Custom Output Formats](/templates/output-formats). It is already very powerful. GettyPubs are using it in [Quire](https://github.com/gettypubs/quire) to build [beautiful multi-platform publications](http://www.getty.edu/publications/digital/digitalpubs.html). But it can be improved. For rendering of content files, you are currently restricted to HTML. It would be great if we could configure alternative renderers per output format, such as LaTeX and EPUB.
|
||||
|
||||
Related to this is also to add a configurable "Markdown URL rewriter", which should make more portable URLs in Markdown, e.g. image links that work both when viewed on GitHub and your published site.
|
||||
|
||||
### The Road to the Future
|
||||
|
||||
These are the items that first comes to mind if you ask me to think even further ahead:
|
||||
|
||||
Dependency manager for Theme Components
|
||||
: In Hugo `0.42` we added [Theme Components](/themes/theme-components/) and Theme Inheritance. With SCSS support in Hugo `0.43`, which also follows the same project/themes precedence order (add `_variables.scss` to your project, configure SASS colour variables in `config.toml`), we have a solid foundation for creating easy to use and extensible themes. But we are missing some infrastructure around this. We have a site with 235+ [themes](https://themes.gohugo.io/)[^themes] listed, but you currently need to do some added work to get the theme up and running for your site. In the Go world, we don't have NPM to use, which is a curse and a blessing, but I have some ideas about building a simple dependency manager into Hugo, modelled after how Go is doing it (`hugo install`). You should be able to configure what theme and theme components you want to use, and Hugo should handle the installation of the correct versions. This should make it easier for the user, but it would also enable community driven and even commercial "theme stores".
|
||||
|
||||
|
||||
{{< imgproc graph-themes Fit "600x400" >}}
|
||||
Number of Hugo themes on themes.gohugo.io in relation to the Hugo release dates.
|
||||
{{< /imgproc >}}
|
||||
|
||||
|
||||
The "New York Times on Hugo" Use Case
|
||||
: There are recurring questions on the support forum from [really big sites](https://discourse.gohugo.io/t/transition-2m-posts-from-wordpress-to-hugo/12704) that want to move to Hugo. There are many [good reasons](https://www.netlify.com/blog/2016/05/18/9-reasons-your-site-should-be-static/) why they want this (security, cost-saving, EU regulations etc.). And while there have been reports about companies building 600 000 pages with Hugo on very powerful hardware, we will have to rethink the build model to make this usable. Keywords are: streaming builds, segmented builds, partial rebuilds. There are other site generators also talking about this. It should be possible, and my instinct tells me that it should be easier to do when your starting point is "really fast". But this is not a small weekend project for me, and I have already talked to several companies about sponsoring this.
|
||||
|
||||
Plugins
|
||||
: A Theme Component could also be called a plugin. But there are several potential plugin hooks into Hugo's build pipeline: Resource transformations, content rendering etc. We will eventually get there, but we should do it without giving up too much of the Hugo speed and simplicity.
|
||||
|
||||
|
||||
## Thanks
|
||||
|
||||
So, thanks to everyone who have contributed to getting Hugo where it is today. It is hard to single out individuals, but a big shout-out to all the Hugo experts and moderators helping out making the [discourse.gohugo.io](https://discourse.gohugo.io/) a very active and possibly one of the best support forums out there.
|
||||
|
||||
And the last shout-out goes to two maintainers who have been there more or less from the start. [@digitalcraftsman](https://github.com/digitalcraftsman/) has been doing a fantastic job keeping the fast growing theme site and [repository](https://github.com/gohugoio/hugoThemes) in pristine condition. I have it on my watch list, but that is just out of curiosity. There are lots of activity, but it runs as clock work. [Anthony Fok](https://github.com/anthonyfok) has contributed with a variety of things but is most notable as the Linux expert on the team. He manages the Debian build and is the one to thank for up-to-date binaries on Debian and Ubuntu.
|
||||
|
||||
One final note: If you have not done so already, please visit [github.com/gohugoio/hugo](https://github.com/gohugoio/hugo) and push the "star button".
|
||||
|
||||
Gopher artwork by [Ashley McNamara](https://github.com/ashleymcnamara/gophers/) (licensed under [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/)). Inspired by [Renee French](https://reneefrench.blogspot.com/).
|
||||
|
||||
[^2]: Numbers from Google Analytics. The Hugo websites are https://discourse.gohugo.io/, https://gohugo.io/ and https://themes.gohugo.io/. It is rumoured that when [Matt Biilman](https://twitter.com/biilmann?lang=en), CEO and Co-founder of Netlify, opened the first power bill after sponsoring Hugo's hosting, said: "Du må lave fis med mig, those Hugo sites have lots of web traffic!"
|
||||
[^sgen]: That was at the time of writing this article. _Next_, a React based static site generator, has momentum and is closing in on Hugo's 2nd place.
|
||||
[^themes]: We pull all the themes from GitHub and build the theme site and 235 demo sites on Netlify in 4 minutes. And that is impressing.
|
||||
|
After Width: | Height: | Size: 378 KiB |
@@ -43,6 +43,16 @@
|
||||
Blackfriday flag: **`HTML_HREF_TARGET_BLANK`** <br>
|
||||
Purpose: `true` opens <s>external links</s> **absolute** links in a new window or tab. While the `target="_blank"` attribute is typically used for external links, Blackfriday does that for _all_ absolute links ([ref](https://discourse.gohugo.io/t/internal-links-in-same-tab-external-links-in-new-tab/11048/8)). One needs to make note of this if they use absolute links throughout, for internal links too (for example, by setting `canonifyURLs` to `true` or via `absURL`).
|
||||
|
||||
`nofollowLinks`
|
||||
: default: **`false`** <br>
|
||||
Blackfriday flag: **`HTML_NOFOLLOW_LINKS`** <br>
|
||||
Purpose: `true` creates <s>external links</s> **absolute** links with `nofollow` being added to their `rel` attribute. Thereby crawlers are advised to not follow the link. While the `rel="nofollow"` attribute is typically used for external links, Blackfriday does that for _all_ absolute links. One needs to make note of this if they use absolute links throughout, for internal links too (for example, by setting `canonifyURLs` to `true` or via `absURL`).
|
||||
|
||||
`noreferrerLinks`
|
||||
: default: **`false`** <br>
|
||||
Blackfriday flag: **`HTML_NOREFERRER_LINKS`** <br>
|
||||
Purpose: `true` creates <s>external links</s> **absolute** links with `noreferrer` being added to their `rel` attribute. Thus when following the link no referrer information will be leaked. While the `rel="noreferrer"` attribute is typically used for external links, Blackfriday does that for _all_ absolute links. One needs to make note of this if they use absolute links throughout, for internal links too (for example, by setting `canonifyURLs` to `true` or via `absURL`).
|
||||
|
||||
`plainIDAnchors`
|
||||
: default **`true`** <br>
|
||||
Blackfriday flag: **`FootnoteAnchorPrefix` and `HeaderIDSuffix`** <br>
|
||||
|
||||
@@ -29,7 +29,7 @@ Go templates provide an extremely simple template language that adheres to the b
|
||||
|
||||
## Basic Syntax
|
||||
|
||||
Golang templates are HTML files with the addition of [variables][variables] and [functions][functions]. Golang template variables and functions are accessible within `{{ }}`.
|
||||
Go templates are HTML files with the addition of [variables][variables] and [functions][functions]. Go template variables and functions are accessible within `{{ }}`.
|
||||
|
||||
### Access a Predefined Variable
|
||||
|
||||
@@ -104,7 +104,7 @@ Go templates only ship with a few basic functions but also provide a mechanism f
|
||||
Note that both examples make use of Go template's [math functions][].
|
||||
|
||||
{{% note "Additional Boolean Operators" %}}
|
||||
There are more boolean operators than those listed in the Hugo docs in the [Golang template documentation](http://golang.org/pkg/text/template/#hdr-Functions).
|
||||
There are more boolean operators than those listed in the Hugo docs in the [Go template documentation](http://golang.org/pkg/text/template/#hdr-Functions).
|
||||
{{% /note %}}
|
||||
|
||||
## Includes
|
||||
@@ -526,8 +526,8 @@ Go allows you to do more than what's shown here. Using Hugo's [`where` function]
|
||||
[first]: /functions/first/
|
||||
[front matter]: /content-management/front-matter/
|
||||
[functions]: /functions/ "See the full list of Hugo's templating functions with a quick start reference guide and basic and advanced examples."
|
||||
[Go html/template]: http://golang.org/pkg/html/template/ "Godocs references for Golang's html templating"
|
||||
[gohtmltemplate]: http://golang.org/pkg/html/template/ "Godocs references for Golang's html templating"
|
||||
[Go html/template]: http://golang.org/pkg/html/template/ "Godocs references for Go's html templating"
|
||||
[gohtmltemplate]: http://golang.org/pkg/html/template/ "Godocs references for Go's html templating"
|
||||
[index]: /functions/index/
|
||||
[math functions]: /functions/math/
|
||||
[partials]: /templates/partials/ "Link to the partial templates page inside of the templating section of the Hugo docs"
|
||||
|
||||
@@ -77,12 +77,12 @@ Using the above example, let's assume you have the following in `content/post/_i
|
||||
|
||||
{{< code file="content/post/_index.md" >}}
|
||||
---
|
||||
title: My Golang Journey
|
||||
title: My Go Journey
|
||||
date: 2017-03-23
|
||||
publishdate: 2017-03-24
|
||||
---
|
||||
|
||||
I decided to start learning Golang in March 2017.
|
||||
I decided to start learning Go in March 2017.
|
||||
|
||||
Follow my journey through this new blog.
|
||||
{{< /code >}}
|
||||
@@ -118,9 +118,9 @@ This above will output the following HTML:
|
||||
<main>
|
||||
<article>
|
||||
<header>
|
||||
<h1>My Golang Journey</h1>
|
||||
<h1>My Go Journey</h1>
|
||||
</header>
|
||||
<p>I decided to start learning Golang in March 2017.</p>
|
||||
<p>I decided to start learning Go in March 2017.</p>
|
||||
<p>Follow my journey through this new blog.</p>
|
||||
</article>
|
||||
<ul>
|
||||
@@ -457,7 +457,7 @@ In the above example, you may want `{{.Title}}` to point the `title` field you h
|
||||
|
||||
### By Page Parameter in Date Format
|
||||
|
||||
The following template takes grouping by `date` a step further and uses Golang's layout string. See the [`Format` function][] for more examples of how to use Golang's layout string to format dates in Hugo.
|
||||
The following template takes grouping by `date` a step further and uses Go's layout string. See the [`Format` function][] for more examples of how to use Go's layout string to format dates in Hugo.
|
||||
|
||||
{{< code file="layouts/partials/by-page-param-as-date.html" >}}
|
||||
<!-- Groups content by month according to the "param_key" field in front matter -->
|
||||
|
||||
@@ -5,7 +5,7 @@ description: Hugo searches for the layout to use for a given page in a well defi
|
||||
godocref:
|
||||
date: 2017-02-01
|
||||
publishdate: 2017-02-01
|
||||
lastmod: 2017-05-25
|
||||
lastmod: 2017-07-05
|
||||
categories: [templates,fundamentals]
|
||||
keywords: [templates]
|
||||
menu:
|
||||
@@ -32,7 +32,7 @@ Output Format
|
||||
: See [Custom Output Formats](/templates/output-formats). An output format has both a `name` (e.g. `rss`, `amp`, `html`) and a `suffix` (e.g. `xml`, `html`). We prefer matches with both (e.g. `index.amp.html`, but look for less specific templates.
|
||||
|
||||
Language
|
||||
: We will consider a language code in the template name. If the site language is `fr`, `index.fr.amp.html` will win over `index.amp.html`, but we will `index.amp.html` will be chosen before `index.fr.html`.
|
||||
: We will consider a language code in the template name. If the site language is `fr`, `index.fr.amp.html` will win over `index.amp.html`, but `index.amp.html` will be chosen before `index.fr.html`.
|
||||
|
||||
Layout
|
||||
: Can be set in page front matter.
|
||||
@@ -58,14 +58,7 @@ Section
|
||||
|
||||
## Hugo Layouts Lookup Rules With Theme
|
||||
|
||||
In Hugo, layouts can live in either the project's or theme's layout folder, and the most specific layout will be chosen. Hugo will interleave the lookups:
|
||||
|
||||
|
||||
1. layouts/page/index.html
|
||||
2. demoTheme/layouts/page/index.html
|
||||
3. layouts/...
|
||||
|
||||
This way it is possible to override specific templates from the theme.
|
||||
In Hugo, layouts can live in either the project's or the themes' layout folders, and the most specific layout will be chosen. Hugo will interleave the lookups listed below, finding the most specific one either in the project or themes.
|
||||
|
||||
## Examples: Layout Lookup for Regular Pages
|
||||
|
||||
|
||||
@@ -29,59 +29,44 @@ Hugo can initialize a new blank theme directory within your existing `themes` us
|
||||
hugo new theme [name]
|
||||
```
|
||||
|
||||
## Theme Components
|
||||
## Theme Folders
|
||||
|
||||
A theme consists of templates and static assets such as javascript and css files. Themes can also provide [archetypes][], which are archetypal content types used by the `hugo new` command to scaffold new content files with preconfigured front matter.
|
||||
A theme component can provide files in one or more of the following standard Hugo folders:
|
||||
|
||||
layouts
|
||||
: Templates used to render content in Hugo. Also see [Templates Lookup Order](/templates/lookup-order/).
|
||||
|
||||
static
|
||||
: Static files, such as logos, CSS and JavaScript.
|
||||
|
||||
i18n
|
||||
: Language bundles.
|
||||
|
||||
data
|
||||
: Data files.
|
||||
|
||||
archetypes
|
||||
: Content templates used in `hugo new`.
|
||||
|
||||
|
||||
## Theme Configuration File
|
||||
|
||||
A theme component can also provide its own [Configuration File](/getting-started/configuration/), e.g. `config.toml`. There are some restrictions to what can be configured in a theme component, and it is not possible to overwrite settings in the project.
|
||||
|
||||
The following settings can be set:
|
||||
|
||||
* `params` (global and per language)
|
||||
* `menu` (global and per language)
|
||||
* `outputformats` and `mediatypes`
|
||||
|
||||
|
||||
## Theme Description File
|
||||
|
||||
In addition to the configuration file, a theme can also provide a `theme.toml` file that describes the theme, the author and origin etc. See [Add Your Hugo Theme to the Showcase](/contribute/themes/).
|
||||
|
||||
|
||||
{{% note "Use the Hugo Generator Tag" %}}
|
||||
The [`.Hugo.Generator`](/variables/hugo/) tag is included in all themes featured in the [Hugo Themes Showcase](http://themes.gohugo.io). We ask that you include the generator tag in all sites and themes you create with Hugo to help the core team track Hugo's usage and popularity.
|
||||
{{% /note %}}
|
||||
|
||||
## Layouts
|
||||
|
||||
Hugo is built around the concept that things should be as simple as possible.
|
||||
Fundamentally, website content is displayed in two different ways, a single
|
||||
piece of content and a list of content items. With Hugo, a theme layout starts
|
||||
with the defaults. As additional layouts are defined, they are used for the
|
||||
content type or section they apply to. This keeps layouts simple, but permits
|
||||
a large amount of flexibility.
|
||||
|
||||
## Single Content
|
||||
|
||||
The default single file layout is located at `layouts/_default/single.html`.
|
||||
|
||||
## List of Contents
|
||||
|
||||
The default list file layout is located at `layouts/_default/list.html`.
|
||||
|
||||
## Partial Templates
|
||||
|
||||
Theme creators should liberally use [partial templates](/templates/partials/)
|
||||
throughout their theme files. Not only is a good DRY practice to include shared
|
||||
code, but partials are a special template type that enables the themes end user
|
||||
to be able to overwrite just a small piece of a file or inject code into the
|
||||
theme from their local /layouts. These partial templates are perfect for easy
|
||||
injection into the theme with minimal maintenance to ensure future
|
||||
compatibility.
|
||||
|
||||
## Static
|
||||
|
||||
Everything in the static directory will be copied directly into the final site
|
||||
when rendered. No structure is provided here to enable complete freedom. It is
|
||||
common to organize the static content into:
|
||||
|
||||
```
|
||||
/css
|
||||
/js
|
||||
/img
|
||||
```
|
||||
|
||||
The actual structure is entirely up to you, the theme creator, on how you would like to organize your files.
|
||||
|
||||
## Archetypes
|
||||
|
||||
If your theme makes use of specific keys in the front matter, it is a good idea
|
||||
to provide an archetype for each content type you have. [Read more about archetypes][archetypes].
|
||||
|
||||
[archetypes]: /content-management/archetypes/
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
---
|
||||
title: Customize a Theme
|
||||
linktitle: Customize a Theme
|
||||
description: Customize a theme by overriding theme layouts and static assets in your top-level project directories.
|
||||
date: 2017-02-01
|
||||
publishdate: 2017-02-01
|
||||
lastmod: 2017-02-01
|
||||
categories: [themes]
|
||||
keywords: [themes, source, organization, directories]
|
||||
menu:
|
||||
docs:
|
||||
parent: "themes"
|
||||
weight: 20
|
||||
weight: 20
|
||||
sections_weight: 20
|
||||
draft: false
|
||||
aliases: [/themes/customize/]
|
||||
toc: true
|
||||
wip: true
|
||||
---
|
||||
|
||||
The following are key concepts for Hugo site customization with themes. Hugo permits you to supplement *or* override any theme template or static file with files in your working directory.
|
||||
|
||||
{{% note %}}
|
||||
When you use a theme cloned from its git repository, do not edit the theme's files directly. Instead, theme customization in Hugo is a matter of *overriding* the templates made available to you in a theme. This provides the added flexibility of tweaking a theme to meet your needs while staying current with a theme's upstream.
|
||||
{{% /note %}}
|
||||
|
||||
## Override Static Files
|
||||
|
||||
There are times where you want to include static assets that differ from versions of the same asset that ships with a theme.
|
||||
|
||||
For example, a theme may use jQuery 1.8 in the following location:
|
||||
|
||||
```
|
||||
/themes/<THEME>/static/js/jquery.min.js
|
||||
```
|
||||
|
||||
You want to replace the version of jQuery that ships with the theme with the newer `jquery-3.1.1.js`. The easiest way to do this is to replace the file *with a file of the same name* in the same relative path in your project's root. Therefore, change `jquery-3.1.1.js` to `jquery.min.js` so that it is *identical* to the theme's version and place the file here:
|
||||
|
||||
```
|
||||
/static/js/jquery.min.js
|
||||
```
|
||||
|
||||
## Override Template Files
|
||||
|
||||
Anytime Hugo looks for a matching template, it will first check the working directory before looking in the theme directory. If you would like to modify a template, simply create that template in your local `layouts` directory.
|
||||
|
||||
The [template lookup order][lookup] explains the rules Hugo uses to determine which template to use for a given piece of content. Read and understand these rules carefully.
|
||||
|
||||
This is especially helpful when the theme creator used [partial templates][partials]. These partial templates are perfect for easy injection into the theme with minimal maintenance to ensure future compatibility.
|
||||
|
||||
For example:
|
||||
|
||||
```
|
||||
/themes/<THEME>/layouts/_default/single.html
|
||||
```
|
||||
|
||||
Would be overwritten by
|
||||
|
||||
```
|
||||
/layouts/_default/single.html
|
||||
```
|
||||
|
||||
{{% warning %}}
|
||||
This only works for templates that Hugo "knows about" (i.e., that follow its convention for folder structure and naming). If a theme imports template files in a creatively named directory, Hugo won’t know to look for the local `/layouts` first.
|
||||
{{% /warning %}}
|
||||
|
||||
## Override Archetypes
|
||||
|
||||
If the archetype that ships with the theme for a given content type (or all content types) doesn’t fit with how you are using the theme, feel free to copy it to your `/archetypes` directory and make modifications as you see fit.
|
||||
|
||||
{{% warning "Beware of `layouts/_default`" %}}
|
||||
The `_default` directory is a very powerful force in Hugo, especially as it pertains to overwriting theme files. If a default file is located in the local [archetypes](/content-management/archetypes/) or layout directory (i.e., `archetypes/default.md` or `/layouts/_default/*.html`, respectively), it will override the file of the same name in the corresponding theme directory (i.e., `themes/<THEME>/archetypes/default.md` or `themes/<THEME>/layout/_defaults/*.html`, respectively).
|
||||
|
||||
It is usually better to override specific files; i.e. rather than using `layouts/_default/*.html` in your working directory.
|
||||
{{% /warning %}}
|
||||
|
||||
[archetypes]: /content-management/archetypes/
|
||||
[lookup]: /templates/lookup-order/
|
||||
[partials]: /templates/partials/
|
||||
@@ -0,0 +1,51 @@
|
||||
---
|
||||
title: Theme Components
|
||||
linktitle: Theme Components
|
||||
description: Hugo provides advanced theming support with Theme Components.
|
||||
date: 2017-02-01
|
||||
categories: [themes]
|
||||
keywords: [themes, theme, source, organization, directories]
|
||||
menu:
|
||||
docs:
|
||||
parent: "themes"
|
||||
weight: 20
|
||||
weight: 20
|
||||
sections_weight: 20
|
||||
draft: false
|
||||
aliases: [/themes/customize/,/themes/customizing/]
|
||||
toc: true
|
||||
---
|
||||
|
||||
Since Hugo `0.42` a project can configure a theme as a composite of as many theme components you need:
|
||||
|
||||
{{< code-toggle file="config">}}
|
||||
theme = ["my-shortcodes", "base-theme", "hyde"]
|
||||
{{< /code-toggle >}}
|
||||
|
||||
|
||||
You can even nest this, and have the theme component itself include theme components in its own `config.toml` (theme inheritance).[^1]
|
||||
|
||||
The theme definition example above in `config.toml` creates a theme with 3 theme components with precedence from left to right.
|
||||
|
||||
For any given file, data entry, etc., Hugo will look first in the project and then in `my-shortcode`, `base-theme`, and lastly `hyde`.
|
||||
|
||||
Hugo uses two different algorithms to merge the filesystems, depending on the file type:
|
||||
|
||||
* For `i18n` and `data` files, Hugo merges deeply using the translation id and data key inside the files.
|
||||
* For `static`, `layouts` (templates), and `archetypes` files, these are merged on file level. So the left-most file will be chosen.
|
||||
|
||||
The name used in the `theme` definition above must match a folder in `/your-site/themes`, e.g. `/your-site/themes/my-shortcodes`. There are plans to improve on this and get a URL scheme so this can be resolved automatically.
|
||||
|
||||
Also note that a component that is part of a theme can have its own configuration file, e.g. `config.toml`. There are currently some restrictions to what a theme component can configure:
|
||||
|
||||
* `params` (global and per language)
|
||||
* `menu` (global and per language)
|
||||
* `outputformats` and `mediatypes`
|
||||
|
||||
The same rules apply here: The left-most param/menu etc. with the same ID will win. There are some hidden and experimental namespace support in the above, which we will work to improve in the future, but theme authors are encouraged to create their own namespaces to avoid naming conflicts.
|
||||
|
||||
|
||||
[^1]: Including theme components in the themes is currently not supported for themes hosted on [The Hugo Themes Site](https://themes.gohugo.io/), but can be really useful if you want to create your own theme based on a theme you find on that site.
|
||||
|
||||
|
||||
|
||||
@@ -20,6 +20,9 @@ toc: false
|
||||
|
||||
[Shortcodes][shortcodes] have access to parameters delimited in the shortcode declaration via [`.Get`][getfunction], page- and site-level variables, and also the following shortcode-specific fields:
|
||||
|
||||
.Ordinal
|
||||
: Zero-based ordinal in relation to its parent. If the parent is the page itself, this ordinal will represent the position of this shortcode in the page content.
|
||||
|
||||
.Parent
|
||||
: provides access to the parent shortcode context in nested shortcodes. This can be very useful for inheritance of common shortcode parameters from the root.
|
||||
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
|
||||
---
|
||||
date: 2018-04-23
|
||||
title: "0.40"
|
||||
description: "0.40"
|
||||
categories: ["Releases"]
|
||||
---
|
||||
|
||||
Hugo `0.40` is **The Revival of the Shortcodes**. Shortcodes is one of the prime features in Hugo. Really useful, but it has had some known shortcomings. [@bep](https://github.com/bep) has been really busy the last week to address those.
|
||||
|
||||
In summary:
|
||||
|
||||
* `.Content` for a page retrieved in a query in a shortcode is now _almost_ always available. Note that shortcodes can include content that can include shortcodes that can include content... It is possible to bite your tail. See more below.
|
||||
* Shortcodes are now processed and rendered in their order of appearance.
|
||||
* Related to the above, we have now added a zero-based `.Ordinal` to the shortcode.
|
||||
|
||||
|
||||
The first bullet above resolves some surprising behaviour when reading other pages' content from shortcodes. Before this release, that behaviour was undefined. Note that this has never been an issue from regular templates.
|
||||
|
||||
It will still not be possible to get **the current shortcode's page's rendered content**. That would have impressed Einstein.
|
||||
|
||||
The new and well defined rules are:
|
||||
|
||||
* `.Page.Content` from a shortcode will be empty. The related `.Page.Truncated` `.Page.Summary`, `.Page.WordCount`, `.Page.ReadingTime`, `.Page.Plain` and `.Page.PlainWords` will also have empty values.
|
||||
* For _other pages_ (retrieved via `.Page.Site.GetPage`, `.Site.Pages` etc.) the `.Content` is there to use as you please as long as you don't have infinite content recursion in your shortcode/content setup. See below.
|
||||
* `.Page.TableOfContents` is good to go (but does not support shortcodes in headlines; this is unchanged)
|
||||
|
||||
If you get into a situation of infinite recursion, the `.Content` will be empty. Run `hugo -v` for more information.
|
||||
|
||||
This release represents **19 contributions by 3 contributors** to the main Hugo code base.
|
||||
|
||||
Many have also been busy writing and fixing the documentation in [hugoDocs](https://github.com/gohugoio/hugoDocs),
|
||||
which has received **13 contributions by 6 contributors**. A special thanks to [@kaushalmodi](https://github.com/kaushalmodi), [@anthonyfok](https://github.com/anthonyfok), [@bep](https://github.com/bep), and [@regisphilibert](https://github.com/regisphilibert) for their work on the documentation site.
|
||||
|
||||
|
||||
Hugo now has:
|
||||
|
||||
* 25071+ [stars](https://github.com/gohugoio/hugo/stargazers)
|
||||
* 446+ [contributors](https://github.com/gohugoio/hugo/graphs/contributors)
|
||||
* 222+ [themes](http://themes.gohugo.io/)
|
||||
|
||||
## Notes
|
||||
|
||||
* We have added a `timeout` configuration setting. This is currently only used to time out the `.Content` creation, to bail out of recursive recursions. Run `hugo -v` to see potential warnings about this. The `timeout` is set default to `10000` (10 seconds).
|
||||
|
||||
## Enhancements
|
||||
|
||||
### Templates
|
||||
|
||||
* Add `path.Ext`, `path.Dir` and `path.Base` [47e7788b](https://github.com/gohugoio/hugo/commit/47e7788b3c30de6fb895522096baf2c13598c317) [@bep](https://github.com/bep)
|
||||
* Make `fileExist` use the same filesystem as `readFile` [51af1d2e](https://github.com/gohugoio/hugo/commit/51af1d2eadcad89e8c2906c05549352ef69ab016) [@bep](https://github.com/bep) [#4633](https://github.com/gohugoio/hugo/issues/4633)
|
||||
|
||||
### Other
|
||||
|
||||
* Add `.Page.BundleType` [402f6788](https://github.com/gohugoio/hugo/commit/402f6788ee955ad2aace84e8fba1625db7b356d9) [@bep](https://github.com/bep) [#4662](https://github.com/gohugoio/hugo/issues/4662)
|
||||
* Add zero-based `Ordinal` to shortcode [3decf4a3](https://github.com/gohugoio/hugo/commit/3decf4a327157e98d3da3502b6d777de63437c39) [@bep](https://github.com/bep) [#3359](https://github.com/gohugoio/hugo/issues/3359)
|
||||
* Process and render shortcodes in their order of appearance [85535084](https://github.com/gohugoio/hugo/commit/85535084dea4d3e3adf1ebd08ae57b39d76e1904) [@bep](https://github.com/bep) [#3359](https://github.com/gohugoio/hugo/issues/3359)
|
||||
* Init the content and shortcodes early [19084eaf](https://github.com/gohugoio/hugo/commit/19084eaf74246feac61d618c55031369520dfa8e) [@bep](https://github.com/bep) [#4632](https://github.com/gohugoio/hugo/issues/4632)
|
||||
* Prepare child page resources before the page itself [3238e14f](https://github.com/gohugoio/hugo/commit/3238e14fdfeedf189a5af122e20bff040ac059bd) [@bep](https://github.com/bep) [#4632](https://github.com/gohugoio/hugo/issues/4632)
|
||||
* Make .Content (almost) always available in shortcodes [4d26ab33](https://github.com/gohugoio/hugo/commit/4d26ab33dcef704086f43828d1dfb4b8beae2593) [@bep](https://github.com/bep) [#4632](https://github.com/gohugoio/hugo/issues/4632)[#4653](https://github.com/gohugoio/hugo/issues/4653)[#4655](https://github.com/gohugoio/hugo/issues/4655)
|
||||
* Add language merge support for Pages in resource.Resources [47c05c47](https://github.com/gohugoio/hugo/commit/47c05c47e0b663632a649ee5d256acc1a32fe9e4) [@bep](https://github.com/bep) [#4644](https://github.com/gohugoio/hugo/issues/4644)
|
||||
* Improve .Content vs shortcodes [e590cc26](https://github.com/gohugoio/hugo/commit/e590cc26eb1363a4b84603f051b20bd43fd1f7bd) [@bep](https://github.com/bep) [#4632](https://github.com/gohugoio/hugo/issues/4632)
|
||||
* Improve .Get docs [74520d2c](https://github.com/gohugoio/hugo/commit/74520d2cfd39bb4428182e26c57afa9df83ce7b5) [@paulcmal](https://github.com/paulcmal)
|
||||
* Update missing positional parameter test for .Get [e2b277bb](https://github.com/gohugoio/hugo/commit/e2b277bba5935c0686cb83f132eae021ef2dc5e1) [@paulcmal](https://github.com/paulcmal)
|
||||
* Improve error message in metadata parse [d681ea55](https://github.com/gohugoio/hugo/commit/d681ea55a0a59b7096dacd194ee0cb8fe15b0757) [@bep](https://github.com/bep) [#3696](https://github.com/gohugoio/hugo/issues/3696)
|
||||
* Add some context to front matter parse error [159bed34](https://github.com/gohugoio/hugo/commit/159bed34c3a850d58d08a36ddc40372ed96af2db) [@bep](https://github.com/bep) [#4638](https://github.com/gohugoio/hugo/issues/4638)
|
||||
* Updated GetCSV error message (#4636) [5cc944ff](https://github.com/gohugoio/hugo/commit/5cc944ffd77289ab0b8efd69d628fb11d1280993) [@CubeLuke](https://github.com/CubeLuke)
|
||||
* .Get doesn't crash on missing positional param fixes #4619 [236f0c84](https://github.com/gohugoio/hugo/commit/236f0c840b45e0c41fcbb2fb6ee556c0fb2d4859) [@paulcmal](https://github.com/paulcmal)
|
||||
* fix syntax signature [cd6a2612](https://github.com/gohugoio/hugo/commit/cd6a261242b63555ac2c3ca7a8462b874b490701) [@paulcmal](https://github.com/paulcmal)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
|
||||
---
|
||||
date: 2018-04-25
|
||||
title: "0.40.1"
|
||||
description: "0.40.1"
|
||||
categories: ["Releases"]
|
||||
images:
|
||||
- images/blog/hugo-bug-poster.png
|
||||
|
||||
---
|
||||
|
||||
|
||||
|
||||
This release fixes some shortcode vs `.Content` corner cases introduced in Hugo `0.40` [288c3964](https://github.com/gohugoio/hugo/commit/288c39643906b4194a0a6acfbaf87cb0fbdeb361) [@bep](https://github.com/bep) [#4632](https://github.com/gohugoio/hugo/issues/4632)[#4664](https://github.com/gohugoio/hugo/issues/4664).
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
|
||||
---
|
||||
date: 2018-04-30
|
||||
title: "0.40.2"
|
||||
description: "0.40.2"
|
||||
categories: ["Releases"]
|
||||
images:
|
||||
- images/blog/hugo-bug-poster.png
|
||||
|
||||
---
|
||||
|
||||
|
||||
|
||||
This release fixes some regressions introduced in Hugo `0.40`. See the [milestone](https://github.com/gohugoio/hugo/milestone/62?closed=1) for an issue list.
|
||||
|
||||
* Reset .Page.Scratch on live-reload [655983a2](https://github.com/gohugoio/hugo/commit/655983a22dc35b2ee5119dcc4acb9918498d2d68) [@bep](https://github.com/bep) [#4683](https://github.com/gohugoio/hugo/issues/4683)
|
||||
* Fix .WordCount, .FuzzyWordCount, .ReadingTime when summary marker is set [001a28c2](https://github.com/gohugoio/hugo/commit/001a28c2f9ed121b33df18fe792859ab378784c6) [@bep](https://github.com/bep) [#4675](https://github.com/gohugoio/hugo/issues/4675)[#4682](https://github.com/gohugoio/hugo/issues/4682)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
|
||||
---
|
||||
date: 2018-05-09
|
||||
title: "0.40.3"
|
||||
description: "0.40.3"
|
||||
categories: ["Releases"]
|
||||
images:
|
||||
- images/blog/hugo-bug-poster.png
|
||||
|
||||
---
|
||||
|
||||
Hugo `0.40.3` fixes a possible `.Content` truncation issue introduced in `0.40.1` [90d0d830](https://github.com/gohugoio/hugo/commit/90d0d83097a20a3f521ffc1f5a54a2fbfaf14ce2) [@bep](https://github.com/bep) [#4706](https://github.com/gohugoio/hugo/issues/4706). This should be very rare. It has been reported by only one user on a synthetic site. We have tested a number of big sites that does not show this problem with `0.40.2`, but this is serious enough to warrant a patch release.
|
||||
@@ -107,7 +107,7 @@
|
||||
date = "2016-10-22"
|
||||
|
||||
[[article]]
|
||||
title = "通过 Gitlab-cl 将 Hugo blog 自动部署至 GitHub <small>(Chinese, Continious integration)</small>"
|
||||
title = "通过 Gitlab-cl 将 Hugo blog 自动部署至 GitHub <small>(Chinese, Continuous integration)</small>"
|
||||
url = "https://zetaoyang.github.io/post/2016/10/17/gitlab-cl.html"
|
||||
author = "Zetao Yang"
|
||||
date = "2016-10-17"
|
||||
|
||||
@@ -1187,6 +1187,15 @@
|
||||
"mkd"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "plaintext",
|
||||
"Aliases": [
|
||||
"no-highlight",
|
||||
"plain",
|
||||
"text",
|
||||
"txt"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "reStructuredText",
|
||||
"Aliases": [
|
||||
@@ -1507,22 +1516,6 @@
|
||||
"layouts/_default/single.html"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Example": "Single page in \"posts\" section with theme",
|
||||
"Kind": "page",
|
||||
"OutputFormat": "HTML",
|
||||
"Suffix": "html",
|
||||
"Template Lookup Order": [
|
||||
"layouts/posts/single.html.html",
|
||||
"demoTheme/layouts/posts/single.html.html",
|
||||
"layouts/posts/single.html",
|
||||
"demoTheme/layouts/posts/single.html",
|
||||
"layouts/_default/single.html.html",
|
||||
"demoTheme/layouts/_default/single.html.html",
|
||||
"layouts/_default/single.html",
|
||||
"demoTheme/layouts/_default/single.html"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Example": "AMP single page",
|
||||
"Kind": "page",
|
||||
@@ -1621,38 +1614,6 @@
|
||||
"layouts/_default/list.html"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Example": "Home page with theme",
|
||||
"Kind": "home",
|
||||
"OutputFormat": "HTML",
|
||||
"Suffix": "html",
|
||||
"Template Lookup Order": [
|
||||
"layouts/index.html.html",
|
||||
"demoTheme/layouts/index.html.html",
|
||||
"layouts/home.html.html",
|
||||
"demoTheme/layouts/home.html.html",
|
||||
"layouts/list.html.html",
|
||||
"demoTheme/layouts/list.html.html",
|
||||
"layouts/index.html",
|
||||
"demoTheme/layouts/index.html",
|
||||
"layouts/home.html",
|
||||
"demoTheme/layouts/home.html",
|
||||
"layouts/list.html",
|
||||
"demoTheme/layouts/list.html",
|
||||
"layouts/_default/index.html.html",
|
||||
"demoTheme/layouts/_default/index.html.html",
|
||||
"layouts/_default/home.html.html",
|
||||
"demoTheme/layouts/_default/home.html.html",
|
||||
"layouts/_default/list.html.html",
|
||||
"demoTheme/layouts/_default/list.html.html",
|
||||
"layouts/_default/index.html",
|
||||
"demoTheme/layouts/_default/index.html",
|
||||
"layouts/_default/home.html",
|
||||
"demoTheme/layouts/_default/home.html",
|
||||
"layouts/_default/list.html",
|
||||
"demoTheme/layouts/_default/list.html"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Example": "AMP home, French language\"",
|
||||
"Kind": "home",
|
||||
@@ -1706,39 +1667,25 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"Example": "RSS home with theme",
|
||||
"Example": "RSS home",
|
||||
"Kind": "home",
|
||||
"OutputFormat": "RSS",
|
||||
"Suffix": "xml",
|
||||
"Template Lookup Order": [
|
||||
"layouts/index.rss.xml",
|
||||
"demoTheme/layouts/index.rss.xml",
|
||||
"layouts/home.rss.xml",
|
||||
"demoTheme/layouts/home.rss.xml",
|
||||
"layouts/rss.xml",
|
||||
"demoTheme/layouts/rss.xml",
|
||||
"layouts/list.rss.xml",
|
||||
"demoTheme/layouts/list.rss.xml",
|
||||
"layouts/index.xml",
|
||||
"demoTheme/layouts/index.xml",
|
||||
"layouts/home.xml",
|
||||
"demoTheme/layouts/home.xml",
|
||||
"layouts/list.xml",
|
||||
"demoTheme/layouts/list.xml",
|
||||
"layouts/_default/index.rss.xml",
|
||||
"demoTheme/layouts/_default/index.rss.xml",
|
||||
"layouts/_default/home.rss.xml",
|
||||
"demoTheme/layouts/_default/home.rss.xml",
|
||||
"layouts/_default/rss.xml",
|
||||
"demoTheme/layouts/_default/rss.xml",
|
||||
"layouts/_default/list.rss.xml",
|
||||
"demoTheme/layouts/_default/list.rss.xml",
|
||||
"layouts/_default/index.xml",
|
||||
"demoTheme/layouts/_default/index.xml",
|
||||
"layouts/_default/home.xml",
|
||||
"demoTheme/layouts/_default/home.xml",
|
||||
"layouts/_default/list.xml",
|
||||
"demoTheme/layouts/_default/list.xml",
|
||||
"layouts/_internal/_default/rss.xml"
|
||||
]
|
||||
},
|
||||
@@ -2978,6 +2925,24 @@
|
||||
}
|
||||
},
|
||||
"path": {
|
||||
"Base": {
|
||||
"Description": "",
|
||||
"Args": null,
|
||||
"Aliases": null,
|
||||
"Examples": null
|
||||
},
|
||||
"Dir": {
|
||||
"Description": "",
|
||||
"Args": null,
|
||||
"Aliases": null,
|
||||
"Examples": null
|
||||
},
|
||||
"Ext": {
|
||||
"Description": "",
|
||||
"Args": null,
|
||||
"Aliases": null,
|
||||
"Examples": null
|
||||
},
|
||||
"Join": {
|
||||
"Description": "Join joins any number of path elements into a single path, adding a\nseparating slash if necessary. All the input\npath elements are passed into filepath.ToSlash converting any Windows slashes\nto forward slashes.\nThe result is Cleaned; in particular,\nall empty strings are ignored.",
|
||||
"Args": [
|
||||
@@ -2992,6 +2957,18 @@
|
||||
[
|
||||
"{{ path.Join \"my\" \"path\" \"filename.txt\" }}",
|
||||
"my/path/filename.txt"
|
||||
],
|
||||
[
|
||||
"{{ \"my/path/filename.txt\" | path.Ext }}",
|
||||
".txt"
|
||||
],
|
||||
[
|
||||
"{{ \"my/path/filename.txt\" | path.Base }}",
|
||||
"filename.txt"
|
||||
],
|
||||
[
|
||||
"{{ \"my/path/filename.txt\" | path.Dir }}",
|
||||
"my/path"
|
||||
]
|
||||
]
|
||||
},
|
||||
@@ -3201,6 +3178,20 @@
|
||||
"Aliases": null,
|
||||
"Examples": null
|
||||
},
|
||||
"Repeat": {
|
||||
"Description": "Repeat returns a new string consisting of count copies of the string s.",
|
||||
"Args": [
|
||||
"n",
|
||||
"s"
|
||||
],
|
||||
"Aliases": null,
|
||||
"Examples": [
|
||||
[
|
||||
"{{ \"yo\" | strings.Repeat 4 }}",
|
||||
"yoyoyoyo"
|
||||
]
|
||||
]
|
||||
},
|
||||
"Replace": {
|
||||
"Description": "Replace returns a copy of the string s with all occurrences of old replaced\nwith new.",
|
||||
"Args": [
|
||||
@@ -3230,6 +3221,14 @@
|
||||
],
|
||||
"Examples": []
|
||||
},
|
||||
"RuneCount": {
|
||||
"Description": "RuneCount returns the number of runes in s.",
|
||||
"Args": [
|
||||
"s"
|
||||
],
|
||||
"Aliases": null,
|
||||
"Examples": []
|
||||
},
|
||||
"SliceString": {
|
||||
"Description": "SliceString slices a string by specifying a half-open range with\ntwo indices, start and end. 1 and 4 creates a slice including elements 1 through 3.\nThe end index can be omitted, it defaults to the string's length.",
|
||||
"Args": [
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{{ $original := .Page.Resources.GetMatch (printf "%s*" (.Get 0)) }}
|
||||
{{ $original := .Page.Resources.GetMatch (printf "*%s*" (.Get 0)) }}
|
||||
{{ $command := .Get 1 }}
|
||||
{{ $options := .Get 2 }}
|
||||
{{ if eq $command "Fit"}}
|
||||
@@ -11,8 +11,8 @@
|
||||
{{ errorf "Invalid image processing command: Must be one of Fit, Fill or Resize."}}
|
||||
{{ end }}
|
||||
{{ $image := .Scratch.Get "image" }}
|
||||
<figure style="width: {{ add $image.Width 3 }}px; padding: 3px; background-color: #cccc">
|
||||
<img src="{{ $image.RelPermalink }}" width="{{ $image.Width }}" height="{{ $image.Height }}">
|
||||
<figure style="padding: 0.25rem; margin: 2rem 0; background-color: #cccc">
|
||||
<img style="max-width: 100%; height: auto;" src="{{ $image.RelPermalink }}" width="{{ $image.Width }}" height="{{ $image.Height }}">
|
||||
<figcaption>
|
||||
<small>
|
||||
{{ with .Inner }}
|
||||
|
||||
@@ -3,7 +3,7 @@ publish = "public"
|
||||
command = "hugo"
|
||||
|
||||
[context.production.environment]
|
||||
HUGO_VERSION = "0.40.3"
|
||||
HUGO_VERSION = "0.42.2"
|
||||
HUGO_ENV = "production"
|
||||
HUGO_ENABLEGITINFO = "true"
|
||||
|
||||
@@ -11,20 +11,20 @@ HUGO_ENABLEGITINFO = "true"
|
||||
command = "hugo --enableGitInfo"
|
||||
|
||||
[context.split1.environment]
|
||||
HUGO_VERSION = "0.40.3"
|
||||
HUGO_VERSION = "0.42.2"
|
||||
HUGO_ENV = "production"
|
||||
|
||||
[context.deploy-preview]
|
||||
command = "hugo -b $DEPLOY_PRIME_URL"
|
||||
command = "hugo --buildFuture -b $DEPLOY_PRIME_URL"
|
||||
|
||||
[context.deploy-preview.environment]
|
||||
HUGO_VERSION = "0.40.3"
|
||||
HUGO_VERSION = "0.42.2"
|
||||
|
||||
[context.branch-deploy]
|
||||
command = "hugo -b $DEPLOY_PRIME_URL"
|
||||
|
||||
[context.branch-deploy.environment]
|
||||
HUGO_VERSION = "0.40.3"
|
||||
HUGO_VERSION = "0.42.2"
|
||||
|
||||
[context.next.environment]
|
||||
HUGO_ENABLEGITINFO = "true"
|
||||
|
||||
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 47 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 51 KiB |
|
After Width: | Height: | Size: 59 KiB |
|
After Width: | Height: | Size: 87 KiB |