Compare commits

...

474 Commits

Author SHA1 Message Date
hugoreleaser b6a4ae4ad5 releaser: Add release notes to /docs for release of 0.89.1
[ci skip]
2021-11-05 15:44:32 +00:00
hugoreleaser 84de0c3255 releaser: Bump versions for release of 0.89.1
[ci skip]
2021-11-05 15:44:32 +00:00
hugoreleaser a074102262 releaser: Add release notes for 0.89.1
[ci skip]
2021-11-05 15:44:32 +00:00
Bjørn Erik Pedersen da4406ea50 Revert "releaser: Fat MacOS binaries"
This had some side effect that I'm not prepared to fix today ...

This reverts commit 3a977485eb.

Updates #9131
Updates #9128
2021-11-05 16:31:19 +01:00
Bjørn Erik Pedersen 166862a096 create: Make sure the build lock is released before we open editor
Fixes #9121
2021-11-04 15:40:02 +01:00
Andreas Deininger 82c33c7105 readme: Update dependency list 2021-11-03 17:15:33 +01:00
hugoreleaser 41e9e9fe14 releaser: Prepare repository for 0.90.0-DEV
[ci skip]
2021-11-02 10:40:00 +00:00
hugoreleaser ade966b84b releaser: Add release notes to /docs for release of 0.89.0
[ci skip]
2021-11-02 10:00:17 +00:00
hugoreleaser a93d4ba64e releaser: Bump versions for release of 0.89.0
[ci skip]
2021-11-02 10:00:17 +00:00
hugoreleaser 110512a65c releaser: Add release notes for 0.89.0 2021-11-02 10:47:54 +01:00
Bjørn Erik Pedersen f503b63957 docs: Regen CLI docs 2021-11-02 09:01:26 +01:00
Bjørn Erik Pedersen 30aba7fb09 source: Make ContentBaseName() return the directory for branch bundles
Fixes #9112
2021-11-01 21:06:39 +01:00
Joe Mooring 04a3b45db4 Fix description of lang.FormatNumberCustom
It currently refers to itself as a simple alternative, when it should
refer to lang.FormatNumber.
2021-11-01 18:54:43 +01:00
Joe Mooring 0cc39af682 Update Twitter shortcode oEmbed endpoint
The existing endpoint will be retired and removed on November 23, 2021.
References:

- https://twittercommunity.com/t/consolidating-the-oembed-functionality/154690
- https://developer.twitter.com/en/docs/twitter-for-websites/oembed-api#Embedded

This is a backward compatible change.

The existing endpoint requires a single parameter: the id of the tweet.

The new endpoint requires two parameters: the id of the tweet, and the
user with whom it is associated. For the moment, if you supply the wrong
user, the request will be redirected (with a small delay) to the correct
user/id pair. This behavior is undocumented, but we will take advantage
of it as Hugo site authors transition to the new syntax.

{{< tweet 1453110110599868418 >}} --> works, throws warning, deprecate at some point

{{< tweet user="SanDiegoZoo" id="1453110110599868418" >}} --> new syntax

Fixes #8130
2021-11-01 15:51:00 +01:00
Bjørn Erik Pedersen ed6fd26ce8 common/htime: Fix time.Format with Go layouts
Fixes #9107
2021-11-01 15:45:59 +01:00
dependabot[bot] 7fa66425aa build(deps): bump github.com/evanw/esbuild from 0.13.10 to 0.13.12
Bumps [github.com/evanw/esbuild](https://github.com/evanw/esbuild) from 0.13.10 to 0.13.12.
- [Release notes](https://github.com/evanw/esbuild/releases)
- [Changelog](https://github.com/evanw/esbuild/blob/master/CHANGELOG.md)
- [Commits](https://github.com/evanw/esbuild/compare/v0.13.10...v0.13.12)

---
updated-dependencies:
- dependency-name: github.com/evanw/esbuild
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-11-01 15:44:19 +01:00
dependabot[bot] 69210cfdf3 build(deps): bump github.com/yuin/goldmark from 1.4.1 to 1.4.2
Bumps [github.com/yuin/goldmark](https://github.com/yuin/goldmark) from 1.4.1 to 1.4.2.
- [Release notes](https://github.com/yuin/goldmark/releases)
- [Commits](https://github.com/yuin/goldmark/compare/v1.4.1...v1.4.2)

---
updated-dependencies:
- dependency-name: github.com/yuin/goldmark
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-11-01 15:43:42 +01:00
Bjørn Erik Pedersen 4b36498a85 Merge commit 'aa5ac36a3eb68b86c803caec703869efefc8447e' 2021-10-31 13:53:55 +01:00
Bjørn Erik Pedersen aa5ac36a3e Squashed 'docs/' changes from 327003421..39a7fac34
39a7fac34 Add .hugo_build.lock to .gitignore
920c716a4 fix a typo: to -> two (#1545)
6f0ba9593 Remove godocref from front matter (#1543)
8ec3d5948 remove link to wercker (#1544)
b56008719 Delete deployment-with-wercker.md (#1542)
e33d29b02 Fix broken links (#1538)
29e9d4c21 Sort commenting systems (#1541)
0b7ea60a7 Delete the news page "HTTP/2 Server Push in Hugo"
6e1515857 Fix quick-start.md (#1525)
62168ab35 Update comments.md (#1535)
d92191512 Small typo (#1539)
129c8834a Correct the PostCSS noMap default value (#1534)
6a5b29fcc Add example to index function (#1536)
e3dd8c507 Update output-formats.md
0c9321ca0 Remove reference to using LiveReload in production environment
4072d6776 Mod testing
09fabf7d6 Fix typo (#1524)
2fce813c8 Fix grammatical error in quick-start.md (#1523)
45230ab4a Hugo Mod testing
2dd4cd9e7 Update index.md
2c3ed62fd netlify: Bump to 0.88.1
648e2a007 Merge branch 'tempv0.88.1'
f216eade1 releaser: Add release notes to /docs for release of 0.88.1
8a7b64d4b Fix typographical errors in 0.88.0 release notes
a4bf86300 Release 0.88
738bb8f38 releaser: Add release notes to /docs for release of 0.88.0
8fcf2c55d highlight: Remove some pygments references
f2b173de2 HTTPS link
c88881c8e Adding link to nginx documentation
6b0a74fe0 Fix typos in docs (#1516)
498b8f0f1 Fix typos in time.Format (#1515)
28723fad6 Fix taxonomy and term examples (#1514)
3ffd00e12 Update front-matter.md
7cc1da82e Fix grammar in 0.86.1 release notes (#1510)
0009c51c3 Update docs helper
7e2f430f4 Update index.md
7857eae7e releaser: Add release notes to /docs for release of 0.87.0
1f08b684b releaser: Add release notes to /docs for release of 0.87.0
36a9e701c docs: Adjust config docs
0f588438e docs: Regen CLI docs
1b4682cd8 docs: Regen docs helper
bc8bbaae9 Merge commit 'bd77f6e1c99e04a476f0b1bb4e44569134e02399' into release-0.87.0
6f2480643 docs: Adjust time zone docs

git-subtree-dir: docs
git-subtree-split: 39a7fac343
2021-10-31 13:51:51 +01:00
Bjørn Erik Pedersen 3a977485eb releaser: Fat MacOS binaries
Fixes #9035
2021-10-31 11:30:12 +01:00
Bjørn Erik Pedersen 0f248606d5 releaser: Only build amd64 binary for freebsd, netbsd, openbsd, dragonfly
Fixes #9102
2021-10-31 10:04:01 +01:00
Bjørn Erik Pedersen e82cbd746f tpl/time: Use configured location when date passed to Format is string
Updates #9084
2021-10-30 16:09:38 +02:00
dependabot[bot] 3339c2bb61 build(deps): bump github.com/aws/aws-sdk-go from 1.40.8 to 1.41.14
Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.40.8 to 1.41.14.
- [Release notes](https://github.com/aws/aws-sdk-go/releases)
- [Changelog](https://github.com/aws/aws-sdk-go/blob/main/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-go/compare/v1.40.8...v1.41.14)

---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-30 11:17:12 +02:00
dependabot[bot] 03bbdba8be build(deps): bump github.com/getkin/kin-openapi from 0.79.0 to 0.80.0
Bumps [github.com/getkin/kin-openapi](https://github.com/getkin/kin-openapi) from 0.79.0 to 0.80.0.
- [Release notes](https://github.com/getkin/kin-openapi/releases)
- [Commits](https://github.com/getkin/kin-openapi/compare/v0.79.0...v0.80.0)

---
updated-dependencies:
- dependency-name: github.com/getkin/kin-openapi
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-30 11:16:46 +02:00
dependabot[bot] a772b8fc38 build(deps): bump github.com/evanw/esbuild from 0.13.8 to 0.13.10
Bumps [github.com/evanw/esbuild](https://github.com/evanw/esbuild) from 0.13.8 to 0.13.10.
- [Release notes](https://github.com/evanw/esbuild/releases)
- [Changelog](https://github.com/evanw/esbuild/blob/master/CHANGELOG.md)
- [Commits](https://github.com/evanw/esbuild/compare/v0.13.8...v0.13.10)

---
updated-dependencies:
- dependency-name: github.com/evanw/esbuild
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-30 09:35:06 +02:00
Anthony Fok dce49d1333 resources: Rename excepted filenames for image golden testdata
As documented in commit 30eea3915b,
some filenames have changed due to cache busting of PNG and Webp images.

This resolves recent TestImageOperationsGolden failure on arm64, ppc64le
and s390x.

See #6387 and #8729
2021-10-30 08:47:22 +02:00
dependabot[bot] 61c5b7a2e6 build(deps): bump github.com/frankban/quicktest from 1.13.1 to 1.14.0
Bumps [github.com/frankban/quicktest](https://github.com/frankban/quicktest) from 1.13.1 to 1.14.0.
- [Release notes](https://github.com/frankban/quicktest/releases)
- [Commits](https://github.com/frankban/quicktest/compare/v1.13.1...v1.14.0)

---
updated-dependencies:
- dependency-name: github.com/frankban/quicktest
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-27 14:30:23 +02:00
Joe Mooring 1d60bd1efa Fix typo in error message 2021-10-26 12:59:15 +02:00
Bjørn Erik Pedersen 75c9b893d9 create: Validate the target path in hugo new
Fixes #9072
2021-10-25 19:50:18 +02:00
Bjørn Erik Pedersen 64e1613fb3 Fix panic when specifying multiple excludeFiles directives
Fixes #9076
2021-10-25 19:50:18 +02:00
satotake b959ecbc81 htime: Set zone of datetime from from go-toml
`go-toml/v2`'s unmarshaler does not specify zone name even if value has
offset explicitly.
To make time-formatting behaviour consistent, convert them into string
in hugo.

Close #8895
2021-10-25 19:49:44 +02:00
Sergio Garcia 70e454812e Added nodesource apt repository to snap package 2021-10-22 16:26:07 -06:00
Anthony Fok 355ff83e74 config: Set HUGO_ENABLEGITINFO=false override in Set_in_string
This allows TestLoadConfigWithOsEnvOverrides/Set_in_string to PASS
even if there is no .git directory, e.g. during Debian package build.
2021-10-22 19:40:18 +02:00
Bjørn Erik Pedersen 471ed91c60 hugofs: Add includeFiles and excludeFiles to mount configuration
Fixes #9042
2021-10-20 05:00:17 +02:00
dependabot[bot] 94a5bac5b2 build(deps): bump github.com/mitchellh/mapstructure from 1.4.1 to 1.4.2
Bumps [github.com/mitchellh/mapstructure](https://github.com/mitchellh/mapstructure) from 1.4.1 to 1.4.2.
- [Release notes](https://github.com/mitchellh/mapstructure/releases)
- [Changelog](https://github.com/mitchellh/mapstructure/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mitchellh/mapstructure/compare/v1.4.1...v1.4.2)

---
updated-dependencies:
- dependency-name: github.com/mitchellh/mapstructure
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-20 04:17:44 +02:00
Bjørn Erik Pedersen 9830ca9e31 resources: Always preserve the original transform error 2021-10-19 20:38:38 +02:00
itsAftabAlam b64fd0577b readme: Add hyperlink to the banner 2021-10-19 15:59:12 +02:00
dependabot[bot] 2706437a7d build(deps): bump github.com/getkin/kin-openapi from 0.78.0 to 0.79.0
Bumps [github.com/getkin/kin-openapi](https://github.com/getkin/kin-openapi) from 0.78.0 to 0.79.0.
- [Release notes](https://github.com/getkin/kin-openapi/releases)
- [Commits](https://github.com/getkin/kin-openapi/compare/v0.78.0...v0.79.0)

---
updated-dependencies:
- dependency-name: github.com/getkin/kin-openapi
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-19 15:35:31 +02:00
Bjørn Erik Pedersen ec7c993cfe deps: github.com/evanw/esbuild v0.13.5 => v0.13.8 2021-10-19 15:33:29 +02:00
Bjørn Erik Pedersen 32c6f656d9 create: Return error on no content dirs
Closes #9056
2021-10-19 08:08:21 +02:00
Bjørn Erik Pedersen e02e0727e5 Fix file permissions in new archetype implementation
Closes #9057
2021-10-18 19:08:19 +02:00
Bjørn Erik Pedersen 096f5e1921 Fix the "page picker" logic in --navigateToChanged
Fixes #9051
2021-10-18 12:13:13 +02:00
Bjørn Erik Pedersen ba35e69856 Add a cross process build lock and use it in the archetype content builder
Fixes #9048
2021-10-18 12:13:13 +02:00
nabbisen c7957c90e8 readme: Fix a typo on OpenBSD 2021-10-17 21:23:01 +02:00
Bjørn Erik Pedersen bb05377033 deps: github.com/alecthomas/chroma v0.9.2 => v0.9.4
Fixes #8532
2021-10-17 17:14:03 +02:00
Bjørn Erik Pedersen 9185e11eff Reimplement archetypes
The old implementation had some issues, mostly related to the context (e.g. name, file paths) passed to the template.

This new implementation is using the exact same code path for evaluating the pages as in a regular build.

This also makes it more robust and easier to reason about in a multilingual setup.

Now, if you are explicit about the target path, Hugo will now always pick the correct mount and language:

```bash
hugo new content/en/posts/my-first-post.md
```

Fixes #9032
Fixes #7589
Fixes #9043
Fixes #9046
Fixes #9047
2021-10-16 15:22:03 +02:00
dependabot[bot] 168a3aab46 build(deps): bump github.com/tdewolff/minify/v2 from 2.9.21 to 2.9.22
Bumps [github.com/tdewolff/minify/v2](https://github.com/tdewolff/minify) from 2.9.21 to 2.9.22.
- [Release notes](https://github.com/tdewolff/minify/releases)
- [Commits](https://github.com/tdewolff/minify/compare/v2.9.21...v2.9.22)

---
updated-dependencies:
- dependency-name: github.com/tdewolff/minify/v2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-14 10:40:23 +02:00
Bjørn Erik Pedersen 8bcfa3bdf6 deps: Update github.com/evanw/esbuild v0.13.5 2021-10-14 10:25:42 +02:00
Iskander (Alex) Sharipov d7331aaa7e releaser: Fix regexp
Original regexp used a char class which caused the regexp to only
check 1 symbol instead of a substring like "See" and "Closes".
So it would match `e #x` instead of `See #x` and many other
weird combinations.

Tests were passing as they never checked against an input that
would confuse that regexp.

Found with go-critic static analyzer, `badRegexp` checker.
2021-10-12 11:32:09 +02:00
dependabot[bot] cd4e67af18 build(deps): bump github.com/mattn/go-isatty from 0.0.13 to 0.0.14
Bumps [github.com/mattn/go-isatty](https://github.com/mattn/go-isatty) from 0.0.13 to 0.0.14.
- [Release notes](https://github.com/mattn/go-isatty/releases)
- [Commits](https://github.com/mattn/go-isatty/compare/v0.0.13...v0.0.14)

---
updated-dependencies:
- dependency-name: github.com/mattn/go-isatty
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-10 20:45:38 +02:00
dependabot[bot] e6ad1f0e76 build(deps): bump github.com/getkin/kin-openapi from 0.75.0 to 0.78.0
Bumps [github.com/getkin/kin-openapi](https://github.com/getkin/kin-openapi) from 0.75.0 to 0.78.0.
- [Release notes](https://github.com/getkin/kin-openapi/releases)
- [Commits](https://github.com/getkin/kin-openapi/compare/v0.75.0...v0.78.0)

---
updated-dependencies:
- dependency-name: github.com/getkin/kin-openapi
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-10 20:30:52 +02:00
Bjørn Erik Pedersen 625d2c257a releaser: Update to Go go1.17.2
* This now uses the `golang:1.17.2-buster` Docker image which runs GLIBC 2.28-10.
* Also added a build hook to warn us if this happens again in the future.

Fixes #8955
2021-10-10 16:53:44 +02:00
Joe Mooring e6e44b7c41 Fix value of useResourceCacheWhen in TestResourceChainPostCSS 2021-10-10 11:12:01 +02:00
Joe Mooring 64abc83fc4 Allow multiple plugins in the PostCSS options map
Usage:
{{ $options := dict "use" "autoprefixer postcss-color-alpha" }}
{{ $style := resources.Get "main.css" | resources.PostCSS $options }}

Fixes #9015
2021-10-10 11:11:43 +02:00
Joe Mooring f8d132d731 docs: Create path.Clean documentation
Related to #9005
2021-10-09 20:36:57 +02:00
Bjørn Erik Pedersen 26f1919ae0 Skip a test assertion on CI
Need to investigate later, but got to get the tests green.
2021-10-09 20:36:32 +02:00
Brad e55466ce70 tpl/path: Add path.Clean
Fixes #8885
2021-10-05 16:15:10 +02:00
Shalabh Kamboj ecf025f006 readme: Remove tracking image
The server for the tracking image for analytics is currently down,
therefore I found it convenient to remove the link in order to maintain our readme
2021-10-05 15:09:11 +02:00
digitalcraftsman fab1e43de5 Revert "Remove credit from release notes"
See b2eaf4c8c2
2021-09-23 14:02:00 +02:00
Paul Gottschling e03f82eef2 Pass minification errors to the user
Previously, *minifyTransformation.Transform suppressed the
error returned by t.m.Minify. This meant that when minification
returned an error, the error would not reach the user. Instead,
minification would silently fail. For example, if a JavaScript
file included a call to the Date constructor with:

new Date(2020, 04, 02)

The package that the minification library uses to parse JS files,
github.com/tdewolff/parse would return an error, since "04" would
be parsed as a legacy octal. However, the JS file would remain
un-minified with no error.

Fixing this is not as simple as replacing "_" with an "err" in
*minifyTransformation.Transform, however (though this is
necessary). If we only returned this error from Transform,
then hugolib.TestResourceMinifyDisabled would fail. Instead of
being a no-op, as TestResourceMinifyDisabled expects, using the
"minify" template function with a "disableXML=true" config
setting instead returns the error, "minifier does not exist for
mimetype."

The "minifier does not exist" error is returned because of the
way minifiers.New works. If the user's config disables
minification for a particular MIME type, minifiers.New does
not add it to the resulting Client's *minify.M. However, this
also means that when the "minify" template function is executed,
 a *resourceAdapter's transformations still add a minification.
When it comes time to call the minify.Minifier for a specific
MIME type via *M.MinifyMimetype, the github.com/tdewolff/minify
library throws the "does not exist" error for the missing MIME
type.

The solution was to change minifiers.New so, instead of skipping
a minifier for each disabled MIME type, it adds  a NoOpMinifier,
which simply copies the source to the destination without
minification. This means that when the "minify" template
function is used for a particular resource, and that resource's
MIME type has minification disabled, minification is genuinely
skipped, and does not result in an error.

In order to add this, I've fixed a possibly unwanted interaction
between minifiers.TestConfigureMinify and
hugolib.TestResourceMinifyDisabled. The latter disables
minification and expects minification to be a no-op. The former
disables minification and expects it to result in an error. The
only reason hugolib.TestResourceMinifyDisabled passes in the
original code is that the "does not exist" error is suppressed.
However, we shouldn't suppress minification errors, since they
can leave users perplexed. I've changed the test assertion in
minifiers.TestConfigureMinify to expect no errors and a no-op
if minification is disabled for a particular MIME type.

Fixes #8954
2021-09-22 20:54:40 +02:00
Paul Gottschling a864ffe9ac Clarify "precision" in currency format functions
The documentation of the FormatAccounting and FormatCurrency
functions could be clearer in terms of how the precision param
works. This commit makes it more explicit that adding a precision
of < 2 will not format the return values to include fewer decimals.

Resolves #8858
2021-09-22 20:00:30 +02:00
dependabot[bot] b49da33280 build(deps): bump github.com/evanw/esbuild from 0.12.24 to 0.12.29
Bumps [github.com/evanw/esbuild](https://github.com/evanw/esbuild) from 0.12.24 to 0.12.29.
- [Release notes](https://github.com/evanw/esbuild/releases)
- [Changelog](https://github.com/evanw/esbuild/blob/master/CHANGELOG.md)
- [Commits](https://github.com/evanw/esbuild/compare/v0.12.24...v0.12.29)

---
updated-dependencies:
- dependency-name: github.com/evanw/esbuild
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-09-22 20:00:05 +02:00
Emmanuel T Odeke 7c21eca74f resources: Use default math/rand.Source for concurrency safety
The source from NewSource is documented not to be safe for
concurrency, and instead use the eefault source which is documented
as safe.

Fixes #8981
2021-09-19 12:18:30 +02:00
Bjørn Erik Pedersen 13ad8408fc commands: Make the error handling for the mod commands more lenient
So it at least is possible to do a `hugo mod clean --all` if the cache is in a funky state.
2021-09-17 17:16:34 +02:00
Bjørn Erik Pedersen 1cabf61ddf modules: Add some help text to the 'unknown revision' error
I had a head scratching moment with this myself, so it's safe to say that others will.

See #6825
2021-09-17 09:34:35 +02:00
Joe Mooring 268e3069f3 deps: Update github.com/yuin/goldmark v1.4.0 => v1.4.1
Fixes #8855
2021-09-12 21:55:37 +02:00
hugoreleaser 3efc2e2af8 releaser: Prepare repository for 0.89.0-DEV
[ci skip]
2021-09-04 10:33:09 +00:00
hugoreleaser 5bc547389a releaser: Add release notes to /docs for release of 0.88.1
[ci skip]
2021-09-04 09:39:19 +00:00
hugoreleaser bb3254385a releaser: Bump versions for release of 0.88.1
[ci skip]
2021-09-04 09:39:19 +00:00
hugoreleaser 9b1d6d7e30 releaser: Add release notes for 0.88.1
[ci skip]
2021-09-04 09:39:19 +00:00
Bjørn Erik Pedersen e1ead4dbca Bump down again to Go 1.16.7 for the release builds
Note that this commit has nothing to do with "Hugo not working with Go 1.17", but this is the simplest fix of some build related issues in Hugo 0.88.0.

Updates #8952
Updates #8955
2021-09-04 11:22:51 +02:00
hugoreleaser 5b59b9c171 releaser: Prepare repository for 0.89.0-DEV
[ci skip]
2021-09-02 09:57:36 +00:00
hugoreleaser acc5eb5b51 releaser: Add release notes to /docs for release of 0.88.0
[ci skip]
2021-09-02 09:27:27 +00:00
hugoreleaser 6cacfa329c releaser: Bump versions for release of 0.88.0
[ci skip]
2021-09-02 09:27:27 +00:00
Bjørn Erik Pedersen 4d03cd780e Release 0.88.0 2021-09-02 11:11:08 +02:00
Bjørn Erik Pedersen 8b14fdbf89 Update 0.88.0-relnotes.md
[ci skip]
2021-09-02 11:10:40 +02:00
hugoreleaser fc21b63b46 releaser: Add release notes for 0.88.0
Rename to *-ready.md to continue.
[ci skip]
2021-09-02 08:09:25 +00:00
Bjørn Erik Pedersen 6631c9c7e0 Run go mod tidy 2021-09-01 10:48:13 +02:00
Bjørn Erik Pedersen cf73cc2ece js: Fix import order for ./foo when both ./foo.js and ./foo/index.js exists
This is in line with how both Node and ESBuild's native import resolver does it.

The ambiguous situations above were discovered trying to build AlpineJS v3.

Note that the above was never an issue if you used `./foo.js` and similar to import the component.

Fixes #8945
2021-09-01 10:47:41 +02:00
Bjørn Erik Pedersen 7d1f806ecb commands: Don't fail on template errors on go mod graph etc.
Fixes #8942
2021-08-31 22:16:12 +02:00
dependabot[bot] 04b5959961 build(deps): bump github.com/getkin/kin-openapi from 0.74.0 to 0.75.0
Bumps [github.com/getkin/kin-openapi](https://github.com/getkin/kin-openapi) from 0.74.0 to 0.75.0.
- [Release notes](https://github.com/getkin/kin-openapi/releases)
- [Commits](https://github.com/getkin/kin-openapi/compare/v0.74.0...v0.75.0)

---
updated-dependencies:
- dependency-name: github.com/getkin/kin-openapi
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-08-31 12:11:39 +02:00
dependabot[bot] c278b6e45d build(deps): bump github.com/frankban/quicktest from 1.13.0 to 1.13.1
Bumps [github.com/frankban/quicktest](https://github.com/frankban/quicktest) from 1.13.0 to 1.13.1.
- [Release notes](https://github.com/frankban/quicktest/releases)
- [Commits](https://github.com/frankban/quicktest/compare/v1.13.0...v1.13.1)

---
updated-dependencies:
- dependency-name: github.com/frankban/quicktest
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-08-31 12:11:08 +02:00
dependabot[bot] 107c86febb build(deps): bump github.com/evanw/esbuild from 0.12.22 to 0.12.24
Bumps [github.com/evanw/esbuild](https://github.com/evanw/esbuild) from 0.12.22 to 0.12.24.
- [Release notes](https://github.com/evanw/esbuild/releases)
- [Changelog](https://github.com/evanw/esbuild/blob/master/CHANGELOG.md)
- [Commits](https://github.com/evanw/esbuild/compare/v0.12.22...v0.12.24)

---
updated-dependencies:
- dependency-name: github.com/evanw/esbuild
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-08-31 12:10:32 +02:00
Bjørn Erik Pedersen a0489c2dfd Avoid failing with "module not found" for hugo mod init and similar
Fixes #8940
2021-08-31 12:08:11 +02:00
Bjørn Erik Pedersen 0fc2ce9e4b Update to Go 1.17
Go 1.17 now lazy-loads dependencies when `go.mod` is version `go17`. This does not work for us for new projects started with `hugo mod init`.

Before this commit, starting a project with Go 1.17 with `hugo mod init` and then start adding dependencies with transitive dependenies to `config.toml` would treat the transitive dependencies as new, and you would potentially get a too recent version of those.

Note that this does not effect existing projects, where all dependencies are already recorded in `go.mod`.

Fixes #8930
2021-08-31 11:19:51 +02:00
Anthony Fok 32569285c1 Remove Pygments from snapcraft.yml
Pygments support was removed in Hugo v0.60.0
2021-08-25 10:43:32 -06:00
Bjørn Erik Pedersen 5a46eefbc6 Revert "build(deps): bump github.com/fsnotify/fsnotify from 1.4.9 to 1.5.0"
This reverts commit f70165242b.

Closes #8920
2021-08-23 18:20:29 +02:00
Helder Pereira 7a15edafe2 highlight: Add tabindex when code is not highlighted 2021-08-23 12:28:45 +02:00
dependabot[bot] 2f0945bafe build(deps): bump github.com/evanw/esbuild from 0.12.17 to 0.12.22
Bumps [github.com/evanw/esbuild](https://github.com/evanw/esbuild) from 0.12.17 to 0.12.22.
- [Release notes](https://github.com/evanw/esbuild/releases)
- [Changelog](https://github.com/evanw/esbuild/blob/master/CHANGELOG.md)
- [Commits](https://github.com/evanw/esbuild/compare/v0.12.17...v0.12.22)

---
updated-dependencies:
- dependency-name: github.com/evanw/esbuild
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-08-22 13:58:10 +02:00
Bjørn Erik Pedersen f4ffeea71d Fix it so disableKinds etc. does not get merged in from theme
Unless the merge strategy is set up to do so.

For `disableKinds` the current workaround is to make sure the project config has an entry, even if is empty:

```
disableKinds = []
```

Note that this issue only touches root, non-map config-values that either is not set in project config or in Hugo's defaults.

Fixes #8866
2021-08-22 13:25:20 +02:00
dependabot[bot] 7ba3f3d201 build(deps): bump golang.org/x/text from 0.3.6 to 0.3.7
Bumps [golang.org/x/text](https://github.com/golang/text) from 0.3.6 to 0.3.7.
- [Release notes](https://github.com/golang/text/releases)
- [Commits](https://github.com/golang/text/compare/v0.3.6...v0.3.7)

---
updated-dependencies:
- dependency-name: golang.org/x/text
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-08-22 12:52:31 +02:00
dependabot[bot] f70165242b build(deps): bump github.com/fsnotify/fsnotify from 1.4.9 to 1.5.0
Bumps [github.com/fsnotify/fsnotify](https://github.com/fsnotify/fsnotify) from 1.4.9 to 1.5.0.
- [Release notes](https://github.com/fsnotify/fsnotify/releases)
- [Changelog](https://github.com/fsnotify/fsnotify/blob/master/CHANGELOG.md)
- [Commits](https://github.com/fsnotify/fsnotify/compare/v1.4.9...v1.5.0)

---
updated-dependencies:
- dependency-name: github.com/fsnotify/fsnotify
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-08-22 12:52:04 +02:00
Bjørn Erik Pedersen bc0743ed8e Prevent minifier from removing quoutes around post-processed attributes
Fixes #8884
2021-08-22 12:47:47 +02:00
Bjørn Erik Pedersen ffa2fe6117 Revert "commands: Avoid too many watch file handles causing the server to fail to start"
This reverts commit 3f38c785b7.
2021-08-21 16:32:20 +02:00
Helder Pereira d966f5d08d highlight: Remove some pygments references 2021-08-21 15:50:49 +02:00
Shiming Zhang 3f38c785b7 commands: Avoid too many watch file handles causing the server to fail to start
Fixes #8904
2021-08-19 11:04:09 +02:00
dependabot[bot] 24589c0814 build(deps): bump github.com/getkin/kin-openapi from 0.68.0 to 0.74.0
Bumps [github.com/getkin/kin-openapi](https://github.com/getkin/kin-openapi) from 0.68.0 to 0.74.0.
- [Release notes](https://github.com/getkin/kin-openapi/releases)
- [Commits](https://github.com/getkin/kin-openapi/compare/v0.68.0...v0.74.0)

---
updated-dependencies:
- dependency-name: github.com/getkin/kin-openapi
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-08-17 10:50:10 +02:00
Bjørn Erik Pedersen efebd756eb deps: Update github.com/spf13/cast v1.4.0 => v1.4.1
Closes #8891
2021-08-16 09:16:41 +02:00
Bjørn Erik Pedersen 58b6742cfe Import time/tzdata on Windows
Updates #8892
2021-08-14 12:09:41 +02:00
Bjørn Erik Pedersen 32ead4b1e7 releaser: Bump to Go 1.16.7 2021-08-10 14:00:49 +02:00
Bjørn Erik Pedersen abd969a670 Revert "tpl/time: Handle nil values in time.AsTime"
This reverts commit 3e11072892.
2021-08-10 13:21:49 +02:00
Bjørn Erik Pedersen 3e11072892 tpl/time: Handle nil values in time.AsTime
Closes #8865
2021-08-09 18:44:35 +02:00
Bjørn Erik Pedersen 9bba9a3a98 parser: Indent TOML tables
Fixes #8850
2021-08-04 11:39:16 +02:00
Salim B d6c8cd7718 Fix lang.FormatPercent description
Successor PR for https://github.com/gohugoio/hugoDocs/pull/1504
2021-08-03 16:56:06 +02:00
hugoreleaser dfe54d3216 releaser: Prepare repository for 0.88.0-DEV
[ci skip]
2021-08-03 12:11:56 +00:00
hugoreleaser b0c541e496 releaser: Add release notes to /docs for release of 0.87.0
[ci skip]
2021-08-03 10:57:26 +00:00
hugoreleaser 2ed7be295c releaser: Bump versions for release of 0.87.0
[ci skip]
2021-08-03 10:57:26 +00:00
Bjørn Erik Pedersen d9d1ef8b07 Release 0.87 2021-08-03 12:42:22 +02:00
Bjørn Erik Pedersen ec1c1c3459 Merge branch 'b087' into release-0.87.0 2021-08-03 12:38:58 +02:00
Bjørn Erik Pedersen c7fd134625 Update 0.87.0-relnotes.md
[ci skip]
2021-08-03 12:31:41 +02:00
Bjørn Erik Pedersen a5d2632ebb Update 0.87.0-relnotes.md
[ci skip]
2021-08-03 12:30:42 +02:00
Bjørn Erik Pedersen 494f284be3 docs: Adjust config docs 2021-08-03 12:22:02 +02:00
Bjørn Erik Pedersen bf738d2f43 docs: Regen CLI docs 2021-08-03 11:55:02 +02:00
Bjørn Erik Pedersen 8d19850e2d docs: Regen docs helper 2021-08-03 11:53:34 +02:00
Bjørn Erik Pedersen 0934983529 Merge commit 'bd77f6e1c99e04a476f0b1bb4e44569134e02399' into release-0.87.0 2021-08-03 11:52:57 +02:00
Bjørn Erik Pedersen bd77f6e1c9 Squashed 'docs/' changes from 60a58d123..327003421
327003421 Update index.md
cafdccc13 Hugo 0.86.1
467a89a02 Merge branch 'v0861'
a22c37bc9 Merge branch 'release-0.86.1'
276da91a8 releaser: Add release notes to /docs for release of 0.86.1
198cdf8f0 tpl/lang: Add new localized versions of lang.FormatNumber etc.
93f986ecc Add timezone support for front matter dates without one
b30b876bb Localize time.Format
950fdab90 Fix AddDate documentation
78d7b52b6 Document config.cascade
fd1e1e4b7 Fix grammar and spelling (#1497)
05bf3aa32 Fix grammar / typos in news
32060a3b4 One more try
f6e24ddfa PNG to JPG for the rel notes image
9ec5bdfad Update index.md
5f5d7f69d Release Hugo 0.86.0
2dd60bb71 releaser: Add release notes to /docs for release of 0.86.0
6445fb36c Merge commit '53a352795a69a9d4a373f50ec62138595948c6ea'
cb57ca73a Simplify "active menu" logic for section menus

git-subtree-dir: docs
git-subtree-split: 327003421d
2021-08-03 11:51:36 +02:00
Bjørn Erik Pedersen 1c5b025dd0 docs: Adjust time zone docs 2021-08-03 11:51:28 +02:00
hugoreleaser c13d33dd5e releaser: Add release notes for 0.87.0
Rename to *-ready.md to continue.
[ci skip]
2021-08-03 08:45:16 +00:00
Bjørn Erik Pedersen d70c485707 Make sure module config loading errors have file positioning info
Fixes #8845
2021-08-03 09:57:14 +02:00
Bjørn Erik Pedersen 9ff17c3324 tpl/time: Adjust tests to handle matching local time zones
Closes #8843
2021-08-03 08:54:45 +02:00
Bjørn Erik Pedersen 7aaaf7e33a mod: Remove superflous replace statement 2021-08-02 20:33:13 +02:00
Bjørn Erik Pedersen 3a96655592 Reduce binary size vs locale, update to CLDR v36.1
Test building with `go build -ldflags="-s -w"`

Hugo 0.86.2: 46MB
Before this commit: 77MB
After this commit: 54MB

Fixes #8839
Fixes #8841
2021-08-02 19:40:32 +02:00
Joe Mooring 9a7383caf3 deps: Update github.com/tdewolff/minify/v2 v2.9.20 => v2.9.21
Closes #8831
2021-08-02 17:27:07 +02:00
Bjørn Erik Pedersen 6c70e1f22f Fix error handling for the time func alias
Fixes #8835
2021-08-01 13:39:30 +02:00
Bjørn Erik Pedersen 4d221ce468 Fail on invalid time zone
Fixes #8832
2021-08-01 13:39:30 +02:00
Bjørn Erik Pedersen e3dc5240f0 Improve handling of <nil> Params
Fixes #8825
2021-07-30 21:07:52 +02:00
Bjørn Erik Pedersen 268065cb2d Merge branch 'release-0.86.1' 2021-07-30 12:58:26 +02:00
hugoreleaser e0304c06ed releaser: Add release notes for 0.86.1
[ci skip]
2021-07-30 12:58:03 +02:00
hugoreleaser 7aa8b1cd7d releaser: Prepare repository for 0.87.0-DEV
[ci skip]
2021-07-30 10:54:50 +00:00
hugoreleaser f6821b88ab releaser: Add release notes to /docs for release of 0.86.1
[ci skip]
2021-07-30 10:13:32 +00:00
hugoreleaser 580d320a66 releaser: Bump versions for release of 0.86.1
[ci skip]
2021-07-30 10:13:32 +00:00
hugoreleaser b75d4526e4 releaser: Add release notes for 0.86.1
[ci skip]
2021-07-30 10:13:32 +00:00
Bjørn Erik Pedersen 94b616bdfa config: Fix a potential deadlock in config reading
Note that the deadlock has not been seen earlier, in tests on in real Hugo sites.

Fixes #8791
2021-07-30 11:53:27 +02:00
dependabot[bot] e90b3591a1 build(deps): bump github.com/evanw/esbuild from 0.12.16 to 0.12.17
Bumps [github.com/evanw/esbuild](https://github.com/evanw/esbuild) from 0.12.16 to 0.12.17.
- [Release notes](https://github.com/evanw/esbuild/releases)
- [Changelog](https://github.com/evanw/esbuild/blob/master/CHANGELOG.md)
- [Commits](https://github.com/evanw/esbuild/compare/v0.12.16...v0.12.17)

---
updated-dependencies:
- dependency-name: github.com/evanw/esbuild
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-07-30 11:11:10 +02:00
dependabot[bot] 4b7da6a9d7 build(deps): bump github.com/getkin/kin-openapi from 0.67.0 to 0.68.0
Bumps [github.com/getkin/kin-openapi](https://github.com/getkin/kin-openapi) from 0.67.0 to 0.68.0.
- [Release notes](https://github.com/getkin/kin-openapi/releases)
- [Commits](https://github.com/getkin/kin-openapi/compare/v0.67.0...v0.68.0)

---
updated-dependencies:
- dependency-name: github.com/getkin/kin-openapi
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-07-30 11:10:45 +02:00
Bjørn Erik Pedersen 7907d24ba1 tpl/lang: Add new localized versions of lang.FormatNumber etc.
Fixes #8820
2021-07-29 16:40:06 +02:00
Bjørn Erik Pedersen 726fe9c3c9 Go back to WARNING for Page deprecations
Do that in the next release, let's reduce the noise, we have enough changes as it is.
2021-07-29 16:18:38 +02:00
Bjørn Erik Pedersen b5de37ee79 Handle toml.LocalDate and toml.LocalDateTime in front matter
See #8801
2021-07-28 18:02:42 +02:00
Bjørn Erik Pedersen bf301daf15 deps: Upgrade github.com/pelletier/go-toml/v2 v2.0.0-beta.3 => v2.0.0-beta.3.0.20210727221244-fa0796069526 2021-07-28 17:27:31 +02:00
Bjørn Erik Pedersen a3701e0931 Switch to go-toml v2
We have been using `go-toml` for language files only. This commit makes it the only TOML library.

It's spec compliant and very fast.

A benchark building a site with 200 pages with TOML front matter:

```bash
name                                  old time/op    new time/op    delta
SiteNew/Regular_TOML_front_matter-16    48.5ms ± 1%    47.1ms ± 1%  -2.85%  (p=0.029 n=4+4)

name                                  old alloc/op   new alloc/op   delta
SiteNew/Regular_TOML_front_matter-16    16.9MB ± 0%    16.7MB ± 0%  -1.56%  (p=0.029 n=4+4)

name                                  old allocs/op  new allocs/op  delta
SiteNew/Regular_TOML_front_matter-16      302k ± 0%      296k ± 0%  -2.20%  (p=0.029 n=4+4)
```

Note that the front matter unmarshaling is only a small part of building a site, so the above is very good.

Fixes #8801
2021-07-28 11:51:13 +02:00
dependabot[bot] 40b6016cf3 build(deps): bump github.com/tdewolff/minify/v2 from 2.9.19 to 2.9.20
Bumps [github.com/tdewolff/minify/v2](https://github.com/tdewolff/minify) from 2.9.19 to 2.9.20.
- [Release notes](https://github.com/tdewolff/minify/releases)
- [Commits](https://github.com/tdewolff/minify/compare/v2.9.19...v2.9.20)

---
updated-dependencies:
- dependency-name: github.com/tdewolff/minify/v2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-07-28 11:21:50 +02:00
Bjørn Erik Pedersen 7e1305710f Add a TOML front matter benchmark 2021-07-27 19:27:54 +02:00
Bjørn Erik Pedersen efa5760db5 Add timezone support for front matter dates without one
Fixes #8810
2021-07-27 19:02:48 +02:00
Bjørn Erik Pedersen a57dda854b Localize time.Format
Fixes #8797
2021-07-27 19:02:48 +02:00
dependabot[bot] f9afba9335 build(deps): bump github.com/getkin/kin-openapi from 0.61.0 to 0.67.0
Bumps [github.com/getkin/kin-openapi](https://github.com/getkin/kin-openapi) from 0.61.0 to 0.67.0.
- [Release notes](https://github.com/getkin/kin-openapi/releases)
- [Commits](https://github.com/getkin/kin-openapi/compare/v0.61.0...v0.67.0)

---
updated-dependencies:
- dependency-name: github.com/getkin/kin-openapi
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-07-27 16:25:09 +02:00
dependabot[bot] a5d2ba429d build(deps): bump github.com/spf13/cast from 1.3.1 to 1.4.0
Bumps [github.com/spf13/cast](https://github.com/spf13/cast) from 1.3.1 to 1.4.0.
- [Release notes](https://github.com/spf13/cast/releases)
- [Commits](https://github.com/spf13/cast/compare/v1.3.1...v1.4.0)

---
updated-dependencies:
- dependency-name: github.com/spf13/cast
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-07-27 15:37:30 +02:00
dependabot[bot] 31972f3647 build(deps): bump google.golang.org/api from 0.45.0 to 0.51.0
Bumps [google.golang.org/api](https://github.com/googleapis/google-api-go-client) from 0.45.0 to 0.51.0.
- [Release notes](https://github.com/googleapis/google-api-go-client/releases)
- [Changelog](https://github.com/googleapis/google-api-go-client/blob/master/CHANGES.md)
- [Commits](https://github.com/googleapis/google-api-go-client/compare/v0.45.0...v0.51.0)

---
updated-dependencies:
- dependency-name: google.golang.org/api
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-07-27 15:04:20 +02:00
dependabot[bot] 2e58782f96 build(deps): bump github.com/sanity-io/litter from 1.5.0 to 1.5.1
Bumps [github.com/sanity-io/litter](https://github.com/sanity-io/litter) from 1.5.0 to 1.5.1.
- [Release notes](https://github.com/sanity-io/litter/releases)
- [Changelog](https://github.com/sanity-io/litter/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sanity-io/litter/compare/v1.5.0...v1.5.1)

---
updated-dependencies:
- dependency-name: github.com/sanity-io/litter
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-07-27 15:01:24 +02:00
dependabot[bot] 7b68f6524d build(deps): bump github.com/mattn/go-isatty from 0.0.12 to 0.0.13
Bumps [github.com/mattn/go-isatty](https://github.com/mattn/go-isatty) from 0.0.12 to 0.0.13.
- [Release notes](https://github.com/mattn/go-isatty/releases)
- [Commits](https://github.com/mattn/go-isatty/compare/v0.0.12...v0.0.13)

---
updated-dependencies:
- dependency-name: github.com/mattn/go-isatty
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-07-27 14:58:39 +02:00
dependabot[bot] 81265af2cc build(deps): bump github.com/spf13/cobra from 1.1.3 to 1.2.1
Bumps [github.com/spf13/cobra](https://github.com/spf13/cobra) from 1.1.3 to 1.2.1.
- [Release notes](https://github.com/spf13/cobra/releases)
- [Changelog](https://github.com/spf13/cobra/blob/master/CHANGELOG.md)
- [Commits](https://github.com/spf13/cobra/compare/v1.1.3...v1.2.1)

---
updated-dependencies:
- dependency-name: github.com/spf13/cobra
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-07-27 14:05:28 +02:00
dependabot[bot] c102c9719b build(deps): bump github.com/mitchellh/mapstructure from 1.3.3 to 1.4.1
Bumps [github.com/mitchellh/mapstructure](https://github.com/mitchellh/mapstructure) from 1.3.3 to 1.4.1.
- [Release notes](https://github.com/mitchellh/mapstructure/releases)
- [Changelog](https://github.com/mitchellh/mapstructure/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mitchellh/mapstructure/compare/v1.3.3...v1.4.1)

Signed-off-by: dependabot[bot] <support@github.com>
2021-07-27 13:16:44 +02:00
dependabot[bot] 7c0f904f29 build(deps): bump github.com/google/go-cmp from 0.5.5 to 0.5.6
Bumps [github.com/google/go-cmp](https://github.com/google/go-cmp) from 0.5.5 to 0.5.6.
- [Release notes](https://github.com/google/go-cmp/releases)
- [Commits](https://github.com/google/go-cmp/compare/v0.5.5...v0.5.6)

---
updated-dependencies:
- dependency-name: github.com/google/go-cmp
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-07-27 12:42:16 +02:00
dependabot[bot] b2fbd4d13a build(deps): bump github.com/mitchellh/hashstructure from 1.0.0 to 1.1.0
Bumps [github.com/mitchellh/hashstructure](https://github.com/mitchellh/hashstructure) from 1.0.0 to 1.1.0.
- [Release notes](https://github.com/mitchellh/hashstructure/releases)
- [Commits](https://github.com/mitchellh/hashstructure/compare/v1.0.0...v1.1.0)

Signed-off-by: dependabot[bot] <support@github.com>
2021-07-27 12:36:11 +02:00
dependabot[bot] 90041d1b6d build(deps): bump github.com/gobuffalo/flect from 0.2.2 to 0.2.3
Bumps [github.com/gobuffalo/flect](https://github.com/gobuffalo/flect) from 0.2.2 to 0.2.3.
- [Release notes](https://github.com/gobuffalo/flect/releases)
- [Commits](https://github.com/gobuffalo/flect/compare/v0.2.2...v0.2.3)

---
updated-dependencies:
- dependency-name: github.com/gobuffalo/flect
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-07-27 10:07:34 +02:00
dependabot[bot] 05047096f5 build(deps): bump github.com/pelletier/go-toml from 1.9.0 to 1.9.3
Bumps [github.com/pelletier/go-toml](https://github.com/pelletier/go-toml) from 1.9.0 to 1.9.3.
- [Release notes](https://github.com/pelletier/go-toml/releases)
- [Commits](https://github.com/pelletier/go-toml/compare/v1.9.0...v1.9.3)

---
updated-dependencies:
- dependency-name: github.com/pelletier/go-toml
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-07-27 09:37:05 +02:00
dependabot[bot] a469156ea4 build(deps): bump github.com/aws/aws-sdk-go from 1.38.23 to 1.40.8
Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.38.23 to 1.40.8.
- [Release notes](https://github.com/aws/aws-sdk-go/releases)
- [Changelog](https://github.com/aws/aws-sdk-go/blob/main/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-go/compare/v1.38.23...v1.40.8)

---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-07-26 21:21:26 +02:00
dependabot[bot] 18fdd85bcc build(deps): bump github.com/tdewolff/minify/v2 from 2.9.18 to 2.9.19
Bumps [github.com/tdewolff/minify/v2](https://github.com/tdewolff/minify) from 2.9.18 to 2.9.19.
- [Release notes](https://github.com/tdewolff/minify/releases)
- [Commits](https://github.com/tdewolff/minify/compare/v2.9.18...v2.9.19)

---
updated-dependencies:
- dependency-name: github.com/tdewolff/minify/v2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-07-26 20:23:32 +02:00
Bjørn Erik Pedersen aeb1935d44 deps: Update github.com/evanw/esbuild v0.11.16 => v0.12.16 2021-07-26 20:23:00 +02:00
Bjørn Erik Pedersen c7252224c4 Deprecate Blackfriday and fix a potential deadlock in config
Note that the deadlock has not been seen earlier, in tests on in real Hugo sites.

Fixes #8792
Fixes #8791
2021-07-26 16:28:16 +02:00
Bjørn Erik Pedersen e09d7882c8 deps: Update github.com/yuin/goldmark v1.3.9 => v1.4.0 2021-07-26 14:54:56 +02:00
dependabot[bot] 15c0eed048 build(deps): bump github.com/frankban/quicktest from 1.12.0 to 1.13.0
Bumps [github.com/frankban/quicktest](https://github.com/frankban/quicktest) from 1.12.0 to 1.13.0.
- [Release notes](https://github.com/frankban/quicktest/releases)
- [Commits](https://github.com/frankban/quicktest/compare/v1.12.0...v1.13.0)

Signed-off-by: dependabot[bot] <support@github.com>
2021-07-26 11:31:33 +02:00
Bjørn Erik Pedersen 91cbb96302 Bump all long-living deprecations to ERRORs 2021-07-25 17:17:21 +02:00
Digitalcraftsman a352d19d88 Fix theme count in release notes 2021-07-21 16:35:38 +02:00
hugoreleaser 11bb67dcfd releaser: Prepare repository for 0.87.0-DEV
[ci skip]
2021-07-21 11:13:04 +00:00
hugoreleaser 41c6c52ead releaser: Add release notes to /docs for release of 0.86.0
[ci skip]
2021-07-21 09:53:11 +00:00
hugoreleaser d270eaf4fc releaser: Bump versions for release of 0.86.0
[ci skip]
2021-07-21 09:53:11 +00:00
Bjørn Erik Pedersen b2e67505f8 Release 0.86.0 2021-07-21 11:37:16 +02:00
Bjørn Erik Pedersen 32508045d3 navigation: Check Page first in URL()
In Hugo #8776 we added `pageRef`, a way to connect menu items in site config to pages.

This means that you now can have both a Page and a configured URL.

Having the configured URL as a fallback if the Page isn't found is obviously more useful, especially in multilingual sites.

See #8776
2021-07-21 11:36:15 +02:00
Bjørn Erik Pedersen e521c9a36d Update 0.86.0-relnotes.md
[ci skip]
2021-07-21 11:28:32 +02:00
hugoreleaser dfb1cc4315 releaser: Add release notes for 0.86.0
Rename to *-ready.md to continue.
[ci skip]
2021-07-21 09:04:02 +00:00
Bjørn Erik Pedersen 0294a4a4f8 Merge commit '53a352795a69a9d4a373f50ec62138595948c6ea' 2021-07-21 10:45:53 +02:00
Bjørn Erik Pedersen 53a352795a Squashed 'docs/' changes from 6ebb5dad9..60a58d123
60a58d123 Remove outdated references in scss-sass.md
225a03834 Revert "Update menus.md"
7d149dd1e Update menus.md
3694ecafc Fix theme submission process/repository
0277c202c Update index.md - fix typo (#1490)
8921f0462 Fix link to theme components in 0.42 release notes (#1489)
c948bd519 Release 0.85.0
ee5bc5be9 releaser: Add release notes to /docs for release of 0.85.0
f2f692c32 commands: Make the --poll flag a duration
13070337a docs: Regen CLI docs

git-subtree-dir: docs
git-subtree-split: 60a58d123d
2021-07-21 10:45:05 +02:00
Bjørn Erik Pedersen 351ed0f569 commands: Fix panic on invalid config in "hugo mod get" and similar
Fixes #8773
2021-07-20 18:23:09 +02:00
Bjørn Erik Pedersen d831d2fce8 Simplify "active menu" logic for section menus
Fixes #8776
2021-07-20 17:50:59 +02:00
Bjørn Erik Pedersen 634481ba8c Fix Params case handling for menu items defined in site config
Fixes #8775
2021-07-20 17:50:59 +02:00
Bjørn Erik Pedersen c19f65f956 minifiers: Make keepWhitespace = true default for HTML
Fixes #8771
2021-07-19 23:35:20 +02:00
Bjørn Erik Pedersen 022c479551 hugofs: Make FileMeta a struct
This commit started out investigating a `concurrent map read write` issue, ending by replacing the map with a struct.

This is easier to reason about, and it's more effective:

```
name                                  old time/op    new time/op    delta
SiteNew/Regular_Deep_content_tree-16    71.5ms ± 3%    69.4ms ± 5%    ~     (p=0.200 n=4+4)

name                                  old alloc/op   new alloc/op   delta
SiteNew/Regular_Deep_content_tree-16    29.7MB ± 0%    27.9MB ± 0%  -5.82%  (p=0.029 n=4+4)

name                                  old allocs/op  new allocs/op  delta
SiteNew/Regular_Deep_content_tree-16      313k ± 0%      303k ± 0%  -3.35%  (p=0.029 n=4+4)
```

See #8749
2021-07-15 17:14:26 +02:00
rhymes f27e542442 markup: Add tabindex="0" to default <pre> wrapper
Currently the generated `<pre>` element isn't fully accessible as it can't be focused by keyboard users.
To make this fully accessible, the attribute `tabindex="0"` should be added to the `<pre>` tag.

Closes #7194
2021-07-15 16:48:39 +02:00
Bjørn Erik Pedersen ae6cf93c84 Fix default values when loading from config dir
By waiting until we've loaded the config dir config before applying the default values.

Fixes #8763
2021-07-15 16:15:32 +02:00
Bjørn Erik Pedersen a70da2b74a Fix the deprecation error/warn log levels 2021-07-15 12:24:20 +02:00
Bjørn Erik Pedersen 805664818d markup/goldmark: Rename/reorder the hook methods
To make them easier to follow.

See #8755
2021-07-15 10:14:52 +02:00
Bjørn Erik Pedersen ee3d2bb1d3 markup/goldmark: Support auto links in render hook
Fixes #8755
2021-07-15 10:14:52 +02:00
Bjørn Erik Pedersen eb2a500367 Adjust a test helper 2021-07-14 21:47:26 +02:00
Bjørn Erik Pedersen 5cb52c2315 Add config.cascade
This commit adds support for using the `cascade` keyword in your configuration file(s), e.g. `config.toml`.

Note that

* Every feature of `cascade` is available, e.g. `_target` to target specific page sets.
* Pages, e.g. the home page, can overwrite the cascade defined in config.

Fixes #8741
2021-07-10 11:13:41 +02:00
Bjørn Erik Pedersen 30eea3915b resources: Regenerate image golden testdata
Keep this as a separate commit as this isn't because the files have changed. The filenames have changed due to cache busting of PNG and Webp images.

See #8729
2021-07-07 17:25:14 +02:00
Bjørn Erik Pedersen 8f40f34cd1 Fix transparency problem when converting 32-bit images to WebP
Fixes #8729
2021-07-07 17:25:14 +02:00
hugoreleaser 8ddbc95466 releaser: Prepare repository for 0.86.0-DEV
[ci skip]
2021-07-05 11:37:38 +00:00
hugoreleaser 724d5db580 releaser: Add release notes to /docs for release of 0.85.0
[ci skip]
2021-07-05 10:46:25 +00:00
hugoreleaser 875fe4050c releaser: Bump versions for release of 0.85.0
[ci skip]
2021-07-05 10:46:25 +00:00
Bjørn Erik Pedersen 56362e4bc7 Update 0.85.0-relnotes.md 2021-07-05 12:38:14 +02:00
hugoreleaser f5cfb9e251 releaser: Add release notes for 0.85.0
Rename to *-ready.md to continue.
[ci skip]
2021-07-05 10:27:32 +00:00
John Hollowell 04dc469fbd commands: Move time notification to after any build errors
This allows error parsers (VSCode problemMatchers) to use the time notification as bounds for detecting errors.

Closes #8403
2021-07-05 10:38:54 +02:00
Brandon Woodford 07919d1ccb exif: Log warning for metadata decode error
see #8519
2021-07-05 10:31:35 +02:00
Raoul f75f90079a Fix tab selection of disabled items in internal pagination template 2021-07-05 10:30:59 +02:00
Bjørn Erik Pedersen e31b1d1946 commands: Make the --poll flag a duration
So you can do:

```
hugo server --poll 700ms
```

See #8720
2021-07-05 10:23:29 +02:00
Bjørn Erik Pedersen 43a23239b2 docs: Regen CLI docs 2021-07-04 16:35:21 +02:00
Bjørn Erik Pedersen 4479f09c9c Merge commit '7eb0e10a80708c638554b8221a3120dc1168566c' 2021-07-04 16:34:53 +02:00
Bjørn Erik Pedersen 7eb0e10a80 Squashed 'docs/' changes from 710856e5a..6ebb5dad9
6ebb5dad9 Remove file
27cc23ef4 Hugo 0.84.4
94dccbfa4 Merge branch 'tempv0.84.4'
e9d8b61fb releaser: Add release notes to /docs for release of 0.84.4
51e472005 Improve readability of examples on shortcode templates page
0aef26479 Fix lookup order typos (#1484)
534a527fe Fix two typos (#1483)
394aabd5a Higo "0.84.3
03ee92c1c Merge branch 'tempv0.84.3'
96a8be0f1 releaser: Add release notes to /docs for release of 0.84.3
9a770323f Update index.md
7f65cfcbe Hugo 0.84.2
444422515 releaser: Add release notes to /docs for release of 0.84.2
a2f29c5d8 modules: Add module.import.noMounts config
e00e4a7e7 releaser: Add release notes to /docs for release of 0.84.2
af04b53b3 modules: Add module.import.noMounts config
f7d5669c7 Remove Appernetic (#1481)
14f8d4029 Clarify interaction of sections and top-level leaf bundles
d140b6a62 Update lookup-order.md
399904959 Update shortcode-templates.md
e78aa4865 Hugo 0.84.1
35d7c1c22 Merge branch 'tempv0.84.1'
a6be65b0d releaser: Add release notes to /docs for release of 0.84.1
7b3b3ca45 Hugo 0.84.0 News Grammar fixes
cbc23bf5a Remove trailing newlines
69349198d Fix erroridf docs
dbc1157c1 Fix missing deep

git-subtree-dir: docs
git-subtree-split: 6ebb5dad9a
2021-07-04 16:34:26 +02:00
Bjørn Erik Pedersen 24ce98b6d1 Add polling as a fallback to native filesystem events in server watch
Fixes #8720
Fixes #6849
Fixes #7930
2021-07-04 16:12:28 +02:00
Bjørn Erik Pedersen 0019d60f67 deps: Bump github.com/yuin/goldmark v1.3.9
Closes #8727
2021-07-04 15:48:33 +02:00
Bjørn Erik Pedersen e451b984cf Fix panic when theme has permalinks config
Fixes #8724
2021-07-03 15:53:21 +02:00
hugoreleaser b4d60b3db1 releaser: Prepare repository for 0.85.0-DEV
[ci skip]
2021-07-01 12:59:47 +00:00
hugoreleaser 020e4acee4 releaser: Add release notes to /docs for release of 0.84.4
[ci skip]
2021-07-01 11:51:53 +00:00
hugoreleaser 4c34faf426 releaser: Bump versions for release of 0.84.4
[ci skip]
2021-07-01 11:51:53 +00:00
hugoreleaser a339f62664 releaser: Add release notes for 0.84.4
[ci skip]
2021-07-01 11:51:53 +00:00
Bjørn Erik Pedersen 4c8552b114 Fix Cloudflare vs Netlify cache dir issue
Re-add the additional environment checks to determine if its Netlify. Seems that Cloudflare also sets `NETLIFY=true`.

This makes it look, basically, like a variant of the conditional we had before we started fixing this, but I have checked this logic on Netlify now and it should work.

Fixes #8714
2021-06-30 12:58:43 +02:00
Joe Mooring 34e4742f0c Fix date format in schema and opengraph templates
Fixes #8671
2021-06-29 20:20:38 +02:00
hugoreleaser bffa2a2a98 releaser: Prepare repository for 0.85.0-DEV
[ci skip]
2021-06-29 12:27:15 +00:00
hugoreleaser a1b0353ccb releaser: Add release notes to /docs for release of 0.84.3
[ci skip]
2021-06-29 11:40:19 +00:00
hugoreleaser bc6f84c581 releaser: Bump versions for release of 0.84.3
[ci skip]
2021-06-29 11:40:19 +00:00
hugoreleaser 80410257e3 releaser: Add release notes for 0.84.3
[ci skip]
2021-06-29 11:40:19 +00:00
Bjørn Erik Pedersen 6c8c0c8b6a config: Fix Netlify default cache dir logic
Fixes #8710
2021-06-29 09:51:09 +02:00
Bjørn Erik Pedersen 49fedbc51c config: Fix handling of invalid OS env config overrides
Fixes #8709
2021-06-29 09:38:05 +02:00
hugoreleaser 8290720107 releaser: Prepare repository for 0.85.0-DEV
[ci skip]
2021-06-28 11:41:38 +00:00
hugoreleaser e0c67958f1 releaser: Add release notes to /docs for release of 0.84.2
[ci skip]
2021-06-28 10:59:18 +00:00
hugoreleaser f6b9ce6ebd releaser: Bump versions for release of 0.84.2
[ci skip]
2021-06-28 10:59:18 +00:00
hugoreleaser 4b03399b78 releaser: Add release notes for 0.84.2
[ci skip]
2021-06-28 10:59:18 +00:00
Bjørn Erik Pedersen 40dfdd0952 modules: Add module.import.noMounts config
Fixes #8708
2021-06-28 10:39:52 +02:00
Bjørn Erik Pedersen 3a6dc6d3f4 modules: Use value type for module.Time
Which is in line with how we do it elsewhere.
2021-06-27 18:06:52 +02:00
Bjørn Erik Pedersen 6cd2110ab2 commands: Add version time to "hugo config mounts" 2021-06-27 18:00:20 +02:00
Bjørn Erik Pedersen 6a365c2712 commands: Add some more info to "hugo config mounts"
* Add owner path and version.
* Also add thme meta info and Hugo version when run with -v flag
2021-06-27 16:08:28 +02:00
Bjørn Erik Pedersen 19aa95fc7f Fix config handling with empty config entries after merge
Fixes #8701
2021-06-27 15:01:56 +02:00
Bjørn Erik Pedersen 923dd9d1c1 Fix config loading for "hugo mod init"
We have some commands that will continue even if the config loading fails (e.g. because a module can not be found). In Hugo 0.84.0 we introduced a new `_merge` flag that we removed once the configuration was loaded. But we did not do that in error situations, leading to failures in some situations.

This commit fixes that by making sure the configuration is always cleaned before return, even in error situations.

Fixes #8697
2021-06-27 12:03:43 +02:00
Bjørn Erik Pedersen d9bdd37d35 deps: Update to Minify v2.9.18
Closes #8693
2021-06-26 17:15:55 +02:00
digitalcraftsman b2eaf4c8c2 Remove credit from release notes 2021-06-25 21:14:11 +02:00
hugoreleaser efb6ee6c1c releaser: Prepare repository for 0.85.0-DEV
[ci skip]
2021-06-24 12:33:45 +00:00
hugoreleaser 4bd65e224f releaser: Add release notes to /docs for release of 0.84.1
[ci skip]
2021-06-24 11:44:21 +00:00
hugoreleaser ff2266300a releaser: Bump versions for release of 0.84.1
[ci skip]
2021-06-24 11:44:21 +00:00
hugoreleaser 8677cfb04f releaser: Add release notes for 0.84.1
[ci skip]
2021-06-24 11:44:21 +00:00
Bjørn Erik Pedersen 093dacab29 Fix language menu config regression
Fixes #8672
2021-06-24 13:03:09 +02:00
Bjørn Erik Pedersen 4a9d408fe0 config: Fix merge of config with map[string]string values.
Fixes #8679
2021-06-22 21:38:28 +02:00
Bjørn Erik Pedersen 9312059888 releaser: Bump to Goreleaser v0.171.0
Closes #8665
2021-06-21 16:12:18 +02:00
Bjørn Erik Pedersen a7e3da242f markup: Rename Header(s) to Heading(s) in ToC struct
Because that is what it is.
2021-06-19 18:19:46 +02:00
Bjørn Erik Pedersen b70a12ec45 Merge commit '4dd90050f154c91373329a5d7e348289c40be12f' 2021-06-18 17:50:27 +02:00
Bjørn Erik Pedersen 4dd90050f1 Squashed 'docs/' changes from 3a923e155..710856e5a
710856e5a Release 0.84.0
362f4ea7b releaser: Add release notes to /docs for release of 0.84.0
6bb8800f7 docs: Regenerate docs helper
00a522e6a docs: Regenerate docshelper
bc171954b Merge commit '92405e5b0adc5d8c3dfde88d6a8b67eb09169190'
ef73ffc3b Misc config loading fixes
0b4117f7f docs: Regenerate docs helper
9b9452b9c Merge commit '32ba623541d74ee0b7ae4efb1b8326dc49af28b8'
9c4413dd9 tpl/fmt: Add erroridf template func
e1875742e tpl/data: Misc header improvements, tests, allow multiple headers of same key
e4560893c Add math.Max and math.Min
7dc282eaf common/maps: Add Scratch.DeleteInMap
b9cd77171 docs: Update querify function description and examples

git-subtree-dir: docs
git-subtree-split: 710856e5a6
2021-06-18 17:49:54 +02:00
hugoreleaser 3d544c9ae4 releaser: Prepare repository for 0.85.0-DEV
[ci skip]
2021-06-18 15:36:43 +00:00
hugoreleaser 2c4689f7b8 releaser: Add release notes to /docs for release of 0.84.0
[ci skip]
2021-06-18 14:55:51 +00:00
hugoreleaser 9c0860f749 releaser: Bump versions for release of 0.84.0
[ci skip]
2021-06-18 14:55:51 +00:00
Bjørn Erik Pedersen a1694b06af releaser: Increase timeout 2021-06-18 16:44:12 +02:00
hugoreleaser 219ec38007 releaser: Add release notes for 0.84.0 2021-06-18 14:42:14 +02:00
Bjørn Erik Pedersen be6b901cf7 docs: Regenerate docs helper 2021-06-18 13:21:10 +02:00
Bjørn Erik Pedersen 643b671931 output: Make WebAppManifestFormat NotAlternative=true
Updates #8624
2021-06-18 13:19:37 +02:00
Bjørn Erik Pedersen ab4e1dfa4e media: Adjust test assertion
Closes #8625
2021-06-18 13:15:00 +02:00
Rohan Kumar 02f31897b4 media: support application/manifest+json
The standard file extension for Web App Manifest files is
".webmanifest". This commit allows Hugo to recognize .webmanifest files
as "application/manifest+json" files and to minify them using its
JSON minifier.

The .webmanifest file extension is recommended in the w3c spec to
simplify media type registration:
https://www.w3.org/TR/appmanifest/#media-type-registration

Webhint docs are also relevant:
https://webhint.io/docs/user-guide/hints/hint-manifest-file-extension/

Closes #8624
2021-06-18 13:11:44 +02:00
Bjørn Erik Pedersen 402da3f8f3 docs: Regenerate docshelper 2021-06-18 12:58:07 +02:00
Bjørn Erik Pedersen 92405e5b0a Squashed 'docs/' changes from 4c81c6c2a..3a923e155
3a923e155 Update configuration.md

git-subtree-dir: docs
git-subtree-split: 3a923e1550
2021-06-18 12:57:19 +02:00
Bjørn Erik Pedersen a074f758b0 Merge commit '92405e5b0adc5d8c3dfde88d6a8b67eb09169190' 2021-06-18 12:57:19 +02:00
Bjørn Erik Pedersen bb2aa08709 Implement configuration in a directory for modules
Fixes #8654
2021-06-18 12:54:30 +02:00
Bjørn Erik Pedersen 9096842b04 tpl: Rename err-missing-instagram-accesstoken => error-missing-instagram-accesstoken
To get it in line with the other.
2021-06-18 12:27:37 +02:00
Bjørn Erik Pedersen 3aa7f0b27f deps: Update github.com/alecthomas/chroma v0.9.1 => v0.9.2
Closes #8658
2021-06-18 12:14:52 +02:00
Bjørn Erik Pedersen 9b870aa788 deps: Run go mod tidy 2021-06-18 12:13:17 +02:00
Bjørn Erik Pedersen 93aad3c543 Split out the puthe path/filepath functions into common/paths
So they can be used from the config package without cyclic troubles.

Updates #8654
2021-06-18 10:55:00 +02:00
Bjørn Erik Pedersen 5af045ebab resources/image: Fix fill with smartcrop sometimes returning 0 bytes images
Fixes #7955
2021-06-17 23:52:27 +02:00
Joe Mooring 8eafe0845d deps: Update to Goldmark v1.3.8
Fixes #8648
2021-06-17 19:34:26 +02:00
Bjørn Erik Pedersen 31fb29fb3f Do not read config from os.Environ when running tests
Fixes #8655
2021-06-16 18:58:40 +02:00
Bjørn Erik Pedersen d392893cd7 Misc config loading fixes
The main motivation behind this is simplicity and correctnes, but the new small config library is also faster:

```
BenchmarkDefaultConfigProvider/Viper-16         	  252418	      4546 ns/op	    2720 B/op	      30 allocs/op
BenchmarkDefaultConfigProvider/Custom-16        	  450756	      2651 ns/op	    1008 B/op	       6 allocs/op
```

Fixes #8633
Fixes #8618
Fixes #8630
Updates #8591
Closes #6680
Closes #5192
2021-06-14 17:00:32 +02:00
Bjørn Erik Pedersen a886dd53b8 github: Set a dummy Instagram token
For now, need to debug why this fails.
2021-06-13 11:09:50 +02:00
Bjørn Erik Pedersen a91cd7652f docs: Regenerate docs helper 2021-06-08 18:52:38 +02:00
Bjørn Erik Pedersen 162f41d0ef Merge commit '32ba623541d74ee0b7ae4efb1b8326dc49af28b8' 2021-06-08 18:47:53 +02:00
Bjørn Erik Pedersen 32ba623541 Squashed 'docs/' changes from bcc4f9324..4c81c6c2a
4c81c6c2a live reload: add section about `--navigateToChanged`
271014257 Update netify hugo version to 0.83.1
14199cff1 Add pull_request event
0c33b05de Hosting on GitHub: Little wording fixes and update Ubuntu runner in example workflow to 20.04 (#1457)
e47b6c33a Hugo Modules plural typo (#1266)
0f2bbacdd Add node_modules to .gitignore
1d645d79f Overhaul scratch.md (#1451)
572766889 Add link to golang regex syntax, change modified date
21b0c7459 Add info about contentType config
de7d96fa2 Document Go template's multiline support
0c8f2dcb1 Avoid scratch usage
696fa92e1 Rename scratch var
44193f267 Update usage instructions
4230f8fa5 Rename and refactor shortcode
e9953751e Strip leading whitespaces
d61a58010 Add `insertpages` shortcode
04d30677d Mention WebP under 'Target Format' (#1431)
946784508 Update lookup-order.md (#1443)
a7b587988 Update index.md
27907f7ea netlify: Hugo 0.83.1
044d37e57 Merge branch 'tempv0.83.1'
b81aedb03 Fix page `.Kind`
fcf7775ad releaser: Add release notes to /docs for release of 0.83.1
9b39c77c8 fix typo in 0.83 release notes
1c38993ce Update index.md
45b8aefa6 Update index.md
43902dfaa Update index.md
3d959c7ae Merge branch 'tempv0.83.0'
6c22dc327 Fix URL
497ea3224 Use Hugo version badge shortcode
a182d10dd releaser: Add release notes to /docs for release of 0.83.0
287fd9ac0 docs: Fix shortcode
e789c879a docs: Regenerate docs helper
1666c7f31 docs: Regenerate CLI docs
117de1d12 Merge commit 'c239c643fee10bfa217cb108755b798f8f5f3b10'
a6bf3f7d9 docs: Regen docs helper

git-subtree-dir: docs
git-subtree-split: 4c81c6c2ac
2021-06-08 18:46:58 +02:00
Bjørn Erik Pedersen 552cef5c57 Update to Go 1.16.5, Goreleaser 0.169.0
Fixes #8619
Fixes #8263
2021-06-08 18:46:35 +02:00
Joe Mooring 73483d0f9e tpl: Add a terse pagination template variant to improve performance
These calls are equivalent:

{{ template "_internal/pagination.html" . }}
{{ template "_internal/pagination.html" (dict "page" .) }}
{{ template "_internal/pagination.html" (dict "page" . "format" "default") }}

To use an alternate format:

{{ template "_internal/pagination.html" (dict "page" . "format" "terse") }}

Fixes #8599
2021-06-08 10:41:21 +02:00
Bjørn Erik Pedersen 9b5debe4b8 Upgrade Instagram shortcode
Fixes #7879
2021-06-08 10:30:45 +02:00
Bjørn Erik Pedersen 12530519d8 Fix nested OS env config override when parent does not exist
Fixes #8618
2021-06-08 09:57:18 +02:00
Bjørn Erik Pedersen f55d2f4376 tpl/fmt: Add erroridf template func
Fixes #8613
2021-06-07 19:11:03 +02:00
Bjørn Erik Pedersen 282f1aa3db tpl/data: Print response body on HTTP errors
Which makes it easier to debug.
2021-06-07 12:06:27 +02:00
Bjørn Erik Pedersen fcd63de3a5 tpl/data: Misc header improvements, tests, allow multiple headers of same key
Closes #5617
2021-06-06 13:32:12 +02:00
Paul Chamberlain 150d75738b tpl/data: Allows user-defined HTTP headers with getJSON and getCSV
Updates #5617
2021-06-06 13:32:12 +02:00
Bjørn Erik Pedersen 06d295427f hugofs: Set modTime at creation time
As `ModTime()` should return the same value on each invocation.

See #6161
2021-06-05 11:45:56 +02:00
Anthony Fok 26ae12c0c6 Fix invalid timestamp of the "public" folder
Special thanks to both Richard Mortimer (@oldelvet) and
Joshua M. Clulow (@jclulow) for their analysis and suggested fix:

 * https://github.com/gohugoio/hugo/issues/6161#issuecomment-574336088
 * https://github.com/gohugoio/hugo/issues/6161#issuecomment-596805273

Fixes #6161
2021-06-04 14:50:30 -06:00
卜木 ee733085b7 config: Fix env split to allow = character in values
Fixes #8589
2021-05-30 20:25:37 +02:00
Joe Mooring 01758f99b9 Add math.Max and math.Min
Closes #8583
2021-05-28 20:38:45 +02:00
satotake 845a7ba4fc Catch incomplete shortcode error
Currently, no name shortcodes (`{{< >}}`) enter unexpected branch and
throw `BUG: template info not set`. This patch checks if shortcode has
name or not earlier and throws specific error.

Closes #6866
2021-05-24 14:59:02 +02:00
Joe Mooring 10f60de89a Use SPDX license identifier
See <https://spdx.org/licenses/>
Fixes #8555
2021-05-24 11:54:46 +02:00
satotake 785a31b5b8 navigation: Cache and copy Menu for sorting
.Site.Menus is mutated when it is sorted for now and this causes concurrency problem (#7594)
In this patch, each related sort function copies Menu before sorting to prevent
race condition.

Pages already have such a sort and cache logic and this patch is identical to it.

Closes #7594
2021-05-23 10:42:01 +02:00
Bjørn Erik Pedersen bc1e05286a deps: Update to LibSASS 3.6.5
See https://github.com/sass/libsass/releases/tag/3.6.5
2021-05-23 10:33:56 +02:00
Bjørn Erik Pedersen f518b4f71e publisher: Make the HTML element collector more robust
Fixes #8530
2021-05-19 20:43:49 +02:00
Bjørn Erik Pedersen dc6b7a75ff Revert "publisher: Make the HTML element collector more robust"
This reverts commit ef0f1a7269.
2021-05-19 03:45:36 +02:00
Bjørn Erik Pedersen 3f515f0e33 Revert "publisher: Get the collector in line with the io.Writer interface"
This reverts commit a9bcd38181.
2021-05-19 03:45:30 +02:00
Bjørn Erik Pedersen a9bcd38181 publisher: Get the collector in line with the io.Writer interface
As in: Do not retain the input slice.
2021-05-17 19:39:40 +02:00
Bjørn Erik Pedersen ef0f1a7269 publisher: Make the HTML element collector more robust
Fixes #8530
2021-05-17 17:15:32 +02:00
meehawk abbc99d4c6 common/maps: Add Scratch.DeleteInMap
Add Scratch.DeleteInMap method. This method works similar to Scratch.SetInMap. It takes in two string parameters, key and mapKey and deletes the value mapped to mapKey in key

Closes #8504
2021-05-17 15:45:33 +02:00
Joe Mooring 76c95f55a5 Display version when building site (#8533)
Closes #8531
2021-05-14 16:45:13 +02:00
Joe Mooring 2c7f5b62f6 docs: Update querify function description and examples
The querify function now accepts a slice per #8305.
2021-05-10 17:18:37 +02:00
Ujjwal Goyal c46fc838a9 tpl: Allow 'Querify' to take lone slice/interface argument
Querify can now take a lone string/interface slice (with string
keys) as a parameter, or multiple string parameters, to build
URL queries.

Querify earlier used 'Dictionary' to add key/value pairs to a
map to build URL queries. Changed to dynamically generate ordered
key/value pairs. Cannot take string slice as key (earlier
possible due to Dictionary).

Added tests and benchmarks for querify.

Closes #6735
2021-05-09 13:14:14 +02:00
Shohei Ueda 504c78da4b modules/npm: Change SetEscapeHTML to false
Closes #8512
2021-05-09 00:20:28 +02:00
Bjørn Erik Pedersen b660ea8d54 Add a benchmark 2021-05-04 17:59:04 +02:00
Bjørn Erik Pedersen 64f88f3011 readme: Update dependency list 2021-05-03 15:55:28 +02:00
Julien Midedji 7a2c10ae60 tpl: Fix countwords to handle special chars
Fixes #8479
2021-05-03 09:10:06 +02:00
hugoreleaser e1c328df25 releaser: Prepare repository for 0.84.0-DEV
[ci skip]
2021-05-02 15:28:40 +00:00
hugoreleaser 5afe0a57d0 releaser: Add release notes to /docs for release of 0.83.1
[ci skip]
2021-05-02 14:38:02 +00:00
hugoreleaser 8900e33918 releaser: Bump versions for release of 0.83.1
[ci skip]
2021-05-02 14:38:02 +00:00
hugoreleaser 9753e1b9c5 releaser: Add release notes for 0.83.1
[ci skip]
2021-05-02 14:38:02 +00:00
Bjørn Erik Pedersen ececd1b122 langs/i18n: Fix warning regression in i18n
Fix this by

1. Making sure that only numerical values are treated as plural counts
2. Making sure that `i18n.pluralFormNotFoundError` is not logged as a warning if `other` resolved.

Note that 2. isn't a new problem, but became visible because of the plural improvements in Hugo `0.83.0`.

Fixes #8492
2021-05-02 16:27:22 +02:00
hugoreleaser b0ca723eb2 releaser: Prepare repository for 0.84.0-DEV
[ci skip]
2021-05-01 12:56:59 +00:00
hugoreleaser 4c65ceccc7 releaser: Add release notes to /docs for release of 0.83.0
[ci skip]
2021-05-01 12:10:05 +00:00
hugoreleaser 57a471a0db releaser: Bump versions for release of 0.83.0
[ci skip]
2021-05-01 12:10:05 +00:00
Bjørn Erik Pedersen 9b63af55bd Update 0.83.0-relnotes.md 2021-05-01 13:53:25 +02:00
Bjørn Erik Pedersen 23fc65832c docs: Fix shortcode 2021-05-01 13:01:23 +02:00
hugoreleaser e7b5e36e04 releaser: Add release notes for 0.83.0
Rename to *-ready.md to continue.
[ci skip]
2021-05-01 10:23:21 +00:00
Bjørn Erik Pedersen a9b52b4175 docs: Regenerate docs helper 2021-05-01 12:06:24 +02:00
Bjørn Erik Pedersen b073a1c972 docs: Regenerate CLI docs 2021-05-01 12:05:31 +02:00
Bjørn Erik Pedersen 4227cc1bd3 commands: Remove all dates from gendoc
It creates lots of diffs even if there are no changes.
2021-05-01 12:03:56 +02:00
Bjørn Erik Pedersen c239c643fe Squashed 'docs/' changes from fb551cc75..bcc4f9324
bcc4f9324 Add transparent background in rgba for search field
fce835fea Trim newlines from .Inner in the 'code' shortcode
9117f54b3 Remove code toggle from netlify.toml
babbb9090 fix version number - 404 error
d28cf15e1 The input search is not displayed correctly in Safari because of the one declaration CSS background property. Safari needs the no-repeat to be after position and size property. Adjusting the search icon to be vertically on center.
f4ef4c146 Repairing link from issue 131 using jamesrhea's comment https://github.com/gohugoio/hugoDocs/issues/131#issuecomment-324083739
7f73f5685 Update related.md (#1436)
41d24297c Mention `not` (#1432)

git-subtree-dir: docs
git-subtree-split: bcc4f93242
2021-05-01 11:45:45 +02:00
Bjørn Erik Pedersen d7b22aee46 Merge commit 'c239c643fee10bfa217cb108755b798f8f5f3b10' 2021-05-01 11:45:45 +02:00
Bjørn Erik Pedersen 3cc4fdd6f3 deps: Update getkin/kin-openapi v0.60.0 => v0.61. 2021-04-30 14:27:21 +02:00
Bjørn Erik Pedersen 7eb80a9e6f langs/i18n: Fix multiple unknown language codes
This fixes a bug upstream by temporarily using a patched version of go-i18n.

Closes #7838
2021-04-30 14:26:49 +02:00
Bjørn Erik Pedersen 78c1a6a7c6 deps: Update github.com/evanw/esbuild v0.11.14 => v0.11.16 2021-04-30 12:43:39 +02:00
Joe Mooring f6745ad358 Remove .Site.Authors from embedded templates
Closes #4458
2021-04-29 17:07:05 +02:00
Robert van Gent f523e9f0fd deploy: Don't treat a NotFound response for Delete as a fatal error. 2021-04-29 07:07:01 +02:00
Anthony Fok 63cd05ce5a snap: Switch to deb packages of nodejs and python3-pygments
node/14/stable snap package is not available on ppc64el and s390x.

nodejs deb package currently at 10.19.0~dfsg-3ubuntu1
in Ubuntu 20.04 LTS (base: core20)
2021-04-27 09:04:24 -06:00
Anthony Fok 902535ef11 snapcraft.yaml: Install bin/node from node/14/stable
Resolves regression introduced in my previous commit 243951e.
Special thanks to @jmooring for reporting the issue!

TODO: Strip the bin/node binary?
2021-04-26 10:17:44 -06:00
dependabot[bot] 70aebba04d build(deps): bump github.com/getkin/kin-openapi from 0.55.0 to 0.60.0
Bumps [github.com/getkin/kin-openapi](https://github.com/getkin/kin-openapi) from 0.55.0 to 0.60.0.
- [Release notes](https://github.com/getkin/kin-openapi/releases)
- [Commits](https://github.com/getkin/kin-openapi/compare/v0.55.0...v0.60.0)

Signed-off-by: dependabot[bot] <support@github.com>
2021-04-26 10:56:48 +02:00
dependabot[bot] 3e3b7d4474 build(deps): bump github.com/evanw/esbuild from 0.11.13 to 0.11.14
Bumps [github.com/evanw/esbuild](https://github.com/evanw/esbuild) from 0.11.13 to 0.11.14.
- [Release notes](https://github.com/evanw/esbuild/releases)
- [Changelog](https://github.com/evanw/esbuild/blob/master/CHANGELOG.md)
- [Commits](https://github.com/evanw/esbuild/compare/v0.11.13...v0.11.14)

Signed-off-by: dependabot[bot] <support@github.com>
2021-04-26 10:56:03 +02:00
Bjørn Erik Pedersen c13d368746 resources/page: Fix permalinks pattern detection for some of the sections variants
See #8363
2021-04-25 16:57:09 +02:00
Carlos Alexandro Becker 048418ba74 deps: Update to Chroma v0.9.1 2021-04-25 11:14:25 +02:00
Bjørn Erik Pedersen eebde0c2ac langs/i18n: Improve plural handling of floats
The go-i18n library expects plural counts with floats to be represented as strings.

Fixes #8464
2021-04-25 11:12:30 +02:00
Bjørn Erik Pedersen e4dc9a82b5 tpl/collections: Fix where on type mismatches
Fixes #8353
2021-04-23 18:06:49 +02:00
Bjørn Erik Pedersen 0d86a32d8f Make the shortcode template lookup for output formats stable
Fixes #7774
2021-04-23 15:04:35 +02:00
dependabot[bot] 65c502cc81 build(deps): bump github.com/evanw/esbuild from 0.11.12 to 0.11.13
Bumps [github.com/evanw/esbuild](https://github.com/evanw/esbuild) from 0.11.12 to 0.11.13.
- [Release notes](https://github.com/evanw/esbuild/releases)
- [Changelog](https://github.com/evanw/esbuild/blob/master/CHANGELOG.md)
- [Commits](https://github.com/evanw/esbuild/compare/v0.11.12...v0.11.13)

Signed-off-by: dependabot[bot] <support@github.com>
2021-04-23 09:03:16 +02:00
Bjørn Erik Pedersen 537c905ec1 langs/i18n: Revise the plural implementation
There were some issues introduced with the plural counting when we upgraded from v1 to v2 of go-i18n.

This commit improves that situation given the following rules:

* A single integer argument is used as plural count and passed to the i18n template as a int type with a `.Count` method. The latter is to preserve compability with v1.
* Else the plural count is either fetched from the `Count`/`count` field/method/map or from the value itself.
* Any data type is accepted, if it can be converted to an integer, that value is used.

The above means that you can now do pass a single integer and both of the below will work:

```
{{ . }} minutes to read
{{ .Count }} minutes to read
```

Fixes #8454
Closes #7822
See https://github.com/gohugoio/hugoDocs/issues/1410
2021-04-23 07:39:59 +02:00
Anthony Fok 243951ebe9 snapcraft.yaml: Update to "base: core20"
That is, switch to using Ubuntu 20.04 LTS as base,
leveraging new features in Snapcraft 4.x, etc.

It is far from complete, with npm temporarily disabled (hence no PostCSS)
and with Pandoc probably not working yet, but would hopefully get our
Hugo Snap build, which stopped working shortly after v0.80.0, working again.
2021-04-22 09:57:40 -06:00
dependabot[bot] fe2ee02802 build(deps): bump github.com/frankban/quicktest from 1.11.3 to 1.12.0
Bumps [github.com/frankban/quicktest](https://github.com/frankban/quicktest) from 1.11.3 to 1.12.0.
- [Release notes](https://github.com/frankban/quicktest/releases)
- [Commits](https://github.com/frankban/quicktest/compare/v1.11.3...v1.12.0)

Signed-off-by: dependabot[bot] <support@github.com>
2021-04-22 15:24:15 +02:00
dependabot[bot] 316d65cd70 build(deps): bump google.golang.org/api from 0.44.0 to 0.45.0
Bumps [google.golang.org/api](https://github.com/googleapis/google-api-go-client) from 0.44.0 to 0.45.0.
- [Release notes](https://github.com/googleapis/google-api-go-client/releases)
- [Changelog](https://github.com/googleapis/google-api-go-client/blob/master/CHANGES.md)
- [Commits](https://github.com/googleapis/google-api-go-client/compare/v0.44.0...v0.45.0)

Signed-off-by: dependabot[bot] <support@github.com>
2021-04-22 13:43:11 +02:00
dependabot[bot] b95229ab49 build(deps): bump github.com/aws/aws-sdk-go from 1.37.11 to 1.38.23
Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.37.11 to 1.38.23.
- [Release notes](https://github.com/aws/aws-sdk-go/releases)
- [Changelog](https://github.com/aws/aws-sdk-go/blob/main/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-go/compare/v1.37.11...v1.38.23)

Signed-off-by: dependabot[bot] <support@github.com>
2021-04-22 13:42:15 +02:00
Santiago De la Cruz 0551df090e Correct function name in comment
IsInt to IsNumber
2021-04-22 12:24:12 +02:00
Bjørn Erik Pedersen bca40cf0c9 Fix Params case handling in where with slices of structs (e.g. Pages)
Fixes #7009
2021-04-21 19:28:18 +02:00
Bjørn Erik Pedersen 057e5a22af deps: Upgraded github.com/evanw/esbuild v0.11.0 => v0.11.12 2021-04-21 13:07:16 +02:00
Bjørn Erik Pedersen fd96f65a3d docs: Regen docs helper 2021-04-20 20:23:36 +02:00
Bjørn Erik Pedersen 8f7891e70c Merge commit '07b8d9466dfb59c429c1b470a0443337bc0aeefe' 2021-04-20 20:22:53 +02:00
Bjørn Erik Pedersen 07b8d9466d Squashed 'docs/' changes from 9cece6640..fb551cc75
fb551cc75 Update index.md
7af894857 Update index.md
d235753ea Hugo 0.82.1
e03e72deb Merge branch 'temp0821'
e62648961 Merge branch 'release-0.82.1'
e1ab0f6eb releaser: Add release notes to /docs for release of 0.82.1
5d354c38d Replaced ``` code blocks with Code Toggler
c9d065c20 Remove duplicate YAML keys (#1420)
8ae31e701 Add webp image encoding support
848f2af26 Update internal.md (#1407)
c103a86a4 Fix `ref` shortcode example output (#1409)
9f8ba56dc Remove leading dot from where function KEY (#1419)
363251a51 Improve presentation of template lookup order (#1382)
b73da986d Improve description of Page Resources (#1381)
4e0bb96d5 Rework robots.txt page (#1405)
edf893e6f Update migrations.md (#1412)
450f1580b Add link to `site` function doc (#1417)
cfffa6e6f Added one extension to the list (#1414)
05f1665a0 Update theme
5de0b1c6a Update theme
250e20552 Add hugo.IsExtended
dea5e1fd7 Fix typo on merge function page (#1408)
1bbed2cf3 Update configuration.md
be0b64a46 Omit ISO
cbb5b8367 Fix `dateFormat` documentation
698f15466 Regenerate the docshelper
f9a8a7cb6 Update multilingual.md
a22dc6267 Fix grammar (#1398)
eb98b0997 Fix pretty URL example (#1397)
f4c4153dc Mention date var complementation in post scheduling (#1396)
17fae284c Fix resources.ExecuteAsTemplate argument order (#1394)
97e2c2abb Use code-toggle shortcode in `multilingual.md` (#1388)
3a84929bb Harmonize capitalization (#1393)
17f15daa6 fix file naming used in example (#1392)
5d97b6a18 Add slice syntax to sections permalinks config
00665b97b Improve description of `site.md`
edcf5e3fc Fix example in `merge.md`
f275ab778 Update postprocess.md
9593e3991 Fix file name
59bd9656f Update postprocess.md
1172fb6d0 Update to theNewDynamic repository (#1263)
f5b5c1d2c Update Hugo container image
4f2e92f2a Adapt anchorize.md to Goldmark
98aa19073 Directly link to `highlight` shortcode (#1384)
4c75c2422 Fix header level
f15c06f23 markdownify: add note about render-hooks and .RenderString (#1281)
69c82eb68 Remove Blackfriday reference from shortcode desc (#1380)
36de478df Update description of ignoreFiles config setting (#1377)
6337699d8 Remove "Authors" page from documentation (#1371)
35e73ca90 fix indent in example (#1372)
d3f01f19a Remove opening body tag from header example (#1376)
341a5a7d8 Update index.md
c9bfdbee6 Release 0.82.0
119644949 releaser: Add release notes to /docs for release of 0.82.0
32efaed78 docs: Regenerate docs helper
dea5449a2 docs: Regen CLI docs
eeab18fce Merge commit '81689af79901f0cdaff765cda6322dd4a9a7ccb3'
d508a1259 Attributes for code fences should be placed after the lang indicator only
c80905cef deps: Update to esbuild v0.9.0
95350eb79 Add support for Google Analytics v4
02d36f9bc Allow markdown attribute lists to be used in title render hooks
7df220a64 Merge commit '9d31f650da964a52f05fc27b7fb99cf3e09778cf'
d80bf61b7 Fixes #7698.

git-subtree-dir: docs
git-subtree-split: fb551cc750
2021-04-20 20:21:45 +02:00
dependabot[bot] d3a64708f4 build(deps): bump github.com/tdewolff/minify/v2 from 2.9.15 to 2.9.16
Bumps [github.com/tdewolff/minify/v2](https://github.com/tdewolff/minify) from 2.9.15 to 2.9.16.
- [Release notes](https://github.com/tdewolff/minify/releases)
- [Commits](https://github.com/tdewolff/minify/compare/v2.9.15...v2.9.16)

Signed-off-by: dependabot[bot] <support@github.com>
2021-04-20 19:19:07 +02:00
dependabot[bot] 3b56244f42 build(deps): bump golang.org/x/text from 0.3.5 to 0.3.6
Bumps [golang.org/x/text](https://github.com/golang/text) from 0.3.5 to 0.3.6.
- [Release notes](https://github.com/golang/text/releases)
- [Commits](https://github.com/golang/text/compare/v0.3.5...v0.3.6)

Signed-off-by: dependabot[bot] <support@github.com>
2021-04-20 18:06:30 +02:00
Bjørn Erik Pedersen f5d3d635e6 publisher: Remove some unreachable code 2021-04-20 17:47:09 +02:00
dependabot[bot] 0d3c42da56 build(deps): bump github.com/getkin/kin-openapi from 0.39.0 to 0.55.0
Bumps [github.com/getkin/kin-openapi](https://github.com/getkin/kin-openapi) from 0.39.0 to 0.55.0.
- [Release notes](https://github.com/getkin/kin-openapi/releases)
- [Commits](https://github.com/getkin/kin-openapi/compare/v0.39.0...v0.55.0)

Signed-off-by: dependabot[bot] <support@github.com>
2021-04-20 17:34:05 +02:00
Bjørn Erik Pedersen ef34dd8f0e publisher: Some performance tweaks for the HTML elements collector 2021-04-20 17:24:17 +02:00
Dirk Olbrich bc80022e03 publisher: Exclude comment and doctype elements from writeStats
- Reorder code blocks
- Rename cssClassCollectorWriter to htmlElementCollectorWriter, as it just collect html element information
- Expand benchmark to test for minified and unminified content

Fixes #8396
Fixes #8417
2021-04-20 17:24:17 +02:00
Bjørn Erik Pedersen 2bb9496ce2 Merge branch 'release-0.82.1' 2021-04-20 13:48:04 +02:00
hugoreleaser fda3c4d1ed releaser: Prepare repository for 0.83.0-DEV
[ci skip]
2021-04-20 11:44:34 +00:00
hugoreleaser 60618210b8 releaser: Add release notes to /docs for release of 0.82.1
[ci skip]
2021-04-20 11:02:48 +00:00
hugoreleaser f8b064f3c0 releaser: Bump versions for release of 0.82.1
[ci skip]
2021-04-20 11:02:48 +00:00
hugoreleaser 4713e509b6 releaser: Add release notes for 0.82.1
[ci skip]
2021-04-20 11:02:48 +00:00
Bjørn Erik Pedersen 6e9d2bf0c9 Regression in media type suffix lookup
Introduced in Hugo 0.82.0.

Fixes #8406
2021-04-20 12:52:30 +02:00
Bjørn Erik Pedersen e73f7a770d Regression in media type suffix lookup
Introduced in Hugo 0.82.0.

Fixes #8406
2021-04-20 12:51:11 +02:00
Joe Mooring 3ddffd064d build(deps): bump github.com/yuin/goldmark from 1.3.2 to 1.3.5
Updated test per <https://github.com/yuin/goldmark/pull/205>.

Fixes #8377
2021-04-16 09:12:28 +02:00
Joe Mooring 6fc52d185a Remove duplicate references from release notes
Closes #8360
2021-04-15 21:15:20 +02:00
dependabot[bot] 73c3ae818a build(deps): bump github.com/spf13/afero from 1.5.1 to 1.6.0
Bumps [github.com/spf13/afero](https://github.com/spf13/afero) from 1.5.1 to 1.6.0.
- [Release notes](https://github.com/spf13/afero/releases)
- [Commits](https://github.com/spf13/afero/compare/v1.5.1...v1.6.0)

Signed-off-by: dependabot[bot] <support@github.com>
2021-04-15 21:08:33 +02:00
dependabot[bot] 7ca118fdfd build(deps): bump github.com/pelletier/go-toml from 1.8.1 to 1.9.0
Bumps [github.com/pelletier/go-toml](https://github.com/pelletier/go-toml) from 1.8.1 to 1.9.0.
- [Release notes](https://github.com/pelletier/go-toml/releases)
- [Commits](https://github.com/pelletier/go-toml/compare/v1.8.1...v1.9.0)

Signed-off-by: dependabot[bot] <support@github.com>
2021-04-15 21:05:43 +02:00
Bjørn Erik Pedersen 33d5f80592 Add webp image encoding support
Fixes #5924
2021-04-15 17:22:55 +02:00
dependabot[bot] 509d39fa6d build(deps): bump google.golang.org/api from 0.40.0 to 0.44.0
Bumps [google.golang.org/api](https://github.com/googleapis/google-api-go-client) from 0.40.0 to 0.44.0.
- [Release notes](https://github.com/googleapis/google-api-go-client/releases)
- [Changelog](https://github.com/googleapis/google-api-go-client/blob/master/CHANGES.md)
- [Commits](https://github.com/googleapis/google-api-go-client/compare/v0.40.0...v0.44.0)

Signed-off-by: dependabot[bot] <support@github.com>
2021-04-15 16:13:49 +02:00
dependabot[bot] 7725c41d40 build(deps): bump github.com/nicksnyder/go-i18n/v2 from 2.1.1 to 2.1.2
Bumps [github.com/nicksnyder/go-i18n/v2](https://github.com/nicksnyder/go-i18n) from 2.1.1 to 2.1.2.
- [Release notes](https://github.com/nicksnyder/go-i18n/releases)
- [Changelog](https://github.com/nicksnyder/go-i18n/blob/main/CHANGELOG.md)
- [Commits](https://github.com/nicksnyder/go-i18n/compare/v2.1.1...v2.1.2)

Signed-off-by: dependabot[bot] <support@github.com>
2021-04-15 16:13:26 +02:00
dependabot[bot] 5d36d80153 build(deps): bump github.com/rogpeppe/go-internal from 1.6.2 to 1.8.0
Bumps [github.com/rogpeppe/go-internal](https://github.com/rogpeppe/go-internal) from 1.6.2 to 1.8.0.
- [Release notes](https://github.com/rogpeppe/go-internal/releases)
- [Commits](https://github.com/rogpeppe/go-internal/compare/v1.6.2...v1.8.0)

Signed-off-by: dependabot[bot] <support@github.com>
2021-04-15 14:44:37 +02:00
Joe Mooring 9b34d42bb2 Remove extraneous space from figure shortcode
Fixes #8401
2021-04-15 14:43:32 +02:00
dependabot[bot] c2d8f87cfc build(deps): bump github.com/magefile/mage from 1.10.0 to 1.11.0
Bumps [github.com/magefile/mage](https://github.com/magefile/mage) from 1.10.0 to 1.11.0.
- [Release notes](https://github.com/magefile/mage/releases)
- [Changelog](https://github.com/magefile/mage/blob/master/.goreleaser.yml)
- [Commits](https://github.com/magefile/mage/compare/v1.10.0...v1.11.0)

Signed-off-by: dependabot[bot] <support@github.com>
2021-04-14 11:55:38 +02:00
dependabot[bot] cbc246616e build(deps): bump github.com/google/go-cmp from 0.5.4 to 0.5.5
Bumps [github.com/google/go-cmp](https://github.com/google/go-cmp) from 0.5.4 to 0.5.5.
- [Release notes](https://github.com/google/go-cmp/releases)
- [Commits](https://github.com/google/go-cmp/compare/v0.5.4...v0.5.5)

Signed-off-by: dependabot[bot] <support@github.com>
2021-04-14 11:55:18 +02:00
Niklas Fasching fa432b17b3 org: Disable broken pretty relative links feature
go-org PrettyRelativeLinks rewrites relative org links by
- adding `../` in front
- removing any `.org` suffix

This was meant to play well with hugo pretty urls (which pretty much renders
posts in a subdirectory without the file suffix) and allow use of normal org
file links to reference other posts.

There's a lot of edge cases I didn't consider and multiple bug reports in
go-org [1] later I don't think the complexity of handling those edge cases is
worth it - so let's disable it.

[1]
- https://github.com/niklasfasching/go-org/issues/53
- https://github.com/niklasfasching/go-org/commit/5dadf8c4c2924cbb3b93be45f96e1147596ca6f2 (comment)
- https://github.com/niklasfasching/go-org/issues/51
2021-04-12 08:08:53 +02:00
Niklas Fasching 0cd55c66d3 deps: Update go-org to v1.5.0 2021-04-12 08:08:53 +02:00
dependabot[bot] 0d5cf256e4 build(deps): bump github.com/jdkato/prose from 1.2.0 to 1.2.1
Bumps [github.com/jdkato/prose](https://github.com/jdkato/prose) from 1.2.0 to 1.2.1.
- [Release notes](https://github.com/jdkato/prose/releases)
- [Commits](https://github.com/jdkato/prose/compare/v1.2.0...v1.2.1)

Signed-off-by: dependabot[bot] <support@github.com>
2021-04-11 13:54:16 +02:00
dependabot[bot] 36527576b3 build(deps): bump github.com/spf13/cobra from 1.1.1 to 1.1.3
Bumps [github.com/spf13/cobra](https://github.com/spf13/cobra) from 1.1.1 to 1.1.3.
- [Release notes](https://github.com/spf13/cobra/releases)
- [Changelog](https://github.com/spf13/cobra/blob/master/CHANGELOG.md)
- [Commits](https://github.com/spf13/cobra/compare/v1.1.1...v1.1.3)

Signed-off-by: dependabot[bot] <support@github.com>
2021-04-11 13:53:45 +02:00
Bjørn Erik Pedersen 9b83f45b6d Add complete dependency list in "hugo env -v"
Fixes #8400
2021-04-09 08:07:22 +02:00
Bjørn Erik Pedersen 7fdd2b95e2 Add hugo.IsExtended
Fixes #8399
2021-04-09 07:28:27 +02:00
Bjørn Erik Pedersen 3d5dbdcb1a publisher: Also test minified HTML in the element collector
Updates #7567
2021-04-07 16:40:15 +02:00
Bjørn Erik Pedersen 8a308944e4 publisher: Skip script, pre and textarea content when looking for HTML elements
Updates #7567
2021-04-07 00:26:02 +02:00
Bjørn Erik Pedersen 7b4ade56dd output: Only output mediaType once in docshelper JSON
Fixes #8379
2021-04-01 19:05:33 +02:00
Joe Mooring 7c7974b711 Fix typo in docshelper.go
Fixes #8380
2021-04-01 18:44:39 +02:00
Bjørn Erik Pedersen 5656a908d8 tpl: Remove the FuzzMarkdownify func for now
It has gotten us nothing but "build fails" mail and work we don't have time to follow up on.
2021-03-30 20:57:31 +02:00
Bjørn Erik Pedersen 2dc222cec4 Add slice syntax to sections permalinks config
Fixes #8363
2021-03-30 07:55:24 +02:00
Bjørn Erik Pedersen 4d22ad580e deps: Upgrade github.com/evanw/esbuild v0.9.6 => v0.11.0 2021-03-29 12:00:47 +02:00
Bjørn Erik Pedersen 5e2f128911 Try to fix the fuzz build 2021-03-28 21:42:44 +02:00
hugoreleaser 97934779ed releaser: Prepare repository for 0.83.0-DEV
[ci skip]
2021-03-21 18:12:42 +00:00
hugoreleaser 9d96078439 releaser: Add release notes to /docs for release of 0.82.0
[ci skip]
2021-03-21 17:28:02 +00:00
hugoreleaser 1efd93c097 releaser: Bump versions for release of 0.82.0
[ci skip]
2021-03-21 17:28:02 +00:00
hugoreleaser 584a9b3e2e releaser: Add release notes for 0.82.0 2021-03-21 18:16:55 +01:00
Bjørn Erik Pedersen 86b4fd35e7 docs: Regenerate docs helper 2021-03-21 13:33:26 +01:00
Bjørn Erik Pedersen 195d108da7 docs: Regen CLI docs 2021-03-21 13:32:12 +01:00
Bjørn Erik Pedersen 81689af799 Squashed 'docs/' changes from bb15e9804..9cece6640
9cece6640 Function sort: fix example labels (#1344)
84444120f Revert "Fix sample data for sort function (#1363)" (#1364)
05c8619f4 Fix sample data for sort function (#1363)
2beb1c0ed Fix "Configure taxonomies" title (#1361)
cd777b9fb Fix sitemap configuration link (#1360)
52251fb42 Update the 'Customize Dates' example to not error (#1357)
1a14cc08a Update quick-start.md
17bb98a94 Add note about image metadata removal
ec4f7bfff Update 404.md
cebfb7a90 explaination that `weight` key is used for sorting
83190ff12 fix typo: "advance settings" → "advanced settings"
75743968c Update quick-start.md
f1c64cd5a Improved documentation.
8af3b236c Update theme

git-subtree-dir: docs
git-subtree-split: 9cece66400
2021-03-21 13:31:17 +01:00
Bjørn Erik Pedersen c94aa5cf46 Merge commit '81689af79901f0cdaff765cda6322dd4a9a7ccb3' 2021-03-21 13:31:17 +01:00
Bjørn Erik Pedersen df8bb8812f Simplify some config loading code 2021-03-21 13:29:11 +01:00
Bjørn Erik Pedersen 57d8d208ed deps: Update github.com/evanw/esbuild v0.9.0 => v0.9.6 2021-03-21 11:24:43 +01:00
Bjørn Erik Pedersen fc06e85082 Apply OS env overrides twice
The recent fix for #8346 had an unfortunate side-effect, as it prevented overrides of config options used in the module collector, e.g. `HUGO_MODULE_REPLACEMENTS`.

This commit fixes that by applying the overrides twice.
2021-03-21 10:54:30 +01:00
Bjørn Erik Pedersen b725253f9e Attributes for code fences should be placed after the lang indicator only
Fixes #8313
2021-03-20 19:15:11 +01:00
Bjørn Erik Pedersen 35dedf15c0 deps: Bump github.com/tdewolff/minify/v2 v2.9.15
Fixes #8332
2021-03-20 15:51:20 +01:00
Bjørn Erik Pedersen 7ed56c6941 Fix OS env override for nested config param only available in theme
Fixes #8346
2021-03-20 13:34:51 +01:00
Avinash Sonawane 24c716cac3 Fix new theme command description
`hugo new theme foo` creates theme `foo` in `./themes` and not in current directory.
2021-03-14 18:47:23 +01:00
Patrick Kollitsch 137d2dab32 github: More explicit support link to discourse 2021-03-14 18:27:15 +01:00
Bjørn Erik Pedersen ba1d0051b4 media: Make Type comparable
So we can use it and output.Format as map key etc.

This commit also fixes the media.Type implementation so it does not need to mutate itself to handle different suffixes for the same MIME type, e.g. jpg vs. jpeg.

This means that there are no Suffix or FullSuffix on media.Type anymore.

Fixes #8317
Fixes #8324
2021-03-14 15:21:54 +01:00
Bjørn Erik Pedersen 1b1dcf586e deps: Update to esbuild v0.9.0 2021-03-14 11:51:25 +01:00
Cameron Moore f6612d8bd8 exif: Fix handling of utf8 runes in nullString() 2021-03-13 21:20:10 +01:00
Cameron Moore 0a2ab3f8fe exif: Allow more spacing characters in strings
The root cause of issue #8079 was a non-breaking space (U+0160).
`unicode.IsPrint` only allows the ASCII space (U+0020).  Be more lenient
by using `unicode.IsGraphic` instead.

Fixes #8079
2021-03-13 21:20:10 +01:00
Bjørn Erik Pedersen 4d24e2a326 media: Add a basic benchmark 2021-03-11 10:08:51 +01:00
Bjørn Erik Pedersen 18074d0c23 Fix output format handling for render hooks
Fixes #8176
2021-03-09 13:26:39 +01:00
Bjørn Erik Pedersen 35bfb66222 Rename a test 2021-03-04 13:46:31 +01:00
Bjørn Erik Pedersen 6d21559fb5 Add a debug helper 2021-03-03 20:16:58 +01:00
Daniel Atwood ba16a14c6e Add support for Google Analytics v4 2021-03-03 13:30:06 +01:00
Bjørn Erik Pedersen 782c79ae61 Bump go.mod to Go 1.16
Fixes #8294
2021-03-03 09:17:57 +01:00
Systemkern 5afcae7e0b #8210 Upgrade golang version for Dockerfile
https://github.com/gohugoio/hugo/issues/8210
relates to: #8210
2021-02-28 14:14:06 +01:00
Bjørn Erik Pedersen 60469f429e Update CONTRIBUTING.md 2021-02-25 11:50:08 +01:00
Bjørn Erik Pedersen aed7df62a8 markup: Handle attribute lists in code fences
Fixes #8278
2021-02-24 11:16:06 +01:00
Bjørn Erik Pedersen cd0c5d7ef3 Allow markdown attribute lists to be used in title render hooks
Fixes #8270
2021-02-23 18:08:39 +01:00
Bjørn Erik Pedersen e7e194435b Merge commit '9d31f650da964a52f05fc27b7fb99cf3e09778cf' 2021-02-23 17:41:05 +01:00
Bjørn Erik Pedersen 9d31f650da Squashed 'docs/' changes from d343ebf71..bb15e9804
bb15e9804 Update index.md (#1339)
ffb2f21d1 Update index.md
fc154ac02 Regenerate CLI docs
a0a687738 Update index.md
d0e35a844 Update index.md
86d0cc042 Update index.md
bdaf7e022 Release 0.81.0
b51017445 releaser: Add release notes to /docs for release of 0.81.0
888dd8fcc docs: Regen CLI docs
8c3e8b270 docs: Regen docs helper
79e3e1ebc Merge commit 'acb9109df778fa4a51c0d8b29b3212b12988908f'
31f70af7e modules: Add config option modules.vendorClosest
2631df94e markup/goldmark: Add attributes support for blocks (tables etc.)
19dee04ad Update to Dart Sass Protocol beta6
e507721fe Refactor: Write to stdout by default
d204bf160 Refactor: Remove powershell support
91bea48f5 Feat: Add zsh, fish and powershell completion support
9c915ea27 docs: Remove mention of a file size limit for readFile
5acc8b6c7 js: Add Inject config option
45321989e js: Add Shims option

git-subtree-dir: docs
git-subtree-split: bb15e9804a
2021-02-23 17:39:59 +01:00
dependabot[bot] 88a85dcea9 build(deps): bump github.com/kyokomi/emoji/v2 from 2.2.7 to 2.2.8
Bumps [github.com/kyokomi/emoji/v2](https://github.com/kyokomi/emoji) from 2.2.7 to 2.2.8.
- [Release notes](https://github.com/kyokomi/emoji/releases)
- [Commits](https://github.com/kyokomi/emoji/compare/v2.2.7...v2.2.8)

Signed-off-by: dependabot[bot] <support@github.com>
2021-02-23 10:55:29 +01:00
Bjørn Erik Pedersen 7f8530039a tpl: Add method mappings for strings.Contains, strings.ContainsAny
Just to confirm/document the function signature.
2021-02-23 09:36:43 +01:00
gzagatti 01dd7c16af Fixes #7698.
markup: Allow installed arbitrary Asciidoc extension via path validation.
2021-02-22 13:52:04 +01:00
Bjørn Erik Pedersen c8f45d1d86 commands: Fix autocomplete docs 2021-02-20 14:08:51 +01:00
hugoreleaser b3504a0ee8 releaser: Prepare repository for 0.82.0-DEV
[ci skip]
2021-02-19 17:55:53 +00:00
hugoreleaser 59d15c97d8 releaser: Add release notes to /docs for release of 0.81.0
[ci skip]
2021-02-19 17:07:09 +00:00
hugoreleaser 9e2d086ca7 releaser: Bump versions for release of 0.81.0
[ci skip]
2021-02-19 17:07:09 +00:00
Bjørn Erik Pedersen b65518ac63 releaser: Increase build timeout 2021-02-19 17:57:24 +01:00
hugoreleaser 0e9cd8128d releaser: Add release notes for 0.81.0 2021-02-19 16:52:22 +01:00
Bjørn Erik Pedersen fe77f7434b tpl: Make the build green again 2021-02-18 18:17:43 +01:00
Bjørn Erik Pedersen 9e99950c6e docs: Regen CLI docs 2021-02-18 17:55:38 +01:00
Bjørn Erik Pedersen 1b364b003f docs: Regen docs helper 2021-02-18 17:54:25 +01:00
Bjørn Erik Pedersen acb9109df7 Squashed 'docs/' changes from ef9c4913c..d343ebf71
d343ebf71 Document ignoreImports
f912ea1cc Fix the github workflow (#1332)
617894052 Add site function
f3be651f9 Minor typo/markdown fixes (#1328)
7a95e9db5 Fix a formatting error for Github Actions (#1323)
260106669 Fix #1120 Use Github Action
d8847a144 docs: Fix HTML code in .RenderString description being stripped out (#1320)
7a67c38c4 Correct sitemap version (#1318)
6a163f53a Removed noise. (#1317)
b02902121 Fix a minor typo (#1314)
399c74acd Revert "js: Update shims setup"
77def8a8c Revert "Update js.md"
13aeb2c73 Update js.md
704987dc1 js: Update shims setup

git-subtree-dir: docs
git-subtree-split: d343ebf718
2021-02-18 17:52:49 +01:00
Bjørn Erik Pedersen 7d0a261981 Merge commit 'acb9109df778fa4a51c0d8b29b3212b12988908f' 2021-02-18 17:52:49 +01:00
Bjørn Erik Pedersen c60806550a tpl: Regenerate internal templates 2021-02-18 17:52:32 +01:00
Daniel Atwood ffd9dac421 tpl: Update date logic of opengraph and schema internal templates
* Fix: updated date logic in opengraph template

* Updated date logic in schema template

* Reformatted opengraph and schema

* Wrapped PublishDate and Lastmod in with
2021-02-18 17:51:32 +01:00
Bjørn Erik Pedersen 88b93a09dc Run go mod tidy 2021-02-18 14:22:25 +01:00
Bjørn Erik Pedersen 29fb456c9e build: Add arm64 to Darwinextended build and add vendorInfo
Closes #8003
2021-02-18 14:11:48 +01:00
Bjørn Erik Pedersen 718fba7d63 Update Travis, GitHub, CircleCI and Snap to Go 1.16 (only) 2021-02-18 14:11:48 +01:00
Bjørn Erik Pedersen 9650e56841 tpl: Add temporary patch to fix template data race
Keep this as a separate commit so we can reapply it if needed.

Fixes #7293
2021-02-18 14:11:48 +01:00
Bjørn Erik Pedersen e77b2e3aa0 Pull in latest Go 1.16 template source 2021-02-18 14:11:48 +01:00
Bjørn Erik Pedersen b5485aeae7 Add breaking tests for "map read and map write in templates"
The fix upstream in Go was reverted, so we apply a temporary patch for this in Hugo.

Updates #7293
2021-02-18 14:11:48 +01:00
Bjørn Erik Pedersen ccb822eb5a Pull in latest Go template source 2021-02-18 14:11:48 +01:00
Bjørn Erik Pedersen 21e9eb18ac Expand template newline testcase to commands 2021-02-18 14:11:48 +01:00
Bjørn Erik Pedersen ae57ba6a9d Add a test case for Go 1.16 template action newlines 2021-02-18 14:11:48 +01:00
Bjørn Erik Pedersen cf3e077da3 tpl/internal: Synch Go templates fork with Go 1.16dev 2021-02-18 14:11:48 +01:00
Bjørn Erik Pedersen 66beac99c6 deps: Update github.com/tdewolff/minify/v2 v2.6.2 => v2.9.13
Fixes #8258
2021-02-18 10:19:22 +01:00
dependabot[bot] 968dd7a711 build(deps): bump github.com/frankban/quicktest from 1.11.2 to 1.11.3
Bumps [github.com/frankban/quicktest](https://github.com/frankban/quicktest) from 1.11.2 to 1.11.3.
- [Release notes](https://github.com/frankban/quicktest/releases)
- [Commits](https://github.com/frankban/quicktest/compare/v1.11.2...v1.11.3)

Signed-off-by: dependabot[bot] <support@github.com>
2021-02-16 22:10:33 +01:00
dependabot[bot] 38f29e817f build(deps): bump github.com/getkin/kin-openapi from 0.32.0 to 0.39.0
Bumps [github.com/getkin/kin-openapi](https://github.com/getkin/kin-openapi) from 0.32.0 to 0.39.0.
- [Release notes](https://github.com/getkin/kin-openapi/releases)
- [Commits](https://github.com/getkin/kin-openapi/compare/v0.32.0...v0.39.0)

Signed-off-by: dependabot[bot] <support@github.com>
2021-02-16 21:18:35 +01:00
dependabot[bot] cd87813aa0 build(deps): bump github.com/aws/aws-sdk-go from 1.36.33 to 1.37.11
Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.36.33 to 1.37.11.
- [Release notes](https://github.com/aws/aws-sdk-go/releases)
- [Changelog](https://github.com/aws/aws-sdk-go/blob/master/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-go/compare/v1.36.33...v1.37.11)

Signed-off-by: dependabot[bot] <support@github.com>
2021-02-16 18:43:30 +01:00
dependabot[bot] 4e815b063e build(deps): bump github.com/sanity-io/litter from 1.3.0 to 1.5.0
Bumps [github.com/sanity-io/litter](https://github.com/sanity-io/litter) from 1.3.0 to 1.5.0.
- [Release notes](https://github.com/sanity-io/litter/releases)
- [Changelog](https://github.com/sanity-io/litter/blob/master/CHANGELOG.md)
- [Commits](https://github.com/sanity-io/litter/compare/v1.3.0...v1.5.0)

Signed-off-by: dependabot[bot] <support@github.com>
2021-02-16 18:42:55 +01:00
dependabot[bot] 652a59d385 build(deps): bump github.com/olekukonko/tablewriter from 0.0.4 to 0.0.5
Bumps [github.com/olekukonko/tablewriter](https://github.com/olekukonko/tablewriter) from 0.0.4 to 0.0.5.
- [Release notes](https://github.com/olekukonko/tablewriter/releases)
- [Commits](https://github.com/olekukonko/tablewriter/compare/v0.0.4...v0.0.5)

Signed-off-by: dependabot[bot] <support@github.com>
2021-02-16 18:39:44 +01:00
Bjørn Erik Pedersen 84f0ec7f80 deps: Update to esbuild v0.8.46 2021-02-16 18:37:30 +01:00
Bjørn Erik Pedersen bdfbcf6f4b modules: Add config option modules.vendorClosest
Fixes #8235
Fixes #8242
2021-02-16 16:30:01 +01:00
Bjørn Erik Pedersen b60e9279ab js: Fix potential path issue on Windows 2021-02-16 16:10:46 +01:00
dependabot[bot] a9b0fea6a3 build(deps): bump google.golang.org/api from 0.26.0 to 0.40.0
Bumps [google.golang.org/api](https://github.com/googleapis/google-api-go-client) from 0.26.0 to 0.40.0.
- [Release notes](https://github.com/googleapis/google-api-go-client/releases)
- [Changelog](https://github.com/googleapis/google-api-go-client/blob/master/CHANGES.md)
- [Commits](https://github.com/googleapis/google-api-go-client/compare/v0.26.0...v0.40.0)

Signed-off-by: dependabot[bot] <support@github.com>
2021-02-16 16:10:12 +01:00
Anthony Fok e8df097745 Change version string format and add VendorInfo to help with issue triaging
* Change version string format as proposed by @moorereason

 1. shorten program name
 2. make version string semver compliant with +extended.
    The slash is not allowed in semver.
 3. Use key=value pairs for BuildDate etc.

* Add optional vendorInfo to version string

to help with issue triaging, e.g. VendorInfo=debian:0.80.0-7
2021-02-16 16:08:24 +01:00
Bjørn Erik Pedersen 3a5ee0d2d6 modules: Allow absolute paths for any modules resolved via project replacement
Fixes #8240
2021-02-15 11:11:34 +01:00
Bjørn Erik Pedersen 4ffaeaf155 modules: Throw an error running hugo mod vendor on mountless module 2021-02-15 10:47:32 +01:00
susiwen8 bf55afd71f Fix some humanize issues
Fixes #7912
2021-02-14 18:30:59 +01:00
Anthony Fok 5f621df257 commands: Add PowerShell completion support
Revert "Refactor: Remove powershell support" with fixes

Thanks to Ben Mezger (@benmezger) for the original code.
See #8122

This reverts commit a7c515e1b5.
2021-02-09 13:37:36 -07:00
Anthony Fok 7118f89cf3 Refer to mage instead of make in comment regarding commitHash 2021-02-09 09:57:18 -07:00
Bjørn Erik Pedersen e6dd312812 markup/goldmark: Fix handling of legacy attribute config
See #7548
2021-02-09 09:23:18 +01:00
Bjørn Erik Pedersen 2681633db8 markup/goldmark: Add attributes support for blocks (tables etc.)
E.g.:

```
> foo
> bar
{.myclass}
```

There are some current limitations: For tables you can currently only apply it to the full table, and for lists the ul/ol-nodes only, e.g.:

```
* Fruit
  * Apple
  * Orange
  * Banana
  {.fruits}
* Dairy
  * Milk
  * Cheese
  {.dairies}
{.list}
```

Fixes #7548
2021-02-08 19:52:55 +01:00
Bjørn Erik Pedersen 1b24728256 deps: Update to Goldmark v1.3.2
Closes #8143
2021-02-08 12:16:21 +01:00
Bjørn Erik Pedersen 441b11beec Update to Dart Sass Protocol beta6
Note that this version is not backwards compatible, so you have to update the protocol binary.
2021-02-06 18:34:19 +01:00
Jeremy Epstein 4867cd1dea tpl/embedded: Exclude pages without Permalink from sitemap 2021-02-06 18:30:09 +01:00
Bjørn Erik Pedersen 92c6c40419 langs/i18n: Support translation files with suffix *.yml
Fixes #8212
2021-02-06 18:12:54 +01:00
Ben Mezger d36fd5b3ee Refactor: Write to stdout by default 2021-02-04 15:32:51 -07:00
Ben Mezger a7c515e1b5 Refactor: Remove powershell support 2021-02-04 15:32:51 -07:00
Ben Mezger 216b00f358 Feat: Add zsh, fish and powershell completion support
See issue #4296
2021-02-04 15:32:51 -07:00
Bjørn Erik Pedersen 144943798c github: Enable NPM tests on Windows
Fixes #8196
2021-02-01 11:32:17 +01:00
Bjørn Erik Pedersen 440fdb0eb9 deps: Update to esbuild v0.8.39
Fixes #8189
2021-02-01 11:28:12 +01:00
Pavlo Matiash b2a48dce58 Trim whitespace in elements written to hugo_stats.json
Fixes #7958
2021-02-01 09:32:39 +01:00
Baris Ceviz 35def0ae45 tpl/data: Add default user-agent header for getJSON requests 2021-02-01 09:31:02 +01:00
dependabot[bot] 2f9dadae40 build(deps): bump github.com/aws/aws-sdk-go from 1.35.0 to 1.36.33
Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.35.0 to 1.36.33.
- [Release notes](https://github.com/aws/aws-sdk-go/releases)
- [Changelog](https://github.com/aws/aws-sdk-go/blob/master/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-go/compare/v1.35.0...v1.36.33)

Signed-off-by: dependabot[bot] <support@github.com>
2021-01-28 22:20:00 +01:00
Aleksandr Demakin ed3071b753 docs: Remove mention of a file size limit for readFile
The limit itself was removed in this PR: https://github.com/gohugoio/hugo/pull/8172.
2021-01-23 14:14:51 +01:00
Aleksandr Demakin ee9c136763 tpl/os: remove 1mb limit for readFile. 2021-01-23 00:39:14 +01:00
Bjørn Erik Pedersen 32b86076ee js: Add Inject config option
Fixes #8164
2021-01-22 23:43:44 +01:00
Cameron Moore 241b7483ea tpl: Fix race condition in text template baseof
Copy most of the htmltemplate cloning to the textemplate implementation
in the same function.
2021-01-22 19:25:45 +01:00
Bjørn Erik Pedersen e19a046c4b js: Add Shims option
This commit adds a new `shims` option to `js.Build` that allows swapping out a component with another.

Fixes #8165
2021-01-22 09:03:24 +01:00
Bjørn Erik Pedersen a1fe552fc9 Fix nilpointer in js.Build error handling
Fixes #8162
2021-01-21 10:09:33 +01:00
Bjørn Erik Pedersen a1a9f088b1 Merge commit 'e48ffb763572814a3788780bb9653dfa2daeae22' 2021-01-20 12:48:39 +01:00
Bjørn Erik Pedersen e48ffb7635 Squashed 'docs/' changes from 1de7a358c..ef9c4913c
ef9c4913c Clean up and removal of outdated examples
46122c9aa add godot tutorials to showcase
06d1d1ea2 Update scss-sass.md
1fc63c100 Spelling fix in 0.79.1 release notes
ad2f50e3d Update plainwords description (#1296)
33021d451 Update substr examples (#1304)
6b1cc59bb Release 0.80.0
521db8c6d Merge branch 'tempv0.80.0'
58626c2b3 releaser: Add release notes to /docs for release of 0.80.0
f81d118af dartsass: Dart Sass only supports `expanded` and `compressed`
7da6f54be Add Dart Sass support
b1f2661bb Replace jsconfig.js with jsconfig.json
38de0c1a4 Update index.md
223ceae80 Update index.md
f7ac0e59d Release v0.79.1
2d4583d43 Merge branch 'temp791-2'
1d34e609b releaser: Add release notes to /docs for release of 0.79.1
e26769988 Merge branch 'temp791'
75694d904 Fix Resource.ResourceType so it always returns MIME's main type
0f65d7783 Typo s/adds/add (#1298)
0b896b2c0 images: Add images.Overlay filter
0d4257dcd Clarify documentation on shimming
fcf601ddf Update index.html
6bf9bc1c1 Update index.html
1ce76bf3a Update index.html
e7d976eec Update index.html
db2996e64 Update index.html
245e5bfc9 news: Add post about Apple M1
3ad4115ed tpl: Add title parameter to YouTube shortcode
76ed976f8 Added two useful extensions to the list (#1243)
e5a30dd11 Update related.md
25cf8f48b Improve substr examples
e16e57e9a Update path.Split.md
2749b88fd Update path.Split.md
d76cad3ff Release 0.79.0
f5ccfbe98 releaser: Add release notes to /docs for release of 0.79.0
ebf1b87b0 Merge commit '9f1265fde4b9ef186148337c99f08601633b6056'
1f1e8f39c Allow setting the delimiter used for setting config via OS env, e.g. HUGO_
e9b1414dd deps: Update to github.com/evanw/esbuild 0.8.11 to 0.8.14
0f76cf66c docs: Regen docshelper
1ada5d47e Add menu params
1c120aef0 Revert "docs: Regenerate docshelper"
7b60b5624 docs: Regenerate docshelper

git-subtree-dir: docs
git-subtree-split: ef9c4913cd
2021-01-20 12:47:49 +01:00
Robert-André Mauchin 07ad283f68 build(deps): bump github.com/spf13/afero from 1.4.1 to 1.5.1
Signed-off-by: Robert-André Mauchin <zebob.m@gmail.com>
2021-01-19 17:25:20 +01:00
Andreas Richter 2c8b5d9165 pipes: Add external source map support to js.Build and Babel
Fixes #8132
2021-01-18 10:38:09 +01:00
Cameron Moore 0004a733c8 tpl: Fix metrics hint tracking
When tracking for cache hints, track the same template name as the call
to MeasureSince in Execute.  When referencing a partial "foo", the value
of `n` does not match `templ.Name()` (`partials/foo` versus
`partials/foo.html`).  This was causing hints to go untracked since
there was no existing metric to append the hint to.

Fixes #8125
2021-01-08 20:01:11 +01:00
Cameron Moore 8a26ab0bc5 tpl: Do not return errors in substr for out-of-bounds cases
Most other substr implementations don't error out in out-of-bounds cases
but simply return an empty string (or a value that's printed as an empty
string). We'll follow their lead and not exit template execution.  Allow
the user decide what to do with the empty result.

Fixes #8113
2021-01-08 10:13:10 +01:00
Cameron Moore 788e50ad3a tpl: Add missing test scenario for strings.Substr 2021-01-08 10:13:10 +01:00
Bjørn Erik Pedersen 4d2b6fc4c0 Run go mod tidy 2021-01-03 18:48:35 +01:00
Niklas Fasching 212e5e5542 deps: Update go-org to v1.4.0
- Add support for pretty urls [1]. Rewrite file links:
  1. replace the `.org` extension with `/` (`/foo.org` -> `/foo/`)
  2. prefix unrooted links with `../` as relative links start in the fake
  subdirectory `/foo/` rather than `/`
- Fix case-sensitivity of org drawer `🔚`

[1] https://gohugo.io/content-management/urls/#pretty-urls
2021-01-02 22:29:06 +01:00
Bjørn Erik Pedersen 4fdec67b11 rst: Adjust log level 2021-01-01 11:50:13 +01:00
hugoreleaser 9b681ecfbd releaser: Prepare repository for 0.81.0-DEV
[ci skip]
2020-12-31 13:49:02 +00:00
1024 changed files with 31048 additions and 7855 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
defaults: &defaults
docker:
- image: bepsays/ci-goreleaser:1.15.1
- image: bepsays/ci-goreleaser:1.17.2
environment:
CGO_ENABLED: "0"
+2 -2
View File
@@ -1,5 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: Support
- name: SUPPORT, ISSUES and TROUBLESHOOTING
url: https://discourse.gohugo.io/
about: Please do not use Github for support requests. Visit https://discourse.gohugo.io for support!
about: Please DO NOT use Github for support requests. Please visit https://discourse.gohugo.io for support! You will be helped much faster there. If you ignore this request your issue might be closed with a discourse label.
+11 -10
View File
@@ -7,7 +7,7 @@ jobs:
GO111MODULE: on
strategy:
matrix:
go-version: [1.14.x, 1.15.x]
go-version: [1.16.x, 1.17.x]
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
@@ -48,23 +48,23 @@ jobs:
- if: matrix.os == 'ubuntu-latest'
name: Install dart-sass-embedded Linux
run: |
curl -LJO https://github.com/sass/dart-sass-embedded/releases/download/1.0.0-beta.5/sass_embedded-1.0.0-beta.5-linux-x64.tar.gz;
echo "642738beaea4ef1b9168446bc105267a2948a5e939537f5bd5afb48159140a44 sass_embedded-1.0.0-beta.5-linux-x64.tar.gz" | sha256sum -c;
tar -xvf sass_embedded-1.0.0-beta.5-linux-x64.tar.gz;
curl -LJO https://github.com/sass/dart-sass-embedded/releases/download/1.0.0-beta.6/sass_embedded-1.0.0-beta.6-linux-x64.tar.gz;
echo "04fc1e5e28d29a4585a701941b6dace56771d94bfbe7f9e4db28d24417ceeec3 sass_embedded-1.0.0-beta.6-linux-x64.tar.gz" | sha256sum -c;
tar -xvf sass_embedded-1.0.0-beta.6-linux-x64.tar.gz;
echo "$GITHUB_WORKSPACE/sass_embedded/" >> $GITHUB_PATH
- if: matrix.os == 'macos-latest'
name: Install dart-sass-embedded MacOS
run: |
curl -LJO https://github.com/sass/dart-sass-embedded/releases/download/1.0.0-beta.5/sass_embedded-1.0.0-beta.5-macos-x64.tar.gz;
echo "47b55a39126155f89fdfb8eea7c19ba976b3f6fadbdb6867e5582a18137bd180 sass_embedded-1.0.0-beta.5-macos-x64.tar.gz" | shasum -a 256 -c;
tar -xvf sass_embedded-1.0.0-beta.5-macos-x64.tar.gz;
curl -LJO https://github.com/sass/dart-sass-embedded/releases/download/1.0.0-beta.6/sass_embedded-1.0.0-beta.6-macos-x64.tar.gz;
echo "b3b984675a9b04aa22f6f2302dda4191b507ac2ca124467db2dfe7e58e72fbad sass_embedded-1.0.0-beta.6-macos-x64.tar.gz" | shasum -a 256 -c;
tar -xvf sass_embedded-1.0.0-beta.6-macos-x64.tar.gz;
echo "$GITHUB_WORKSPACE/sass_embedded/" >> $GITHUB_PATH
- if: matrix.os == 'windows-latest'
name: Install dart-sass-embedded Windows
run: |
curl -LJO https://github.com/sass/dart-sass-embedded/releases/download/1.0.0-beta.5/sass_embedded-1.0.0-beta.5-windows-x64.zip;
echo "5e65c0d8cbe038b6a120a3e7f390ad731708998f37c2de8ba565c51746a4588c sass_embedded-1.0.0-beta.5-windows-x64.zip" | sha256sum -c;
unzip sass_embedded-1.0.0-beta.5-windows-x64.zip;
curl -LJO https://github.com/sass/dart-sass-embedded/releases/download/1.0.0-beta.6/sass_embedded-1.0.0-beta.6-windows-x64.zip;
echo "6ae442129dbb3334bc21ef851261da6c0c1b560da790ca2e1350871d00ab816d sass_embedded-1.0.0-beta.6-windows-x64.zip" | sha256sum -c;
unzip sass_embedded-1.0.0-beta.6-windows-x64.zip;
echo "$env:GITHUB_WORKSPACE/sass_embedded/" | Out-File -FilePath $Env:GITHUB_PATH -Encoding utf-8 -Append
- name: Test
run: |
@@ -75,6 +75,7 @@ jobs:
HUGO_BUILD_TAGS: extended
HUGO_TIMEOUT: 31000
HUGO_IGNOREERRORS: error-remote-getjson
HUGO_SERVICES_INSTAGRAM_ACCESSTOKEN: dummytoken
run: |
mage -v hugo
./hugo -s docs/
+3 -1
View File
@@ -50,7 +50,9 @@ Hugo has become a fully featured static site generator, so any new functionality
If it is of some complexity, the contributor is expected to maintain and support the new feature in the future (answer questions on the forum, fix any bugs etc.).
It is recommended to open up a discussion on the [Hugo Forum](https://discourse.gohugo.io/) to get feedback on your idea before you begin. If you are submitting a complex feature, create a small design proposal on the [Hugo issue tracker](https://github.com/gohugoio/hugo/issues) before you start.
It is recommended to open up a discussion on the [Hugo Forum](https://discourse.gohugo.io/) to get feedback on your idea before you begin.
Any non-trivial code change needs to update an open [issue](https://github.com/gohugoio/hugo/issues). A non-trivial code change without an issue reference with one of the labels `bug` or `enhancement` will not be merged.
Note that we do not accept new features that require [CGO](https://github.com/golang/go/wiki/cgo).
We have one exception to this rule which is LibSASS.
+1 -1
View File
@@ -2,7 +2,7 @@
# Twitter: https://twitter.com/gohugoio
# Website: https://gohugo.io/
FROM golang:1.15-alpine AS build
FROM golang:1.16-alpine AS build
# Optionally set HUGO_BUILD_TAGS to "extended" or "nodeploy" when building like so:
# docker build --build-arg HUGO_BUILD_TAGS=extended .
+100 -72
View File
@@ -1,4 +1,4 @@
<img src="https://raw.githubusercontent.com/gohugoio/gohugoioTheme/master/static/images/hugo-logo-wide.svg?sanitize=true" alt="Hugo" width="565">
<a href="https://gohugo.io/"><img src="https://raw.githubusercontent.com/gohugoio/gohugoioTheme/master/static/images/hugo-logo-wide.svg?sanitize=true" alt="Hugo" width="565"></a>
A Fast and Flexible Static Site Generator built with love by [bep](https://github.com/bep), [spf13](http://spf13.com/) and [friends](https://github.com/gohugoio/hugo/graphs/contributors) in [Go][].
@@ -29,7 +29,7 @@ Hugo is designed to work well for any kind of website including blogs, tumbles,
#### Supported Architectures
Currently, we provide pre-built Hugo binaries for Windows, Linux, FreeBSD, NetBSD, DragonFly BSD, Open BSD, macOS (Darwin), and [Android](https://gist.github.com/bep/a0d8a26cf6b4f8bc992729b8e50b480b) for x64, i386 and ARM architectures.
Currently, we provide pre-built Hugo binaries for Windows, Linux, FreeBSD, NetBSD, DragonFly BSD, OpenBSD, macOS (Darwin), and [Android](https://gist.github.com/bep/a0d8a26cf6b4f8bc992729b8e50b480b) for x64, i386 and ARM architectures.
Hugo may also be compiled from source wherever the Go compiler tool chain can run, e.g. for other operating systems including Plan 9 and Solaris.
@@ -54,7 +54,7 @@ Use the [installation instructions in the Hugo documentation](https://gohugo.io/
#### Prerequisite Tools
* [Git](https://git-scm.com/)
* [Go (we test it with the last 2 major versions)](https://golang.org/dl/)
* [Go (we test it with the last 2 major versions; but note that Hugo 0.81.0 only builds with >= Go 1.16.)](https://golang.org/dl/)
#### Fetch from GitHub
@@ -119,78 +119,106 @@ If you are unfamiliar with the contribution process, the Hugo team will help you
For a complete guide to contributing code to Hugo, see the [Contribution Guide](CONTRIBUTING.md).
[![Analytics](https://ga-beacon.appspot.com/UA-7131036-6/hugo/readme)](https://github.com/igrigorik/ga-beacon)
[Go]: https://golang.org/
[Hugo Documentation]: https://gohugo.io/overview/introduction/
## Dependencies
Hugo stands on the shoulder of many great open source libraries, in lexical order:
Hugo stands on the shoulder of many great open source libraries.
If you run `hugo env -v` you will get a complete and up to date list.
In Hugo 0.89.0 that list is, in lexical order:
```
cloud.google.com/go/storage="v1.10.0"
cloud.google.com/go="v0.87.0"
github.com/Azure/azure-pipeline-go="v0.2.2"
github.com/Azure/azure-storage-blob-go="v0.9.0"
github.com/BurntSushi/locker="v0.0.0-20171006230638-a6e239ea1c69"
github.com/BurntSushi/toml="v0.3.1"
github.com/PuerkitoBio/purell="v1.1.1"
github.com/PuerkitoBio/urlesc="v0.0.0-20170810143723-de5bf2ad4578"
github.com/alecthomas/chroma="v0.9.4"
github.com/armon/go-radix="v1.0.0"
github.com/aws/aws-sdk-go="v1.41.14"
github.com/bep/debounce="v1.2.0"
github.com/bep/gitmap="v1.1.2"
github.com/bep/godartsass="v0.12.0"
github.com/bep/golibsass="v1.0.0"
github.com/bep/gowebp="v0.1.0"
github.com/bep/tmc="v0.5.1"
github.com/cli/safeexec="v1.0.0"
github.com/cpuguy83/go-md2man/v2="v2.0.0"
github.com/disintegration/gift="v1.2.1"
github.com/dlclark/regexp2="v1.4.0"
github.com/dustin/go-humanize="v1.0.0"
github.com/evanw/esbuild="v0.13.12"
github.com/fsnotify/fsnotify="v1.5.1"
github.com/getkin/kin-openapi="v0.80.0"
github.com/ghodss/yaml="v1.0.0"
github.com/go-openapi/jsonpointer="v0.19.5"
github.com/go-openapi/swag="v0.19.5"
github.com/gobuffalo/flect="v0.2.3"
github.com/gobwas/glob="v0.2.3"
github.com/gohugoio/go-i18n/v2="v2.1.3-0.20210430103248-4c28c89f8013"
github.com/gohugoio/locales="v0.14.0"
github.com/gohugoio/localescompressed="v0.14.0"
github.com/golang/groupcache="v0.0.0-20200121045136-8c9f03a8e57e"
github.com/golang/protobuf="v1.5.2"
github.com/google/go-cmp="v0.5.6"
github.com/google/uuid="v1.1.2"
github.com/google/wire="v0.4.0"
github.com/googleapis/gax-go/v2="v2.0.5"
github.com/googleapis/gax-go="v2.0.2+incompatible"
github.com/gorilla/websocket="v1.4.2"
github.com/inconshreveable/mousetrap="v1.0.0"
github.com/jdkato/prose="v1.2.1"
github.com/jmespath/go-jmespath="v0.4.0"
github.com/kyokomi/emoji/v2="v2.2.8"
github.com/mailru/easyjson="v0.0.0-20190626092158-b2ccc519800e"
github.com/mattn/go-ieproxy="v0.0.1"
github.com/mattn/go-isatty="v0.0.14"
github.com/mattn/go-runewidth="v0.0.9"
github.com/miekg/mmark="v1.3.6"
github.com/mitchellh/hashstructure="v1.1.0"
github.com/mitchellh/mapstructure="v1.4.2"
github.com/muesli/smartcrop="v0.3.0"
github.com/niklasfasching/go-org="v1.5.0"
github.com/olekukonko/tablewriter="v0.0.5"
github.com/pelletier/go-toml/v2="v2.0.0-beta.3.0.20210727221244-fa0796069526"
github.com/pkg/errors="v0.9.1"
github.com/rogpeppe/go-internal="v1.8.0"
github.com/russross/blackfriday/v2="v2.0.1"
github.com/russross/blackfriday="v1.5.3-0.20200218234912-41c5fccfd6f6"
github.com/rwcarlsen/goexif="v0.0.0-20190401172101-9e8deecbddbd"
github.com/sanity-io/litter="v1.5.1"
github.com/sass/libsass="3.6.5"
github.com/shurcooL/sanitized_anchor_name="v1.0.0"
github.com/spf13/afero="v1.6.0"
github.com/spf13/cast="v1.4.1"
github.com/spf13/cobra="v1.2.1"
github.com/spf13/fsync="v0.9.0"
github.com/spf13/jwalterweatherman="v1.1.0"
github.com/spf13/pflag="v1.0.5"
github.com/tdewolff/minify/v2="v2.9.22"
github.com/tdewolff/parse/v2="v2.5.21"
github.com/webmproject/libwebp="v1.2.0"
github.com/yuin/goldmark-highlighting="v0.0.0-20200307114337-60d527fdb691"
github.com/yuin/goldmark="v1.4.2"
go.opencensus.io="v0.23.0"
gocloud.dev="v0.20.0"
golang.org/x/image="v0.0.0-20210220032944-ac19c3e999fb"
golang.org/x/net="v0.0.0-20210614182718-04defd469f4e"
golang.org/x/oauth2="v0.0.0-20210628180205-a41e5a781914"
golang.org/x/sync="v0.0.0-20210220032951-036812b2e83c"
golang.org/x/sys="v0.0.0-20210908233432-aa78b53d3365"
golang.org/x/text="v0.3.7"
golang.org/x/xerrors="v0.0.0-20200804184101-5ec99f83aff1"
google.golang.org/api="v0.51.0"
google.golang.org/genproto="v0.0.0-20210716133855-ce7ef5c701ea"
google.golang.org/grpc="v1.39.0"
google.golang.org/protobuf="v1.27.1"
gopkg.in/yaml.v2="v2.4.0"
```
| Dependency | License |
| :------------- | :------------- |
| [github.com/alecthomas/chroma](https://github.com/alecthomas/chroma) | MIT License |
| [github.com/armon/go-radix](https://github.com/armon/go-radix) | MIT License |
| [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) | Apache License 2.0 |
| [github.com/bep/debounce](https://github.com/bep/debounce) | MIT License |
| [github.com/bep/gitmap](https://github.com/bep/gitmap) | MIT License |
| [github.com/bep/golibsass](https://github.com/bep/golibsass) | MIT License |
| [github.com/bep/tmc](https://github.com/bep/tmc) | MIT License |
| [github.com/BurntSushi/locker](https://github.com/BurntSushi/locker) | The Unlicense |
| [github.com/BurntSushi/toml](https://github.com/BurntSushi/toml) | MIT License |
| [github.com/cpuguy83/go-md2man](https://github.com/cpuguy83/go-md2man) | MIT License |
| [github.com/danwakefield/fnmatch](https://github.com/danwakefield/fnmatch) | BSD 2-Clause "Simplified" License |
| [github.com/disintegration/gift](https://github.com/disintegration/gift) | MIT License |
| [github.com/dustin/go-humanize](https://github.com/dustin/go-humanize) | MIT License |
| [github.com/fsnotify/fsnotify](https://github.com/fsnotify/fsnotify) | BSD 3-Clause "New" or "Revised" License |
| [github.com/gobwas/glob](https://github.com/gobwas/glob) | MIT License |
| [github.com/gorilla/websocket](https://github.com/gorilla/websocket) | BSD 2-Clause "Simplified" License |
| [github.com/hashicorp/golang-lru](https://github.com/hashicorp/golang-lru) | Mozilla Public License 2.0 |
| [github.com/hashicorp/hcl](https://github.com/hashicorp/hcl) | Mozilla Public License 2.0 |
| [github.com/jdkato/prose](https://github.com/jdkato/prose) | MIT License |
| [github.com/kr/pretty](https://github.com/kr/pretty) | MIT License |
| [github.com/kyokomi/emoji](https://github.com/kyokomi/emoji) | MIT License |
| [github.com/magiconair/properties](https://github.com/magiconair/properties) | BSD 2-Clause "Simplified" License |
| [github.com/markbates/inflect](https://github.com/markbates/inflect) | MIT License |
| [github.com/mattn/go-isatty](https://github.com/mattn/go-isatty) | MIT License |
| [github.com/mattn/go-runewidth](https://github.com/mattn/go-runewidth) | MIT License |
| [github.com/miekg/mmark](https://github.com/miekg/mmark) | Simplified BSD License |
| [github.com/mitchellh/hashstructure](https://github.com/mitchellh/hashstructure) | MIT License |
| [github.com/mitchellh/mapstructure](https://github.com/mitchellh/mapstructure) | MIT License |
| [github.com/muesli/smartcrop](https://github.com/muesli/smartcrop) | MIT License |
| [github.com/nicksnyder/go-i18n](https://github.com/nicksnyder/go-i18n) | MIT License |
| [github.com/niklasfasching/go-org](https://github.com/niklasfasching/go-org) | MIT License |
| [github.com/olekukonko/tablewriter](https://github.com/olekukonko/tablewriter) | MIT License |
| [github.com/pelletier/go-toml](https://github.com/pelletier/go-toml) | MIT License |
| [github.com/pkg/errors](https://github.com/pkg/errors) | BSD 2-Clause "Simplified" License |
| [github.com/PuerkitoBio/purell](https://github.com/PuerkitoBio/purell) | BSD 3-Clause "New" or "Revised" License |
| [github.com/PuerkitoBio/urlesc](https://github.com/PuerkitoBio/urlesc) | BSD 3-Clause "New" or "Revised" License |
| [github.com/rogpeppe/go-internal](https://github.com/rogpeppe/go-internal) | BSD 3-Clause "New" or "Revised" License |
| [github.com/russross/blackfriday](https://github.com/russross/blackfriday) | Simplified BSD License |
| [github.com/rwcarlsen/goexif](https://github.com/rwcarlsen/goexif) | BSD 2-Clause "Simplified" License |
| [github.com/spf13/afero](https://github.com/spf13/afero) | Apache License 2.0 |
| [github.com/spf13/cast](https://github.com/spf13/cast) | MIT License |
| [github.com/spf13/cobra](https://github.com/spf13/cobra) | Apache License 2.0 |
| [github.com/spf13/fsync](https://github.com/spf13/fsync) | MIT License |
| [github.com/spf13/jwalterweatherman](https://github.com/spf13/jwalterweatherman) | MIT License |
| [github.com/spf13/pflag](https://github.com/spf13/pflag) | BSD 3-Clause "New" or "Revised" License |
| [github.com/spf13/viper](https://github.com/spf13/viper) | MIT License |
| [github.com/tdewolff/minify](https://github.com/tdewolff/minify) | MIT License |
| [github.com/tdewolff/parse](https://github.com/tdewolff/parse) | MIT License |
| [github.com/yuin/goldmark](https://github.com/yuin/goldmark) | MIT License |
| [github.com/yuin/goldmark-highlighting](https://github.com/yuin/goldmark-highlighting) | MIT License |
| [go.opencensus.io](https://go.opencensus.io) | Apache License 2.0 |
| [go.uber.org/atomic](https://go.uber.org/atomic) | MIT License |
| [gocloud.dev](https://gocloud.dev) | Apache License 2.0 |
| [golang.org/x/image](https://golang.org/x/image) | BSD 3-Clause "New" or "Revised" License |
| [golang.org/x/net](https://golang.org/x/net) | BSD 3-Clause "New" or "Revised" License |
| [golang.org/x/oauth2](https://golang.org/x/oauth2) | BSD 3-Clause "New" or "Revised" License |
| [golang.org/x/sync](https://golang.org/x/sync) | BSD 3-Clause "New" or "Revised" License |
| [golang.org/x/sys](https://golang.org/x/sys) | BSD 3-Clause "New" or "Revised" License |
| [golang.org/x/text](https://golang.org/x/text) | BSD 3-Clause "New" or "Revised" License |
| [golang.org/x/xerrors](https://golang.org/x/xerrors) | BSD 3-Clause "New" or "Revised" License |
| [google.golang.org/api](https://google.golang.org/api) | BSD 3-Clause "New" or "Revised" License |
| [google.golang.org/genproto](https://google.golang.org/genproto) | Apache License 2.0 |
| [gopkg.in/ini.v1](https://gopkg.in/ini.v1) | Apache License 2.0 |
| [gopkg.in/yaml.v2](https://gopkg.in/yaml.v2) | Apache License 2.0 |
+6 -1
View File
@@ -19,6 +19,8 @@ import (
"strings"
"time"
"github.com/gohugoio/hugo/common/maps"
"github.com/gohugoio/hugo/config"
"github.com/gohugoio/hugo/helpers"
@@ -123,6 +125,9 @@ func DecodeConfig(fs afero.Fs, cfg config.Provider) (Configs, error) {
_, isOsFs := fs.(*afero.OsFs)
for k, v := range m {
if _, ok := v.(maps.Params); !ok {
continue
}
cc := defaultCacheConfig
dc := &mapstructure.DecoderConfig{
@@ -137,7 +142,7 @@ func DecodeConfig(fs afero.Fs, cfg config.Provider) (Configs, error) {
}
if err := decoder.Decode(v); err != nil {
return nil, err
return nil, errors.Wrap(err, "failed to decode filecache config")
}
if cc.Dir == "" {
+2 -3
View File
@@ -25,7 +25,6 @@ import (
"github.com/gohugoio/hugo/config"
qt "github.com/frankban/quicktest"
"github.com/spf13/viper"
)
func TestDecodeConfig(t *testing.T) {
@@ -178,8 +177,8 @@ dir = "/"
c.Assert(err, qt.Not(qt.IsNil))
}
func newTestConfig() *viper.Viper {
cfg := viper.New()
func newTestConfig() config.Provider {
cfg := config.New()
cfg.Set("workingDir", filepath.FromSlash("/my/cool/hugoproject"))
cfg.Set("contentDir", "content")
cfg.Set("dataDir", "data")
+34 -14
View File
@@ -61,6 +61,11 @@ type commandeer struct {
logger loggers.Logger
serverConfig *config.Server
// Loading state
mustHaveConfigFile bool
failOnInitErr bool
running bool
// 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
@@ -153,7 +158,7 @@ func (c *commandeer) initFs(fs *hugofs.Fs) error {
return nil
}
func newCommandeer(mustHaveConfigFile, running bool, h *hugoBuilderCommon, f flagsToConfigHandler, cfgInit func(c *commandeer) error, subCmdVs ...*cobra.Command) (*commandeer, error) {
func newCommandeer(mustHaveConfigFile, failOnInitErr, running bool, h *hugoBuilderCommon, f flagsToConfigHandler, cfgInit func(c *commandeer) error, subCmdVs ...*cobra.Command) (*commandeer, error) {
var rebuildDebouncer func(f func())
if running {
// The time value used is tested with mass content replacements in a fairly big Hugo site.
@@ -175,11 +180,17 @@ func newCommandeer(mustHaveConfigFile, running bool, h *hugoBuilderCommon, f fla
visitedURLs: types.NewEvictingStringQueue(10),
debounce: rebuildDebouncer,
fullRebuildSem: semaphore.NewWeighted(1),
// Init state
mustHaveConfigFile: mustHaveConfigFile,
failOnInitErr: failOnInitErr,
running: running,
// This will be replaced later, but we need something to log to before the configuration is read.
logger: loggers.NewLogger(jww.LevelWarn, jww.LevelError, out, ioutil.Discard, running),
}
return c, c.loadConfig(mustHaveConfigFile, running)
return c, c.loadConfig()
}
type fileChangeDetector struct {
@@ -244,7 +255,7 @@ func (f *fileChangeDetector) PrepareNew() {
f.current = make(map[string]string)
}
func (c *commandeer) loadConfig(mustHaveConfigFile, running bool) error {
func (c *commandeer) loadConfig() error {
if c.DepsCfg == nil {
c.DepsCfg = &deps.DepsCfg{}
}
@@ -256,7 +267,7 @@ func (c *commandeer) loadConfig(mustHaveConfigFile, running bool) error {
cfg := c.DepsCfg
c.configured = false
cfg.Running = running
cfg.Running = c.running
var dir string
if c.h.source != "" {
@@ -270,7 +281,7 @@ func (c *commandeer) loadConfig(mustHaveConfigFile, running bool) error {
sourceFs = c.DepsCfg.Fs.Source
}
environment := c.h.getEnvironment(running)
environment := c.h.getEnvironment(c.running)
doWithConfig := func(cfg config.Provider) error {
if c.ftch != nil {
@@ -303,15 +314,22 @@ func (c *commandeer) loadConfig(mustHaveConfigFile, running bool) error {
WorkingDir: dir,
Filename: c.h.cfgFile,
AbsConfigDir: c.h.getConfigDir(dir),
Environ: os.Environ(),
Environment: environment,
},
cfgSetAndInit,
doWithConfig)
if err != nil && mustHaveConfigFile {
return err
} else if mustHaveConfigFile && len(configFiles) == 0 {
if err != nil {
// We should improve the error handling here,
// but with hugo mod init and similar there is a chicken and egg situation
// with modules already configured in config.toml, so ignore those errors.
if c.mustHaveConfigFile || (c.failOnInitErr && !moduleNotFoundRe.MatchString(err.Error())) {
return err
} else {
// Just make it a warning.
c.logger.Warnln(err)
}
} else if c.mustHaveConfigFile && len(configFiles) == 0 {
return hugolib.ErrNoConfigFile
}
@@ -323,7 +341,7 @@ func (c *commandeer) loadConfig(mustHaveConfigFile, running bool) error {
}
// Set some commonly used flags
c.doLiveReload = running && !c.Cfg.GetBool("disableLiveReload")
c.doLiveReload = c.running && !c.Cfg.GetBool("disableLiveReload")
c.fastRenderMode = c.doLiveReload && !c.Cfg.GetBool("disableFastRender")
c.showErrorInBrowser = c.doLiveReload && !c.Cfg.GetBool("disableBrowserError")
@@ -335,7 +353,7 @@ func (c *commandeer) loadConfig(mustHaveConfigFile, running bool) error {
}
}
logger, err := c.createLogger(config, running)
logger, err := c.createLogger(config)
if err != nil {
return err
}
@@ -395,7 +413,11 @@ func (c *commandeer) loadConfig(mustHaveConfigFile, running bool) error {
var h *hugolib.HugoSites
h, err = hugolib.NewHugoSites(*c.DepsCfg)
var createErr error
h, createErr = hugolib.NewHugoSites(*c.DepsCfg)
if h == nil || c.failOnInitErr {
err = createErr
}
c.hugoSites = h
close(c.created)
})
@@ -410,7 +432,5 @@ func (c *commandeer) loadConfig(mustHaveConfigFile, running bool) error {
}
config.Set("cacheDir", cacheDir)
cfg.Logger.Infoln("Using config file:", config.ConfigFileUsed())
return nil
}
+12 -2
View File
@@ -162,13 +162,21 @@ Complete documentation is available at http://gohugo.io/.`,
return nil
}
c, err := initializeConfig(true, cc.buildWatch, &cc.hugoBuilderCommon, cc, cfgInit)
// prevent cobra printing error so it can be handled here (before the timeTrack prints)
cmd.SilenceErrors = true
c, err := initializeConfig(true, true, cc.buildWatch, &cc.hugoBuilderCommon, cc, cfgInit)
if err != nil {
cmd.PrintErrln("Error:", err.Error())
return err
}
cc.c = c
return c.build()
err = c.build()
if err != nil {
cmd.PrintErrln("Error:", err.Error())
}
return err
},
})
@@ -204,6 +212,7 @@ type hugoBuilderCommon struct {
environment string
buildWatch bool
poll string
gc bool
@@ -291,6 +300,7 @@ func (cc *hugoBuilderCommon) handleFlags(cmd *cobra.Command) {
cmd.Flags().StringVarP(&cc.baseURL, "baseURL", "b", "", "hostname (and path) to the root, e.g. http://spf13.com/")
cmd.Flags().Bool("enableGitInfo", false, "add Git revision, date and author info to the pages")
cmd.Flags().BoolVar(&cc.gc, "gc", false, "enable to run some cleanup tasks (remove unused cache files) after the build")
cmd.Flags().StringVar(&cc.poll, "poll", "", "set this to a poll interval, e.g --poll 700ms, to use a poll based approach to watch for file system changes")
cmd.Flags().Bool("templateMetrics", false, "display metrics about template executions")
cmd.Flags().Bool("templateMetricsHints", false, "calculate some improvement hints when combined with --templateMetrics")
+6 -5
View File
@@ -20,6 +20,8 @@ import (
"path/filepath"
"testing"
"github.com/gohugoio/hugo/config"
"github.com/gohugoio/hugo/htesting"
"github.com/spf13/afero"
@@ -29,7 +31,6 @@ import (
"github.com/gohugoio/hugo/common/types"
"github.com/spf13/cobra"
"github.com/spf13/viper"
qt "github.com/frankban/quicktest"
)
@@ -120,7 +121,7 @@ func TestExecute(t *testing.T) {
resp := Execute([]string{"new", "site", siteDir, "-e=staging"})
c.Assert(resp.Err, qt.IsNil)
config := readFileFrom(c, filepath.Join(siteDir, "config.toml"))
c.Assert(config, qt.Contains, "baseURL = \"http://example.org/\"")
c.Assert(config, qt.Contains, "baseURL = 'http://example.org/'")
checkNewSiteInited(c, siteDir)
})
}
@@ -166,7 +167,7 @@ func TestFlags(t *testing.T) {
name: "ignoreVendor as bool",
args: []string{"server", "--ignoreVendor"},
check: func(c *qt.C, cmd *serverCmd) {
cfg := viper.New()
cfg := config.New()
cmd.flagsToConfig(cfg)
c.Assert(cfg.Get("ignoreVendor"), qt.Equals, true)
},
@@ -176,7 +177,7 @@ func TestFlags(t *testing.T) {
name: "ignoreVendorPaths",
args: []string{"server", "--ignoreVendorPaths=github.com/**"},
check: func(c *qt.C, cmd *serverCmd) {
cfg := viper.New()
cfg := config.New()
cmd.flagsToConfig(cfg)
c.Assert(cfg.Get("ignoreVendorPaths"), qt.Equals, "github.com/**")
},
@@ -216,7 +217,7 @@ func TestFlags(t *testing.T) {
c.Assert(sc.serverPort, qt.Equals, 1366)
c.Assert(sc.environment, qt.Equals, "testing")
cfg := viper.New()
cfg := config.New()
sc.flagsToConfig(cfg)
c.Assert(cfg.GetString("publishDir"), qt.Equals, "/tmp/mydestination")
c.Assert(cfg.GetString("contentDir"), qt.Equals, "mycontent")
+51 -12
View File
@@ -21,6 +21,9 @@ import (
"regexp"
"sort"
"strings"
"time"
"github.com/gohugoio/hugo/common/maps"
"github.com/gohugoio/hugo/parser"
"github.com/gohugoio/hugo/parser/metadecoders"
@@ -28,7 +31,6 @@ import (
"github.com/gohugoio/hugo/modules"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
var _ cmder = (*configCmd)(nil)
@@ -60,7 +62,7 @@ func (b *commandsBuilder) newConfigCmd() *configCmd {
}
func (c *configCmd) printMounts(cmd *cobra.Command, args []string) error {
cfg, err := initializeConfig(true, false, &c.hugoBuilderCommon, c, nil)
cfg, err := initializeConfig(true, false, false, &c.hugoBuilderCommon, c, nil)
if err != nil {
return err
}
@@ -68,7 +70,7 @@ func (c *configCmd) printMounts(cmd *cobra.Command, args []string) error {
allModules := cfg.Cfg.Get("allmodules").(modules.Modules)
for _, m := range allModules {
if err := parser.InterfaceToConfig(&modMounts{m: m}, metadecoders.JSON, os.Stdout); err != nil {
if err := parser.InterfaceToConfig(&modMounts{m: m, verbose: c.verbose}, metadecoders.JSON, os.Stdout); err != nil {
return err
}
}
@@ -76,12 +78,12 @@ func (c *configCmd) printMounts(cmd *cobra.Command, args []string) error {
}
func (c *configCmd) printConfig(cmd *cobra.Command, args []string) error {
cfg, err := initializeConfig(true, false, &c.hugoBuilderCommon, c, nil)
cfg, err := initializeConfig(true, false, false, &c.hugoBuilderCommon, c, nil)
if err != nil {
return err
}
allSettings := cfg.Cfg.(*viper.Viper).AllSettings()
allSettings := cfg.Cfg.Get("").(maps.Params)
// We need to clean up this, but we store objects in the config that
// isn't really interesting to the end user, so filter these.
@@ -114,7 +116,8 @@ func (c *configCmd) printConfig(cmd *cobra.Command, args []string) error {
}
type modMounts struct {
m modules.Module
verbose bool
m modules.Module
}
type modMount struct {
@@ -134,13 +137,49 @@ func (m *modMounts) MarshalJSON() ([]byte, error) {
})
}
var ownerPath string
if m.m.Owner() != nil {
ownerPath = m.m.Owner().Path()
}
if m.verbose {
config := m.m.Config()
return json.Marshal(&struct {
Path string `json:"path"`
Version string `json:"version"`
Time time.Time `json:"time"`
Owner string `json:"owner"`
Dir string `json:"dir"`
Meta map[string]interface{} `json:"meta"`
HugoVersion modules.HugoVersion `json:"hugoVersion"`
Mounts []modMount `json:"mounts"`
}{
Path: m.m.Path(),
Version: m.m.Version(),
Time: m.m.Time(),
Owner: ownerPath,
Dir: m.m.Dir(),
Meta: config.Params,
HugoVersion: config.HugoVersion,
Mounts: mounts,
})
}
return json.Marshal(&struct {
Path string `json:"path"`
Dir string `json:"dir"`
Mounts []modMount `json:"mounts"`
Path string `json:"path"`
Version string `json:"version"`
Time time.Time `json:"time"`
Owner string `json:"owner"`
Dir string `json:"dir"`
Mounts []modMount `json:"mounts"`
}{
Path: m.m.Path(),
Dir: m.m.Dir(),
Mounts: mounts,
Path: m.m.Path(),
Version: m.m.Version(),
Time: m.m.Time(),
Owner: ownerPath,
Dir: m.m.Dir(),
Mounts: mounts,
})
}
+1 -1
View File
@@ -102,7 +102,7 @@ func (cc *convertCmd) convertContents(format metadecoders.Format) error {
return newUserError("Unsafe operation not allowed, use --unsafe or set a different output path")
}
c, err := initializeConfig(true, false, &cc.hugoBuilderCommon, cc, nil)
c, err := initializeConfig(true, false, false, &cc.hugoBuilderCommon, cc, nil)
if err != nil {
return err
}
+1 -1
View File
@@ -60,7 +60,7 @@ documentation.
c.Set("maxDeletes", cc.maxDeletes)
return nil
}
comm, err := initializeConfig(true, false, &cc.hugoBuilderCommon, cc, cfgInit)
comm, err := initializeConfig(true, true, false, &cc.hugoBuilderCommon, cc, cfgInit)
if err != nil {
return err
}
+16 -1
View File
@@ -16,6 +16,8 @@ package commands
import (
"runtime"
"github.com/gohugoio/hugo/common/hugo"
"github.com/spf13/cobra"
jww "github.com/spf13/jwalterweatherman"
)
@@ -31,15 +33,28 @@ func newEnvCmd() *envCmd {
baseCmd: newBaseCmd(&cobra.Command{
Use: "env",
Short: "Print Hugo version and environment info",
Long: `Print Hugo version and environment info. This is useful in Hugo bug reports.`,
Long: `Print Hugo version and environment info. This is useful in Hugo bug reports.
If you add the -v flag, you will get a full dependency list.
`,
RunE: func(cmd *cobra.Command, args []string) error {
printHugoVersion()
jww.FEEDBACK.Printf("GOOS=%q\n", runtime.GOOS)
jww.FEEDBACK.Printf("GOARCH=%q\n", runtime.GOARCH)
jww.FEEDBACK.Printf("GOVERSION=%q\n", runtime.Version())
isVerbose, _ := cmd.Flags().GetBool("verbose")
if isVerbose {
deps := hugo.GetDependencyList()
for _, dep := range deps {
jww.FEEDBACK.Printf("%s\n", dep)
}
}
return nil
},
}),
}
}
+34 -20
View File
@@ -14,6 +14,9 @@
package commands
import (
"io"
"os"
"github.com/spf13/cobra"
jww "github.com/spf13/jwalterweatherman"
)
@@ -23,7 +26,7 @@ var _ cmder = (*genautocompleteCmd)(nil)
type genautocompleteCmd struct {
autocompleteTarget string
// bash for now (zsh and others will come)
// bash, zsh, fish or powershell
autocompleteType string
*baseCmd
@@ -37,43 +40,54 @@ func newGenautocompleteCmd() *genautocompleteCmd {
Short: "Generate shell autocompletion script for Hugo",
Long: `Generates a shell autocompletion script for Hugo.
NOTE: The current version supports Bash only.
This should work for *nix systems with Bash installed.
The script is written to the console (stdout).
By default, the file is written directly to /etc/bash_completion.d
for convenience, and the command may need superuser rights, e.g.:
To write to file, add the ` + "`--completionfile=/path/to/file`" + ` flag.
$ sudo hugo gen autocomplete
Add ` + "`--completionfile=/path/to/file`" + ` flag to set alternative
file-path and name.
Add ` + "`--type={bash, zsh, fish or powershell}`" + ` flag to set alternative
shell type.
Logout and in again to reload the completion scripts,
or just source them in directly:
$ . /etc/bash_completion`,
$ . /etc/bash_completion or /path/to/file`,
RunE: func(cmd *cobra.Command, args []string) error {
if cc.autocompleteType != "bash" {
return newUserError("Only Bash is supported for now")
var err error
var target io.Writer
if cc.autocompleteTarget == "" {
target = os.Stdout
} else {
target, _ = os.OpenFile(cc.autocompleteTarget, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
}
switch cc.autocompleteType {
case "bash":
err = cmd.Root().GenBashCompletion(target)
case "zsh":
err = cmd.Root().GenZshCompletion(target)
case "fish":
err = cmd.Root().GenFishCompletion(target, true)
case "powershell":
err = cmd.Root().GenPowerShellCompletion(target)
default:
return newUserError("Unsupported completion type")
}
err := cmd.Root().GenBashCompletionFile(cc.autocompleteTarget)
if err != nil {
return err
}
jww.FEEDBACK.Println("Bash completion file for Hugo saved to", cc.autocompleteTarget)
if cc.autocompleteTarget != "" {
jww.FEEDBACK.Println(cc.autocompleteType+" completion file for Hugo saved to", cc.autocompleteTarget)
}
return nil
},
})
cc.cmd.PersistentFlags().StringVarP(&cc.autocompleteTarget, "completionfile", "", "/etc/bash_completion.d/hugo.sh", "autocompletion file")
cc.cmd.PersistentFlags().StringVarP(&cc.autocompleteType, "type", "", "bash", "autocompletion type (currently only bash supported)")
// For bash-completion
cc.cmd.PersistentFlags().SetAnnotation("completionfile", cobra.BashCompFilenameExt, []string{})
cc.cmd.PersistentFlags().StringVarP(&cc.autocompleteTarget, "completionfile", "f", "", "autocompletion file, defaults to stdout")
cc.cmd.PersistentFlags().StringVarP(&cc.autocompleteType, "type", "t", "bash", "autocompletion type (bash, zsh, fish, or powershell)")
return cc
}
+3 -3
View File
@@ -37,9 +37,9 @@ func createGenChromaStyles() *genChromaStyles {
baseCmd: newBaseCmd(&cobra.Command{
Use: "chromastyles",
Short: "Generate CSS stylesheet for the Chroma code highlighter",
Long: `Generate CSS stylesheet for the Chroma code highlighter for a given style. This stylesheet is needed if pygmentsUseClasses is enabled in config.
Long: `Generate CSS stylesheet for the Chroma code highlighter for a given style. This stylesheet is needed if markup.highlight.noClasses is disabled in config.
See https://help.farbox.com/pygments.html for preview of available styles`,
See https://xyproto.github.io/splash/docs/all.html for a preview of the available styles`,
}),
}
@@ -47,7 +47,7 @@ See https://help.farbox.com/pygments.html for preview of available styles`,
return g.generate()
}
g.cmd.PersistentFlags().StringVar(&g.style, "style", "friendly", "highlighter style (see https://help.farbox.com/pygments.html)")
g.cmd.PersistentFlags().StringVar(&g.style, "style", "friendly", "highlighter style (see https://xyproto.github.io/splash/docs/)")
g.cmd.PersistentFlags().StringVar(&g.highlightStyle, "highlightStyle", "bg:#ffffcc", "style used for highlighting lines (see https://github.com/alecthomas/chroma)")
g.cmd.PersistentFlags().StringVar(&g.linesStyle, "linesStyle", "", "style used for line numbers (see https://github.com/alecthomas/chroma)")
+7 -5
View File
@@ -18,7 +18,6 @@ import (
"path"
"path/filepath"
"strings"
"time"
"github.com/gohugoio/hugo/helpers"
"github.com/gohugoio/hugo/hugofs"
@@ -36,7 +35,6 @@ type genDocCmd struct {
func newGenDocCmd() *genDocCmd {
const gendocFrontmatterTemplate = `---
date: %s
title: "%s"
slug: %s
url: %s
@@ -57,6 +55,12 @@ It creates one Markdown file per command with front matter suitable
for rendering in Hugo.`,
RunE: func(cmd *cobra.Command, args []string) error {
cmd.VisitParents(func(c *cobra.Command) {
// Disable the "Auto generated by spf13/cobra on DATE"
// as it creates a lot of diffs.
c.DisableAutoGenTag = true
})
if !strings.HasSuffix(cc.gendocdir, helpers.FilePathSeparator) {
cc.gendocdir += helpers.FilePathSeparator
}
@@ -66,19 +70,17 @@ for rendering in Hugo.`,
return err
}
}
now := time.Now().Format("2006-01-02")
prepender := func(filename string) string {
name := filepath.Base(filename)
base := strings.TrimSuffix(name, path.Ext(name))
url := "/commands/" + strings.ToLower(base) + "/"
return fmt.Sprintf(gendocFrontmatterTemplate, now, strings.Replace(base, "_", " ", -1), base, url)
return fmt.Sprintf(gendocFrontmatterTemplate, strings.Replace(base, "_", " ", -1), base, url)
}
linkHandler := func(name string) string {
base := strings.TrimSuffix(name, path.Ext(name))
return "/commands/" + strings.ToLower(base) + "/"
}
jww.FEEDBACK.Println("Generating Hugo command-line documentation in", cc.gendocdir, "...")
doc.GenMarkdownTreeCustom(cmd.Root(), cc.gendocdir, prepender, linkHandler)
jww.FEEDBACK.Println("Done.")
+60 -31
View File
@@ -30,6 +30,10 @@ import (
"syscall"
"time"
"github.com/gohugoio/hugo/hugofs/files"
"github.com/gohugoio/hugo/common/types"
"github.com/gohugoio/hugo/hugofs"
"github.com/gohugoio/hugo/resources/page"
@@ -37,6 +41,7 @@ import (
"github.com/pkg/errors"
"github.com/gohugoio/hugo/common/herrors"
"github.com/gohugoio/hugo/common/hugo"
"github.com/gohugoio/hugo/common/loggers"
"github.com/gohugoio/hugo/common/terminal"
@@ -113,11 +118,11 @@ func Execute(args []string) Response {
}
// InitializeConfig initializes a config file with sensible default configuration flags.
func initializeConfig(mustHaveConfigFile, running bool,
func initializeConfig(mustHaveConfigFile, failOnInitErr, running bool,
h *hugoBuilderCommon,
f flagsToConfigHandler,
cfgInit func(c *commandeer) error) (*commandeer, error) {
c, err := newCommandeer(mustHaveConfigFile, running, h, f, cfgInit)
c, err := newCommandeer(mustHaveConfigFile, failOnInitErr, running, h, f, cfgInit)
if err != nil {
return nil, err
}
@@ -125,7 +130,7 @@ func initializeConfig(mustHaveConfigFile, running bool,
return c, nil
}
func (c *commandeer) createLogger(cfg config.Provider, running bool) (loggers.Logger, error) {
func (c *commandeer) createLogger(cfg config.Provider) (loggers.Logger, error) {
var (
logHandle = ioutil.Discard
logThreshold = jww.LevelWarn
@@ -169,7 +174,7 @@ func (c *commandeer) createLogger(cfg config.Provider, running bool) (loggers.Lo
loggers.InitGlobalLogger(stdoutThreshold, logThreshold, outHandle, logHandle)
helpers.InitLoggers()
return loggers.NewLogger(stdoutThreshold, logThreshold, outHandle, logHandle, running), nil
return loggers.NewLogger(stdoutThreshold, logThreshold, outHandle, logHandle, c.running), nil
}
func initializeFlags(cmd *cobra.Command, cfg config.Provider) {
@@ -275,7 +280,8 @@ func isTerminal() bool {
return terminal.IsTerminal(os.Stdout)
}
func (c *commandeer) fullBuild() error {
func (c *commandeer) fullBuild(noBuildLock bool) error {
var (
g errgroup.Group
langCount map[string]uint64
@@ -283,6 +289,7 @@ func (c *commandeer) fullBuild() error {
if !c.h.quiet {
fmt.Println("Start building sites … ")
fmt.Println(hugo.BuildVersionString())
if isTerminal() {
defer func() {
fmt.Print(showCursor + clearLine)
@@ -299,7 +306,7 @@ func (c *commandeer) fullBuild() error {
return nil
}
buildSitesFunc := func() error {
if err := c.buildSites(); err != nil {
if err := c.buildSites(noBuildLock); err != nil {
return errors.Wrap(err, "Error building site")
}
return nil
@@ -492,7 +499,7 @@ func (c *commandeer) build() error {
}
}()
if err := c.fullBuild(); err != nil {
if err := c.fullBuild(false); err != nil {
return err
}
@@ -521,7 +528,7 @@ func (c *commandeer) build() error {
c.logger.Printf("Watching for changes in %s%s{%s}\n", baseWatchDir, helpers.FilePathSeparator, rootWatchDirs)
c.logger.Println("Press Ctrl+C to stop")
watcher, err := c.newWatcher(watchDirs...)
watcher, err := c.newWatcher(c.h.poll, watchDirs...)
checkErr(c.Logger, err)
defer watcher.Close()
@@ -535,7 +542,6 @@ func (c *commandeer) build() error {
}
func (c *commandeer) serverBuild() error {
defer c.timeTrack(time.Now(), "Built")
stopProfiling, err := c.initProfiling()
if err != nil {
@@ -548,7 +554,7 @@ func (c *commandeer) serverBuild() error {
}
}()
if err := c.fullBuild(); err != nil {
if err := c.fullBuild(false); err != nil {
return err
}
@@ -694,7 +700,7 @@ func (c *commandeer) getDirList() ([]string, error) {
return filepath.SkipDir
}
filenames = append(filenames, fi.Meta().Filename())
filenames = append(filenames, fi.Meta().Filename)
}
return nil
@@ -703,7 +709,7 @@ func (c *commandeer) getDirList() ([]string, error) {
watchFiles := c.hugo().PathSpec.BaseFs.WatchDirs()
for _, fi := range watchFiles {
if !fi.IsDir() {
filenames = append(filenames, fi.Meta().Filename())
filenames = append(filenames, fi.Meta().Filename)
continue
}
@@ -718,8 +724,8 @@ func (c *commandeer) getDirList() ([]string, error) {
return filenames, nil
}
func (c *commandeer) buildSites() (err error) {
return c.hugo().Build(hugolib.BuildCfg{})
func (c *commandeer) buildSites(noBuildLock bool) (err error) {
return c.hugo().Build(hugolib.BuildCfg{NoBuildLock: noBuildLock})
}
func (c *commandeer) handleBuildErr(err error, msg string) {
@@ -733,7 +739,6 @@ func (c *commandeer) handleBuildErr(err error, msg string) {
}
func (c *commandeer) rebuildSites(events []fsnotify.Event) error {
defer c.timeTrack(time.Now(), "Total")
c.buildErr = nil
visited := c.visitedURLs.PeekAllSet()
@@ -748,7 +753,7 @@ func (c *commandeer) rebuildSites(events []fsnotify.Event) error {
visited[home] = true
}
}
return c.hugo().Build(hugolib.BuildCfg{RecentlyVisited: visited, ErrRecovery: c.wasError}, events...)
return c.hugo().Build(hugolib.BuildCfg{NoBuildLock: true, RecentlyVisited: visited, ErrRecovery: c.wasError}, events...)
}
func (c *commandeer) partialReRender(urls ...string) error {
@@ -760,7 +765,7 @@ func (c *commandeer) partialReRender(urls ...string) error {
for _, url := range urls {
visited[url] = true
}
return c.hugo().Build(hugolib.BuildCfg{RecentlyVisited: visited, PartialReRender: true, ErrRecovery: c.wasError})
return c.hugo().Build(hugolib.BuildCfg{NoBuildLock: true, RecentlyVisited: visited, PartialReRender: true, ErrRecovery: c.wasError})
}
func (c *commandeer) fullRebuild(changeType string) {
@@ -790,7 +795,7 @@ func (c *commandeer) fullRebuild(changeType string) {
defer c.timeTrack(time.Now(), "Rebuilt")
c.commandeerHugoState = newCommandeerHugoState()
err := c.loadConfig(true, true)
err := c.loadConfig()
if err != nil {
// Set the processing on pause until the state is recovered.
c.paused = true
@@ -807,7 +812,7 @@ func (c *commandeer) fullRebuild(changeType string) {
return
}
err = c.buildSites()
err = c.buildSites(true)
if err != nil {
c.logger.Errorln(err)
} else if !c.h.buildWatch && !c.Cfg.GetBool("disableLiveReload") {
@@ -818,7 +823,7 @@ func (c *commandeer) fullRebuild(changeType string) {
}
// newWatcher creates a new watcher to watch filesystem events.
func (c *commandeer) newWatcher(dirList ...string) (*watcher.Batcher, error) {
func (c *commandeer) newWatcher(pollIntervalStr string, dirList ...string) (*watcher.Batcher, error) {
if runtime.GOOS == "darwin" {
tweakLimit()
}
@@ -828,7 +833,17 @@ func (c *commandeer) newWatcher(dirList ...string) (*watcher.Batcher, error) {
return nil, err
}
watcher, err := watcher.New(1 * time.Second)
var pollInterval time.Duration
poll := pollIntervalStr != ""
if poll {
pollInterval, err = types.ToDurationE(pollIntervalStr)
if err != nil {
return nil, fmt.Errorf("invalid value for flag poll: %s", err)
}
c.logger.Printf("Use watcher with poll interval %v", pollInterval)
}
watcher, err := watcher.New(500*time.Millisecond, pollInterval, poll)
if err != nil {
return nil, err
}
@@ -852,13 +867,19 @@ func (c *commandeer) newWatcher(dirList ...string) (*watcher.Batcher, error) {
for {
select {
case evs := <-watcher.Events:
unlock, err := c.hugo().BaseFs.LockBuild()
if err != nil {
c.logger.Errorln("Failed to acquire a build lock: %s", err)
return
}
c.handleEvents(watcher, staticSyncer, evs, configSet)
if c.showErrorInBrowser && c.errCount() > 0 {
// Need to reload browser to show the error
livereload.ForceRefresh()
}
case err := <-watcher.Errors:
if err != nil {
unlock()
case err := <-watcher.Errors():
if err != nil && !os.IsNotExist(err) {
c.logger.Errorln("Error while watching:", err)
}
}
@@ -1110,9 +1131,13 @@ func (c *commandeer) handleEvents(watcher *watcher.Batcher,
c.printChangeDetected("")
c.changeDetector.PrepareNew()
if err := c.rebuildSites(dynamicEvents); err != nil {
c.handleBuildErr(err, "Rebuild failed")
}
func() {
defer c.timeTrack(time.Now(), "Total")
if err := c.rebuildSites(dynamicEvents); err != nil {
c.handleBuildErr(err, "Rebuild failed")
}
}()
if doLiveReload {
if len(partitionedEvents.ContentEvents) == 0 && len(partitionedEvents.AssetEvents) > 0 {
@@ -1177,12 +1202,16 @@ func partitionDynamicEvents(sourceFs *filesystems.SourceFilesystems, events []fs
func pickOneWriteOrCreatePath(events []fsnotify.Event) string {
name := ""
// Some editors (for example notepad.exe on Windows) triggers a change
// both for directory and file. So we pick the longest path, which should
// be the file itself.
for _, ev := range events {
if (ev.Op&fsnotify.Write == fsnotify.Write || ev.Op&fsnotify.Create == fsnotify.Create) && len(ev.Name) > len(name) {
name = ev.Name
if ev.Op&fsnotify.Write == fsnotify.Write || ev.Op&fsnotify.Create == fsnotify.Create {
if files.IsIndexContentFile(ev.Name) {
return ev.Name
}
if files.IsContentFile(ev.Name) {
name = ev.Name
}
}
}
+7 -1
View File
@@ -13,7 +13,13 @@
package commands
import "github.com/spf13/cobra"
import (
// For time zone lookups on Windows without Go installed.
// See #8892
_ "time/tzdata"
"github.com/spf13/cobra"
)
func init() {
// This message to show to Windows users if Hugo is opened from explorer.exe
+1 -1
View File
@@ -40,7 +40,7 @@ func (lc *listCmd) buildSites(config map[string]interface{}) (*hugolib.HugoSites
return nil
}
c, err := initializeConfig(true, false, &lc.hugoBuilderCommon, lc, cfgInit)
c, err := initializeConfig(true, true, false, &lc.hugoBuilderCommon, lc, cfgInit)
if err != nil {
return nil, err
}
+4 -3
View File
@@ -71,11 +71,12 @@ Also note that if you configure a positive maxAge for the "modules" file cache,
if all {
com, err := c.initConfig(false)
if err != nil && !moduleNotFoundRe.MatchString(err.Error()) {
if err != nil && com == nil {
return err
}
_, err = com.hugo().FileCaches.ModulesCache().Prune(true)
count, err := com.hugo().FileCaches.ModulesCache().Prune(true)
com.logger.Printf("Deleted %d files from module cache.", count)
return err
}
return c.withModsClient(true, func(c *modules.Client) error {
@@ -284,7 +285,7 @@ func (c *modCmd) withHugo(f func(*hugolib.HugoSites) error) error {
}
func (c *modCmd) initConfig(failOnNoConfig bool) (*commandeer, error) {
com, err := initializeConfig(failOnNoConfig, false, &c.hugoBuilderCommon, c, nil)
com, err := initializeConfig(failOnNoConfig, false, false, &c.hugoBuilderCommon, c, nil)
if err != nil {
return nil, err
}
+3 -13
View File
@@ -71,7 +71,7 @@ func (n *newCmd) newContent(cmd *cobra.Command, args []string) error {
return nil
}
c, err := initializeConfig(true, false, &n.hugoBuilderCommon, n, cfgInit)
c, err := initializeConfig(true, true, false, &n.hugoBuilderCommon, n, cfgInit)
if err != nil {
return err
}
@@ -80,17 +80,7 @@ func (n *newCmd) newContent(cmd *cobra.Command, args []string) error {
return newUserError("path needs to be provided")
}
createPath := args[0]
var kind string
createPath, kind = newContentPathSection(c.hugo(), createPath)
if n.contentType != "" {
kind = n.contentType
}
return create.NewContent(c.hugo(), kind, createPath)
return create.NewContent(c.hugo(), n.contentType, args[0])
}
func mkdir(x ...string) {
@@ -118,7 +108,7 @@ func newContentPathSection(h *hugolib.HugoSites, path string) (string, string) {
if h != nil {
for _, dir := range h.BaseFs.Content.Dirs {
createpath = strings.TrimPrefix(createpath, dir.Meta().Filename())
createpath = strings.TrimPrefix(createpath, dir.Meta().Filename)
}
}
+3 -3
View File
@@ -19,6 +19,7 @@ import (
"path/filepath"
"strings"
"github.com/gohugoio/hugo/config"
"github.com/gohugoio/hugo/parser/metadecoders"
_errors "github.com/pkg/errors"
@@ -29,7 +30,6 @@ import (
"github.com/gohugoio/hugo/parser"
"github.com/spf13/cobra"
jww "github.com/spf13/jwalterweatherman"
"github.com/spf13/viper"
)
var _ cmder = (*newSiteCmd)(nil)
@@ -102,7 +102,7 @@ func (n *newSiteCmd) doNewSite(fs *hugofs.Fs, basepath string, force bool) error
// Create a default archetype file.
helpers.SafeWriteToDisk(filepath.Join(archeTypePath, "default.md"),
strings.NewReader(create.ArchetypeTemplateTemplate), fs.Source)
strings.NewReader(create.DefaultArchetypeTemplateTemplate), fs.Source)
jww.FEEDBACK.Printf("Congratulations! Your new Hugo site is created in %s.\n\n", basepath)
jww.FEEDBACK.Println(nextStepsText())
@@ -123,7 +123,7 @@ func (n *newSiteCmd) newSite(cmd *cobra.Command, args []string) error {
forceNew, _ := cmd.Flags().GetBool("force")
return n.doNewSite(hugofs.NewDefault(viper.New()), createpath, forceNew)
return n.doNewSite(hugofs.NewDefault(config.New()), createpath, forceNew)
}
func createConfig(fs *hugofs.Fs, inpath string, kind string) (err error) {
+2 -2
View File
@@ -38,7 +38,7 @@ func (b *commandsBuilder) newNewThemeCmd() *newThemeCmd {
cmd := &cobra.Command{
Use: "theme [name]",
Short: "Create a new theme",
Long: `Create a new theme (skeleton) called [name] in the current directory.
Long: `Create a new theme (skeleton) called [name] in ./themes.
New theme is a skeleton. Please add content to the touched files. Add your
name to the copyright line in the license and adjust the theme.toml file
as you see fit.`,
@@ -52,7 +52,7 @@ as you see fit.`,
// newTheme creates a new Hugo theme template
func (n *newThemeCmd) newTheme(cmd *cobra.Command, args []string) error {
c, err := initializeConfig(false, false, &n.hugoBuilderCommon, n, nil)
c, err := initializeConfig(false, false, false, &n.hugoBuilderCommon, n, nil)
if err != nil {
return err
}
+18 -4
View File
@@ -31,6 +31,8 @@ import (
"syscall"
"time"
"github.com/gohugoio/hugo/common/paths"
"github.com/pkg/errors"
"github.com/gohugoio/hugo/livereload"
@@ -234,12 +236,24 @@ func (sc *serverCmd) server(cmd *cobra.Command, args []string) error {
jww.WARN.Println("memstats error:", err)
}
c, err := initializeConfig(true, true, &sc.hugoBuilderCommon, sc, cfgInit)
// silence errors in cobra so we can handle them here
cmd.SilenceErrors = true
c, err := initializeConfig(true, true, true, &sc.hugoBuilderCommon, sc, cfgInit)
if err != nil {
cmd.PrintErrln("Error:", err.Error())
return err
}
if err := c.serverBuild(); err != nil {
err = func() error {
defer c.timeTrack(time.Now(), "Built")
err := c.serverBuild()
if err != nil {
cmd.PrintErrln("Error:", err.Error())
}
return err
}()
if err != nil {
return err
}
@@ -260,7 +274,7 @@ func (sc *serverCmd) server(cmd *cobra.Command, args []string) error {
for _, group := range watchGroups {
jww.FEEDBACK.Printf("Watching for changes in %s\n", group)
}
watcher, err := c.newWatcher(watchDirs...)
watcher, err := c.newWatcher(sc.poll, watchDirs...)
if err != nil {
return err
}
@@ -275,7 +289,7 @@ func (sc *serverCmd) server(cmd *cobra.Command, args []string) error {
func getRootWatchDirsStr(baseDir string, watchDirs []string) string {
relWatchDirs := make([]string, len(watchDirs))
for i, dir := range watchDirs {
relWatchDirs[i], _ = helpers.GetRelativePath(dir, baseDir)
relWatchDirs[i], _ = paths.GetRelativePath(dir, baseDir)
}
return strings.Join(helpers.UniqueStringsSorted(helpers.ExtractRootPaths(relWatchDirs)), ",")
+2 -2
View File
@@ -22,10 +22,10 @@ import (
"testing"
"time"
"github.com/gohugoio/hugo/config"
"github.com/gohugoio/hugo/helpers"
qt "github.com/frankban/quicktest"
"github.com/spf13/viper"
)
func TestServer(t *testing.T) {
@@ -101,7 +101,7 @@ func TestFixURL(t *testing.T) {
t.Run(test.TestName, func(t *testing.T) {
b := newCommandsBuilder()
s := b.newServerCmd()
v := viper.New()
v := config.New()
baseURL := test.CLIBaseURL
v.Set("baseURL", test.CfgBaseURL)
s.serverAppend = test.AppendPort
+1 -1
View File
@@ -58,7 +58,7 @@ func (s *staticSyncer) syncsStaticEvents(staticEvents []fsnotify.Event) error {
syncer.DestFs = c.Fs.Destination
// prevent spamming the log on changes
logger := helpers.NewDistinctFeedbackLogger()
logger := helpers.NewDistinctErrorLogger()
for _, ev := range staticEvents {
// Due to our approach of layering both directories and the content's rendered output
+11
View File
@@ -100,6 +100,17 @@ func WithFileContextForFile(e error, realFilename, filename string, fs afero.Fs,
return WithFileContext(e, realFilename, f, matcher)
}
// WithFileContextForFileDefault tries to add file context using the default line matcher.
func WithFileContextForFileDefault(err error, filename string, fs afero.Fs) error {
err, _ = WithFileContextForFile(
err,
filename,
filename,
fs,
SimpleLineMatcher)
return err
}
// WithFileContextForFile will try to add a file context with lines matching the given matcher.
// If no match could be found, the original error is returned with false as the second return value.
func WithFileContext(e error, realFilename string, r io.Reader, matcher LineMatcherFn) (error, bool) {
-1
View File
@@ -36,7 +36,6 @@ func TestToLineNumberError(t *testing.T) {
{errors.New(`template: _default/single.html:4:15: executing "_default/single.html" at <.Titles>: can't evaluate field Titles in type *hugolib.PageOutput`), 0, 4, 15},
{errors.New("parse failed: template: _default/bundle-resource-meta.html:11: unexpected in operand"), 0, 11, 1},
{errors.New(`failed:: template: _default/bundle-resource-meta.html:2:7: executing "main" at <.Titles>`), 0, 2, 7},
{errors.New("error in front matter: Near line 32 (last key parsed 'title')"), 0, 32, 1},
{errors.New(`failed to load translations: (6, 7): was expecting token =, but got "g" instead`), 0, 6, 7},
} {
+13 -2
View File
@@ -16,6 +16,10 @@ package herrors
import (
"regexp"
"strconv"
"github.com/pkg/errors"
"github.com/pelletier/go-toml/v2"
)
var lineNumberExtractors = []lineNumberExtractor{
@@ -24,8 +28,7 @@ var lineNumberExtractors = []lineNumberExtractor{
newLineNumberErrHandlerFromRegexp(".*:(\\d+):"),
// TOML parse errors
newLineNumberErrHandlerFromRegexp(".*Near line (\\d+)(\\s.*)"),
tomlLineNumberExtractor,
// YAML parse errors
newLineNumberErrHandlerFromRegexp("line (\\d+):"),
@@ -35,6 +38,14 @@ var lineNumberExtractors = []lineNumberExtractor{
type lineNumberExtractor func(e error) (int, int)
var tomlLineNumberExtractor = func(e error) (int, int) {
e = errors.Cause(e)
if terr, ok := e.(*toml.DecodeError); ok {
return terr.Position()
}
return -1, -1
}
func newLineNumberErrHandlerFromRegexp(expression string) lineNumberExtractor {
re := regexp.MustCompile(expression)
return extractLineNo(re)
+1 -1
View File
@@ -23,7 +23,7 @@ import (
)
// TODO(bep) replace the private versions in /tpl with these.
// IsInt returns whether the given kind is a number.
// IsNumber returns whether the given kind is a number.
func IsNumber(kind reflect.Kind) bool {
return IsInt(kind) || IsUint(kind) || IsFloat(kind)
}
+150
View File
@@ -0,0 +1,150 @@
// Copyright 2021 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 htime
import (
"strings"
"time"
"github.com/spf13/cast"
toml "github.com/pelletier/go-toml/v2"
"github.com/gohugoio/locales"
)
var (
longDayNames = []string{
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
}
shortDayNames = []string{
"Sun",
"Mon",
"Tue",
"Wed",
"Thu",
"Fri",
"Sat",
}
shortMonthNames = []string{
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec",
}
longMonthNames = []string{
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December",
}
)
func NewTimeFormatter(ltr locales.Translator) TimeFormatter {
if ltr == nil {
panic("must provide a locales.Translator")
}
return TimeFormatter{
ltr: ltr,
}
}
// TimeFormatter is locale aware.
type TimeFormatter struct {
ltr locales.Translator
}
func (f TimeFormatter) Format(t time.Time, layout string) string {
if layout == "" {
return ""
}
if layout[0] == ':' {
// It may be one of Hugo's custom layouts.
switch strings.ToLower(layout[1:]) {
case "date_full":
return f.ltr.FmtDateFull(t)
case "date_long":
return f.ltr.FmtDateLong(t)
case "date_medium":
return f.ltr.FmtDateMedium(t)
case "date_short":
return f.ltr.FmtDateShort(t)
case "time_full":
return f.ltr.FmtTimeFull(t)
case "time_long":
return f.ltr.FmtTimeLong(t)
case "time_medium":
return f.ltr.FmtTimeMedium(t)
case "time_short":
return f.ltr.FmtTimeShort(t)
}
}
s := t.Format(layout)
monthIdx := t.Month() - 1 // Month() starts at 1.
dayIdx := t.Weekday()
s = strings.ReplaceAll(s, longMonthNames[monthIdx], f.ltr.MonthWide(t.Month()))
if !strings.Contains(s, f.ltr.MonthWide(t.Month())) {
s = strings.ReplaceAll(s, shortMonthNames[monthIdx], f.ltr.MonthAbbreviated(t.Month()))
}
s = strings.ReplaceAll(s, longDayNames[dayIdx], f.ltr.WeekdayWide(t.Weekday()))
if !strings.Contains(s, f.ltr.WeekdayWide(t.Weekday())) {
s = strings.ReplaceAll(s, shortDayNames[dayIdx], f.ltr.WeekdayAbbreviated(t.Weekday()))
}
return s
}
func ToTimeInDefaultLocationE(i interface{}, location *time.Location) (tim time.Time, err error) {
switch vv := i.(type) {
case toml.LocalDate:
return vv.AsTime(location), nil
case toml.LocalDateTime:
return vv.AsTime(location), nil
// issue #8895
// datetimes parsed by `go-toml` have empty zone name
// convert back them into string and use `cast`
case time.Time:
i = vv.Format(time.RFC3339)
}
return cast.ToTimeInDefaultLocationE(i, location)
}
+148
View File
@@ -0,0 +1,148 @@
// Copyright 2021 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 htime
import (
"testing"
"time"
qt "github.com/frankban/quicktest"
translators "github.com/gohugoio/localescompressed"
)
func TestTimeFormatter(t *testing.T) {
c := qt.New(t)
june06, _ := time.Parse("2006-Jan-02", "2018-Jun-06")
june06 = june06.Add(7777 * time.Second)
jan06, _ := time.Parse("2006-Jan-02", "2018-Jan-06")
jan06 = jan06.Add(32 * time.Second)
mondayNovemberFirst, _ := time.Parse("2006-Jan-02", "2021-11-01")
mondayNovemberFirst = mondayNovemberFirst.Add(33 * time.Second)
c.Run("Norsk nynorsk", func(c *qt.C) {
f := NewTimeFormatter(translators.GetTranslator("nn"))
c.Assert(f.Format(june06, "Monday Jan 2 2006"), qt.Equals, "onsdag juni 6 2018")
c.Assert(f.Format(june06, "Mon January 2 2006"), qt.Equals, "on. juni 6 2018")
c.Assert(f.Format(june06, "Mon Mon"), qt.Equals, "on. on.")
})
c.Run("Custom layouts Norsk nynorsk", func(c *qt.C) {
f := NewTimeFormatter(translators.GetTranslator("nn"))
c.Assert(f.Format(june06, ":date_full"), qt.Equals, "onsdag 6. juni 2018")
c.Assert(f.Format(june06, ":date_long"), qt.Equals, "6. juni 2018")
c.Assert(f.Format(june06, ":date_medium"), qt.Equals, "6. juni 2018")
c.Assert(f.Format(june06, ":date_short"), qt.Equals, "06.06.2018")
c.Assert(f.Format(june06, ":time_full"), qt.Equals, "kl. 02:09:37 UTC")
c.Assert(f.Format(june06, ":time_long"), qt.Equals, "02:09:37 UTC")
c.Assert(f.Format(june06, ":time_medium"), qt.Equals, "02:09:37")
c.Assert(f.Format(june06, ":time_short"), qt.Equals, "02:09")
})
c.Run("Custom layouts English", func(c *qt.C) {
f := NewTimeFormatter(translators.GetTranslator("en"))
c.Assert(f.Format(june06, ":date_full"), qt.Equals, "Wednesday, June 6, 2018")
c.Assert(f.Format(june06, ":date_long"), qt.Equals, "June 6, 2018")
c.Assert(f.Format(june06, ":date_medium"), qt.Equals, "Jun 6, 2018")
c.Assert(f.Format(june06, ":date_short"), qt.Equals, "6/6/18")
c.Assert(f.Format(june06, ":time_full"), qt.Equals, "2:09:37 am UTC")
c.Assert(f.Format(june06, ":time_long"), qt.Equals, "2:09:37 am UTC")
c.Assert(f.Format(june06, ":time_medium"), qt.Equals, "2:09:37 am")
c.Assert(f.Format(june06, ":time_short"), qt.Equals, "2:09 am")
})
c.Run("English", func(c *qt.C) {
f := NewTimeFormatter(translators.GetTranslator("en"))
c.Assert(f.Format(june06, "Monday Jan 2 2006"), qt.Equals, "Wednesday Jun 6 2018")
c.Assert(f.Format(june06, "Mon January 2 2006"), qt.Equals, "Wed June 6 2018")
c.Assert(f.Format(june06, "Mon Mon"), qt.Equals, "Wed Wed")
})
c.Run("Weekdays German", func(c *qt.C) {
tr := translators.GetTranslator("de")
f := NewTimeFormatter(tr)
// Issue #9107
for i, weekDayWideGerman := range []string{"Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag", "Sonntag"} {
date := mondayNovemberFirst.Add(time.Duration(i*24) * time.Hour)
c.Assert(tr.WeekdayWide(date.Weekday()), qt.Equals, weekDayWideGerman)
c.Assert(f.Format(date, "Monday"), qt.Equals, weekDayWideGerman)
}
for i, weekDayAbbreviatedGerman := range []string{"Mo.", "Di.", "Mi.", "Do.", "Fr.", "Sa.", "So."} {
date := mondayNovemberFirst.Add(time.Duration(i*24) * time.Hour)
c.Assert(tr.WeekdayAbbreviated(date.Weekday()), qt.Equals, weekDayAbbreviatedGerman)
c.Assert(f.Format(date, "Mon"), qt.Equals, weekDayAbbreviatedGerman)
}
})
c.Run("Months German", func(c *qt.C) {
tr := translators.GetTranslator("de")
f := NewTimeFormatter(tr)
// Issue #9107
for i, monthWideNorway := range []string{"Januar", "Februar", "März", "April", "Mai", "Juni", "Juli"} {
date := jan06.Add(time.Duration(i*24*31) * time.Hour)
c.Assert(tr.MonthWide(date.Month()), qt.Equals, monthWideNorway)
c.Assert(f.Format(date, "January"), qt.Equals, monthWideNorway)
}
})
}
func BenchmarkTimeFormatter(b *testing.B) {
june06, _ := time.Parse("2006-Jan-02", "2018-Jun-06")
b.Run("Native", func(b *testing.B) {
for i := 0; i < b.N; i++ {
got := june06.Format("Monday Jan 2 2006")
if got != "Wednesday Jun 6 2018" {
b.Fatalf("invalid format, got %q", got)
}
}
})
b.Run("Localized", func(b *testing.B) {
f := NewTimeFormatter(translators.GetTranslator("nn"))
b.ResetTimer()
for i := 0; i < b.N; i++ {
got := f.Format(june06, "Monday Jan 2 2006")
if got != "onsdag juni 6 2018" {
b.Fatalf("invalid format, got %q", got)
}
}
})
b.Run("Localized Custom", func(b *testing.B) {
f := NewTimeFormatter(translators.GetTranslator("nn"))
b.ResetTimer()
for i := 0; i < b.N; i++ {
got := f.Format(june06, ":date_medium")
if got != "6. juni 2018" {
b.Fatalf("invalid format, got %q", got)
}
}
})
}
+54 -3
View File
@@ -18,6 +18,8 @@ import (
"html/template"
"os"
"path/filepath"
"runtime/debug"
"sort"
"strings"
"github.com/gohugoio/hugo/hugofs/files"
@@ -34,12 +36,15 @@ const (
)
var (
// commitHash contains the current Git revision. Use make to build to make
// sure this gets set.
// commitHash contains the current Git revision.
// Use mage to build to make sure this gets set.
commitHash string
// buildDate contains the date of the current build.
buildDate string
// vendorInfo contains vendor notes about the current build.
vendorInfo string
)
// Info contains information about the current Hugo environment
@@ -68,6 +73,10 @@ func (i Info) IsProduction() bool {
return i.Environment == EnvironmentProduction
}
func (i Info) IsExtended() bool {
return IsExtended
}
// NewInfo creates a new Hugo Info object.
func NewInfo(environment string) Info {
if environment == "" {
@@ -93,10 +102,52 @@ func GetExecEnviron(workDir string, cfg config.Provider, fs afero.Fs) []string {
if err == nil {
for _, fi := range fis {
key := fmt.Sprintf("HUGO_FILE_%s", strings.ReplaceAll(strings.ToUpper(fi.Name()), ".", "_"))
value := fi.(hugofs.FileMetaInfo).Meta().Filename()
value := fi.(hugofs.FileMetaInfo).Meta().Filename
config.SetEnvVars(&env, key, value)
}
}
return env
}
// GetDependencyList returns a sorted dependency list on the format package="version".
// It includes both Go dependencies and (a manually maintained) list of C(++) dependencies.
func GetDependencyList() []string {
var deps []string
formatDep := func(path, version string) string {
return fmt.Sprintf("%s=%q", path, version)
}
if IsExtended {
deps = append(
deps,
// TODO(bep) consider adding a DepsNonGo() method to these upstream projects.
formatDep("github.com/sass/libsass", "3.6.5"),
formatDep("github.com/webmproject/libwebp", "v1.2.0"),
)
}
bi, ok := debug.ReadBuildInfo()
if !ok {
return deps
}
for _, dep := range bi.Deps {
deps = append(deps, formatDep(dep.Path, dep.Version))
}
sort.Strings(deps)
return deps
}
// IsRunningAsTest reports whether we are running as a test.
func IsRunningAsTest() bool {
for _, arg := range os.Args {
if strings.HasPrefix(arg, "-test") {
return true
}
}
return false
}
+1
View File
@@ -32,6 +32,7 @@ func TestHugoInfo(t *testing.T) {
c.Assert(hugoInfo.Environment, qt.Equals, "production")
c.Assert(string(hugoInfo.Generator()), qt.Contains, fmt.Sprintf("Hugo %s", hugoInfo.Version()))
c.Assert(hugoInfo.IsProduction(), qt.Equals, true)
c.Assert(hugoInfo.IsExtended(), qt.Equals, IsExtended)
devHugoInfo := NewInfo("development")
c.Assert(devHugoInfo.IsProduction(), qt.Equals, false)
+11 -3
View File
@@ -127,14 +127,15 @@ func (v Version) NextPatchLevel(level int) Version {
// BuildVersionString creates a version string. This is what you see when
// running "hugo version".
func BuildVersionString() string {
program := "Hugo Static Site Generator"
// program := "Hugo Static Site Generator"
program := "hugo"
version := "v" + CurrentVersion.String()
if commitHash != "" {
version += "-" + strings.ToUpper(commitHash)
}
if IsExtended {
version += "/extended"
version += "+extended"
}
osArch := runtime.GOOS + "/" + runtime.GOARCH
@@ -144,7 +145,14 @@ func BuildVersionString() string {
date = "unknown"
}
return fmt.Sprintf("%s %s %s BuildDate: %s", program, version, osArch, date)
versionString := fmt.Sprintf("%s %s %s BuildDate=%s",
program, version, osArch, date)
if vendorInfo != "" {
versionString += " VendorInfo=" + vendorInfo
}
return versionString
}
func version(version float32, patchVersion int, suffix string) string {
+2 -2
View File
@@ -16,7 +16,7 @@ package hugo
// CurrentVersion represents the current build version.
// This should be the only one.
var CurrentVersion = Version{
Number: 0.80,
PatchLevel: 0,
Number: 0.89,
PatchLevel: 1,
Suffix: "",
}
+8
View File
@@ -22,6 +22,7 @@ import (
type IgnorableLogger interface {
Logger
Errorsf(statementID, format string, v ...interface{})
Apply(logger Logger) IgnorableLogger
}
type ignorableLogger struct {
@@ -55,3 +56,10 @@ ignoreErrors = [%q]`, statementID)
l.Errorf(format, v...)
}
func (l ignorableLogger) Apply(logger Logger) IgnorableLogger {
return ignorableLogger{
Logger: logger,
statements: l.statements,
}
}
+10
View File
@@ -59,6 +59,8 @@ type Logger interface {
Println(v ...interface{})
PrintTimerIfDelayed(start time.Time, name string)
Debug() *log.Logger
Debugf(format string, v ...interface{})
Debugln(v ...interface{})
Info() *log.Logger
Infof(format string, v ...interface{})
Infoln(v ...interface{})
@@ -108,6 +110,14 @@ func (l *logger) Debug() *log.Logger {
return l.DEBUG
}
func (l *logger) Debugf(format string, v ...interface{}) {
l.DEBUG.Printf(format, v...)
}
func (l *logger) Debugln(v ...interface{}) {
l.DEBUG.Println(v...)
}
func (l *logger) Infof(format string, v ...interface{}) {
l.INFO.Printf(format, v...)
}
+60 -34
View File
@@ -17,54 +17,81 @@ import (
"fmt"
"strings"
"github.com/gobwas/glob"
"github.com/gohugoio/hugo/common/types"
"github.com/gobwas/glob"
"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 Params.
func ToLower(m Params) {
for k, v := range m {
var retyped bool
switch v.(type) {
case map[interface{}]interface{}:
var p Params = cast.ToStringMap(v)
v = p
ToLower(p)
retyped = true
case map[string]interface{}:
var p Params = v.(map[string]interface{})
v = p
ToLower(p)
retyped = true
}
lKey := strings.ToLower(k)
if retyped || k != lKey {
delete(m, k)
m[lKey] = v
}
}
}
// ToStringMapE converts in to map[string]interface{}.
func ToStringMapE(in interface{}) (map[string]interface{}, error) {
switch in.(type) {
switch vv := in.(type) {
case Params:
return in.(Params), nil
return vv, nil
case map[string]string:
var m = map[string]interface{}{}
for k, v := range vv {
m[k] = v
}
return m, nil
default:
return cast.ToStringMapE(in)
}
}
// ToParamsAndPrepare converts in to Params and prepares it for use.
// If in is nil, an empty map is returned.
// See PrepareParams.
func ToParamsAndPrepare(in interface{}) (Params, bool) {
if types.IsNil(in) {
return Params{}, true
}
m, err := ToStringMapE(in)
if err != nil {
return nil, false
}
PrepareParams(m)
return m, true
}
// MustToParamsAndPrepare calls ToParamsAndPrepare and panics if it fails.
func MustToParamsAndPrepare(in interface{}) Params {
if p, ok := ToParamsAndPrepare(in); ok {
return p
} else {
panic(fmt.Sprintf("cannot convert %T to maps.Params", in))
}
}
// ToStringMap converts in to map[string]interface{}.
func ToStringMap(in interface{}) map[string]interface{} {
m, _ := ToStringMapE(in)
return m
}
// ToStringMapStringE converts in to map[string]string.
func ToStringMapStringE(in interface{}) (map[string]string, error) {
m, err := ToStringMapE(in)
if err != nil {
return nil, err
}
return cast.ToStringMapStringE(m)
}
// ToStringMapString converts in to map[string]string.
func ToStringMapString(in interface{}) map[string]string {
m, _ := ToStringMapStringE(in)
return m
}
// ToStringMapBool converts in to bool.
func ToStringMapBool(in interface{}) map[string]bool {
m, _ := ToStringMapE(in)
return cast.ToStringMapBool(m)
}
// ToSliceStringMap converts in to []map[string]interface{}.
func ToSliceStringMap(in interface{}) ([]map[string]interface{}, error) {
switch v := in.(type) {
case []map[string]interface{}:
@@ -127,9 +154,8 @@ func (KeyRenamer) keyPath(k1, k2 string) string {
k1, k2 = strings.ToLower(k1), strings.ToLower(k2)
if k1 == "" {
return k2
} else {
return k1 + "/" + k2
}
return k1 + "/" + k2
}
func (r KeyRenamer) renamePath(parentKeyPath string, m map[string]interface{}) {
+21 -5
View File
@@ -21,10 +21,10 @@ import (
qt "github.com/frankban/quicktest"
)
func TestToLower(t *testing.T) {
func TestPrepareParams(t *testing.T) {
tests := []struct {
input map[string]interface{}
expected map[string]interface{}
input Params
expected Params
}{
{
map[string]interface{}{
@@ -47,6 +47,9 @@ func TestToLower(t *testing.T) {
"gHi": map[string]interface{}{
"J": 25,
},
"jKl": map[string]string{
"M": "26",
},
},
Params{
"abc": 32,
@@ -60,14 +63,17 @@ func TestToLower(t *testing.T) {
"ghi": Params{
"j": 25,
},
"jkl": Params{
"m": "26",
},
},
},
}
for i, test := range tests {
t.Run(fmt.Sprint(i), func(t *testing.T) {
// ToLower modifies input.
ToLower(test.input)
// PrepareParams modifies input.
PrepareParams(test.input)
if !reflect.DeepEqual(test.expected, test.input) {
t.Errorf("[%d] Expected\n%#v, got\n%#v\n", i, test.expected, test.input)
}
@@ -108,6 +114,16 @@ func TestToSliceStringMap(t *testing.T) {
}
}
func TestToParamsAndPrepare(t *testing.T) {
c := qt.New(t)
_, ok := ToParamsAndPrepare(map[string]interface{}{"A": "av"})
c.Assert(ok, qt.IsTrue)
params, ok := ToParamsAndPrepare(nil)
c.Assert(ok, qt.IsTrue)
c.Assert(params, qt.DeepEquals, Params{})
}
func TestRenameKeys(t *testing.T) {
c := qt.New(t)
+179
View File
@@ -14,6 +14,7 @@
package maps
import (
"fmt"
"strings"
"github.com/spf13/cast"
@@ -29,6 +30,118 @@ func (p Params) Get(indices ...string) interface{} {
return v
}
// Set overwrites values in p with values in pp for common or new keys.
// This is done recursively.
func (p Params) Set(pp Params) {
for k, v := range pp {
vv, found := p[k]
if !found {
p[k] = v
} else {
switch vvv := vv.(type) {
case Params:
if pv, ok := v.(Params); ok {
vvv.Set(pv)
} else {
p[k] = v
}
default:
p[k] = v
}
}
}
}
// IsZero returns true if p is considered empty.
func (p Params) IsZero() bool {
if p == nil || len(p) == 0 {
return true
}
if len(p) > 1 {
return false
}
for k, _ := range p {
return k == mergeStrategyKey
}
return false
}
// Merge transfers values from pp to p for new keys.
// This is done recursively.
func (p Params) Merge(pp Params) {
p.merge("", pp)
}
// MergeRoot transfers values from pp to p for new keys where p is the
// root of the tree.
// This is done recursively.
func (p Params) MergeRoot(pp Params) {
ms, _ := p.GetMergeStrategy()
p.merge(ms, pp)
}
func (p Params) merge(ps ParamsMergeStrategy, pp Params) {
ns, found := p.GetMergeStrategy()
var ms = ns
if !found && ps != "" {
ms = ps
}
noUpdate := ms == ParamsMergeStrategyNone
noUpdate = noUpdate || (ps != "" && ps == ParamsMergeStrategyShallow)
for k, v := range pp {
if k == mergeStrategyKey {
continue
}
vv, found := p[k]
if found {
// Key matches, if both sides are Params, we try to merge.
if vvv, ok := vv.(Params); ok {
if pv, ok := v.(Params); ok {
vvv.merge(ms, pv)
}
}
} else if !noUpdate {
p[k] = v
}
}
}
func (p Params) GetMergeStrategy() (ParamsMergeStrategy, bool) {
if v, found := p[mergeStrategyKey]; found {
if s, ok := v.(ParamsMergeStrategy); ok {
return s, true
}
}
return ParamsMergeStrategyShallow, false
}
func (p Params) DeleteMergeStrategy() bool {
if _, found := p[mergeStrategyKey]; found {
delete(p, mergeStrategyKey)
return true
}
return false
}
func (p Params) SetDefaultMergeStrategy(s ParamsMergeStrategy) {
switch s {
case ParamsMergeStrategyDeep, ParamsMergeStrategyNone, ParamsMergeStrategyShallow:
default:
panic(fmt.Sprintf("invalid merge strategy %q", s))
}
p[mergeStrategyKey] = s
}
func getNested(m map[string]interface{}, indices []string) (interface{}, string, map[string]interface{}) {
if len(indices) == 0 {
return nil, "", nil
@@ -108,3 +221,69 @@ func GetNestedParamFn(keyStr, separator string, lookupFn func(key string) interf
return nil, "", nil, nil
}
// ParamsMergeStrategy tells what strategy to use in Params.Merge.
type ParamsMergeStrategy string
const (
// Do not merge.
ParamsMergeStrategyNone ParamsMergeStrategy = "none"
// Only add new keys.
ParamsMergeStrategyShallow ParamsMergeStrategy = "shallow"
// Add new keys, merge existing.
ParamsMergeStrategyDeep ParamsMergeStrategy = "deep"
mergeStrategyKey = "_merge"
)
func toMergeStrategy(v interface{}) ParamsMergeStrategy {
s := ParamsMergeStrategy(cast.ToString(v))
switch s {
case ParamsMergeStrategyDeep, ParamsMergeStrategyNone, ParamsMergeStrategyShallow:
return s
default:
return ParamsMergeStrategyDeep
}
}
// PrepareParams
// * makes all the keys in the given map lower cased and will do so
// * This will modify the map given.
// * Any nested map[interface{}]interface{}, map[string]interface{},map[string]string will be converted to Params.
// * Any _merge value will be converted to proper type and value.
func PrepareParams(m Params) {
for k, v := range m {
var retyped bool
lKey := strings.ToLower(k)
if lKey == mergeStrategyKey {
v = toMergeStrategy(v)
retyped = true
} else {
switch vv := v.(type) {
case map[interface{}]interface{}:
var p Params = cast.ToStringMap(v)
v = p
PrepareParams(p)
retyped = true
case map[string]interface{}:
var p Params = v.(map[string]interface{})
v = p
PrepareParams(p)
retyped = true
case map[string]string:
p := make(Params)
for k, v := range vv {
p[k] = v
}
v = p
PrepareParams(p)
retyped = true
}
}
if retyped || k != lKey {
delete(m, k)
m[lKey] = v
}
}
}
+99
View File
@@ -69,3 +69,102 @@ func TestGetNestedParamFnNestedNewKey(t *testing.T) {
c.Assert(nestedKey, qt.Equals, "new")
c.Assert(owner, qt.DeepEquals, nested)
}
func TestParamsSetAndMerge(t *testing.T) {
c := qt.New(t)
createParamsPair := func() (Params, Params) {
p1 := Params{"a": "av", "c": "cv", "nested": Params{"al2": "al2v", "cl2": "cl2v"}}
p2 := Params{"b": "bv", "a": "abv", "nested": Params{"bl2": "bl2v", "al2": "al2bv"}, mergeStrategyKey: ParamsMergeStrategyDeep}
return p1, p2
}
p1, p2 := createParamsPair()
p1.Set(p2)
c.Assert(p1, qt.DeepEquals, Params{
"a": "abv",
"c": "cv",
"nested": Params{
"al2": "al2bv",
"cl2": "cl2v",
"bl2": "bl2v",
},
"b": "bv",
mergeStrategyKey: ParamsMergeStrategyDeep,
})
p1, p2 = createParamsPair()
p1.Merge(p2)
// Default is to do a shallow merge.
c.Assert(p1, qt.DeepEquals, Params{
"c": "cv",
"nested": Params{
"al2": "al2v",
"cl2": "cl2v",
},
"b": "bv",
"a": "av",
})
p1, p2 = createParamsPair()
p1.SetDefaultMergeStrategy(ParamsMergeStrategyNone)
p1.Merge(p2)
p1.DeleteMergeStrategy()
c.Assert(p1, qt.DeepEquals, Params{
"a": "av",
"c": "cv",
"nested": Params{
"al2": "al2v",
"cl2": "cl2v",
},
})
p1, p2 = createParamsPair()
p1.SetDefaultMergeStrategy(ParamsMergeStrategyShallow)
p1.Merge(p2)
p1.DeleteMergeStrategy()
c.Assert(p1, qt.DeepEquals, Params{
"a": "av",
"c": "cv",
"nested": Params{
"al2": "al2v",
"cl2": "cl2v",
},
"b": "bv",
})
p1, p2 = createParamsPair()
p1.SetDefaultMergeStrategy(ParamsMergeStrategyDeep)
p1.Merge(p2)
p1.DeleteMergeStrategy()
c.Assert(p1, qt.DeepEquals, Params{
"nested": Params{
"al2": "al2v",
"cl2": "cl2v",
"bl2": "bl2v",
},
"b": "bv",
"a": "av",
"c": "cv",
})
}
func TestParamsIsZero(t *testing.T) {
c := qt.New(t)
var nilParams Params
c.Assert(Params{}.IsZero(), qt.IsTrue)
c.Assert(nilParams.IsZero(), qt.IsTrue)
c.Assert(Params{"foo": "bar"}.IsZero(), qt.IsFalse)
c.Assert(Params{"_merge": "foo", "foo": "bar"}.IsZero(), qt.IsFalse)
c.Assert(Params{"_merge": "foo"}.IsZero(), qt.IsTrue)
}
+11
View File
@@ -129,6 +129,17 @@ func (c *Scratch) SetInMap(key string, mapKey string, value interface{}) string
return ""
}
// DeleteInMap deletes a value to a map with the given key in the Node context.
func (c *Scratch) DeleteInMap(key string, mapKey string) string {
c.mu.Lock()
_, found := c.values[key]
if found {
delete(c.values[key].(map[string]interface{}), mapKey)
}
c.mu.Unlock()
return ""
}
// GetSortedMapValues returns a sorted map previously filled with SetInMap.
func (c *Scratch) GetSortedMapValues(key string) interface{} {
c.mu.RLock()
+14
View File
@@ -188,6 +188,20 @@ func TestScratchSetInMap(t *testing.T) {
c.Assert(scratch.GetSortedMapValues("key"), qt.DeepEquals, []interface{}{0: "Abc (updated)", 1: "Def", 2: "Lux", 3: "Zyx"})
}
func TestScratchDeleteInMap(t *testing.T) {
t.Parallel()
c := qt.New(t)
scratch := NewScratch()
scratch.SetInMap("key", "lux", "Lux")
scratch.SetInMap("key", "abc", "Abc")
scratch.SetInMap("key", "zyx", "Zyx")
scratch.DeleteInMap("key", "abc")
scratch.SetInMap("key", "def", "Def")
scratch.DeleteInMap("key", "lmn") // Do nothing
c.Assert(scratch.GetSortedMapValues("key"), qt.DeepEquals, []interface{}{0: "Def", 1: "Lux", 2: "Zyx"})
}
func TestScratchGetSortedMapValues(t *testing.T) {
t.Parallel()
scratch := NewScratch()
+312
View File
@@ -0,0 +1,312 @@
// Copyright 2021 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 paths
import (
"errors"
"fmt"
"os"
"path"
"path/filepath"
"regexp"
"strings"
)
// FilePathSeparator as defined by os.Separator.
const FilePathSeparator = string(filepath.Separator)
// filepathPathBridge is a bridge for common functionality in filepath vs path
type filepathPathBridge interface {
Base(in string) string
Clean(in string) string
Dir(in string) string
Ext(in string) string
Join(elem ...string) string
Separator() string
}
type filepathBridge struct {
}
func (filepathBridge) Base(in string) string {
return filepath.Base(in)
}
func (filepathBridge) Clean(in string) string {
return filepath.Clean(in)
}
func (filepathBridge) Dir(in string) string {
return filepath.Dir(in)
}
func (filepathBridge) Ext(in string) string {
return filepath.Ext(in)
}
func (filepathBridge) Join(elem ...string) string {
return filepath.Join(elem...)
}
func (filepathBridge) Separator() string {
return FilePathSeparator
}
var fpb filepathBridge
// ToSlashTrimLeading is just a filepath.ToSlash with an added / prefix trimmer.
func ToSlashTrimLeading(s string) string {
return strings.TrimPrefix(filepath.ToSlash(s), "/")
}
// MakeTitle converts the path given to a suitable title, trimming whitespace
// and replacing hyphens with whitespace.
func MakeTitle(inpath string) string {
return strings.Replace(strings.TrimSpace(inpath), "-", " ", -1)
}
// ReplaceExtension takes a path and an extension, strips the old extension
// and returns the path with the new extension.
func ReplaceExtension(path string, newExt string) string {
f, _ := fileAndExt(path, fpb)
return f + "." + newExt
}
func makePathRelative(inPath string, possibleDirectories ...string) (string, error) {
for _, currentPath := range possibleDirectories {
if strings.HasPrefix(inPath, currentPath) {
return strings.TrimPrefix(inPath, currentPath), nil
}
}
return inPath, errors.New("can't extract relative path, unknown prefix")
}
// Should be good enough for Hugo.
var isFileRe = regexp.MustCompile(`.*\..{1,6}$`)
// GetDottedRelativePath expects a relative path starting after the content directory.
// It returns a relative path with dots ("..") navigating up the path structure.
func GetDottedRelativePath(inPath string) string {
inPath = filepath.Clean(filepath.FromSlash(inPath))
if inPath == "." {
return "./"
}
if !isFileRe.MatchString(inPath) && !strings.HasSuffix(inPath, FilePathSeparator) {
inPath += FilePathSeparator
}
if !strings.HasPrefix(inPath, FilePathSeparator) {
inPath = FilePathSeparator + inPath
}
dir, _ := filepath.Split(inPath)
sectionCount := strings.Count(dir, FilePathSeparator)
if sectionCount == 0 || dir == FilePathSeparator {
return "./"
}
var dottedPath string
for i := 1; i < sectionCount; i++ {
dottedPath += "../"
}
return dottedPath
}
// ExtNoDelimiter takes a path and returns the extension, excluding the delimiter, i.e. "md".
func ExtNoDelimiter(in string) string {
return strings.TrimPrefix(Ext(in), ".")
}
// Ext takes a path and returns the extension, including the delimiter, i.e. ".md".
func Ext(in string) string {
_, ext := fileAndExt(in, fpb)
return ext
}
// PathAndExt is the same as FileAndExt, but it uses the path package.
func PathAndExt(in string) (string, string) {
return fileAndExt(in, pb)
}
// FileAndExt takes a path and returns the file and extension separated,
// the extension including the delimiter, i.e. ".md".
func FileAndExt(in string) (string, string) {
return fileAndExt(in, fpb)
}
// FileAndExtNoDelimiter takes a path and returns the file and extension separated,
// the extension excluding the delimiter, e.g "md".
func FileAndExtNoDelimiter(in string) (string, string) {
file, ext := fileAndExt(in, fpb)
return file, strings.TrimPrefix(ext, ".")
}
// Filename takes a file path, strips out the extension,
// and returns the name of the file.
func Filename(in string) (name string) {
name, _ = fileAndExt(in, fpb)
return
}
// PathNoExt takes a path, strips out the extension,
// and returns the name of the file.
func PathNoExt(in string) string {
return strings.TrimSuffix(in, path.Ext(in))
}
// FileAndExt returns the filename and any extension of a file path as
// two separate strings.
//
// If the path, in, contains a directory name ending in a slash,
// then both name and ext will be empty strings.
//
// If the path, in, is either the current directory, the parent
// directory or the root directory, or an empty string,
// then both name and ext will be empty strings.
//
// If the path, in, represents the path of a file without an extension,
// then name will be the name of the file and ext will be an empty string.
//
// If the path, in, represents a filename with an extension,
// then name will be the filename minus any extension - including the dot
// and ext will contain the extension - minus the dot.
func fileAndExt(in string, b filepathPathBridge) (name string, ext string) {
ext = b.Ext(in)
base := b.Base(in)
return extractFilename(in, ext, base, b.Separator()), ext
}
func extractFilename(in, ext, base, pathSeparator string) (name string) {
// No file name cases. These are defined as:
// 1. any "in" path that ends in a pathSeparator
// 2. any "base" consisting of just an pathSeparator
// 3. any "base" consisting of just an empty string
// 4. any "base" consisting of just the current directory i.e. "."
// 5. any "base" consisting of just the parent directory i.e. ".."
if (strings.LastIndex(in, pathSeparator) == len(in)-1) || base == "" || base == "." || base == ".." || base == pathSeparator {
name = "" // there is NO filename
} else if ext != "" { // there was an Extension
// return the filename minus the extension (and the ".")
name = base[:strings.LastIndex(base, ".")]
} else {
// no extension case so just return base, which willi
// be the filename
name = base
}
return
}
// GetRelativePath returns the relative path of a given path.
func GetRelativePath(path, base string) (final string, err error) {
if filepath.IsAbs(path) && base == "" {
return "", errors.New("source: missing base directory")
}
name := filepath.Clean(path)
base = filepath.Clean(base)
name, err = filepath.Rel(base, name)
if err != nil {
return "", err
}
if strings.HasSuffix(filepath.FromSlash(path), FilePathSeparator) && !strings.HasSuffix(name, FilePathSeparator) {
name += FilePathSeparator
}
return name, nil
}
// PathPrep prepares the path using the uglify setting to create paths on
// either the form /section/name/index.html or /section/name.html.
func PathPrep(ugly bool, in string) string {
if ugly {
return Uglify(in)
}
return PrettifyPath(in)
}
// PrettifyPath is the same as PrettifyURLPath but for file paths.
// /section/name.html becomes /section/name/index.html
// /section/name/ becomes /section/name/index.html
// /section/name/index.html becomes /section/name/index.html
func PrettifyPath(in string) string {
return prettifyPath(in, fpb)
}
func prettifyPath(in string, b filepathPathBridge) string {
if filepath.Ext(in) == "" {
// /section/name/ -> /section/name/index.html
if len(in) < 2 {
return b.Separator()
}
return b.Join(in, "index.html")
}
name, ext := fileAndExt(in, b)
if name == "index" {
// /section/name/index.html -> /section/name/index.html
return b.Clean(in)
}
// /section/name.html -> /section/name/index.html
return b.Join(b.Dir(in), name, "index"+ext)
}
type NamedSlice struct {
Name string
Slice []string
}
func (n NamedSlice) String() string {
if len(n.Slice) == 0 {
return n.Name
}
return fmt.Sprintf("%s%s{%s}", n.Name, FilePathSeparator, strings.Join(n.Slice, ","))
}
// FindCWD returns the current working directory from where the Hugo
// executable is run.
func FindCWD() (string, error) {
serverFile, err := filepath.Abs(os.Args[0])
if err != nil {
return "", fmt.Errorf("can't get absolute path for executable: %v", err)
}
path := filepath.Dir(serverFile)
realFile, err := filepath.EvalSymlinks(serverFile)
if err != nil {
if _, err = os.Stat(serverFile + ".exe"); err == nil {
realFile = filepath.Clean(serverFile + ".exe")
}
}
if err == nil && realFile != serverFile {
path = filepath.Dir(realFile)
}
return path, nil
}
// AddTrailingSlash adds a trailing Unix styled slash (/) if not already
// there.
func AddTrailingSlash(path string) string {
if !strings.HasSuffix(path, "/") {
path += "/"
}
return path
}
+252
View File
@@ -0,0 +1,252 @@
// Copyright 2021 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 paths
import (
"path/filepath"
"testing"
qt "github.com/frankban/quicktest"
)
func TestGetRelativePath(t *testing.T) {
tests := []struct {
path string
base string
expect interface{}
}{
{filepath.FromSlash("/a/b"), filepath.FromSlash("/a"), filepath.FromSlash("b")},
{filepath.FromSlash("/a/b/c/"), filepath.FromSlash("/a"), filepath.FromSlash("b/c/")},
{filepath.FromSlash("/c"), filepath.FromSlash("/a/b"), filepath.FromSlash("../../c")},
{filepath.FromSlash("/c"), "", false},
}
for i, this := range tests {
// ultimately a fancy wrapper around filepath.Rel
result, err := GetRelativePath(this.path, this.base)
if b, ok := this.expect.(bool); ok && !b {
if err == nil {
t.Errorf("[%d] GetRelativePath didn't return an expected error", i)
}
} else {
if err != nil {
t.Errorf("[%d] GetRelativePath failed: %s", i, err)
continue
}
if result != this.expect {
t.Errorf("[%d] GetRelativePath got %v but expected %v", i, result, this.expect)
}
}
}
}
func TestMakePathRelative(t *testing.T) {
type test struct {
inPath, path1, path2, output string
}
data := []test{
{"/abc/bcd/ab.css", "/abc/bcd", "/bbc/bcd", "/ab.css"},
{"/abc/bcd/ab.css", "/abcd/bcd", "/abc/bcd", "/ab.css"},
}
for i, d := range data {
output, _ := makePathRelative(d.inPath, d.path1, d.path2)
if d.output != output {
t.Errorf("Test #%d failed. Expected %q got %q", i, d.output, output)
}
}
_, error := makePathRelative("a/b/c.ss", "/a/c", "/d/c", "/e/f")
if error == nil {
t.Errorf("Test failed, expected error")
}
}
func TestGetDottedRelativePath(t *testing.T) {
// on Windows this will receive both kinds, both country and western ...
for _, f := range []func(string) string{filepath.FromSlash, func(s string) string { return s }} {
doTestGetDottedRelativePath(f, t)
}
}
func doTestGetDottedRelativePath(urlFixer func(string) string, t *testing.T) {
type test struct {
input, expected string
}
data := []test{
{"", "./"},
{urlFixer("/"), "./"},
{urlFixer("post"), "../"},
{urlFixer("/post"), "../"},
{urlFixer("post/"), "../"},
{urlFixer("tags/foo.html"), "../"},
{urlFixer("/tags/foo.html"), "../"},
{urlFixer("/post/"), "../"},
{urlFixer("////post/////"), "../"},
{urlFixer("/foo/bar/index.html"), "../../"},
{urlFixer("/foo/bar/foo/"), "../../../"},
{urlFixer("/foo/bar/foo"), "../../../"},
{urlFixer("foo/bar/foo/"), "../../../"},
{urlFixer("foo/bar/foo/bar"), "../../../../"},
{"404.html", "./"},
{"404.xml", "./"},
{"/404.html", "./"},
}
for i, d := range data {
output := GetDottedRelativePath(d.input)
if d.expected != output {
t.Errorf("Test %d failed. Expected %q got %q", i, d.expected, output)
}
}
}
func TestMakeTitle(t *testing.T) {
type test struct {
input, expected string
}
data := []test{
{"Make-Title", "Make Title"},
{"MakeTitle", "MakeTitle"},
{"make_title", "make_title"},
}
for i, d := range data {
output := MakeTitle(d.input)
if d.expected != output {
t.Errorf("Test %d failed. Expected %q got %q", i, d.expected, output)
}
}
}
// Replace Extension is probably poorly named, but the intent of the
// function is to accept a path and return only the file name with a
// new extension. It's intentionally designed to strip out the path
// and only provide the name. We should probably rename the function to
// be more explicit at some point.
func TestReplaceExtension(t *testing.T) {
type test struct {
input, newext, expected string
}
data := []test{
// These work according to the above definition
{"/some/random/path/file.xml", "html", "file.html"},
{"/banana.html", "xml", "banana.xml"},
{"./banana.html", "xml", "banana.xml"},
{"banana/pie/index.html", "xml", "index.xml"},
{"../pies/fish/index.html", "xml", "index.xml"},
// but these all fail
{"filename-without-an-ext", "ext", "filename-without-an-ext.ext"},
{"/filename-without-an-ext", "ext", "filename-without-an-ext.ext"},
{"/directory/mydir/", "ext", ".ext"},
{"mydir/", "ext", ".ext"},
}
for i, d := range data {
output := ReplaceExtension(filepath.FromSlash(d.input), d.newext)
if d.expected != output {
t.Errorf("Test %d failed. Expected %q got %q", i, d.expected, output)
}
}
}
func TestExtNoDelimiter(t *testing.T) {
c := qt.New(t)
c.Assert(ExtNoDelimiter(filepath.FromSlash("/my/data.json")), qt.Equals, "json")
}
func TestFilename(t *testing.T) {
type test struct {
input, expected string
}
data := []test{
{"index.html", "index"},
{"./index.html", "index"},
{"/index.html", "index"},
{"index", "index"},
{"/tmp/index.html", "index"},
{"./filename-no-ext", "filename-no-ext"},
{"/filename-no-ext", "filename-no-ext"},
{"filename-no-ext", "filename-no-ext"},
{"directory/", ""}, // no filename case??
{"directory/.hidden.ext", ".hidden"},
{"./directory/../~/banana/gold.fish", "gold"},
{"../directory/banana.man", "banana"},
{"~/mydir/filename.ext", "filename"},
{"./directory//tmp/filename.ext", "filename"},
}
for i, d := range data {
output := Filename(filepath.FromSlash(d.input))
if d.expected != output {
t.Errorf("Test %d failed. Expected %q got %q", i, d.expected, output)
}
}
}
func TestFileAndExt(t *testing.T) {
type test struct {
input, expectedFile, expectedExt string
}
data := []test{
{"index.html", "index", ".html"},
{"./index.html", "index", ".html"},
{"/index.html", "index", ".html"},
{"index", "index", ""},
{"/tmp/index.html", "index", ".html"},
{"./filename-no-ext", "filename-no-ext", ""},
{"/filename-no-ext", "filename-no-ext", ""},
{"filename-no-ext", "filename-no-ext", ""},
{"directory/", "", ""}, // no filename case??
{"directory/.hidden.ext", ".hidden", ".ext"},
{"./directory/../~/banana/gold.fish", "gold", ".fish"},
{"../directory/banana.man", "banana", ".man"},
{"~/mydir/filename.ext", "filename", ".ext"},
{"./directory//tmp/filename.ext", "filename", ".ext"},
}
for i, d := range data {
file, ext := fileAndExt(filepath.FromSlash(d.input), fpb)
if d.expectedFile != file {
t.Errorf("Test %d failed. Expected filename %q got %q.", i, d.expectedFile, file)
}
if d.expectedExt != ext {
t.Errorf("Test %d failed. Expected extension %q got %q.", i, d.expectedExt, ext)
}
}
}
func TestFindCWD(t *testing.T) {
type test struct {
expectedDir string
expectedErr error
}
// cwd, _ := os.Getwd()
data := []test{
//{cwd, nil},
// Commenting this out. It doesn't work properly.
// There's a good reason why we don't use os.Getwd(), it doesn't actually work the way we want it to.
// I really don't know a better way to test this function. - SPF 2014.11.04
}
for i, d := range data {
dir, err := FindCWD()
if d.expectedDir != dir {
t.Errorf("Test %d failed. Expected %q but got %q", i, d.expectedDir, dir)
}
if d.expectedErr != err {
t.Errorf("Test %d failed. Expected %q but got %q", i, d.expectedErr, err)
}
}
}
+212
View File
@@ -0,0 +1,212 @@
// Copyright 2021 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 paths
import (
"fmt"
"net/url"
"path"
"strings"
"github.com/PuerkitoBio/purell"
)
type pathBridge struct {
}
func (pathBridge) Base(in string) string {
return path.Base(in)
}
func (pathBridge) Clean(in string) string {
return path.Clean(in)
}
func (pathBridge) Dir(in string) string {
return path.Dir(in)
}
func (pathBridge) Ext(in string) string {
return path.Ext(in)
}
func (pathBridge) Join(elem ...string) string {
return path.Join(elem...)
}
func (pathBridge) Separator() string {
return "/"
}
var pb pathBridge
func sanitizeURLWithFlags(in string, f purell.NormalizationFlags) string {
s, err := purell.NormalizeURLString(in, f)
if err != nil {
return in
}
// Temporary workaround for the bug fix and resulting
// behavioral change in purell.NormalizeURLString():
// a leading '/' was inadvertently added to relative links,
// but no longer, see #878.
//
// I think the real solution is to allow Hugo to
// make relative URL with relative path,
// e.g. "../../post/hello-again/", as wished by users
// in issues #157, #622, etc., without forcing
// relative URLs to begin with '/'.
// Once the fixes are in, let's remove this kludge
// and restore SanitizeURL() to the way it was.
// -- @anthonyfok, 2015-02-16
//
// Begin temporary kludge
u, err := url.Parse(s)
if err != nil {
panic(err)
}
if len(u.Path) > 0 && !strings.HasPrefix(u.Path, "/") {
u.Path = "/" + u.Path
}
return u.String()
// End temporary kludge
// return s
}
// SanitizeURL sanitizes the input URL string.
func SanitizeURL(in string) string {
return sanitizeURLWithFlags(in, purell.FlagsSafe|purell.FlagRemoveTrailingSlash|purell.FlagRemoveDotSegments|purell.FlagRemoveDuplicateSlashes|purell.FlagRemoveUnnecessaryHostDots|purell.FlagRemoveEmptyPortSeparator)
}
// SanitizeURLKeepTrailingSlash is the same as SanitizeURL, but will keep any trailing slash.
func SanitizeURLKeepTrailingSlash(in string) string {
return sanitizeURLWithFlags(in, purell.FlagsSafe|purell.FlagRemoveDotSegments|purell.FlagRemoveDuplicateSlashes|purell.FlagRemoveUnnecessaryHostDots|purell.FlagRemoveEmptyPortSeparator)
}
// MakePermalink combines base URL with content path to create full URL paths.
// Example
// base: http://spf13.com/
// path: post/how-i-blog
// result: http://spf13.com/post/how-i-blog
func MakePermalink(host, plink string) *url.URL {
base, err := url.Parse(host)
if err != nil {
panic(err)
}
p, err := url.Parse(plink)
if err != nil {
panic(err)
}
if p.Host != "" {
panic(fmt.Errorf("can't make permalink from absolute link %q", plink))
}
base.Path = path.Join(base.Path, p.Path)
// path.Join will strip off the last /, so put it back if it was there.
hadTrailingSlash := (plink == "" && strings.HasSuffix(host, "/")) || strings.HasSuffix(p.Path, "/")
if hadTrailingSlash && !strings.HasSuffix(base.Path, "/") {
base.Path = base.Path + "/"
}
return base
}
// IsAbsURL determines whether the given path points to an absolute URL.
func IsAbsURL(path string) bool {
url, err := url.Parse(path)
if err != nil {
return false
}
return url.IsAbs() || strings.HasPrefix(path, "//")
}
// AddContextRoot adds the context root to an URL if it's not already set.
// For relative URL entries on sites with a base url with a context root set (i.e. http://example.com/mysite),
// relative URLs must not include the context root if canonifyURLs is enabled. But if it's disabled, it must be set.
func AddContextRoot(baseURL, relativePath string) string {
url, err := url.Parse(baseURL)
if err != nil {
panic(err)
}
newPath := path.Join(url.Path, relativePath)
// path strips trailing slash, ignore root path.
if newPath != "/" && strings.HasSuffix(relativePath, "/") {
newPath += "/"
}
return newPath
}
// URLizeAn
// PrettifyURL takes a URL string and returns a semantic, clean URL.
func PrettifyURL(in string) string {
x := PrettifyURLPath(in)
if path.Base(x) == "index.html" {
return path.Dir(x)
}
if in == "" {
return "/"
}
return x
}
// PrettifyURLPath takes a URL path to a content and converts it
// to enable pretty URLs.
// /section/name.html becomes /section/name/index.html
// /section/name/ becomes /section/name/index.html
// /section/name/index.html becomes /section/name/index.html
func PrettifyURLPath(in string) string {
return prettifyPath(in, pb)
}
// Uglify does the opposite of PrettifyURLPath().
// /section/name/index.html becomes /section/name.html
// /section/name/ becomes /section/name.html
// /section/name.html becomes /section/name.html
func Uglify(in string) string {
if path.Ext(in) == "" {
if len(in) < 2 {
return "/"
}
// /section/name/ -> /section/name.html
return path.Clean(in) + ".html"
}
name, ext := fileAndExt(in, pb)
if name == "index" {
// /section/name/index.html -> /section/name.html
d := path.Dir(in)
if len(d) > 1 {
return d + ext
}
return in
}
// /.xml -> /index.xml
if name == "" {
return path.Dir(in) + "index" + ext
}
// /section/name.html -> /section/name.html
return path.Clean(in)
}
+129
View File
@@ -0,0 +1,129 @@
// Copyright 2021 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 paths
import (
"strings"
"testing"
qt "github.com/frankban/quicktest"
)
func TestSanitizeURL(t *testing.T) {
tests := []struct {
input string
expected string
}{
{"http://foo.bar/", "http://foo.bar"},
{"http://foo.bar", "http://foo.bar"}, // issue #1105
{"http://foo.bar/zoo/", "http://foo.bar/zoo"}, // issue #931
}
for i, test := range tests {
o1 := SanitizeURL(test.input)
o2 := SanitizeURLKeepTrailingSlash(test.input)
expected2 := test.expected
if strings.HasSuffix(test.input, "/") && !strings.HasSuffix(expected2, "/") {
expected2 += "/"
}
if o1 != test.expected {
t.Errorf("[%d] 1: Expected %#v, got %#v\n", i, test.expected, o1)
}
if o2 != expected2 {
t.Errorf("[%d] 2: Expected %#v, got %#v\n", i, expected2, o2)
}
}
}
func TestMakePermalink(t *testing.T) {
type test struct {
host, link, output string
}
data := []test{
{"http://abc.com/foo", "post/bar", "http://abc.com/foo/post/bar"},
{"http://abc.com/foo/", "post/bar", "http://abc.com/foo/post/bar"},
{"http://abc.com", "post/bar", "http://abc.com/post/bar"},
{"http://abc.com", "bar", "http://abc.com/bar"},
{"http://abc.com/foo/bar", "post/bar", "http://abc.com/foo/bar/post/bar"},
{"http://abc.com/foo/bar", "post/bar/", "http://abc.com/foo/bar/post/bar/"},
}
for i, d := range data {
output := MakePermalink(d.host, d.link).String()
if d.output != output {
t.Errorf("Test #%d failed. Expected %q got %q", i, d.output, output)
}
}
}
func TestAddContextRoot(t *testing.T) {
tests := []struct {
baseURL string
url string
expected string
}{
{"http://example.com/sub/", "/foo", "/sub/foo"},
{"http://example.com/sub/", "/foo/index.html", "/sub/foo/index.html"},
{"http://example.com/sub1/sub2", "/foo", "/sub1/sub2/foo"},
{"http://example.com", "/foo", "/foo"},
// cannot guess that the context root is already added int the example below
{"http://example.com/sub/", "/sub/foo", "/sub/sub/foo"},
{"http://example.com/тря", "/трям/", "/тря/трям/"},
{"http://example.com", "/", "/"},
{"http://example.com/bar", "//", "/bar/"},
}
for _, test := range tests {
output := AddContextRoot(test.baseURL, test.url)
if output != test.expected {
t.Errorf("Expected %#v, got %#v\n", test.expected, output)
}
}
}
func TestPretty(t *testing.T) {
c := qt.New(t)
c.Assert("/section/name/index.html", qt.Equals, PrettifyURLPath("/section/name.html"))
c.Assert("/section/sub/name/index.html", qt.Equals, PrettifyURLPath("/section/sub/name.html"))
c.Assert("/section/name/index.html", qt.Equals, PrettifyURLPath("/section/name/"))
c.Assert("/section/name/index.html", qt.Equals, PrettifyURLPath("/section/name/index.html"))
c.Assert("/index.html", qt.Equals, PrettifyURLPath("/index.html"))
c.Assert("/name/index.xml", qt.Equals, PrettifyURLPath("/name.xml"))
c.Assert("/", qt.Equals, PrettifyURLPath("/"))
c.Assert("/", qt.Equals, PrettifyURLPath(""))
c.Assert("/section/name", qt.Equals, PrettifyURL("/section/name.html"))
c.Assert("/section/sub/name", qt.Equals, PrettifyURL("/section/sub/name.html"))
c.Assert("/section/name", qt.Equals, PrettifyURL("/section/name/"))
c.Assert("/section/name", qt.Equals, PrettifyURL("/section/name/index.html"))
c.Assert("/", qt.Equals, PrettifyURL("/index.html"))
c.Assert("/name/index.xml", qt.Equals, PrettifyURL("/name.xml"))
c.Assert("/", qt.Equals, PrettifyURL("/"))
c.Assert("/", qt.Equals, PrettifyURL(""))
}
func TestUgly(t *testing.T) {
c := qt.New(t)
c.Assert("/section/name.html", qt.Equals, Uglify("/section/name.html"))
c.Assert("/section/sub/name.html", qt.Equals, Uglify("/section/sub/name.html"))
c.Assert("/section/name.html", qt.Equals, Uglify("/section/name/"))
c.Assert("/section/name.html", qt.Equals, Uglify("/section/name/index.html"))
c.Assert("/index.html", qt.Equals, Uglify("/index.html"))
c.Assert("/name.xml", qt.Equals, Uglify("/name.xml"))
c.Assert("/", qt.Equals, Uglify("/"))
c.Assert("/", qt.Equals, Uglify(""))
}
+56 -5
View File
@@ -15,21 +15,72 @@ package types
import (
"encoding/json"
"fmt"
"html/template"
"reflect"
"time"
"github.com/spf13/cast"
)
// ToStringSlicePreserveString converts v to a string slice.
// If v is a string, it will be wrapped in a string slice.
// ToDuration converts v to time.Duration.
// See ToDurationE if you need to handle errors.
func ToDuration(v interface{}) time.Duration {
d, _ := ToDurationE(v)
return d
}
// ToDurationE converts v to time.Duration.
func ToDurationE(v interface{}) (time.Duration, error) {
if n := cast.ToInt(v); n > 0 {
return time.Duration(n) * time.Millisecond, nil
}
d, err := time.ParseDuration(cast.ToString(v))
if err != nil {
return 0, fmt.Errorf("cannot convert %v to time.Duration", v)
}
return d, nil
}
// ToStringSlicePreserveString is the same as ToStringSlicePreserveStringE,
// but it never fails.
func ToStringSlicePreserveString(v interface{}) []string {
vv, _ := ToStringSlicePreserveStringE(v)
return vv
}
// ToStringSlicePreserveStringE converts v to a string slice.
// If v is a string, it will be wrapped in a string slice.
func ToStringSlicePreserveStringE(v interface{}) ([]string, error) {
if v == nil {
return nil
return nil, nil
}
if sds, ok := v.(string); ok {
return []string{sds}
return []string{sds}, nil
}
return cast.ToStringSlice(v)
result, err := cast.ToStringSliceE(v)
if err == nil {
return result, nil
}
// Probably []int or similar. Fall back to reflect.
vv := reflect.ValueOf(v)
switch vv.Kind() {
case reflect.Slice, reflect.Array:
result = make([]string, vv.Len())
for i := 0; i < vv.Len(); i++ {
s, err := cast.ToStringE(vv.Index(i).Interface())
if err != nil {
return nil, err
}
result[i] = s
}
return result, nil
default:
return nil, fmt.Errorf("failed to convert %T to a string slice", v)
}
}
// TypeToString converts v to a string if it's a valid string type.
+13
View File
@@ -16,6 +16,7 @@ package types
import (
"encoding/json"
"testing"
"time"
qt "github.com/frankban/quicktest"
)
@@ -24,7 +25,9 @@ func TestToStringSlicePreserveString(t *testing.T) {
c := qt.New(t)
c.Assert(ToStringSlicePreserveString("Hugo"), qt.DeepEquals, []string{"Hugo"})
c.Assert(ToStringSlicePreserveString(qt.Commentf("Hugo")), qt.DeepEquals, []string{"Hugo"})
c.Assert(ToStringSlicePreserveString([]interface{}{"A", "B"}), qt.DeepEquals, []string{"A", "B"})
c.Assert(ToStringSlicePreserveString([]int{1, 3}), qt.DeepEquals, []string{"1", "3"})
c.Assert(ToStringSlicePreserveString(nil), qt.IsNil)
}
@@ -34,3 +37,13 @@ func TestToString(t *testing.T) {
c.Assert(ToString([]byte("Hugo")), qt.Equals, "Hugo")
c.Assert(ToString(json.RawMessage("Hugo")), qt.Equals, "Hugo")
}
func TestToDuration(t *testing.T) {
c := qt.New(t)
c.Assert(ToDuration("200ms"), qt.Equals, 200*time.Millisecond)
c.Assert(ToDuration("200"), qt.Equals, 200*time.Millisecond)
c.Assert(ToDuration("4m"), qt.Equals, 4*time.Minute)
c.Assert(ToDuration("asdfadf"), qt.Equals, time.Duration(0))
}
+6
View File
@@ -27,6 +27,12 @@ type RLocker interface {
RUnlock()
}
// KeyValue is a interface{} tuple.
type KeyValue struct {
Key interface{}
Value interface{}
}
// KeyValueStr is a string tuple.
type KeyValueStr struct {
Key string
+1 -3
View File
@@ -21,14 +21,12 @@ import (
"github.com/gohugoio/hugo/common/types"
qt "github.com/frankban/quicktest"
"github.com/spf13/viper"
)
func TestBuild(t *testing.T) {
c := qt.New(t)
v := viper.New()
v := New()
v.Set("build", map[string]interface{}{
"useResourceCacheWhen": "always",
})
+117
View File
@@ -0,0 +1,117 @@
// Copyright 2021 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package config
import (
"github.com/gohugoio/hugo/common/maps"
)
// NewCompositeConfig creates a new composite Provider with a read-only base
// and a writeable layer.
func NewCompositeConfig(base, layer Provider) Provider {
return &compositeConfig{
base: base,
layer: layer,
}
}
// compositeConfig contains a read only config base with
// a possibly writeable config layer on top.
type compositeConfig struct {
base Provider
layer Provider
}
func (c *compositeConfig) GetBool(key string) bool {
if c.layer.IsSet(key) {
return c.layer.GetBool(key)
}
return c.base.GetBool(key)
}
func (c *compositeConfig) GetInt(key string) int {
if c.layer.IsSet(key) {
return c.layer.GetInt(key)
}
return c.base.GetInt(key)
}
func (c *compositeConfig) Merge(key string, value interface{}) {
c.layer.Merge(key, value)
}
func (c *compositeConfig) GetParams(key string) maps.Params {
if c.layer.IsSet(key) {
return c.layer.GetParams(key)
}
return c.base.GetParams(key)
}
func (c *compositeConfig) GetStringMap(key string) map[string]interface{} {
if c.layer.IsSet(key) {
return c.layer.GetStringMap(key)
}
return c.base.GetStringMap(key)
}
func (c *compositeConfig) GetStringMapString(key string) map[string]string {
if c.layer.IsSet(key) {
return c.layer.GetStringMapString(key)
}
return c.base.GetStringMapString(key)
}
func (c *compositeConfig) GetStringSlice(key string) []string {
if c.layer.IsSet(key) {
return c.layer.GetStringSlice(key)
}
return c.base.GetStringSlice(key)
}
func (c *compositeConfig) Get(key string) interface{} {
if c.layer.IsSet(key) {
return c.layer.Get(key)
}
return c.base.Get(key)
}
func (c *compositeConfig) IsSet(key string) bool {
if c.layer.IsSet(key) {
return true
}
return c.base.IsSet(key)
}
func (c *compositeConfig) GetString(key string) string {
if c.layer.IsSet(key) {
return c.layer.GetString(key)
}
return c.base.GetString(key)
}
func (c *compositeConfig) Set(key string, value interface{}) {
c.layer.Set(key, value)
}
func (c *compositeConfig) SetDefaults(params maps.Params) {
c.layer.SetDefaults(params)
}
func (c *compositeConfig) WalkParams(walkFn func(params ...KeyParams) bool) {
panic("not supported")
}
func (c *compositeConfig) SetDefaultMergeStrategy() {
panic("not supported")
}
+40
View File
@@ -0,0 +1,40 @@
// Copyright 2021 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"
qt "github.com/frankban/quicktest"
)
func TestCompositeConfig(t *testing.T) {
c := qt.New(t)
c.Run("Set and get", func(c *qt.C) {
base, layer := New(), New()
cfg := NewCompositeConfig(base, layer)
layer.Set("a1", "av")
base.Set("b1", "bv")
cfg.Set("c1", "cv")
c.Assert(cfg.Get("a1"), qt.Equals, "av")
c.Assert(cfg.Get("b1"), qt.Equals, "bv")
c.Assert(cfg.Get("c1"), qt.Equals, "cv")
c.Assert(cfg.IsSet("c1"), qt.IsTrue)
c.Assert(layer.IsSet("c1"), qt.IsTrue)
c.Assert(base.IsSet("c1"), qt.IsFalse)
})
}
+106 -22
View File
@@ -14,13 +14,19 @@
package config
import (
"os"
"path/filepath"
"strings"
"github.com/gohugoio/hugo/common/herrors"
"github.com/pkg/errors"
"github.com/gohugoio/hugo/common/paths"
"github.com/gohugoio/hugo/common/maps"
"github.com/gohugoio/hugo/parser/metadecoders"
"github.com/spf13/afero"
"github.com/spf13/viper"
)
var (
@@ -43,32 +49,20 @@ func IsValidConfigFilename(filename string) bool {
// FromConfigString creates a config from the given YAML, JSON or TOML config. This is useful in tests.
func FromConfigString(config, configType string) (Provider, error) {
v := newViper()
m, err := readConfig(metadecoders.FormatFromString(configType), []byte(config))
if err != nil {
return nil, err
}
v.MergeConfigMap(m)
return v, nil
return NewFrom(m), nil
}
// FromFile loads the configuration from the given filename.
func FromFile(fs afero.Fs, filename string) (Provider, error) {
m, err := loadConfigFromFile(fs, filename)
if err != nil {
return nil, err
return nil, herrors.WithFileContextForFileDefault(err, filename, fs)
}
v := newViper()
err = v.MergeConfigMap(m)
if err != nil {
return nil, err
}
return v, nil
return NewFrom(m), nil
}
// FromFileToMap is the same as FromFile, but it returns the config values
@@ -97,6 +91,102 @@ func loadConfigFromFile(fs afero.Fs, filename string) (map[string]interface{}, e
return m, nil
}
func LoadConfigFromDir(sourceFs afero.Fs, configDir, environment string) (Provider, []string, error) {
defaultConfigDir := filepath.Join(configDir, "_default")
environmentConfigDir := filepath.Join(configDir, environment)
cfg := New()
var configDirs []string
// Merge from least to most specific.
for _, dir := range []string{defaultConfigDir, environmentConfigDir} {
if _, err := sourceFs.Stat(dir); err == nil {
configDirs = append(configDirs, dir)
}
}
if len(configDirs) == 0 {
return nil, nil, nil
}
// Keep track of these so we can watch them for changes.
var dirnames []string
for _, configDir := range configDirs {
err := afero.Walk(sourceFs, configDir, func(path string, fi os.FileInfo, err error) error {
if fi == nil || err != nil {
return nil
}
if fi.IsDir() {
dirnames = append(dirnames, path)
return nil
}
if !IsValidConfigFilename(path) {
return nil
}
name := paths.Filename(filepath.Base(path))
item, err := metadecoders.Default.UnmarshalFileToMap(sourceFs, path)
if err != nil {
// This will be used in error reporting, use the most specific value.
dirnames = []string{path}
return errors.Wrapf(err, "failed to unmarshl config for path %q", path)
}
var keyPath []string
if name != "config" {
// Can be params.jp, menus.en etc.
name, lang := paths.FileAndExtNoDelimiter(name)
keyPath = []string{name}
if lang != "" {
keyPath = []string{"languages", lang}
switch name {
case "menu", "menus":
keyPath = append(keyPath, "menus")
case "params":
keyPath = append(keyPath, "params")
}
}
}
root := item
if len(keyPath) > 0 {
root = make(map[string]interface{})
m := root
for i, key := range keyPath {
if i >= len(keyPath)-1 {
m[key] = item
} else {
nm := make(map[string]interface{})
m[key] = nm
m = nm
}
}
}
// Migrate menu => menus etc.
RenameKeys(root)
// Set will overwrite keys with the same name, recursively.
cfg.Set("", root)
return nil
})
if err != nil {
return nil, dirnames, err
}
}
return cfg, dirnames, nil
}
var keyAliases maps.KeyRenamer
func init() {
@@ -116,9 +206,3 @@ func init() {
func RenameKeys(m map[string]interface{}) {
keyAliases.Rename(m)
}
func newViper() *viper.Viper {
v := viper.New()
return v
}
+6
View File
@@ -14,6 +14,7 @@
package config
import (
"github.com/gohugoio/hugo/common/maps"
"github.com/gohugoio/hugo/common/types"
)
@@ -22,11 +23,16 @@ type Provider interface {
GetString(key string) string
GetInt(key string) int
GetBool(key string) bool
GetParams(key string) maps.Params
GetStringMap(key string) map[string]interface{}
GetStringMapString(key string) map[string]string
GetStringSlice(key string) []string
Get(key string) interface{}
Set(key string, value interface{})
Merge(key string, value interface{})
SetDefaults(params maps.Params)
SetDefaultMergeStrategy()
WalkParams(walkFn func(params ...KeyParams) bool)
IsSet(key string) bool
}
+1 -2
View File
@@ -17,12 +17,11 @@ import (
"testing"
qt "github.com/frankban/quicktest"
"github.com/spf13/viper"
)
func TestGetStringSlicePreserveString(t *testing.T) {
c := qt.New(t)
cfg := viper.New()
cfg := New()
s := "This is a string"
sSlice := []string{"This", "is", "a", "slice"}
+440
View File
@@ -0,0 +1,440 @@
// Copyright 2021 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 (
"fmt"
"sort"
"strings"
"sync"
"github.com/spf13/cast"
"github.com/gohugoio/hugo/common/maps"
)
var (
// ConfigRootKeysSet contains all of the config map root keys.
ConfigRootKeysSet = map[string]bool{
"build": true,
"caches": true,
"cascade": true,
"frontmatter": true,
"languages": true,
"imaging": true,
"markup": true,
"mediatypes": true,
"menus": true,
"minify": true,
"module": true,
"outputformats": true,
"params": true,
"permalinks": true,
"related": true,
"sitemap": true,
"taxonomies": true,
}
// ConfigRootKeys is a sorted version of ConfigRootKeysSet.
ConfigRootKeys []string
)
func init() {
for k := range ConfigRootKeysSet {
ConfigRootKeys = append(ConfigRootKeys, k)
}
sort.Strings(ConfigRootKeys)
}
// New creates a Provider backed by an empty maps.Params.
func New() Provider {
return &defaultConfigProvider{
root: make(maps.Params),
}
}
// NewFrom creates a Provider backed by params.
func NewFrom(params maps.Params) Provider {
maps.PrepareParams(params)
return &defaultConfigProvider{
root: params,
}
}
// defaultConfigProvider is a Provider backed by a map where all keys are lower case.
// All methods are thread safe.
type defaultConfigProvider struct {
mu sync.RWMutex
root maps.Params
keyCache sync.Map
}
func (c *defaultConfigProvider) Get(k string) interface{} {
if k == "" {
return c.root
}
c.mu.RLock()
key, m := c.getNestedKeyAndMap(strings.ToLower(k), false)
if m == nil {
c.mu.RUnlock()
return nil
}
v := m[key]
c.mu.RUnlock()
return v
}
func (c *defaultConfigProvider) GetBool(k string) bool {
v := c.Get(k)
return cast.ToBool(v)
}
func (c *defaultConfigProvider) GetInt(k string) int {
v := c.Get(k)
return cast.ToInt(v)
}
func (c *defaultConfigProvider) IsSet(k string) bool {
var found bool
c.mu.RLock()
key, m := c.getNestedKeyAndMap(strings.ToLower(k), false)
if m != nil {
_, found = m[key]
}
c.mu.RUnlock()
return found
}
func (c *defaultConfigProvider) GetString(k string) string {
v := c.Get(k)
return cast.ToString(v)
}
func (c *defaultConfigProvider) GetParams(k string) maps.Params {
v := c.Get(k)
if v == nil {
return nil
}
return v.(maps.Params)
}
func (c *defaultConfigProvider) GetStringMap(k string) map[string]interface{} {
v := c.Get(k)
return maps.ToStringMap(v)
}
func (c *defaultConfigProvider) GetStringMapString(k string) map[string]string {
v := c.Get(k)
return maps.ToStringMapString(v)
}
func (c *defaultConfigProvider) GetStringSlice(k string) []string {
v := c.Get(k)
return cast.ToStringSlice(v)
}
func (c *defaultConfigProvider) Set(k string, v interface{}) {
c.mu.Lock()
defer c.mu.Unlock()
k = strings.ToLower(k)
if k == "" {
if p, ok := maps.ToParamsAndPrepare(v); ok {
// Set the values directly in root.
c.root.Set(p)
} else {
c.root[k] = v
}
return
}
switch vv := v.(type) {
case map[string]interface{}, map[interface{}]interface{}, map[string]string:
p := maps.MustToParamsAndPrepare(vv)
v = p
}
key, m := c.getNestedKeyAndMap(k, true)
if m == nil {
return
}
if existing, found := m[key]; found {
if p1, ok := existing.(maps.Params); ok {
if p2, ok := v.(maps.Params); ok {
p1.Set(p2)
return
}
}
}
m[key] = v
}
// SetDefaults will set values from params if not already set.
func (c *defaultConfigProvider) SetDefaults(params maps.Params) {
maps.PrepareParams(params)
for k, v := range params {
if _, found := c.root[k]; !found {
c.root[k] = v
}
}
}
func (c *defaultConfigProvider) Merge(k string, v interface{}) {
c.mu.Lock()
defer c.mu.Unlock()
k = strings.ToLower(k)
const (
languagesKey = "languages"
paramsKey = "params"
menusKey = "menus"
)
if k == "" {
rs, f := c.root.GetMergeStrategy()
if f && rs == maps.ParamsMergeStrategyNone {
// The user has set a "no merge" strategy on this,
// nothing more to do.
return
}
if p, ok := maps.ToParamsAndPrepare(v); ok {
// As there may be keys in p not in root, we need to handle
// those as a special case.
var keysToDelete []string
for kk, vv := range p {
if pp, ok := vv.(maps.Params); ok {
if pppi, ok := c.root[kk]; ok {
ppp := pppi.(maps.Params)
if kk == languagesKey {
// Languages is currently a special case.
// We may have languages with menus or params in the
// right map that is not present in the left map.
// With the default merge strategy those items will not
// be passed over.
var hasParams, hasMenus bool
for _, rv := range pp {
if lkp, ok := rv.(maps.Params); ok {
_, hasMenus = lkp[menusKey]
_, hasParams = lkp[paramsKey]
}
}
if hasMenus || hasParams {
for _, lv := range ppp {
if lkp, ok := lv.(maps.Params); ok {
if hasMenus {
if _, ok := lkp[menusKey]; !ok {
p := maps.Params{}
p.SetDefaultMergeStrategy(maps.ParamsMergeStrategyShallow)
lkp[menusKey] = p
}
}
if hasParams {
if _, ok := lkp[paramsKey]; !ok {
p := maps.Params{}
p.SetDefaultMergeStrategy(maps.ParamsMergeStrategyShallow)
lkp[paramsKey] = p
}
}
}
}
}
}
ppp.Merge(pp)
} else {
// We need to use the default merge strategy for
// this key.
np := make(maps.Params)
strategy := c.determineMergeStrategy(KeyParams{Key: "", Params: c.root}, KeyParams{Key: kk, Params: np})
np.SetDefaultMergeStrategy(strategy)
np.Merge(pp)
c.root[kk] = np
if np.IsZero() {
// Just keep it until merge is done.
keysToDelete = append(keysToDelete, kk)
}
}
}
}
// Merge the rest.
c.root.MergeRoot(p)
for _, k := range keysToDelete {
delete(c.root, k)
}
} else {
panic(fmt.Sprintf("unsupported type %T received in Merge", v))
}
return
}
switch vv := v.(type) {
case map[string]interface{}, map[interface{}]interface{}, map[string]string:
p := maps.MustToParamsAndPrepare(vv)
v = p
}
key, m := c.getNestedKeyAndMap(k, true)
if m == nil {
return
}
if existing, found := m[key]; found {
if p1, ok := existing.(maps.Params); ok {
if p2, ok := v.(maps.Params); ok {
p1.Merge(p2)
}
}
} else {
m[key] = v
}
}
func (c *defaultConfigProvider) WalkParams(walkFn func(params ...KeyParams) bool) {
var walk func(params ...KeyParams)
walk = func(params ...KeyParams) {
if walkFn(params...) {
return
}
p1 := params[len(params)-1]
i := len(params)
for k, v := range p1.Params {
if p2, ok := v.(maps.Params); ok {
paramsplus1 := make([]KeyParams, i+1)
copy(paramsplus1, params)
paramsplus1[i] = KeyParams{Key: k, Params: p2}
walk(paramsplus1...)
}
}
}
walk(KeyParams{Key: "", Params: c.root})
}
func (c *defaultConfigProvider) determineMergeStrategy(params ...KeyParams) maps.ParamsMergeStrategy {
if len(params) == 0 {
return maps.ParamsMergeStrategyNone
}
var (
strategy maps.ParamsMergeStrategy
prevIsRoot bool
curr = params[len(params)-1]
)
if len(params) > 1 {
prev := params[len(params)-2]
prevIsRoot = prev.Key == ""
// Inherit from parent (but not from the root unless it's set by user).
s, found := prev.Params.GetMergeStrategy()
if !prevIsRoot && !found {
panic("invalid state, merge strategy not set on parent")
}
if found || !prevIsRoot {
strategy = s
}
}
switch curr.Key {
case "":
// Don't set a merge strategy on the root unless set by user.
// This will be handled as a special case.
case "params":
strategy = maps.ParamsMergeStrategyDeep
case "outputformats", "mediatypes":
if prevIsRoot {
strategy = maps.ParamsMergeStrategyShallow
}
case "menus":
isMenuKey := prevIsRoot
if !isMenuKey {
// Can also be set below languages.
// root > languages > en > menus
if len(params) == 4 && params[1].Key == "languages" {
isMenuKey = true
}
}
if isMenuKey {
strategy = maps.ParamsMergeStrategyShallow
}
default:
if strategy == "" {
strategy = maps.ParamsMergeStrategyNone
}
}
return strategy
}
type KeyParams struct {
Key string
Params maps.Params
}
func (c *defaultConfigProvider) SetDefaultMergeStrategy() {
c.WalkParams(func(params ...KeyParams) bool {
if len(params) == 0 {
return false
}
p := params[len(params)-1].Params
var found bool
if _, found = p.GetMergeStrategy(); found {
// Set by user.
return false
}
strategy := c.determineMergeStrategy(params...)
if strategy != "" {
p.SetDefaultMergeStrategy(strategy)
}
return false
})
}
func (c *defaultConfigProvider) getNestedKeyAndMap(key string, create bool) (string, maps.Params) {
var parts []string
v, ok := c.keyCache.Load(key)
if ok {
parts = v.([]string)
} else {
parts = strings.Split(key, ".")
c.keyCache.Store(key, parts)
}
current := c.root
for i := 0; i < len(parts)-1; i++ {
next, found := current[parts[i]]
if !found {
if create {
next = make(maps.Params)
current[parts[i]] = next
} else {
return "", nil
}
}
var ok bool
current, ok = next.(maps.Params)
if !ok {
// E.g. a string, not a map that we can store values in.
return "", nil
}
}
return parts[len(parts)-1], current
}
+413
View File
@@ -0,0 +1,413 @@
// Copyright 2021 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 (
"context"
"errors"
"fmt"
"strconv"
"strings"
"testing"
"github.com/spf13/viper"
"github.com/gohugoio/hugo/common/para"
"github.com/gohugoio/hugo/common/maps"
qt "github.com/frankban/quicktest"
)
func TestDefaultConfigProvider(t *testing.T) {
c := qt.New(t)
c.Run("Set and get", func(c *qt.C) {
cfg := New()
var k string
var v interface{}
k, v = "foo", "bar"
cfg.Set(k, v)
c.Assert(cfg.Get(k), qt.Equals, v)
c.Assert(cfg.Get(strings.ToUpper(k)), qt.Equals, v)
c.Assert(cfg.GetString(k), qt.Equals, v)
k, v = "foo", 42
cfg.Set(k, v)
c.Assert(cfg.Get(k), qt.Equals, v)
c.Assert(cfg.GetInt(k), qt.Equals, v)
c.Assert(cfg.Get(""), qt.DeepEquals, maps.Params{
"foo": 42,
})
})
c.Run("Set and get map", func(c *qt.C) {
cfg := New()
cfg.Set("foo", map[string]interface{}{
"bar": "baz",
})
c.Assert(cfg.Get("foo"), qt.DeepEquals, maps.Params{
"bar": "baz",
})
c.Assert(cfg.GetStringMap("foo"), qt.DeepEquals, map[string]interface{}{"bar": string("baz")})
c.Assert(cfg.GetStringMapString("foo"), qt.DeepEquals, map[string]string{"bar": string("baz")})
})
c.Run("Set and get nested", func(c *qt.C) {
cfg := New()
cfg.Set("a", map[string]interface{}{
"B": "bv",
})
cfg.Set("a.c", "cv")
c.Assert(cfg.Get("a"), qt.DeepEquals, maps.Params{
"b": "bv",
"c": "cv",
})
c.Assert(cfg.Get("a.c"), qt.Equals, "cv")
cfg.Set("b.a", "av")
c.Assert(cfg.Get("b"), qt.DeepEquals, maps.Params{
"a": "av",
})
cfg.Set("b", map[string]interface{}{
"b": "bv",
})
c.Assert(cfg.Get("b"), qt.DeepEquals, maps.Params{
"a": "av",
"b": "bv",
})
cfg = New()
cfg.Set("a", "av")
cfg.Set("", map[string]interface{}{
"a": "av2",
"b": "bv2",
})
c.Assert(cfg.Get(""), qt.DeepEquals, maps.Params{
"a": "av2",
"b": "bv2",
})
cfg = New()
cfg.Set("a", "av")
cfg.Set("", map[string]interface{}{
"b": "bv2",
})
c.Assert(cfg.Get(""), qt.DeepEquals, maps.Params{
"a": "av",
"b": "bv2",
})
cfg = New()
cfg.Set("", map[string]interface{}{
"foo": map[string]interface{}{
"a": "av",
},
})
cfg.Set("", map[string]interface{}{
"foo": map[string]interface{}{
"b": "bv2",
},
})
c.Assert(cfg.Get("foo"), qt.DeepEquals, maps.Params{
"a": "av",
"b": "bv2",
})
})
c.Run("Merge default strategy", func(c *qt.C) {
cfg := New()
cfg.Set("a", map[string]interface{}{
"B": "bv",
})
cfg.Merge("a", map[string]interface{}{
"B": "bv2",
"c": "cv2",
})
c.Assert(cfg.Get("a"), qt.DeepEquals, maps.Params{
"b": "bv",
"c": "cv2",
})
cfg = New()
cfg.Set("a", "av")
cfg.Merge("", map[string]interface{}{
"a": "av2",
"b": "bv2",
})
c.Assert(cfg.Get(""), qt.DeepEquals, maps.Params{
"a": "av",
})
})
c.Run("Merge shallow", func(c *qt.C) {
cfg := New()
cfg.Set("a", map[string]interface{}{
"_merge": "shallow",
"B": "bv",
"c": map[string]interface{}{
"b": "bv",
},
})
cfg.Merge("a", map[string]interface{}{
"c": map[string]interface{}{
"d": "dv2",
},
"e": "ev2",
})
c.Assert(cfg.Get("a"), qt.DeepEquals, maps.Params{
"e": "ev2",
"_merge": maps.ParamsMergeStrategyShallow,
"b": "bv",
"c": maps.Params{
"b": "bv",
},
})
})
// Issue #8679
c.Run("Merge typed maps", func(c *qt.C) {
for _, left := range []interface{}{
map[string]string{
"c": "cv1",
},
map[string]interface{}{
"c": "cv1",
},
map[interface{}]interface{}{
"c": "cv1",
},
} {
cfg := New()
cfg.Set("", map[string]interface{}{
"b": left,
})
cfg.Merge("", maps.Params{
"b": maps.Params{
"c": "cv2",
"d": "dv2",
},
})
c.Assert(cfg.Get(""), qt.DeepEquals, maps.Params{
"b": maps.Params{
"c": "cv1",
"d": "dv2",
},
})
}
for _, left := range []interface{}{
map[string]string{
"b": "bv1",
},
map[string]interface{}{
"b": "bv1",
},
map[interface{}]interface{}{
"b": "bv1",
},
} {
for _, right := range []interface{}{
map[string]string{
"b": "bv2",
"c": "cv2",
},
map[string]interface{}{
"b": "bv2",
"c": "cv2",
},
map[interface{}]interface{}{
"b": "bv2",
"c": "cv2",
},
} {
cfg := New()
cfg.Set("a", left)
cfg.Merge("a", right)
c.Assert(cfg.Get(""), qt.DeepEquals, maps.Params{
"a": maps.Params{
"b": "bv1",
"c": "cv2",
},
})
}
}
})
// Issue #8701
c.Run("Prevent _merge only maps", func(c *qt.C) {
cfg := New()
cfg.Set("", map[string]interface{}{
"B": "bv",
})
cfg.Merge("", map[string]interface{}{
"c": map[string]interface{}{
"_merge": "shallow",
"d": "dv2",
},
})
c.Assert(cfg.Get(""), qt.DeepEquals, maps.Params{
"b": "bv",
})
})
c.Run("IsSet", func(c *qt.C) {
cfg := New()
cfg.Set("a", map[string]interface{}{
"B": "bv",
})
c.Assert(cfg.IsSet("A"), qt.IsTrue)
c.Assert(cfg.IsSet("a.b"), qt.IsTrue)
c.Assert(cfg.IsSet("z"), qt.IsFalse)
})
c.Run("Para", func(c *qt.C) {
cfg := New()
p := para.New(4)
r, _ := p.Start(context.Background())
setAndGet := func(k string, v int) error {
vs := strconv.Itoa(v)
cfg.Set(k, v)
err := errors.New("get failed")
if cfg.Get(k) != v {
return err
}
if cfg.GetInt(k) != v {
return err
}
if cfg.GetString(k) != vs {
return err
}
if !cfg.IsSet(k) {
return err
}
return nil
}
for i := 0; i < 20; i++ {
i := i
r.Run(func() error {
const v = 42
k := fmt.Sprintf("k%d", i)
if err := setAndGet(k, v); err != nil {
return err
}
m := maps.Params{
"new": 42,
}
cfg.Merge("", m)
return nil
})
}
c.Assert(r.Wait(), qt.IsNil)
})
}
func BenchmarkDefaultConfigProvider(b *testing.B) {
type cfger interface {
Get(key string) interface{}
Set(key string, value interface{})
IsSet(key string) bool
}
newMap := func() map[string]interface{} {
return map[string]interface{}{
"a": map[string]interface{}{
"b": map[string]interface{}{
"c": 32,
"d": 43,
},
},
"b": 62,
}
}
runMethods := func(b *testing.B, cfg cfger) {
m := newMap()
cfg.Set("mymap", m)
cfg.Set("num", 32)
if !(cfg.IsSet("mymap") && cfg.IsSet("mymap.a") && cfg.IsSet("mymap.a.b") && cfg.IsSet("mymap.a.b.c")) {
b.Fatal("IsSet failed")
}
if cfg.Get("num") != 32 {
b.Fatal("Get failed")
}
if cfg.Get("mymap.a.b.c") != 32 {
b.Fatal("Get failed")
}
}
b.Run("Viper", func(b *testing.B) {
v := viper.New()
for i := 0; i < b.N; i++ {
runMethods(b, v)
}
})
b.Run("Custom", func(b *testing.B) {
cfg := New()
for i := 0; i < b.N; i++ {
runMethods(b, cfg)
}
})
}
+45
View File
@@ -0,0 +1,45 @@
// Copyright 2021 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package config
import (
"github.com/gohugoio/hugo/common/maps"
"github.com/gohugoio/hugo/docshelper"
)
// This is is just some helpers used to create some JSON used in the Hugo docs.
func init() {
docsProvider := func() docshelper.DocProvider {
cfg := New()
for _, configRoot := range ConfigRootKeys {
cfg.Set(configRoot, make(maps.Params))
}
lang := maps.Params{
"en": maps.Params{
"menus": maps.Params{},
"params": maps.Params{},
},
}
cfg.Set("languages", lang)
cfg.SetDefaultMergeStrategy()
configHelpers := map[string]interface{}{
"mergeStrategy": cfg.Get(""),
}
return docshelper.DocProvider{"config": configHelpers}
}
docshelper.AddDocProviderFunc(docsProvider)
}
+1 -1
View File
@@ -41,7 +41,7 @@ func SetEnvVars(oldVars *[]string, keyValues ...string) {
}
func SplitEnvVar(v string) (string, string) {
parts := strings.Split(v, "=")
parts := strings.SplitN(v, "=", 2)
return parts[0], parts[1]
}
+1 -2
View File
@@ -18,7 +18,6 @@ import (
qt "github.com/frankban/quicktest"
"github.com/gohugoio/hugo/config"
"github.com/spf13/viper"
)
func TestDecodeConfigFromTOML(t *testing.T) {
@@ -94,7 +93,7 @@ PrivacyENhanced = true
func TestDecodeConfigDefault(t *testing.T) {
c := qt.New(t)
pc, err := DecodeConfig(viper.New())
pc, err := DecodeConfig(config.New())
c.Assert(err, qt.IsNil)
c.Assert(pc, qt.Not(qt.IsNil))
c.Assert(pc.YouTube.PrivacyEnhanced, qt.Equals, false)
+5
View File
@@ -53,6 +53,11 @@ type Instagram struct {
// This means that if you use Bootstrap 4 or want to provide your own CSS, you want
// to disable the inline CSS provided by Hugo.
DisableInlineCSS bool
// App or Client Access Token.
// If you are using a Client Access Token, remember that you must combine it with your App ID
// using a pipe symbol (<APPID>|<CLIENTTOKEN>) otherwise the request will fail.
AccessToken string
}
// Twitter holds the functional configuration settings related to the Twitter shortcodes.
+2 -2
View File
@@ -18,7 +18,7 @@ import (
qt "github.com/frankban/quicktest"
"github.com/gohugoio/hugo/config"
"github.com/spf13/viper"
)
func TestDecodeConfigFromTOML(t *testing.T) {
@@ -55,7 +55,7 @@ disableInlineCSS = true
func TestUseSettingsFromRootIfSet(t *testing.T) {
c := qt.New(t)
cfg := viper.New()
cfg := config.New()
cfg.Set("disqusShortname", "root_short")
cfg.Set("googleAnalytics", "ga_root")
+245 -219
View File
@@ -16,11 +16,16 @@ package create
import (
"bytes"
"fmt"
"io"
"os"
"path/filepath"
"strings"
"github.com/gohugoio/hugo/hugofs/glob"
"github.com/gohugoio/hugo/common/paths"
"github.com/pkg/errors"
"github.com/gohugoio/hugo/common/hexec"
@@ -31,125 +36,165 @@ import (
"github.com/gohugoio/hugo/helpers"
"github.com/gohugoio/hugo/hugolib"
"github.com/spf13/afero"
jww "github.com/spf13/jwalterweatherman"
)
// NewContent creates a new content file in the content directory based upon the
// given kind, which is used to lookup an archetype.
func NewContent(
sites *hugolib.HugoSites, kind, targetPath string) error {
targetPath = filepath.Clean(targetPath)
ext := helpers.Ext(targetPath)
ps := sites.PathSpec
archetypeFs := ps.BaseFs.SourceFilesystems.Archetypes.Fs
sourceFs := ps.Fs.Source
const (
// DefaultArchetypeTemplateTemplate is the template used in 'hugo new site'
// and the template we use as a fall back.
DefaultArchetypeTemplateTemplate = `---
title: "{{ replace .Name "-" " " | title }}"
date: {{ .Date }}
draft: true
---
jww.INFO.Printf("attempting to create %q of %q of ext %q", targetPath, kind, ext)
`
)
archetypeFilename, isDir := findArchetype(ps, kind, ext)
contentPath, s := resolveContentPath(sites, sourceFs, targetPath)
if isDir {
langFs, err := hugofs.NewLanguageFs(sites.LanguageSet(), archetypeFs)
if err != nil {
return err
}
cm, err := mapArcheTypeDir(ps, langFs, archetypeFilename)
if err != nil {
return err
}
if cm.siteUsed {
if err := sites.Build(hugolib.BuildCfg{SkipRender: true}); err != nil {
return err
}
}
name := filepath.Base(targetPath)
return newContentFromDir(archetypeFilename, sites, sourceFs, cm, name, contentPath)
// NewContent creates a new content file in h (or a full bundle if the archetype is a directory)
// in targetPath.
func NewContent(h *hugolib.HugoSites, kind, targetPath string) error {
if h.BaseFs.Content.Dirs == nil {
return errors.New("no existing content directory configured for this project")
}
// Building the sites can be expensive, so only do it if really needed.
siteUsed := false
cf := hugolib.NewContentFactory(h)
if archetypeFilename != "" {
if kind == "" {
kind = cf.SectionFromFilename(targetPath)
}
var err error
siteUsed, err = usesSiteVar(archetypeFs, archetypeFilename)
b := &contentBuilder{
archeTypeFs: h.PathSpec.BaseFs.Archetypes.Fs,
sourceFs: h.PathSpec.Fs.Source,
ps: h.PathSpec,
h: h,
cf: cf,
kind: kind,
targetPath: targetPath,
}
ext := paths.Ext(targetPath)
b.setArcheTypeFilenameToUse(ext)
withBuildLock := func() (string, error) {
unlock, err := h.BaseFs.LockBuild()
if err != nil {
return err
return "", fmt.Errorf("failed to acquire a build lock: %s", err)
}
defer unlock()
if b.isDir {
return "", b.buildDir()
}
if ext == "" {
return "", errors.Errorf("failed to resolve %q to a archetype template", targetPath)
}
if !files.IsContentFile(b.targetPath) {
return "", errors.Errorf("target path %q is not a known content format", b.targetPath)
}
return b.buildFile()
}
if siteUsed {
if err := sites.Build(hugolib.BuildCfg{SkipRender: true}); err != nil {
return err
}
}
content, err := executeArcheTypeAsTemplate(s, "", kind, targetPath, archetypeFilename)
filename, err := withBuildLock()
if err != nil {
return err
}
if err := helpers.SafeWriteToDisk(contentPath, bytes.NewReader(content), s.Fs.Source); err != nil {
return err
}
jww.FEEDBACK.Println(contentPath, "created")
editor := s.Cfg.GetString("newContentEditor")
if editor != "" {
jww.FEEDBACK.Printf("Editing %s with %q ...\n", targetPath, editor)
editorCmd := append(strings.Fields(editor), contentPath)
cmd, err := hexec.SafeCommand(editorCmd[0], editorCmd[1:]...)
if err != nil {
return err
}
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd.Run()
if filename != "" {
return b.openInEditorIfConfigured(filename)
}
return nil
}
func targetSite(sites *hugolib.HugoSites, fi hugofs.FileMetaInfo) *hugolib.Site {
for _, s := range sites.Sites {
if fi.Meta().Lang() == s.Language().Lang {
return s
type contentBuilder struct {
archeTypeFs afero.Fs
sourceFs afero.Fs
ps *helpers.PathSpec
h *hugolib.HugoSites
cf hugolib.ContentFactory
// Builder state
archetypeFilename string
targetPath string
kind string
isDir bool
dirMap archetypeMap
}
func (b *contentBuilder) buildDir() error {
// Split the dir into content files and the rest.
if err := b.mapArcheTypeDir(); err != nil {
return err
}
var contentTargetFilenames []string
var baseDir string
for _, fi := range b.dirMap.contentFiles {
targetFilename := filepath.Join(b.targetPath, strings.TrimPrefix(fi.Meta().Path, b.archetypeFilename))
abs, err := b.cf.CreateContentPlaceHolder(targetFilename)
if err != nil {
return err
}
if baseDir == "" {
baseDir = strings.TrimSuffix(abs, targetFilename)
}
contentTargetFilenames = append(contentTargetFilenames, abs)
}
var contentInclusionFilter *glob.FilenameFilter
if !b.dirMap.siteUsed {
// We don't need to build everything.
contentInclusionFilter = glob.NewFilenameFilterForInclusionFunc(func(filename string) bool {
filename = strings.TrimPrefix(filename, string(os.PathSeparator))
for _, cn := range contentTargetFilenames {
if strings.Contains(cn, filename) {
return true
}
}
return false
})
}
if err := b.h.Build(hugolib.BuildCfg{NoBuildLock: true, SkipRender: true, ContentInclusionFilter: contentInclusionFilter}); err != nil {
return err
}
for i, filename := range contentTargetFilenames {
if err := b.applyArcheType(filename, b.dirMap.contentFiles[i].Meta().Path); err != nil {
return err
}
}
return sites.Sites[0]
}
func newContentFromDir(
archetypeDir string,
sites *hugolib.HugoSites,
targetFs afero.Fs,
cm archetypeMap, name, targetPath string) error {
for _, f := range cm.otherFiles {
// Copy the rest as is.
for _, f := range b.dirMap.otherFiles {
meta := f.Meta()
filename := meta.Path()
// Just copy the file to destination.
filename := meta.Path
in, err := meta.Open()
if err != nil {
return errors.Wrap(err, "failed to open non-content file")
}
targetFilename := filepath.Join(targetPath, strings.TrimPrefix(filename, archetypeDir))
targetFilename := filepath.Join(baseDir, b.targetPath, strings.TrimPrefix(filename, b.archetypeFilename))
targetDir := filepath.Dir(targetFilename)
if err := targetFs.MkdirAll(targetDir, 0777); err != nil && !os.IsExist(err) {
return errors.Wrapf(err, "failed to create target directory for %s:", targetDir)
if err := b.sourceFs.MkdirAll(targetDir, 0o777); err != nil && !os.IsExist(err) {
return errors.Wrapf(err, "failed to create target directory for %q", targetDir)
}
out, err := targetFs.Create(targetFilename)
out, err := b.sourceFs.Create(targetFilename)
if err != nil {
return err
}
@@ -162,41 +207,82 @@ func newContentFromDir(
in.Close()
out.Close()
}
for _, f := range cm.contentFiles {
filename := f.Meta().Path()
s := targetSite(sites, f)
targetFilename := filepath.Join(targetPath, strings.TrimPrefix(filename, archetypeDir))
content, err := executeArcheTypeAsTemplate(s, name, archetypeDir, targetFilename, filename)
if err != nil {
return errors.Wrap(err, "failed to execute archetype template")
}
if err := helpers.SafeWriteToDisk(targetFilename, bytes.NewReader(content), targetFs); err != nil {
return errors.Wrap(err, "failed to save results")
}
}
jww.FEEDBACK.Println(targetPath, "created")
return nil
}
type archetypeMap struct {
// These needs to be parsed and executed as Go templates.
contentFiles []hugofs.FileMetaInfo
// These are just copied to destination.
otherFiles []hugofs.FileMetaInfo
// If the templates needs a fully built site. This can potentially be
// expensive, so only do when needed.
siteUsed bool
func (b *contentBuilder) buildFile() (string, error) {
contentPlaceholderAbsFilename, err := b.cf.CreateContentPlaceHolder(b.targetPath)
if err != nil {
return "", err
}
usesSite, err := b.usesSiteVar(b.archetypeFilename)
if err != nil {
return "", err
}
var contentInclusionFilter *glob.FilenameFilter
if !usesSite {
// We don't need to build everything.
contentInclusionFilter = glob.NewFilenameFilterForInclusionFunc(func(filename string) bool {
filename = strings.TrimPrefix(filename, string(os.PathSeparator))
return strings.Contains(contentPlaceholderAbsFilename, filename)
})
}
if err := b.h.Build(hugolib.BuildCfg{NoBuildLock: true, SkipRender: true, ContentInclusionFilter: contentInclusionFilter}); err != nil {
return "", err
}
if err := b.applyArcheType(contentPlaceholderAbsFilename, b.archetypeFilename); err != nil {
return "", err
}
b.h.Log.Infof("Content %q created", contentPlaceholderAbsFilename)
return contentPlaceholderAbsFilename, nil
}
func mapArcheTypeDir(
ps *helpers.PathSpec,
fs afero.Fs,
archetypeDir string) (archetypeMap, error) {
func (b *contentBuilder) setArcheTypeFilenameToUse(ext string) {
var pathsToCheck []string
if b.kind != "" {
pathsToCheck = append(pathsToCheck, b.kind+ext)
}
pathsToCheck = append(pathsToCheck, "default"+ext, "default")
for _, p := range pathsToCheck {
fi, err := b.archeTypeFs.Stat(p)
if err == nil {
b.archetypeFilename = p
b.isDir = fi.IsDir()
return
}
}
}
func (b *contentBuilder) applyArcheType(contentFilename, archetypeFilename string) error {
p := b.h.GetContentPage(contentFilename)
if p == nil {
panic(fmt.Sprintf("[BUG] no Page found for %q", contentFilename))
}
f, err := b.sourceFs.Create(contentFilename)
if err != nil {
return err
}
defer f.Close()
if archetypeFilename == "" {
return b.cf.AppplyArchetypeTemplate(f, p, b.kind, DefaultArchetypeTemplateTemplate)
}
return b.cf.AppplyArchetypeFilename(f, p, b.kind, archetypeFilename)
}
func (b *contentBuilder) mapArcheTypeDir() error {
var m archetypeMap
walkFn := func(path string, fi hugofs.FileMetaInfo, err error) error {
@@ -213,7 +299,7 @@ func mapArcheTypeDir(
if files.IsContentFile(path) {
m.contentFiles = append(m.contentFiles, fil)
if !m.siteUsed {
m.siteUsed, err = usesSiteVar(fs, path)
m.siteUsed, err = b.usesSiteVar(path)
if err != nil {
return err
}
@@ -228,120 +314,60 @@ func mapArcheTypeDir(
walkCfg := hugofs.WalkwayConfig{
WalkFn: walkFn,
Fs: fs,
Root: archetypeDir,
Fs: b.archeTypeFs,
Root: b.archetypeFilename,
}
w := hugofs.NewWalkway(walkCfg)
if err := w.Walk(); err != nil {
return m, errors.Wrapf(err, "failed to walk archetype dir %q", archetypeDir)
return errors.Wrapf(err, "failed to walk archetype dir %q", b.archetypeFilename)
}
return m, nil
b.dirMap = m
return nil
}
func usesSiteVar(fs afero.Fs, filename string) (bool, error) {
f, err := fs.Open(filename)
func (b *contentBuilder) openInEditorIfConfigured(filename string) error {
editor := b.h.Cfg.GetString("newContentEditor")
if editor == "" {
return nil
}
b.h.Log.Infof("Editing %q with %q ...\n", filename, editor)
cmd, err := hexec.SafeCommand(editor, filename)
if err != nil {
return err
}
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd.Run()
}
func (b *contentBuilder) usesSiteVar(filename string) (bool, error) {
if filename == "" {
return false, nil
}
bb, err := afero.ReadFile(b.archeTypeFs, filename)
if err != nil {
return false, errors.Wrap(err, "failed to open archetype file")
}
defer f.Close()
return helpers.ReaderContains(f, []byte(".Site")), nil
return bytes.Contains(bb, []byte(".Site")) || bytes.Contains(bb, []byte("site.")), nil
}
// Resolve the target content path.
func resolveContentPath(sites *hugolib.HugoSites, fs afero.Fs, targetPath string) (string, *hugolib.Site) {
targetDir := filepath.Dir(targetPath)
first := sites.Sites[0]
var (
s *hugolib.Site
siteContentDir string
)
// Try the filename: my-post.en.md
for _, ss := range sites.Sites {
if strings.Contains(targetPath, "."+ss.Language().Lang+".") {
s = ss
break
}
}
var dirLang string
for _, dir := range sites.BaseFs.Content.Dirs {
meta := dir.Meta()
contentDir := meta.Filename()
if !strings.HasSuffix(contentDir, helpers.FilePathSeparator) {
contentDir += helpers.FilePathSeparator
}
if strings.HasPrefix(targetPath, contentDir) {
siteContentDir = contentDir
dirLang = meta.Lang()
break
}
}
if s == nil && dirLang != "" {
for _, ss := range sites.Sites {
if ss.Lang() == dirLang {
s = ss
break
}
}
}
if s == nil {
s = first
}
if targetDir != "" && targetDir != "." {
exists, _ := helpers.Exists(targetDir, fs)
if exists {
return targetPath, s
}
}
if siteContentDir == "" {
}
if siteContentDir != "" {
pp := filepath.Join(siteContentDir, strings.TrimPrefix(targetPath, siteContentDir))
return s.PathSpec.AbsPathify(pp), s
} else {
var contentDir string
for _, dir := range sites.BaseFs.Content.Dirs {
contentDir = dir.Meta().Filename()
if dir.Meta().Lang() == s.Lang() {
break
}
}
return s.PathSpec.AbsPathify(filepath.Join(contentDir, targetPath)), s
}
}
// 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, isDir bool) {
fs := ps.BaseFs.Archetypes.Fs
var pathsToCheck []string
if kind != "" {
pathsToCheck = append(pathsToCheck, kind+ext)
}
pathsToCheck = append(pathsToCheck, "default"+ext, "default")
for _, p := range pathsToCheck {
fi, err := fs.Stat(p)
if err == nil {
return p, fi.IsDir()
}
}
return "", false
type archetypeMap struct {
// These needs to be parsed and executed as Go templates.
contentFiles []hugofs.FileMetaInfo
// These are just copied to destination.
otherFiles []hugofs.FileMetaInfo
// If the templates needs a fully built site. This can potentially be
// expensive, so only do when needed.
siteUsed bool
}
-147
View File
@@ -1,147 +0,0 @@
// Copyright 2017 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 create
import (
"bytes"
"fmt"
"path/filepath"
"strings"
"time"
"github.com/pkg/errors"
"github.com/gohugoio/hugo/helpers"
"github.com/gohugoio/hugo/source"
"github.com/gohugoio/hugo/hugolib"
"github.com/gohugoio/hugo/tpl"
"github.com/spf13/afero"
)
// ArchetypeFileData represents the data available to an archetype template.
type ArchetypeFileData struct {
// The archetype content type, either given as --kind option or extracted
// from the target path's section, i.e. "blog/mypost.md" will resolve to
// "blog".
Type string
// The current date and time as a RFC3339 formatted string, suitable for use in front matter.
Date string
// The Site, fully equipped with all the pages etc. Note: This will only be set if it is actually
// used in the archetype template. Also, if this is a multilingual setup,
// this site is the site that best matches the target content file, based
// on the presence of language code in the filename.
Site *hugolib.SiteInfo
// Name will in most cases be the same as TranslationBaseName, e.g. "my-post".
// But if that value is "index" (bundles), the Name is instead the owning folder.
// This is the value you in most cases would want to use to construct the title in your
// archetype template.
Name string
// The target content file. Note that the .Content will be empty, as that
// has not been created yet.
source.File
}
const (
// ArchetypeTemplateTemplate is used as initial template when adding an archetype template.
ArchetypeTemplateTemplate = `---
title: "{{ replace .Name "-" " " | title }}"
date: {{ .Date }}
draft: true
---
`
)
var (
archetypeShortcodeReplacementsPre = strings.NewReplacer(
"{{<", "{x{<",
"{{%", "{x{%",
">}}", ">}x}",
"%}}", "%}x}")
archetypeShortcodeReplacementsPost = strings.NewReplacer(
"{x{<", "{{<",
"{x{%", "{{%",
">}x}", ">}}",
"%}x}", "%}}")
)
func executeArcheTypeAsTemplate(s *hugolib.Site, name, kind, targetPath, archetypeFilename string) ([]byte, error) {
var (
archetypeContent []byte
archetypeTemplate []byte
err error
)
f, err := s.SourceSpec.NewFileInfoFrom(targetPath, targetPath)
if err != nil {
return nil, err
}
if name == "" {
name = f.TranslationBaseName()
if name == "index" || name == "_index" {
// Page bundles; the directory name will hopefully have a better name.
dir := strings.TrimSuffix(f.Dir(), helpers.FilePathSeparator)
_, name = filepath.Split(dir)
}
}
data := ArchetypeFileData{
Type: kind,
Date: time.Now().Format(time.RFC3339),
Name: name,
File: f,
Site: s.Info,
}
if archetypeFilename == "" {
// TODO(bep) archetype revive the issue about wrong tpl funcs arg order
archetypeTemplate = []byte(ArchetypeTemplateTemplate)
} else {
archetypeTemplate, err = afero.ReadFile(s.BaseFs.Archetypes.Fs, archetypeFilename)
if err != nil {
return nil, fmt.Errorf("failed to read archetype file %s", err)
}
}
// The archetype template may contain shortcodes, and these does not play well
// with the Go templates. Need to set some temporary delimiters.
archetypeTemplate = []byte(archetypeShortcodeReplacementsPre.Replace(string(archetypeTemplate)))
// Reuse the Hugo template setup to get the template funcs properly set up.
templateHandler := s.Deps.Tmpl().(tpl.TemplateManager)
templateName := helpers.Filename(archetypeFilename)
if err := templateHandler.AddTemplate("_text/"+templateName, string(archetypeTemplate)); err != nil {
return nil, errors.Wrapf(err, "Failed to parse archetype file %q:", archetypeFilename)
}
templ, _ := templateHandler.Lookup(templateName)
var buff bytes.Buffer
if err := templateHandler.Execute(templ, &buff, data); err != nil {
return nil, errors.Wrapf(err, "Failed to process archetype file %q:", archetypeFilename)
}
archetypeContent = []byte(archetypeShortcodeReplacementsPost.Replace(buff.String()))
return archetypeContent, nil
}
+190 -45
View File
@@ -20,6 +20,8 @@ import (
"strings"
"testing"
"github.com/gohugoio/hugo/config"
"github.com/gohugoio/hugo/deps"
"github.com/gohugoio/hugo/hugolib"
@@ -30,30 +32,36 @@ import (
"github.com/gohugoio/hugo/create"
"github.com/gohugoio/hugo/helpers"
"github.com/spf13/afero"
"github.com/spf13/viper"
)
// TODO(bep) clean this up. Export the test site builder in Hugolib or something.
func TestNewContent(t *testing.T) {
cases := []struct {
name string
kind string
path string
expected []string
expected interface{}
}{
{"post", "post/sample-1.md", []string{`title = "Post Arch title"`, `test = "test1"`, "date = \"2015-01-12T19:20:04-07:00\""}},
{"post", "post/org-1.org", []string{`#+title: ORG-1`}},
{"emptydate", "post/sample-ed.md", []string{`title = "Empty Date Arch title"`, `test = "test1"`}},
{"stump", "stump/sample-2.md", []string{`title: "Sample 2"`}}, // no archetype file
{"", "sample-3.md", []string{`title: "Sample 3"`}}, // no archetype
{"product", "product/sample-4.md", []string{`title = "SAMPLE-4"`}}, // empty archetype front matter
{"lang", "post/lang-1.md", []string{`Site Lang: en|Name: Lang 1|i18n: Hugo Rocks!`}},
{"lang", "post/lang-2.en.md", []string{`Site Lang: en|Name: Lang 2|i18n: Hugo Rocks!`}},
{"lang", "content/post/lang-3.nn.md", []string{`Site Lang: nn|Name: Lang 3|i18n: Hugo Rokkar!`}},
{"lang", "content_nn/post/lang-4.md", []string{`Site Lang: nn|Name: Lang 4|i18n: Hugo Rokkar!`}},
{"lang", "content_nn/post/lang-5.en.md", []string{`Site Lang: en|Name: Lang 5|i18n: Hugo Rocks!`}},
{"lang", "post/my-bundle/index.md", []string{`Site Lang: en|Name: My Bundle|i18n: Hugo Rocks!`}},
{"lang", "post/my-bundle/index.en.md", []string{`Site Lang: en|Name: My Bundle|i18n: Hugo Rocks!`}},
{"lang", "content/post/my-bundle/index.nn.md", []string{`Site Lang: nn|Name: My Bundle|i18n: Hugo Rokkar!`}},
{"shortcodes", "shortcodes/go.md", []string{
{"Post", "post", "post/sample-1.md", []string{`title = "Post Arch title"`, `test = "test1"`, "date = \"2015-01-12T19:20:04-07:00\""}},
{"Post org-mode", "post", "post/org-1.org", []string{`#+title: ORG-1`}},
{"Post, unknown content filetype", "post", "post/sample-1.pdoc", false},
{"Empty date", "emptydate", "post/sample-ed.md", []string{`title = "Empty Date Arch title"`, `test = "test1"`}},
{"Archetype file not found", "stump", "stump/sample-2.md", []string{`title: "Sample 2"`}}, // no archetype file
{"No archetype", "", "sample-3.md", []string{`title: "Sample 3"`}}, // no archetype
{"Empty archetype", "product", "product/sample-4.md", []string{`title = "SAMPLE-4"`}}, // empty archetype front matter
{"Filenames", "filenames", "content/mypage/index.md", []string{"title = \"INDEX\"\n+++\n\n\nContentBaseName: mypage"}},
{"Branch Name", "name", "content/tags/tag-a/_index.md", []string{"+++\ntitle = 'Tag A'\n+++"}},
{"Lang 1", "lang", "post/lang-1.md", []string{`Site Lang: en|Name: Lang 1|i18n: Hugo Rocks!`}},
{"Lang 2", "lang", "post/lang-2.en.md", []string{`Site Lang: en|Name: Lang 2|i18n: Hugo Rocks!`}},
{"Lang nn file", "lang", "content/post/lang-3.nn.md", []string{`Site Lang: nn|Name: Lang 3|i18n: Hugo Rokkar!`}},
{"Lang nn dir", "lang", "content_nn/post/lang-4.md", []string{`Site Lang: nn|Name: Lang 4|i18n: Hugo Rokkar!`}},
{"Lang en in nn dir", "lang", "content_nn/post/lang-5.en.md", []string{`Site Lang: en|Name: Lang 5|i18n: Hugo Rocks!`}},
{"Lang en default", "lang", "post/my-bundle/index.md", []string{`Site Lang: en|Name: My Bundle|i18n: Hugo Rocks!`}},
{"Lang en file", "lang", "post/my-bundle/index.en.md", []string{`Site Lang: en|Name: My Bundle|i18n: Hugo Rocks!`}},
{"Lang nn bundle", "lang", "content/post/my-bundle/index.nn.md", []string{`Site Lang: nn|Name: My Bundle|i18n: Hugo Rokkar!`}},
{"Site", "site", "content/mypage/index.md", []string{"RegularPages .Site: 10", "RegularPages site: 10"}},
{"Shortcodes", "shortcodes", "shortcodes/go.md", []string{
`title = "GO"`,
"{{< myshortcode >}}",
"{{% myshortcode %}}",
@@ -61,28 +69,41 @@ func TestNewContent(t *testing.T) {
}}, // shortcodes
}
c := qt.New(t)
for i, cas := range cases {
cas := cas
t.Run(fmt.Sprintf("%s-%d", cas.kind, i), func(t *testing.T) {
t.Parallel()
c := qt.New(t)
c.Run(cas.name, func(c *qt.C) {
c.Parallel()
mm := afero.NewMemMapFs()
c.Assert(initFs(mm), qt.IsNil)
cfg, fs := newTestCfg(c, mm)
h, err := hugolib.NewHugoSites(deps.DepsCfg{Cfg: cfg, Fs: fs})
c.Assert(err, qt.IsNil)
c.Assert(create.NewContent(h, cas.kind, cas.path), qt.IsNil)
err = create.NewContent(h, cas.kind, cas.path)
if b, ok := cas.expected.(bool); ok && !b {
if !b {
c.Assert(err, qt.Not(qt.IsNil))
}
return
}
c.Assert(err, qt.IsNil)
fname := filepath.FromSlash(cas.path)
if !strings.HasPrefix(fname, "content") {
fname = filepath.Join("content", fname)
}
content := readFileFromFs(t, fs.Source, fname)
for _, v := range cas.expected {
content := readFileFromFs(c, fs.Source, fname)
for _, v := range cas.expected.([]string) {
found := strings.Contains(content, v)
if !found {
t.Fatalf("[%d] %q missing from output:\n%q", i, v, content)
c.Fatalf("[%d] %q missing from output:\n%q", i, v, content)
}
}
})
@@ -95,10 +116,10 @@ func TestNewContentFromDir(t *testing.T) {
c := qt.New(t)
archetypeDir := filepath.Join("archetypes", "my-bundle")
c.Assert(mm.MkdirAll(archetypeDir, 0755), qt.IsNil)
c.Assert(mm.MkdirAll(archetypeDir, 0o755), qt.IsNil)
archetypeThemeDir := filepath.Join("themes", "mytheme", "archetypes", "my-theme-bundle")
c.Assert(mm.MkdirAll(archetypeThemeDir, 0755), qt.IsNil)
c.Assert(mm.MkdirAll(archetypeThemeDir, 0o755), qt.IsNil)
contentFile := `
File: %s
@@ -107,15 +128,15 @@ Name: {{ replace .Name "-" " " | title }}
i18n: {{ T "hugo" }}
`
c.Assert(afero.WriteFile(mm, filepath.Join(archetypeDir, "index.md"), []byte(fmt.Sprintf(contentFile, "index.md")), 0755), qt.IsNil)
c.Assert(afero.WriteFile(mm, filepath.Join(archetypeDir, "index.nn.md"), []byte(fmt.Sprintf(contentFile, "index.nn.md")), 0755), qt.IsNil)
c.Assert(afero.WriteFile(mm, filepath.Join(archetypeDir, "index.md"), []byte(fmt.Sprintf(contentFile, "index.md")), 0o755), qt.IsNil)
c.Assert(afero.WriteFile(mm, filepath.Join(archetypeDir, "index.nn.md"), []byte(fmt.Sprintf(contentFile, "index.nn.md")), 0o755), qt.IsNil)
c.Assert(afero.WriteFile(mm, filepath.Join(archetypeDir, "pages", "bio.md"), []byte(fmt.Sprintf(contentFile, "bio.md")), 0755), qt.IsNil)
c.Assert(afero.WriteFile(mm, filepath.Join(archetypeDir, "resources", "hugo1.json"), []byte(`hugo1: {{ printf "no template handling in here" }}`), 0755), qt.IsNil)
c.Assert(afero.WriteFile(mm, filepath.Join(archetypeDir, "resources", "hugo2.xml"), []byte(`hugo2: {{ printf "no template handling in here" }}`), 0755), qt.IsNil)
c.Assert(afero.WriteFile(mm, filepath.Join(archetypeDir, "pages", "bio.md"), []byte(fmt.Sprintf(contentFile, "bio.md")), 0o755), qt.IsNil)
c.Assert(afero.WriteFile(mm, filepath.Join(archetypeDir, "resources", "hugo1.json"), []byte(`hugo1: {{ printf "no template handling in here" }}`), 0o755), qt.IsNil)
c.Assert(afero.WriteFile(mm, filepath.Join(archetypeDir, "resources", "hugo2.xml"), []byte(`hugo2: {{ printf "no template handling in here" }}`), 0o755), qt.IsNil)
c.Assert(afero.WriteFile(mm, filepath.Join(archetypeThemeDir, "index.md"), []byte(fmt.Sprintf(contentFile, "index.md")), 0755), qt.IsNil)
c.Assert(afero.WriteFile(mm, filepath.Join(archetypeThemeDir, "resources", "hugo1.json"), []byte(`hugo1: {{ printf "no template handling in here" }}`), 0755), qt.IsNil)
c.Assert(afero.WriteFile(mm, filepath.Join(archetypeThemeDir, "index.md"), []byte(fmt.Sprintf(contentFile, "index.md")), 0o755), qt.IsNil)
c.Assert(afero.WriteFile(mm, filepath.Join(archetypeThemeDir, "resources", "hugo1.json"), []byte(`hugo1: {{ printf "no template handling in here" }}`), 0o755), qt.IsNil)
c.Assert(initFs(mm), qt.IsNil)
cfg, fs := newTestCfg(c, mm)
@@ -134,15 +155,90 @@ i18n: {{ T "hugo" }}
cContains(c, readFileFromFs(t, fs.Source, filepath.Join("content", "post/my-post/index.md")), `File: index.md`, `Site Lang: en`, `Name: My Post`, `i18n: Hugo Rocks!`)
cContains(c, readFileFromFs(t, fs.Source, filepath.Join("content", "post/my-post/index.nn.md")), `File: index.nn.md`, `Site Lang: nn`, `Name: My Post`, `i18n: Hugo Rokkar!`)
cContains(c, readFileFromFs(t, fs.Source, filepath.Join("content", "post/my-post/pages/bio.md")), `File: bio.md`, `Site Lang: en`, `Name: My Post`)
cContains(c, readFileFromFs(t, fs.Source, filepath.Join("content", "post/my-post/pages/bio.md")), `File: bio.md`, `Site Lang: en`, `Name: Bio`)
c.Assert(create.NewContent(h, "my-theme-bundle", "post/my-theme-post"), qt.IsNil)
cContains(c, readFileFromFs(t, fs.Source, filepath.Join("content", "post/my-theme-post/index.md")), `File: index.md`, `Site Lang: en`, `Name: My Theme Post`, `i18n: Hugo Rocks!`)
cContains(c, readFileFromFs(t, fs.Source, filepath.Join("content", "post/my-theme-post/resources/hugo1.json")), `hugo1: {{ printf "no template handling in here" }}`)
}
func TestNewContentFromDirSiteFunction(t *testing.T) {
mm := afero.NewMemMapFs()
c := qt.New(t)
archetypeDir := filepath.Join("archetypes", "my-bundle")
c.Assert(mm.MkdirAll(archetypeDir, 0o755), qt.IsNil)
contentFile := `
File: %s
site RegularPages: {{ len site.RegularPages }}
`
c.Assert(afero.WriteFile(mm, filepath.Join(archetypeDir, "index.md"), []byte(fmt.Sprintf(contentFile, "index.md")), 0o755), qt.IsNil)
c.Assert(initFs(mm), qt.IsNil)
cfg, fs := newTestCfg(c, mm)
h, err := hugolib.NewHugoSites(deps.DepsCfg{Cfg: cfg, Fs: fs})
c.Assert(err, qt.IsNil)
c.Assert(len(h.Sites), qt.Equals, 2)
c.Assert(create.NewContent(h, "my-bundle", "post/my-post"), qt.IsNil)
cContains(c, readFileFromFs(t, fs.Source, filepath.Join("content", "post/my-post/index.md")), `site RegularPages: 10`)
}
func TestNewContentFromDirNoSite(t *testing.T) {
mm := afero.NewMemMapFs()
c := qt.New(t)
archetypeDir := filepath.Join("archetypes", "my-bundle")
c.Assert(mm.MkdirAll(archetypeDir, 0o755), qt.IsNil)
archetypeThemeDir := filepath.Join("themes", "mytheme", "archetypes", "my-theme-bundle")
c.Assert(mm.MkdirAll(archetypeThemeDir, 0o755), qt.IsNil)
contentFile := `
File: %s
Name: {{ replace .Name "-" " " | title }}
i18n: {{ T "hugo" }}
`
c.Assert(afero.WriteFile(mm, filepath.Join(archetypeDir, "index.md"), []byte(fmt.Sprintf(contentFile, "index.md")), 0o755), qt.IsNil)
c.Assert(afero.WriteFile(mm, filepath.Join(archetypeDir, "index.nn.md"), []byte(fmt.Sprintf(contentFile, "index.nn.md")), 0o755), qt.IsNil)
c.Assert(afero.WriteFile(mm, filepath.Join(archetypeDir, "pages", "bio.md"), []byte(fmt.Sprintf(contentFile, "bio.md")), 0o755), qt.IsNil)
c.Assert(afero.WriteFile(mm, filepath.Join(archetypeDir, "resources", "hugo1.json"), []byte(`hugo1: {{ printf "no template handling in here" }}`), 0o755), qt.IsNil)
c.Assert(afero.WriteFile(mm, filepath.Join(archetypeDir, "resources", "hugo2.xml"), []byte(`hugo2: {{ printf "no template handling in here" }}`), 0o755), qt.IsNil)
c.Assert(afero.WriteFile(mm, filepath.Join(archetypeThemeDir, "index.md"), []byte(fmt.Sprintf(contentFile, "index.md")), 0o755), qt.IsNil)
c.Assert(afero.WriteFile(mm, filepath.Join(archetypeThemeDir, "resources", "hugo1.json"), []byte(`hugo1: {{ printf "no template handling in here" }}`), 0o755), qt.IsNil)
c.Assert(initFs(mm), qt.IsNil)
cfg, fs := newTestCfg(c, mm)
h, err := hugolib.NewHugoSites(deps.DepsCfg{Cfg: cfg, Fs: fs})
c.Assert(err, qt.IsNil)
c.Assert(len(h.Sites), qt.Equals, 2)
c.Assert(create.NewContent(h, "my-bundle", "post/my-post"), qt.IsNil)
cContains(c, readFileFromFs(t, fs.Source, filepath.Join("content", "post/my-post/resources/hugo1.json")), `hugo1: {{ printf "no template handling in here" }}`)
cContains(c, readFileFromFs(t, fs.Source, filepath.Join("content", "post/my-post/resources/hugo2.xml")), `hugo2: {{ printf "no template handling in here" }}`)
cContains(c, readFileFromFs(t, fs.Source, filepath.Join("content", "post/my-post/index.md")), `File: index.md`, `Name: My Post`, `i18n: Hugo Rocks!`)
cContains(c, readFileFromFs(t, fs.Source, filepath.Join("content", "post/my-post/index.nn.md")), `File: index.nn.md`, `Name: My Post`, `i18n: Hugo Rokkar!`)
cContains(c, readFileFromFs(t, fs.Source, filepath.Join("content", "post/my-post/pages/bio.md")), `File: bio.md`, `Name: Bio`)
c.Assert(create.NewContent(h, "my-theme-bundle", "post/my-theme-post"), qt.IsNil)
cContains(c, readFileFromFs(t, fs.Source, filepath.Join("content", "post/my-theme-post/index.md")), `File: index.md`, `Name: My Theme Post`, `i18n: Hugo Rocks!`)
cContains(c, readFileFromFs(t, fs.Source, filepath.Join("content", "post/my-theme-post/resources/hugo1.json")), `hugo1: {{ printf "no template handling in here" }}`)
}
func initFs(fs afero.Fs) error {
perm := os.FileMode(0755)
perm := os.FileMode(0o755)
var err error
// create directories
@@ -158,7 +254,16 @@ func initFs(fs afero.Fs) error {
}
}
// create files
// create some dummy content
for i := 1; i <= 10; i++ {
filename := filepath.Join("content", fmt.Sprintf("page%d.md", i))
afero.WriteFile(fs, filename, []byte(`---
title: Test
---
`), 0666)
}
// create archetype files
for _, v := range []struct {
path string
content string
@@ -171,11 +276,40 @@ func initFs(fs afero.Fs) error {
path: filepath.Join("archetypes", "post.org"),
content: "#+title: {{ .BaseFileName | upper }}",
},
{
path: filepath.Join("archetypes", "name.md"),
content: `+++
title = '{{ replace .Name "-" " " | title }}'
+++`,
},
{
path: filepath.Join("archetypes", "product.md"),
content: `+++
title = "{{ .BaseFileName | upper }}"
+++`,
},
{
path: filepath.Join("archetypes", "filenames.md"),
content: `...
title = "{{ .BaseFileName | upper }}"
+++
ContentBaseName: {{ .File.ContentBaseName }}
`,
},
{
path: filepath.Join("archetypes", "site.md"),
content: `...
title = "{{ .BaseFileName | upper }}"
+++
Len RegularPages .Site: {{ len .Site.RegularPages }}
Len RegularPages site: {{ len site.RegularPages }}
`,
},
{
path: filepath.Join("archetypes", "emptydate.md"),
@@ -183,7 +317,7 @@ title = "{{ .BaseFileName | upper }}"
},
{
path: filepath.Join("archetypes", "lang.md"),
content: `Site Lang: {{ .Site.Language.Lang }}|Name: {{ replace .Name "-" " " | title }}|i18n: {{ T "hugo" }}`,
content: `Site Lang: {{ site.Language.Lang }}|Name: {{ replace .Name "-" " " | title }}|i18n: {{ T "hugo" }}`,
},
// #3623x
{
@@ -226,7 +360,7 @@ func cContains(c *qt.C, v interface{}, matches ...string) {
}
// TODO(bep) extract common testing package with this and some others
func readFileFromFs(t *testing.T, fs afero.Fs, filename string) string {
func readFileFromFs(t testing.TB, fs afero.Fs, filename string) string {
t.Helper()
filename = filepath.FromSlash(filename)
b, err := afero.ReadFile(fs, filename)
@@ -245,7 +379,7 @@ func readFileFromFs(t *testing.T, fs afero.Fs, filename string) string {
return string(b)
}
func newTestCfg(c *qt.C, mm afero.Fs) (*viper.Viper, *hugofs.Fs) {
func newTestCfg(c *qt.C, mm afero.Fs) (config.Provider, *hugofs.Fs) {
cfg := `
theme = "mytheme"
@@ -256,23 +390,34 @@ languageName = "English"
[languages.nn]
weight = 2
languageName = "Nynorsk"
contentDir = "content_nn"
[module]
[[module.mounts]]
source = 'archetypes'
target = 'archetypes'
[[module.mounts]]
source = 'content'
target = 'content'
lang = 'en'
[[module.mounts]]
source = 'content_nn'
target = 'content'
lang = 'nn'
`
if mm == nil {
mm = afero.NewMemMapFs()
}
mm.MkdirAll(filepath.FromSlash("content_nn"), 0777)
mm.MkdirAll(filepath.FromSlash("content_nn"), 0o777)
mm.MkdirAll(filepath.FromSlash("themes/mytheme"), 0777)
mm.MkdirAll(filepath.FromSlash("themes/mytheme"), 0o777)
c.Assert(afero.WriteFile(mm, filepath.Join("i18n", "en.toml"), []byte(`[hugo]
other = "Hugo Rocks!"`), 0755), qt.IsNil)
other = "Hugo Rocks!"`), 0o755), qt.IsNil)
c.Assert(afero.WriteFile(mm, filepath.Join("i18n", "nn.toml"), []byte(`[hugo]
other = "Hugo Rokkar!"`), 0755), qt.IsNil)
other = "Hugo Rokkar!"`), 0o755), qt.IsNil)
c.Assert(afero.WriteFile(mm, "config.toml", []byte(cfg), 0755), qt.IsNil)
c.Assert(afero.WriteFile(mm, "config.toml", []byte(cfg), 0o755), qt.IsNil)
v, _, err := hugolib.LoadConfig(hugolib.ConfigSourceDescriptor{Fs: mm, Filename: "config.toml"})
c.Assert(err, qt.IsNil)
+9 -4
View File
@@ -45,6 +45,7 @@ import (
_ "gocloud.dev/blob/fileblob" // import
_ "gocloud.dev/blob/gcsblob" // import
_ "gocloud.dev/blob/s3blob" // import
"gocloud.dev/gcerrors"
)
// Deployer supports deploying the site to target cloud providers.
@@ -238,9 +239,13 @@ func (d *Deployer) Deploy(ctx context.Context) error {
go func(del string) {
jww.INFO.Printf("Deleting %s...\n", del)
if err := bucket.Delete(ctx, del); err != nil {
errMu.Lock()
defer errMu.Unlock()
errs = append(errs, err)
if gcerrors.Code(err) == gcerrors.NotFound {
jww.WARN.Printf("Failed to delete %q because it wasn't found: %v", del, err)
} else {
errMu.Lock()
defer errMu.Unlock()
errs = append(errs, err)
}
}
<-sem
}(del)
@@ -432,7 +437,7 @@ func (lf *localFile) ContentType() string {
}
ext := filepath.Ext(lf.NativePath)
if mimeType, found := lf.mediaTypes.GetFirstBySuffix(strings.TrimPrefix(ext, ".")); found {
if mimeType, _, found := lf.mediaTypes.GetFirstBySuffix(strings.TrimPrefix(ext, ".")); found {
return mimeType.Type()
}
+2 -2
View File
@@ -21,7 +21,7 @@ import (
qt "github.com/frankban/quicktest"
"github.com/gohugoio/hugo/config"
"github.com/spf13/viper"
)
func TestDecodeConfigFromTOML(t *testing.T) {
@@ -164,7 +164,7 @@ Pattern = "[" # invalid regular expression
func TestDecodeConfigDefault(t *testing.T) {
c := qt.New(t)
dcfg, err := decodeConfig(viper.New())
dcfg, err := decodeConfig(config.New())
c.Assert(err, qt.IsNil)
c.Assert(len(dcfg.Targets), qt.Equals, 0)
c.Assert(len(dcfg.Matchers), qt.Equals, 0)
+4 -9
View File
@@ -34,10 +34,7 @@ type Deps struct {
Log loggers.Logger `json:"-"`
// Used to log errors that may repeat itself many times.
DistinctErrorLog *helpers.DistinctLogger
// Used to log warnings that may repeat itself many times.
DistinctWarningLog *helpers.DistinctLogger
LogDistinct loggers.Logger
// The templates to use. This will usually implement the full tpl.TemplateManager.
tmpl tpl.TemplateHandler
@@ -256,7 +253,7 @@ func New(cfg DepsCfg) (*Deps, error) {
return nil, err
}
sp := source.NewSourceSpec(ps, fs.Source)
sp := source.NewSourceSpec(ps, nil, fs.Source)
timeoutms := cfg.Language.GetInt("timeout")
if timeoutms <= 0 {
@@ -266,14 +263,12 @@ func New(cfg DepsCfg) (*Deps, error) {
ignoreErrors := cast.ToStringSlice(cfg.Cfg.Get("ignoreErrors"))
ignorableLogger := loggers.NewIgnorableLogger(logger, ignoreErrors...)
distinctErrorLogger := helpers.NewDistinctLogger(logger.Error())
distinctWarnLogger := helpers.NewDistinctLogger(logger.Warn())
logDistinct := helpers.NewDistinctLogger(logger)
d := &Deps{
Fs: fs,
Log: ignorableLogger,
DistinctErrorLog: distinctErrorLogger,
DistinctWarningLog: distinctWarnLogger,
LogDistinct: logDistinct,
templateProvider: cfg.TemplateProvider,
translationProvider: cfg.TranslationProvider,
WithTemplate: cfg.WithTemplate,
+3 -1
View File
@@ -1,5 +1,7 @@
/.idea
/public
node_modules
nohup.out
.DS_Store
trace.out
trace.out
.hugo_build.lock
@@ -9,12 +9,6 @@
margin: 0;
}
pre, .pre {
overflow-x: auto;
overflow-y: hidden;
overflow: scroll;
}
code {
padding: 0.2em;
margin: 0;
@@ -23,8 +17,7 @@ code {
border-radius: 3px;
}
pre code {
pre code {
display: block;
padding: 1.5em 1.5em;
font-size: .875rem;
@@ -32,7 +25,6 @@ pre code {
overflow-x: auto;
}
pre {
background-color: #fff;
color: #333;
@@ -4083,7 +4083,7 @@ img { max-width: 100%; }
max-width: 30em;
}
.measure-wide-l {
max-width: 34em;
max-width: 40em;
}
.measure-narrow-l {
max-width: 20em;
@@ -1,9 +1,3 @@
[[banners]]
name = "Forestry.io"
link = "https://forestry.io/"
logo = "/images/sponsors/forestry-logotype.svg"
copy = ""
[[banners]]
name = "Linode"
link = "https://www.linode.com/"
@@ -14,4 +8,12 @@ copy = ""
name = "eSolia"
link = "https://esolia.com/post/why-did-esolia-choose-hugo/"
logo = "/images/sponsors/esolia-logo.svg"
copy = ""
[[banners]]
name = "Brave"
link = "https://brave.com/"
logo = "/images/sponsors/brave-logo.svg"
bgcolor = "#5A2FA1"
copy = ""
@@ -39,6 +39,8 @@
{{ $.Scratch.Set "stylesheet" . }}
{{end}}
<meta name="description"
content="{{ with .Description }}{{ . }}{{ else }}{{ with .Site.Params.description }}{{ . }}{{ end }}{{ end }}">
{{ block "scripts" . }}
{{- partial "site-scripts.html" . -}}
@@ -53,9 +55,6 @@
{{ partial "gtag" . }}
{{ end }}
</head>
<body class="ma0 sans-serif bg-primary-color-light{{ with getenv "HUGO_ENV" }} {{ . }}{{ end }}">
@@ -69,4 +68,4 @@
</body>
</html>
</html>
@@ -1,31 +1,31 @@
{{ define "main" }}
<article class="w-100 ph4 pb5 pb6-ns pt1 pt5-ns">
<div class="flex-l">
<article class="w-100 ph4 pb5 pb6-ns pt1 pt5-ns">
<div class="flex-l">
<div class="order-2 w-100 w-20-l ph5-m ph0-l mb4 sticky">
<div class="order-2 w-100 w-20-l ph5-m ph0-l mb4 sticky">
{{- partial "toc.html" . -}}
</div>
<div class="order-1 w-60-l mw7 ph0 ph5-ns mid-gray nested-copy-line-height no-underline nested-links nested-img nested-copy-seperator nested-blockquote mt0-ns" style="flex-grow:1;">
<div class="documentation-copy center measure-wide-l">
<div id="readout" class="fixed right-0 bottom-0">
</div>
{{ .Render "page" }}
{{ partial "related.html" . }}
</div>
</div>
<div class="order-0 w-20 dn db-l">
{{ partial "nav-links-docs.html" . }}
</div>
</div>
</article>
<div class="order-1 w-60-l mw7 ph0 ph5-ns mid-gray nested-copy-line-height no-underline nested-links nested-img nested-copy-seperator nested-blockquote mt0-ns" style="flex-grow:1;">
<div class="documentation-copy center measure-wide-l">
<div id="readout" class="fixed right-0 bottom-0">
</div>
{{ .Render "page" }}
{{ partial "related.html" . }}
</div>
</div>
<div class="order-0 w-20 dn db-l">
{{ partial "nav-links-docs.html" . }}
</div>
<div class="w-100 bg-light-gray">
<div class="mw7 pa4 center nested-lh-copy lh-copy">
{{ partial "docs/page-meta-data.html" . }}
{{ partial "page-edit.html" . }}
{{ partial "tags.html" . }}
</div>
</article>
<div class="w-100 bg-light-gray">
<div class="mw7 pa4 center nested-lh-copy lh-copy">
{{ partial "docs/page-meta-data.html" . }}
{{ partial "page-edit.html" . }}
{{ partial "tags.html" . }}
</div>
</div>
</div>
{{ end }}
{{ end }}
@@ -6,7 +6,7 @@
gtag('js', new Date());
{{ $site := $.Site.BaseURL | replaceRE "^https?://(www\\.)?([^/]+).*" "$2" }}
gtag('config', '{{ . }}', {'dimension1': '{{ $site }}', 'dimension2': '{{ getenv "BRANCH" }}'});
gtag('config', '{{ . }}', {'anonymize_ip': true, 'dimension1': '{{ $site }}', 'dimension2': '{{ getenv "BRANCH" }}'});
/**
* Function that tracks a click on an outbound link in Analytics.
@@ -14,7 +14,7 @@
<div class="h4">
<img src="/images/gopher-hero.svg" alt="Hugo Gopher" class="h4">
</div>
<p class="f6 mid-gray m0 p0 pt3">Mac OS</p>
<p class="f6 mid-gray m0 p0 pt3">macOS</p>
<div class="code f6 bg-black light-green lh-copy pv3 ph3 br2 w-100 w-50-ns center mb2 tl">
$ brew install hugo <br />
</div>
@@ -35,5 +35,4 @@
<!-- TODO: Animate the gopher https://github.com/rdwatters/hugo-docs-concept/issues/3#issuecomment-287194777 -->
</div>
@@ -1,4 +1,4 @@
{{$classes_box := "ba b--light-gray bg-light-gray br3 flex flex-column flex-wrap items-center justify-center ph3 pv4 mb4 w-100 w-30-l "}}
{{$classes_box := "ba b--dark-gray bg-light-gray br3 flex flex-column flex-wrap items-center justify-center ph3 pv4 mb4 w-100 w-30-l "}}
{{$gtag := .gtag | default "unknown" }}
{{ with .cx.Site.Data.sponsors }}
<section class="{{ $.classes_section | default "bg-primary-color-dark b--dark-gray bb bt ph5 pv4 w-100"}}">
@@ -8,7 +8,7 @@
{{ range .banners }}
{{ $banner := . }}
{{if .logo}}
<div class="{{$classes_box}} o-100">
<div class="{{$classes_box}} o-100"{{ with .bgcolor }} style="background-color: {{ . }};"{{ end}}>
{{with .link -}}
{{ $url := printf "%s?%s" . (querify "utm_source" "homepage" "utm_medium" "banner" "utm_campaign" "hugosponsor") | safeURL }}
{{ if eq (getenv "HUGO_ENV") "production" | or (eq $.cx.Site.Params.env "production") }}
@@ -1,6 +1,6 @@
<form id="site-search-form" action="" role="search">
<fieldset class="bn ma0 pa0">
<label class="clip" for="search-input">Search</label>
<input type="search" id="search-input" class="needs-js bg-left bn f5 input-reset lh-solid mt3 mt0-ns pl4 pv2 w5 white" placeholder="Search the Docs" name="search-input" value="" style="background: transparent url('/images/icon-search.png') no-repeat 0 8px /16px 16px;">
<input type="search" id="search-input" class="needs-js bg-left bn f5 input-reset lh-solid mt3 mt0-ns pl4 pv2 w5 white" placeholder="Search the Docs" name="search-input" value="" style="background: url('/images/icon-search.png') 5px 11px/16px 16px no-repeat; background-color: rgba(255,255,255,0);">
</fieldset>
</form>
</form>
@@ -17,7 +17,7 @@
{{/* pagination.html: https://github.com/gohugoio/hugo/blob/master/tpl/tplimpl/template_embedded.go#L117 */}}
{{ template "_internal/pagination.html" . }}
</div>
<div class="dib f3 mt4">The Showcase articles are copyright the content authors. Any open source license will be attached.</div>
<div class="dib f3 mt4">The Showcase articles are copyrighted by their respective content authors. Any open source license will be attached.</div>
</div>
{{ end }}
@@ -0,0 +1,43 @@
{
"name": "gohugo-default-styles",
"version": "1.1.0",
"description": "Default Theme for Hugo Sites",
"main": "index.js",
"homepage": "https://gohugo.io/",
"bugs": {
"url": "https://github.com/gohugoio/gohugoioTheme/issues"
},
"repository": {
"type": "git",
"url": "git+https://github.com/gohugoio/gohugoioTheme.git"
},
"author": "budparr",
"license": "MIT",
"scripts": {
"build": "NODE_ENV=production webpack",
"build-dev": "NODE_ENV=development webpack --progress --watch",
"start": "npm run build-dev"
},
"devDependencies": {
"clean-webpack-plugin": "^1.0.0",
"clipboard": "^2.0.4",
"css-loader": "^4.3.0",
"docsearch.js": "^2.6.1",
"file-loader": "^2.0.0",
"glob-all": "^3.1.0",
"highlight.js": "^9.13.1",
"lazysizes": "^5.2.1",
"mini-css-extract-plugin": "^0.4.4",
"postcss": "^7.0.32",
"postcss-cssnext": "^3.1.0",
"postcss-import": "^12.0.1",
"postcss-loader": "^3.0.0",
"purgecss-webpack-plugin": "^1.3.1",
"scrolldir": "^1.4.0",
"tachyons": "^4.7.0",
"typeface-muli": "0.0.54",
"webpack": "^4.44.1",
"webpack-command": "^0.4.2"
},
"dependencies": {}
}
File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.6 KiB

+1 -1
View File
@@ -1 +1 @@
# github.com/gohugoio/gohugoioTheme v0.0.0-20200711112515-b0dfe471654f
# github.com/gohugoio/gohugoioTheme v0.0.0-20210409071416-c88da48134b7
+1 -2
View File
@@ -1,7 +1,6 @@
---
linktitle: ""
description: ""
godocref: ""
publishdate: ""
lastmod: ""
categories: []
@@ -10,4 +9,4 @@ weight: 00
slug: ""
aliases: []
toc: false
---
---
+1 -2
View File
@@ -1,7 +1,6 @@
---
linktitle: ""
description: ""
godocref: ""
publishdate: ""
lastmod: ""
categories: [functions]
@@ -14,4 +13,4 @@ aliases: []
relatedfuncs: []
toc: false
deprecated: false
---
---
+7 -1
View File
@@ -7,7 +7,7 @@ footnotereturnlinkcontents = "↩"
languageCode = "en-us"
title = "Hugo"
ignoreErrors = ["error-remote-getjson"]
ignoreErrors = ["error-remote-getjson", "error-missing-instagram-accesstoken"]
googleAnalytics = "UA-7131036-4"
@@ -17,6 +17,12 @@ pluralizeListTitles = false
# We do redirects via Netlify's _redirects file, generated by Hugo (see "outputs" below).
disableAliases = true
[minify]
[minify.tdewolff]
[minify.tdewolff.css]
[minify.tdewolff.html]
keepWhitespace = true
[module]
[module.hugoVersion]
min = "0.56.0"
+24
View File
@@ -1,7 +1,31 @@
defaultMarkdownHandler = "goldmark"
[goldmark]
[goldmark.extensions]
definitionList = true
footnote = true
linkify = true
strikethrough = true
table = true
taskList = true
typographer = true
[goldmark.parser]
autoHeadingID = true
autoHeadingIDType = "github"
[goldmark.parser.attribute]
block = true
title = true
[goldmark.renderer]
hardWraps = false
unsafe = false
xhtml = false
[highlight]
style = "trac"
lineNumbersInTable = true
noClasses = false
[tableOfContents]
endLevel = 2
ordered = false
startLevel = 2
+1 -1
View File
@@ -36,7 +36,7 @@ This has many benefits. The most noticeable is performance. HTTP servers are *ve
["An Introduction to Static Site Generators", David Walsh]: https://davidwalsh.name/introduction-static-site-generators
["Static Site Generators", O'Reilly]: https://www.oreilly.com/web-platform/free/files/static-site-generators.pdf
["Static Site Generators", O'Reilly]: https://github.com/gohugoio/hugoDocs/files/1242701/static-site-generators.pdf
["Top 10 Static Website Generators", Netlify blog]: https://www.netlify.com/blog/2016/05/02/top-ten-static-website-generators/
[hugovwordpress]: https://gettingthingstech.com/hugo-vs.-wordpress-page-load-speed-comparison-hugo-leaves-wordpress-in-its-dust/
[StaticGen: Top Open-Source Static Site Generators (GitHub Stars)]: https://www.staticgen.com/
+3
View File
@@ -92,6 +92,9 @@ respectDoNotTrack
useSessionStorage
: Enabling this will disable the use of Cookies and use Session Storage to Store the GA Client ID.
{{% warning %}}
`useSessionStorage` is not supported when using Google Analytics v4 (gtag.js).
{{% /warning %}}
### Instagram
simple
+2 -2
View File
@@ -1,5 +1,4 @@
---
date: 2020-09-13
title: "hugo"
slug: hugo
url: /commands/hugo/
@@ -52,6 +51,7 @@ hugo [flags]
--noChmod don't sync permission mode of files
--noTimes don't sync modification time of files
--path-warnings print warnings on duplicate target paths etc.
--poll string set this to a poll interval, e.g --poll 700ms, to use a poll based approach to watch for file system changes
--print-mem print memory usage to screen at intervals
--quiet build in quiet mode
--renderToMemory render to memory (only useful for benchmark testing)
@@ -69,6 +69,7 @@ hugo [flags]
### SEE ALSO
* [hugo check](/commands/hugo_check/) - Contains some verification checks
* [hugo completion](/commands/hugo_completion/) - generate the autocompletion script for the specified shell
* [hugo config](/commands/hugo_config/) - Print the site configuration
* [hugo convert](/commands/hugo_convert/) - Convert your content to different formats
* [hugo deploy](/commands/hugo_deploy/) - Deploy your site to a Cloud provider.
@@ -81,4 +82,3 @@ hugo [flags]
* [hugo server](/commands/hugo_server/) - A high performance webserver
* [hugo version](/commands/hugo_version/) - Print the version number of Hugo
###### Auto generated by spf13/cobra on 13-Sep-2020
-6
View File
@@ -1,5 +1,4 @@
---
date: 2020-09-13
title: "hugo check"
slug: hugo_check
url: /commands/hugo_check/
@@ -8,10 +7,6 @@ url: /commands/hugo_check/
Contains some verification checks
### Synopsis
Contains some verification checks
### Options
```
@@ -41,4 +36,3 @@ Contains some verification checks
* [hugo](/commands/hugo/) - hugo builds your site
* [hugo check ulimit](/commands/hugo_check_ulimit/) - Check system ulimit settings
###### Auto generated by spf13/cobra on 13-Sep-2020
@@ -1,5 +1,4 @@
---
date: 2020-09-13
title: "hugo check ulimit"
slug: hugo_check_ulimit
url: /commands/hugo_check_ulimit/
@@ -45,4 +44,3 @@ hugo check ulimit [flags]
* [hugo check](/commands/hugo_check/) - Contains some verification checks
###### Auto generated by spf13/cobra on 13-Sep-2020
@@ -0,0 +1,48 @@
---
title: "hugo completion"
slug: hugo_completion
url: /commands/hugo_completion/
---
## hugo completion
generate the autocompletion script for the specified shell
### Synopsis
Generate the autocompletion script for hugo for the specified shell.
See each sub-command's help for details on how to use the generated script.
### Options
```
-h, --help help for completion
```
### Options inherited from parent commands
```
--config string config file (default is path/config.yaml|json|toml)
--configDir string config dir (default "config")
--debug debug output
-e, --environment string build environment
--ignoreVendor ignores any _vendor directory
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--quiet build in quiet mode
-s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory
-v, --verbose verbose output
--verboseLog verbose logging
```
### SEE ALSO
* [hugo](/commands/hugo/) - hugo builds your site
* [hugo completion bash](/commands/hugo_completion_bash/) - generate the autocompletion script for bash
* [hugo completion fish](/commands/hugo_completion_fish/) - generate the autocompletion script for fish
* [hugo completion powershell](/commands/hugo_completion_powershell/) - generate the autocompletion script for powershell
* [hugo completion zsh](/commands/hugo_completion_zsh/) - generate the autocompletion script for zsh
@@ -0,0 +1,62 @@
---
title: "hugo completion bash"
slug: hugo_completion_bash
url: /commands/hugo_completion_bash/
---
## hugo completion bash
generate the autocompletion script for bash
### Synopsis
Generate the autocompletion script for the bash shell.
This script depends on the 'bash-completion' package.
If it is not installed already, you can install it via your OS's package manager.
To load completions in your current shell session:
$ source <(hugo completion bash)
To load completions for every new session, execute once:
Linux:
$ hugo completion bash > /etc/bash_completion.d/hugo
MacOS:
$ hugo completion bash > /usr/local/etc/bash_completion.d/hugo
You will need to start a new shell for this setup to take effect.
```
hugo completion bash
```
### Options
```
-h, --help help for bash
--no-descriptions disable completion descriptions
```
### Options inherited from parent commands
```
--config string config file (default is path/config.yaml|json|toml)
--configDir string config dir (default "config")
--debug debug output
-e, --environment string build environment
--ignoreVendor ignores any _vendor directory
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--quiet build in quiet mode
-s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory
-v, --verbose verbose output
--verboseLog verbose logging
```
### SEE ALSO
* [hugo completion](/commands/hugo_completion/) - generate the autocompletion script for the specified shell
@@ -0,0 +1,56 @@
---
title: "hugo completion fish"
slug: hugo_completion_fish
url: /commands/hugo_completion_fish/
---
## hugo completion fish
generate the autocompletion script for fish
### Synopsis
Generate the autocompletion script for the fish shell.
To load completions in your current shell session:
$ hugo completion fish | source
To load completions for every new session, execute once:
$ hugo completion fish > ~/.config/fish/completions/hugo.fish
You will need to start a new shell for this setup to take effect.
```
hugo completion fish [flags]
```
### Options
```
-h, --help help for fish
--no-descriptions disable completion descriptions
```
### Options inherited from parent commands
```
--config string config file (default is path/config.yaml|json|toml)
--configDir string config dir (default "config")
--debug debug output
-e, --environment string build environment
--ignoreVendor ignores any _vendor directory
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--quiet build in quiet mode
-s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory
-v, --verbose verbose output
--verboseLog verbose logging
```
### SEE ALSO
* [hugo completion](/commands/hugo_completion/) - generate the autocompletion script for the specified shell
@@ -0,0 +1,54 @@
---
title: "hugo completion powershell"
slug: hugo_completion_powershell
url: /commands/hugo_completion_powershell/
---
## hugo completion powershell
generate the autocompletion script for powershell
### Synopsis
Generate the autocompletion script for powershell.
To load completions in your current shell session:
PS C:\> hugo completion powershell | Out-String | Invoke-Expression
To load completions for every new session, add the output of the above command
to your powershell profile.
```
hugo completion powershell [flags]
```
### Options
```
-h, --help help for powershell
--no-descriptions disable completion descriptions
```
### Options inherited from parent commands
```
--config string config file (default is path/config.yaml|json|toml)
--configDir string config dir (default "config")
--debug debug output
-e, --environment string build environment
--ignoreVendor ignores any _vendor directory
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--quiet build in quiet mode
-s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory
-v, --verbose verbose output
--verboseLog verbose logging
```
### SEE ALSO
* [hugo completion](/commands/hugo_completion/) - generate the autocompletion script for the specified shell
@@ -0,0 +1,61 @@
---
title: "hugo completion zsh"
slug: hugo_completion_zsh
url: /commands/hugo_completion_zsh/
---
## hugo completion zsh
generate the autocompletion script for zsh
### Synopsis
Generate the autocompletion script for the zsh shell.
If shell completion is not already enabled in your environment you will need
to enable it. You can execute the following once:
$ echo "autoload -U compinit; compinit" >> ~/.zshrc
To load completions for every new session, execute once:
# Linux:
$ hugo completion zsh > "${fpath[1]}/_hugo"
# macOS:
$ hugo completion zsh > /usr/local/share/zsh/site-functions/_hugo
You will need to start a new shell for this setup to take effect.
```
hugo completion zsh [flags]
```
### Options
```
-h, --help help for zsh
--no-descriptions disable completion descriptions
```
### Options inherited from parent commands
```
--config string config file (default is path/config.yaml|json|toml)
--configDir string config dir (default "config")
--debug debug output
-e, --environment string build environment
--ignoreVendor ignores any _vendor directory
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--quiet build in quiet mode
-s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory
-v, --verbose verbose output
--verboseLog verbose logging
```
### SEE ALSO
* [hugo completion](/commands/hugo_completion/) - generate the autocompletion script for the specified shell

Some files were not shown because too many files have changed in this diff Show More