Compare commits

..

386 Commits

Author SHA1 Message Date
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 a074f758b0 Merge commit '92405e5b0adc5d8c3dfde88d6a8b67eb09169190' 2021-06-18 12:57:19 +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 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
hugoreleaser 792ef0f41a releaser: Add release notes to /docs for release of 0.80.0
[ci skip]
2020-12-31 13:36:35 +00:00
hugoreleaser 5b3fc1c673 releaser: Bump versions for release of 0.80.0
[ci skip]
2020-12-31 13:36:35 +00:00
Bjørn Erik Pedersen 63a33afee7 Update 0.80.0-relnotes.md 2020-12-31 14:26:00 +01:00
hugoreleaser 69aa3d4599 releaser: Add release notes for 0.80.0
Rename to *-ready.md to continue.
[ci skip]
2020-12-31 13:09:24 +00:00
Bjørn Erik Pedersen ffbf5e45fa Allow Dart Sass transformations to be cached on disk
This enbles people to build their sites/themes on servers where the Dart Sass binary is not available.
2020-12-31 11:32:20 +01:00
Bjørn Erik Pedersen 48994ea766 dartsass: Dart Sass only supports expanded and compressed 2020-12-31 11:18:54 +01:00
Bjørn Erik Pedersen 428b0b3294 dartsass: Add missing OutputStyle option 2020-12-31 10:49:59 +01:00
Cameron Moore 1f7e9f7333 Update emoji import paths and version
Since emoji is v2, we must import it with the `/v2` suffix.  Doing so
allows the Go tools to detect the latest release.
2020-12-30 22:46:19 +01:00
Bjørn Erik Pedersen cea1574023 Add Dart Sass support
But note that the Dart Sass Embedded Protocol is still in beta (beta 5), a main release scheduled for Q1 2021.

Fixes #7380
Fixes #8102
2020-12-30 17:32:25 +01:00
Horst Gutmann f9f779786e GroupByParamDate now supports datetimes
Previously, the method only worked for date strings but not (for
instance) full RFC3339 datetime strings.
2020-12-28 17:50:55 +01:00
Bjørn Erik Pedersen a9718f44cd para: Skip para test when not on CI
Fixes #6963
2020-12-23 19:47:20 +01:00
Bjørn Erik Pedersen f802bb236a Update SECURITY.md 2020-12-22 10:09:59 +01:00
hugoreleaser 6c29418278 releaser: Add release notes to /docs for release of 0.79.1
[ci skip]
2020-12-19 17:09:29 +01:00
Bjørn Erik Pedersen 10ae7c3210 Improve LookPath 2020-12-19 17:03:07 +01:00
Patrick Kollitsch ae2d1bd52d docs: create a SECURITY.md
This file is used by Github as a tab on the repos homepage to access information about how to report security issues. The text is kept simple.

Will solve #8074
2020-12-18 17:55:49 +01:00
Bjørn Erik Pedersen 81975f847d Fix Resource.ResourceType so it always returns MIME's main type
The one exception being for the Page, which does not have a MIME type, in which you will get the value `page`.

Fixes #8052
2020-12-17 22:20:12 +01:00
Cameron Moore 8103188b9b para: Show more detail on failed time test
Give us more visibility into how badly a given host is failing in the
time test.

Updates #6963
2020-12-17 22:19:17 +01:00
Bjørn Erik Pedersen 3ba147e702 images: Add images.Overlay filter
This allows for constructs ala:

```
{{ $overlay := $img.Filter (images.Overlay $logo 50 50 )}}
```
Or:

```
{{ $logoFilter := (images.Overlay $logo 50 50 ) }}
{{ $overlay := $img | images.Filter $logoFilter }}
```

Which will overlay the logo in the top left corner (x=50, y=50) of `$img`.

Fixes #8057
Fixes #4595
Updates #6731
2020-12-17 09:14:18 +01:00
Bjørn Erik Pedersen a2d146ec32 tpl: Regenerate templates 2020-12-16 12:20:02 +01:00
Maciej Sawicki d2d493ab5d tpl: Fix series detection in opengraph
When inside front matter you specified series with spaces,
then the opengraph template wouldn't detect other articles,
because in `.Site.Taxonomies.series` they are stored by 
urlized key.

Example:

```yaml
# in front matter
series:
    - My Series
```

```gohtml
{{/* in a template */}}
{{- $series := index .Site.Taxonomies.series$name }}

{{/* was resolved to */}}
{{- $series := index {'my-series': ...} "MySeries" }}
```
2020-12-16 12:13:30 +01:00
真夜 ce96895deb hugolib/paths: Fix typo 2020-12-16 12:12:14 +01:00
Phil Davis 04b89857e1 all: Fix minor typos 2020-12-16 12:11:32 +01:00
Bjørn Erik Pedersen 21fa1e86f2 Fix BenchmarkMergeByLanguage
Fixes #7914
2020-12-09 17:47:10 +01:00
Anthony Fok c84ad8db82 deps: Bump github.com/spf13/cobra from 0.15.0 to 0.20.0
The substring match in TestExecute deploy test is adjusted accordingly.
2020-12-04 20:43:03 -07:00
Patrick Kollitsch 4e0acb89b7 chore: configure proper link to discourse.gohugo.io (#8020)
* chore: configure proper link to discourse.gohugo.io 

This adds a configuration file to the issue templates for this repo. In this config file, an issue template is added that will look like the existing issue templates, but on click will lead directly to the discourse forum instead of hoping that people read what it says there. The support.md can be deleted.

* chore: remove obsolete support.md configuration

* chore: remove obsolete autoclosing workflow
2020-12-04 10:04:35 +01:00
Bjørn Erik Pedersen 718e09ed4b tpl/internal/go_templates: Revert formatting
Should make future fork synch easier.
2020-12-03 13:47:43 +01:00
Bjørn Erik Pedersen d90e37e0c6 all: Format code with gofumpt
See https://github.com/mvdan/gofumpt
2020-12-03 13:12:58 +01:00
dependabot[bot] 32471b57bd build(deps): bump github.com/evanw/esbuild from 0.8.15 to 0.8.17
Bumps [github.com/evanw/esbuild](https://github.com/evanw/esbuild) from 0.8.15 to 0.8.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.8.15...v0.8.17)

Signed-off-by: dependabot[bot] <support@github.com>
2020-12-02 13:04:16 +01:00
Andrew Zenk 4fc918e02c tpl: Add title parameter to YouTube shortcode 2020-12-02 12:53:53 +01:00
sth 0ad378b09c Use --baseURL path for live-reload URL
Fixes #6595
2020-12-02 12:52:26 +01:00
ivan-meridianbanc-com aebfe156fb Fix RelURL and AbsURL when path starts with language 2020-12-02 12:47:01 +01:00
dependabot[bot] 907d9e9268 build(deps): bump github.com/getkin/kin-openapi from 0.31.0 to 0.32.0
Bumps [github.com/getkin/kin-openapi](https://github.com/getkin/kin-openapi) from 0.31.0 to 0.32.0.
- [Release notes](https://github.com/getkin/kin-openapi/releases)
- [Commits](https://github.com/getkin/kin-openapi/compare/v0.31.0...v0.32.0)

Signed-off-by: dependabot[bot] <support@github.com>
2020-12-02 12:26:27 +01:00
Cameron Moore 5862fd2a60 tpl: Fix substr when length parameter is zero
When length parameter is zero, always return an empty string.

Updates #7993
2020-12-01 23:20:04 +01:00
Cameron Moore 64789fb5dc tpl: Refactor and fix substr logic
Fix miscalculations when start is negative.  Results should now match
PHP substr.

Fixes #7993
2020-11-28 11:53:46 +01:00
hugoreleaser 32d4bf68da releaser: Prepare repository for 0.80.0-DEV
[ci skip]
2020-11-27 09:19:04 +00:00
hugoreleaser 1415efdcd8 releaser: Add release notes to /docs for release of 0.79.0
[ci skip]
2020-11-27 09:06:36 +00:00
hugoreleaser 4e6bf7907d releaser: Bump versions for release of 0.79.0
[ci skip]
2020-11-27 09:06:36 +00:00
Bjørn Erik Pedersen 50be4370b0 Update 0.79.0-relnotes.md 2020-11-27 09:55:51 +01:00
hugoreleaser 3d2e6a30d4 releaser: Add release notes for 0.79.0
Rename to *-ready.md to continue.
[ci skip]
2020-11-27 08:44:33 +00:00
Bjørn Erik Pedersen 4f1e4bb3fe Merge commit '9f1265fde4b9ef186148337c99f08601633b6056' 2020-11-27 09:30:05 +01:00
Bjørn Erik Pedersen 9f1265fde4 Squashed 'docs/' changes from 57c1d1a67..1de7a358c
1de7a358c Clarify that "with" blocks do not render with empty values (#1287)
b48de8b0a Update js.md
e0124e4b1 Update js.md
087b39d74 Update hosting-on-render.md (#1286)
8f02b5412 Update js.md (#1284)
8dd8a8d1d Add link to "Build Websites with Hugo" book (#1174)
ae2dc138a Fix typo in page bundles (#1283)
ab14bfec3 Update configuration directory section
17da77ff1 Update multilingual.md (#1280)
5bce8db3a Fix for site-hierarchy image, issue #60
9d7a2366d Fix typo
ad4210c41 Fix typo
c88bc0383 Fix orphan branch url (#1262)
1cf6cf5b3 Hugo 0.78.2
538c3cb86 Merge branch 'tempv0.78.2'
e5e07fc81 releaser: Add release notes to /docs for release of 0.78.2
120a61a47 Fixed wrong var assignment example
4cebbb1a7 Ignore remote JSON errors (for now)
618fcf9ba Add a link to modules config option 'replacements'
e12722779 Fix typo ("wil" -> "will") (#1273)
0670e9894 Update js.md
5bde834cf Update GH docs to say "main" as default branch
26312f93d Update index.md
eb6f51df1 Update js.md
b890dc84d Merge branch 'tempv0.78.1'
6b73ea450 releaser: Add release notes to /docs for release of 0.78.1
46e582112 Update starter-kits.md (#1268)
a62786235 Update 404 docs: GitLab auto-detects 404.html (#1173)
cbd4fd2d9 Fix typo (#1271)
2ba3f9386 Update js.md
7b5109d90 Update js.md
bc75bc962 Release 0.78.0
0b2e8b0f1 releaser: Add release notes to /docs for release of 0.78.0
9ecba8480 Merge commit 'b74591123eac47a20d1f26ff3e2d291cd9c5cfc0'
60a475df7 js: Add avoidTDZ option
3b895261f Make js.Build fully support modules

git-subtree-dir: docs
git-subtree-split: 1de7a358ca
2020-11-27 09:26:24 +01:00
Bjørn Erik Pedersen d162bbd799 publisher: Fix memory usage in writeStats
```
name                     old time/op    new time/op    delta
ClassCollectorWriter-16    72.1µs ± 0%    32.3µs ± 0%  -55.17%  (p=0.029 n=4+4)

name                     old alloc/op   new alloc/op   delta
ClassCollectorWriter-16    85.9kB ± 0%    35.1kB ± 0%  -59.16%  (p=0.029 n=4+4)

name                     old allocs/op  new allocs/op  delta
ClassCollectorWriter-16       329 ± 0%       149 ± 0%  -54.71%  (p=0.029 n=4+4)
```

Fixes #7945
2020-11-27 09:13:16 +01:00
dependabot[bot] 17e0bbe821 build(deps): bump gopkg.in/yaml.v2 from 2.3.0 to 2.4.0
Bumps [gopkg.in/yaml.v2](https://github.com/go-yaml/yaml) from 2.3.0 to 2.4.0.
- [Release notes](https://github.com/go-yaml/yaml/releases)
- [Commits](https://github.com/go-yaml/yaml/compare/v2.3.0...v2.4.0)

Signed-off-by: dependabot[bot] <support@github.com>
2020-11-26 21:41:21 +01:00
Bjørn Erik Pedersen e442cf30a2 Fix server rebuild issue with partials referenced from render hooks
Fixes #7990
2020-11-26 20:41:54 +01:00
Bjørn Erik Pedersen 7e223b3baa Allow setting the delimiter used for setting config via OS env, e.g. HUGO_
Fixes #7829
2020-11-25 20:34:34 +01:00
Bjørn Erik Pedersen 8a6e706053 deps: Update to github.com/evanw/esbuild 0.8.11 to 0.8.14
Closes #7986
2020-11-25 17:39:51 +01:00
Cameron Moore 34061706e6 output: Add more layout lookup tests
Add more tests to cover more cases and to help with documentation and
discussion of template lookup order.

Updates #7964
2020-11-25 12:52:33 +01:00
dependabot[bot] 6f7633df7d build(deps): bump github.com/google/go-cmp from 0.5.2 to 0.5.3
Bumps [github.com/google/go-cmp](https://github.com/google/go-cmp) from 0.5.2 to 0.5.3.
- [Release notes](https://github.com/google/go-cmp/releases)
- [Commits](https://github.com/google/go-cmp/compare/v0.5.2...v0.5.3)

Signed-off-by: dependabot[bot] <support@github.com>
2020-11-24 20:20:40 +01:00
Christian Oliff a546059a9c examples: Remove unneeded meta tag from blog example
```html
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
```
This was only needed for IE10 and lower (which are no longer supported) and chromeframe which was a Google plugin for IE8 and lower and was discontinued many years ago. So this meta tag can be safely removed.
2020-11-24 20:20:04 +01:00
dependabot[bot] b5d906e31e build(deps): bump github.com/getkin/kin-openapi from 0.30.0 to 0.31.0
Bumps [github.com/getkin/kin-openapi](https://github.com/getkin/kin-openapi) from 0.30.0 to 0.31.0.
- [Release notes](https://github.com/getkin/kin-openapi/releases)
- [Commits](https://github.com/getkin/kin-openapi/compare/v0.30.0...v0.31.0)

Signed-off-by: dependabot[bot] <support@github.com>
2020-11-24 14:48:09 +01:00
Bjørn Erik Pedersen fd70bdafe7 docs: Regen docshelper 2020-11-24 13:49:01 +01:00
David Jones 8f5c9a747f Add menu params
Fixes #7951
2020-11-22 22:09:59 +01:00
SatowTakeshi e4fcb672ed resources: Preserve url set in frontmatter without sanitizing
related #6007 (already closed)
2020-11-21 23:37:58 +01:00
Bjørn Erik Pedersen 18c13adcd4 watcher: Add file deleted by accident
See #7972
2020-11-21 17:21:14 +01:00
Bjørn Erik Pedersen 20a35374a3 Revert "docs: Regenerate docshelper"
This reverts commit caf16c2085.

Closes #7972
2020-11-21 12:48:48 +01:00
Bjørn Erik Pedersen caf16c2085 docs: Regenerate docshelper 2020-11-20 09:32:16 +01:00
Bjørn Erik Pedersen b298c06e05 deps: Update to Chroma v0.8.2
Closes #7970
2020-11-20 09:30:05 +01:00
dependabot[bot] 55e290af41 build(deps): bump github.com/evanw/esbuild from 0.8.8 to 0.8.11
Bumps [github.com/evanw/esbuild](https://github.com/evanw/esbuild) from 0.8.8 to 0.8.11.
- [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.8.8...v0.8.11)

Signed-off-by: dependabot[bot] <support@github.com>
2020-11-19 09:51:30 +01:00
dependabot[bot] 506a190a82 build(deps): bump github.com/getkin/kin-openapi from 0.26.0 to 0.30.0
Bumps [github.com/getkin/kin-openapi](https://github.com/getkin/kin-openapi) from 0.26.0 to 0.30.0.
- [Release notes](https://github.com/getkin/kin-openapi/releases)
- [Commits](https://github.com/getkin/kin-openapi/compare/v0.26.0...v0.30.0)

Signed-off-by: dependabot[bot] <support@github.com>
2020-11-16 12:33:31 +01:00
dependabot[bot] fc81de6439 build(deps): bump github.com/evanw/esbuild from 0.8.6 to 0.8.8
Bumps [github.com/evanw/esbuild](https://github.com/evanw/esbuild) from 0.8.6 to 0.8.8.
- [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.8.6...v0.8.8)

Signed-off-by: dependabot[bot] <support@github.com>
2020-11-16 12:32:33 +01:00
hugoreleaser fcaa324e3c releaser: Prepare repository for 0.79.0-DEV
[ci skip]
2020-11-13 10:19:23 +00:00
hugoreleaser 959724f0e0 releaser: Add release notes to /docs for release of 0.78.2
[ci skip]
2020-11-13 10:07:00 +00:00
hugoreleaser a3012d85d1 releaser: Bump versions for release of 0.78.2
[ci skip]
2020-11-13 10:07:00 +00:00
hugoreleaser fc7f739275 releaser: Add release notes for 0.78.2
[ci skip]
2020-11-13 10:07:00 +00:00
Bjørn Erik Pedersen 78f227b664 js: Let ESBuild handle all imports from node_modules
This commit fixes some issues where modules in /assets share the same name as in node_modules.

This was not intended, and with this commit the node_modules-components should be isolated. If you want to redefine something inside node_modules, use the `defines` option.

Fixes #7948
2020-11-13 08:54:29 +01:00
dependabot[bot] 5e03f644a4 build(deps): bump github.com/evanw/esbuild from 0.8.5 to 0.8.6
Bumps [github.com/evanw/esbuild](https://github.com/evanw/esbuild) from 0.8.5 to 0.8.6.
- [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.8.5...v0.8.6)

Signed-off-by: dependabot[bot] <support@github.com>
2020-11-12 13:59:18 +01:00
dependabot[bot] a92ef20ff6 build(deps): bump github.com/evanw/esbuild from 0.8.4 to 0.8.5
Bumps [github.com/evanw/esbuild](https://github.com/evanw/esbuild) from 0.8.4 to 0.8.5.
- [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.8.4...v0.8.5)

Signed-off-by: dependabot[bot] <support@github.com>
2020-11-11 23:00:27 +01:00
dependabot[bot] 0d54a84406 build(deps): bump github.com/getkin/kin-openapi from 0.22.1 to 0.26.0
Bumps [github.com/getkin/kin-openapi](https://github.com/getkin/kin-openapi) from 0.22.1 to 0.26.0.
- [Release notes](https://github.com/getkin/kin-openapi/releases)
- [Commits](https://github.com/getkin/kin-openapi/compare/v0.22.1...v0.26.0)

Signed-off-by: dependabot[bot] <support@github.com>
2020-11-08 12:44:01 +01:00
Mackenzie Morgan 943f3c932f Update GH docs to say "main" as default branch 2020-11-06 20:57:52 +01:00
AdamKorcz 4f20bf29eb Updated year in header 2020-11-06 13:19:18 +01:00
AdamKorcz 4c613d5d5d Added first fuzzer 2020-11-06 13:19:18 +01:00
dependabot[bot] 82a182e52c build(deps): bump github.com/frankban/quicktest from 1.11.1 to 1.11.2
Bumps [github.com/frankban/quicktest](https://github.com/frankban/quicktest) from 1.11.1 to 1.11.2.
- [Release notes](https://github.com/frankban/quicktest/releases)
- [Commits](https://github.com/frankban/quicktest/compare/v1.11.1...v1.11.2)

Signed-off-by: dependabot[bot] <support@github.com>
2020-11-06 13:18:22 +01:00
dependabot[bot] dfc662b208 build(deps): bump golang.org/x/text from 0.3.3 to 0.3.4
Bumps [golang.org/x/text](https://github.com/golang/text) from 0.3.3 to 0.3.4.
- [Release notes](https://github.com/golang/text/releases)
- [Commits](https://github.com/golang/text/compare/v0.3.3...v0.3.4)

Signed-off-by: dependabot[bot] <support@github.com>
2020-11-06 09:09:13 +01:00
dependabot[bot] 2f0917cc01 build(deps): bump github.com/evanw/esbuild from 0.8.3 to 0.8.4
Bumps [github.com/evanw/esbuild](https://github.com/evanw/esbuild) from 0.8.3 to 0.8.4.
- [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.8.3...v0.8.4)

Signed-off-by: dependabot[bot] <support@github.com>
2020-11-06 09:01:32 +01:00
hugoreleaser 7565cda1ff releaser: Prepare repository for 0.79.0-DEV
[ci skip]
2020-11-05 09:50:35 +00:00
hugoreleaser 347f2de67d releaser: Add release notes to /docs for release of 0.78.1
[ci skip]
2020-11-05 09:38:59 +00:00
hugoreleaser 210f6d38ac releaser: Bump versions for release of 0.78.1
[ci skip]
2020-11-05 09:38:59 +00:00
hugoreleaser 03f87f8f06 releaser: Add release notes for 0.78.1
[ci skip]
2020-11-05 09:38:59 +00:00
Bjørn Erik Pedersen 3437174c3a Disable NPM test on Travis on Windows
For now.
2020-11-05 09:56:22 +01:00
Bjørn Erik Pedersen f66302ca05 travis: Install nodejs on Windows 2020-11-05 07:51:41 +01:00
Bjørn Erik Pedersen 944150bafb js: Remove external source map option
It was merged by accident and the implementation does not look correct.

Fixes #7932
2020-11-04 23:04:12 +01:00
Bjørn Erik Pedersen bf2837a314 js: Misc fixes
* Fix resolve of package.json deps in submodules
* Fix directory logic for writing assets/jsconfig.json

Fixes #7924
Fixes #7923
2020-11-04 19:21:43 +01:00
hugoreleaser cf6131dc18 releaser: Prepare repository for 0.79.0-DEV
[ci skip]
2020-11-03 13:25:12 +00:00
hugoreleaser fd62817bba releaser: Add release notes to /docs for release of 0.78.0
[ci skip]
2020-11-03 13:13:12 +00:00
hugoreleaser 3ebe83aea7 releaser: Bump versions for release of 0.78.0
[ci skip]
2020-11-03 13:13:12 +00:00
Bjørn Erik Pedersen 0c16debc7f Update 0.78.0-relnotes.md 2020-11-03 14:03:53 +01:00
hugoreleaser 794e1f9e72 releaser: Add release notes for 0.78.0
Rename to *-ready.md to continue.
[ci skip]
2020-11-03 12:23:42 +00:00
Bjørn Erik Pedersen c64e9504d8 Merge commit 'b74591123eac47a20d1f26ff3e2d291cd9c5cfc0' 2020-11-03 13:05:34 +01:00
Bjørn Erik Pedersen b74591123e Squashed 'docs/' changes from d1157b687..57c1d1a67
57c1d1a67 Add note about issue with Instagram shortcode
2a4355113 Add example for regional language tags (#1139)
5e9a60fc0 Format dates with "th", "nd", and "rd". (#1254)
43df9a7f6 Update index.md
f15f32590 Update index.md
5a15be93d Update configuration.md
e71c1c545 Update configuration.md
5fd0439ff Release Hugo 0.77.0
5b875477c releaser: Add release notes to /docs for release of 0.77.0
09a2a3199 docs: Regen docs helper
bebef9bbe Merge commit '9cabb46f68bae01aeb1859727dcb21e8a10f5ec7'
f5ed02685 tpl: Refactor time.AsTime location implementation
f3b8eccd2 tpl: Update Hugo time to support optional [LOCATION] parameter

git-subtree-dir: docs
git-subtree-split: 57c1d1a67b
2020-11-03 13:04:56 +01:00
Bjørn Erik Pedersen 3b2fe3cd33 js: Add avoidTDZ option
Fixes #7865
2020-11-03 13:04:37 +01:00
Bjørn Erik Pedersen 85e4dd7370 Make js.Build fully support modules
Fixes #7816
Fixes #7777
Fixes #7916
2020-11-03 13:04:37 +01:00
Andreas Richter 3089fc0ba1 js.Build: Generate tsconfig files
Updates #7777

Added support to allow SourceMap files to be external to the build.
In addition added more information when the js compilation has an error.
Correctly append sourceMappingURL to output file.
Fix merge conflict.
2020-11-03 13:04:37 +01:00
hugoreleaser e10e36cf70 releaser: Prepare repository for 0.78.0-DEV
[ci skip]
2020-10-30 10:24:27 +00:00
hugoreleaser ef290125c9 releaser: Add release notes to /docs for release of 0.77.0
[ci skip]
2020-10-30 10:12:16 +00:00
hugoreleaser 5d2fceecaf releaser: Bump versions for release of 0.77.0
[ci skip]
2020-10-30 10:12:16 +00:00
Bjørn Erik Pedersen 0696df6686 Release 0.77.0 2020-10-30 11:05:21 +01:00
Bjørn Erik Pedersen 5ba49c8778 Update 0.77.0-relnotes.md
[ci skip]
2020-10-30 10:39:04 +01:00
hugoreleaser c3ccda8fab releaser: Add release notes for 0.77.0
Rename to *-ready.md to continue.
[ci skip]
2020-10-30 09:22:42 +00:00
Bjørn Erik Pedersen beabc8d998 modules: Allow absolute paths for project imports
Fixes #7910
2020-10-30 10:14:08 +01:00
Bjørn Erik Pedersen 332b65e4cc docs: Regen docs helper 2020-10-30 09:52:32 +01:00
Bjørn Erik Pedersen 3553fc533a Merge commit '9cabb46f68bae01aeb1859727dcb21e8a10f5ec7' 2020-10-30 09:50:15 +01:00
Bjørn Erik Pedersen 9cabb46f68 Squashed 'docs/' changes from 9abd3043a..d1157b687
d1157b687 Fix typo -- missing word in title
34c9a9ff3 Remove Hartwell Insurance subpage broken link
d42f6d8eb Fix strings.Repeat documentation
09b49debb Release 0.76.5
149877735 Merge branch 'tempv0.76.5'
72ffeb026 releaser: Add release notes to /docs for release of 0.76.5
4150d8ae8 Fixed typo: update PrevPage to Prev
c3e630db1 Update index.md
deb7520a8 Release 0.76.4
f58bd7134 Merge branch 'tempv0.76.4'
2581fe4bc releaser: Add release notes to /docs for release of 0.76.4
26d8417fc Release 0.76.3
34c49e06a Merge branch 'tempv0.76.3'
0de2af2ef releaser: Add release notes to /docs for release of 0.76.3
cce12c0f7 Add missing closing quotes and fix code-block lang (#1250)
8c1c80d9f Update AMP link (#1251)
7b1211ffa Fix typos in multilingual.md
29e9d70fd Update index.md
172a5480b Release 0.76.2
93ff424d3 Merge branch 'temp762'
3cad3c23a releaser: Add release notes to /docs for release of 0.76.2
610221964 Update index.md
8a9d31709 Release 0.76.1
64b245aa4 Merge branch 'temp761'
f19469ff8 releaser: Add release notes to /docs for release of 0.76.1
97f0ed030 Update front-matter.md
cca71f263 Update index.md
23c64f6a3 Fix typo in 0.76.0 release note
5f79e034d Update index.md
b66567de2 netlify: Bump to Hugo 0.76.0
a3e30300d Release 0.76.0
3b057e8fe releaser: Add release notes to /docs for release of 0.76.0
7fa1cd912 docs: Regen docshelper
769712aec Merge commit 'e5568488051a571df48401e03f1304b95dbc9028'
70ce6ae33 pagemeta: Make BuildConfig.Render an enum
a78d3849f Allow cascade to be a slice with a _target discriminator
705fea656 Add force flag to server redirects config
04e4e1cc1 tpl: Add Do Not Track (dnt) option to Vimeo shortcode
025c19fe1 Fix CLI example for PostCSS 8
0c70c47b2 markup/asciidocext: Add preserveTOC option

git-subtree-dir: docs
git-subtree-split: d1157b687e
2020-10-30 09:49:15 +01:00
Bjørn Erik Pedersen 173187e263 Add module.replacements
Fixes #7904
Fixes #7908
2020-10-30 09:41:05 +01:00
Bjørn Erik Pedersen 8a1c637c44 Fix setting HUGO_MODULE_PROXY etc. via env vars
Fixes #7903
2020-10-30 09:41:04 +01:00
Cameron Moore 6d95dc9d74 tpl: Fix reflection bug in merge
Value.Type().Key() must only be called on map values.

Fixes #7899
2020-10-29 19:19:41 +01:00
José Moreira 56a343507c deploy: Do not call CDN service invalidation when executing a dry run deployment
Currently, if cache invalidation is enabled when running `hugo deploy --dryRun` with , the deployer does not take the dry run flag into consideration and triggers CloudFront/GoogleCloudCDN cache invalidation if any of those services are configured.

This change will instead print a feedback message if a dry run is in effect and quiet mode is not enabled.

Fixes #7884
2020-10-28 11:19:40 +01:00
Bhavin Gandhi d48a98c477 create: Pass editor arguments from newContentEditor correctly
If newContentEditor has editor name with arguments like `emacsclient
-n`, it fails with `executable file not found in $PATH`. This change
parses the value correctly and passes it to the given editor.

Signed-off-by: Bhavin Gandhi <bhavin7392@gmail.com>
2020-10-24 20:34:03 +02:00
Anthony Fok 3261678f63 deps: Bump github.com/spf13/cobra from 0.0.7 to 1.1.1
Cobra 1.1.1 fixes internal formatting for go-md2man v2 (which caused
man page generation e.g. "hugo gen man" to be broken since Cobra 0.0.6).
See spf13/cobra#1049 for context.
2020-10-24 03:39:53 -06:00
Eric Hagman f465c5c307 build: Allow optional "nodeploy" tag to exclude deploy command from bin
Fixes #7826
2020-10-23 09:03:41 +02:00
Gareth Watts 3400aff258 Allow cascade _target to work with non toml fm
The TOML lib unmarshals slices of string maps to []map[string]interface{}
whereas YAML and JSON decode to []interface{}

The existing tests only check for TOML working correctly, and _target
with cascade did not work at all for frontmatter defined in other formats.

Add a function to normalize those slices

Fixes #7874
2020-10-22 23:00:19 +02:00
Bjørn Erik Pedersen fdfa4a5fe6 Allow getJSON errors to be ignored
This change is mostly motivated to get a more stable CI build (we're building the Hugo site there, with Instagram and Twitter shortcodes sometimes failing).

Fixes #7866
2020-10-22 09:09:29 +02:00
dependabot[bot] 8cbe2bbfad build(deps): bump github.com/evanw/esbuild from 0.7.15 to 0.7.18
Bumps [github.com/evanw/esbuild](https://github.com/evanw/esbuild) from 0.7.15 to 0.7.18.
- [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.7.15...v0.7.18)

Signed-off-by: dependabot[bot] <support@github.com>
2020-10-21 10:19:40 +02:00
Cameron Moore 807db97af8 tpl: Refactor time.AsTime location implementation 2020-10-21 09:49:25 +02:00
Mark Johnson 26eeb29147 tpl: Update Hugo time to support optional [LOCATION] parameter 2020-10-21 09:49:25 +02:00
Bjørn Erik Pedersen b886fa46bb Revert "Add benchmark for building docs site"
We already have a lot of site building benchmarks. The main problem with adding the "Hugo site docs" to the list is that it cannot easiliy  be compared to any previous release, because its content/template/whatever has changed.

This reverts commit 837e084bbe.
2020-10-17 00:37:42 +02:00
Cameron Moore 14bce18a6c highlight: Avoid making unnecessary allocation
Avoid creating a local copy of the highlight configuration when no
options are passed.

Benchmarks of building the docs site:

name        old time/op    new time/op    delta
DocsSite-2     1.94s ± 4%     1.93s ± 4%    ~     (p=0.841 n=5+5)

name        old alloc/op   new alloc/op   delta
DocsSite-2     666MB ± 1%     656MB ± 0%  -1.48%  (p=0.008 n=5+5)

name        old allocs/op  new allocs/op  delta
DocsSite-2     8.85M ± 0%     8.76M ± 0%  -1.04%  (p=0.029 n=4+4)
2020-10-16 21:14:02 +02:00
Cameron Moore 837e084bbe Add benchmark for building docs site 2020-10-16 21:13:39 +02:00
Cameron Moore 08e4f9ff9c embedded: Always show page number when 5 pages or less
Fixes #7523
2020-10-16 16:16:49 +02:00
Cameron Moore acfa153863 output: Improve layout path construction 2020-10-15 20:54:47 +02:00
dependabot[bot] f033d9f01d build(deps): bump github.com/frankban/quicktest from 1.11.0 to 1.11.1
Bumps [github.com/frankban/quicktest](https://github.com/frankban/quicktest) from 1.11.0 to 1.11.1.
- [Release notes](https://github.com/frankban/quicktest/releases)
- [Commits](https://github.com/frankban/quicktest/compare/v1.11.0...v1.11.1)

Signed-off-by: dependabot[bot] <support@github.com>
2020-10-15 00:01:45 +02:00
dependabot[bot] 59fe279424 build(deps): bump github.com/evanw/esbuild from 0.7.14 to 0.7.15
Bumps [github.com/evanw/esbuild](https://github.com/evanw/esbuild) from 0.7.14 to 0.7.15.
- [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.7.14...v0.7.15)

Signed-off-by: dependabot[bot] <support@github.com>
2020-10-14 21:59:26 +02:00
Bjørn Erik Pedersen 62119022d1 Merge branch 'release-0.76.5' 2020-10-14 17:44:47 +02:00
hugoreleaser 2f3f41f736 releaser: Prepare repository for 0.77.0-DEV
[ci skip]
2020-10-14 15:28:16 +00:00
hugoreleaser 60f0725b3e releaser: Add release notes to /docs for release of 0.76.5
[ci skip]
2020-10-14 15:15:22 +00:00
hugoreleaser dcf70ea5a5 releaser: Bump versions for release of 0.76.5
[ci skip]
2020-10-14 15:15:22 +00:00
hugoreleaser 7487c0abf2 releaser: Add release notes for 0.76.5
[ci skip]
2020-10-14 15:15:22 +00:00
Bjørn Erik Pedersen 79a022a15c Render aliases even if render=link
Fixes #7832
2020-10-14 17:06:34 +02:00
Bjørn Erik Pedersen ead5799f7e Render aliases even if render=link
Fixes #7832
2020-10-14 16:59:37 +02:00
dependabot[bot] d57be11324 build(deps): bump github.com/spf13/afero from 1.4.0 to 1.4.1
Bumps [github.com/spf13/afero](https://github.com/spf13/afero) from 1.4.0 to 1.4.1.
- [Release notes](https://github.com/spf13/afero/releases)
- [Commits](https://github.com/spf13/afero/compare/v1.4.0...v1.4.1)

Signed-off-by: dependabot[bot] <support@github.com>
2020-10-12 22:54:09 +02:00
dependabot[bot] d070596694 build(deps): bump github.com/evanw/esbuild from 0.7.9 to 0.7.14
Bumps [github.com/evanw/esbuild](https://github.com/evanw/esbuild) from 0.7.9 to 0.7.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.7.9...v0.7.14)

Signed-off-by: dependabot[bot] <support@github.com>
2020-10-12 22:51:34 +02:00
Daniel Sutton f5ea359dd3 docker: Update to Go 1.15 and Alpine 3.12 2020-10-12 22:51:08 +02:00
Cameron Moore 78b26d538c output: Test all lookup permutations in TestLayout 2020-10-12 22:24:47 +02:00
Cameron Moore 28179bd556 output: Reformat TestLayout table 2020-10-12 22:24:47 +02:00
hugoreleaser fef057b489 releaser: Prepare repository for 0.77.0-DEV
[ci skip]
2020-10-12 08:45:25 +00:00
hugoreleaser 50dfe40b91 releaser: Add release notes to /docs for release of 0.76.4
[ci skip]
2020-10-12 08:32:44 +00:00
hugoreleaser 1ef4211fea releaser: Bump versions for release of 0.76.4
[ci skip]
2020-10-12 08:32:44 +00:00
hugoreleaser b148063ec0 releaser: Add release notes for 0.76.4
[ci skip]
2020-10-12 08:32:44 +00:00
Anthony Fok e9a7ebaf67 snap: Install postcss v8 explicitly as it is now a peer dependency
Fix Snap build failures since 2020-09-21
2020-10-09 12:23:38 -06:00
Bjørn Erik Pedersen 506820435c lang/i18n: Fix for language code case issue with pt-br etc.
Fixes #7804
2020-10-09 18:02:43 +02:00
Bjørn Erik Pedersen 49972d0792 Merge branch 'release-0.76.3' 2020-10-08 19:33:23 +02:00
Bjørn Erik Pedersen c98132e30e Add merge helper 2020-10-08 19:32:53 +02:00
hugoreleaser af19253f43 releaser: Prepare repository for 0.77.0-DEV
[ci skip]
2020-10-08 17:20:03 +00:00
hugoreleaser e96234590d releaser: Add release notes to /docs for release of 0.76.3
[ci skip]
2020-10-08 17:07:29 +00:00
hugoreleaser d62bc74770 releaser: Bump versions for release of 0.76.3
[ci skip]
2020-10-08 17:07:29 +00:00
hugoreleaser 1b1d62fdc9 releaser: Add release notes for 0.76.3
[ci skip]
2020-10-08 17:07:29 +00:00
Bjørn Erik Pedersen 33e9d79b78 langs/i18n: Add workaround for known language, but missing plural rule error
Closes #7798
2020-10-08 14:20:18 +02:00
Bjørn Erik Pedersen fc6abc39c7 langs/i18n: Fix for bare TOML keys
Hugo 0.76.0 updated go-i18n from v1 to v2. This allowed us to set the TOML unmarshaler to use, so we set the one we use in other places in Hugo.

But that does not support dotted bare keys, which caused some breakage in the wild.

This commit fixes that by:

* Using go-toml for language files
* Updating go-toml to the latest version
2020-10-08 14:20:18 +02:00
hugoreleaser 18ed22be5c releaser: Prepare repository for 0.77.0-DEV
[ci skip]
2020-10-07 09:11:54 +00:00
803 changed files with 29622 additions and 8926 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
defaults: &defaults
docker:
- image: bepsays/ci-goreleaser:1.15.1
- image: bepsays/ci-goreleaser:1.16.5
environment:
CGO_ENABLED: "0"
+5
View File
@@ -0,0 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: SUPPORT, ISSUES and TROUBLESHOOTING
url: https://discourse.gohugo.io/
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.
-10
View File
@@ -1,10 +0,0 @@
---
name: Support (Do not use)
about: Please do not use Github for support requests. Visit https://discourse.gohugo.io for support
title: ''
labels: support
assignees: ''
---
Issues created with this template will be automatically closed. Please visit https://discourse.gohugo.io for the support you really, really, want!
+1 -1
View File
@@ -1,7 +1,7 @@
# See https://docs.github.com/en/github/administering-a-repository/configuration-options-for-dependency-updates#package-ecosystem
version: 2
updates:
- package-ecosystem: "gomod"
- package-ecosystem: "gomod"
directory: "/"
schedule:
interval: "daily"
-14
View File
@@ -1,14 +0,0 @@
on:
schedule:
- cron: 0 5 * * 3
name: Weekly Issue Closure
jobs:
cycle-weekly-close:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- name: weekly-issue-closure
uses: bdougie/close-issues-based-on-label@master
env:
LABEL: support
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+82
View File
@@ -0,0 +1,82 @@
on: [push, pull_request]
name: Test
jobs:
test:
env:
GOPROXY: https://proxy.golang.org
GO111MODULE: on
strategy:
matrix:
go-version: [1.16.x]
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- name: Install Go
uses: actions/setup-go@37335c7bb261b353407cff977110895fa0b4f7d8
with:
go-version: ${{ matrix.go-version }}
- name: Install Ruby
uses: actions/setup-ruby@5f29a1cd8dfebf420691c4c9a0e832e2fae5a526
with:
ruby-version: '2.7'
- name: Install Python
uses: actions/setup-python@3105fb18c05ddd93efea5f9e0bef7a03a6e9e7df
with:
python-version: '3.x'
- name: Install Mage
run: go get github.com/magefile/mage@07afc7d24f4d6d6442305d49552f04fbda5ccb3e
- name: Install asciidoctor
uses: reitzig/actions-asciidoctor@7570212ae20b63653481675fb1ff62d1073632b0
- name: Checkout code
uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f
- name: Install docutils
run: |
pip install docutils
rst2html.py --version
- if: matrix.os == 'ubuntu-latest'
name: Install pandoc on Linux
run: |
sudo apt-get update -y
sudo apt-get install -y pandoc
- if: matrix.os == 'macos-latest'
run: |
brew install pandoc
- if: matrix.os == 'windows-latest'
run: |
choco install pandoc
- run: pandoc -v
- 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.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.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.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: |
mage -v test
mage -v check;
- name: Build Docs
env:
HUGO_BUILD_TAGS: extended
HUGO_TIMEOUT: 31000
HUGO_IGNOREERRORS: error-remote-getjson
HUGO_SERVICES_INSTAGRAM_ACCESSTOKEN: dummytoken
run: |
mage -v hugo
./hugo -s docs/
./hugo --renderToMemory -s docs/
-77
View File
@@ -1,77 +0,0 @@
language: go
dist: bionic
env:
global:
- CACHE_NAME=${TRAVIS_ARCH}
- GO111MODULE=on
- GOPROXY=https://proxy.golang.org
- HUGO_BUILD_TAGS=extended
git:
depth: false
go:
- "1.14.8"
- "1.15.1"
- master
arch:
- amd64
- arm64
os:
- linux
- osx
- windows
jobs:
allow_failures:
- go: master
- arch: arm64
fast_finish: true
exclude:
- os: windows
go: master
- arch: arm64
os: osx
- arch: arm64
os: windows
cache:
directories:
- $HOME/gopath/pkg/mod
- $HOME/.cache/go-build
- $HOME/Library/Caches/go-build
- $HOME/AppData/Local/go-build
before_install:
- df -h
# https://travis-ci.community/t/go-cant-find-gcc-with-go1-11-1-on-windows/293/5
- if [ "$TRAVIS_OS_NAME" = "windows" ]; then
choco install mingw -y;
export PATH=/c/tools/mingw64/bin:"$PATH";
fi
- gem install asciidoctor
- type asciidoctor
install:
- mkdir -p $HOME/src
- mv $TRAVIS_BUILD_DIR $HOME/src
- export TRAVIS_BUILD_DIR=$HOME/src/hugo
- cd $HOME/src/hugo
- go get github.com/magefile/mage
script:
- go mod download
- go mod verify
- mage -v test
- if [ "$TRAVIS_ARCH" = "amd64" ]; then
mage -v check;
else
HUGO_TIMEOUT=30000 mage -v check;
fi
- mage -v hugo
- ./hugo -s docs/
- ./hugo --renderToMemory -s docs/
- df -h
+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.
+3 -3
View File
@@ -2,9 +2,9 @@
# Twitter: https://twitter.com/gohugoio
# Website: https://gohugo.io/
FROM golang:1.13-alpine AS build
FROM golang:1.16-alpine AS build
# Optionally set HUGO_BUILD_TAGS to "extended" when building like so:
# Optionally set HUGO_BUILD_TAGS to "extended" or "nodeploy" when building like so:
# docker build --build-arg HUGO_BUILD_TAGS=extended .
ARG HUGO_BUILD_TAGS
@@ -26,7 +26,7 @@ RUN mage hugo && mage install
# ---
FROM alpine:3.11
FROM alpine:3.12
COPY --from=build /go/bin/hugo /usr/bin/hugo
+99 -69
View File
@@ -10,7 +10,7 @@ A Fast and Flexible Static Site Generator built with love by [bep](https://githu
[Twitter](https://twitter.com/gohugoio)
[![GoDoc](https://godoc.org/github.com/gohugoio/hugo?status.svg)](https://godoc.org/github.com/gohugoio/hugo)
[![Linux and macOS Build Status](https://api.travis-ci.org/gohugoio/hugo.svg?branch=master&label=Windows+and+Linux+and+macOS+build "Windows, Linux and macOS Build Status")](https://travis-ci.org/gohugoio/hugo)
[![Tests on Linux, MacOS and Windows](https://github.com/gohugoio/hugo/workflows/Test/badge.svg)](https://github.com/gohugoio/hugo/actions?query=workflow%3ATest)
[![Go Report Card](https://goreportcard.com/badge/github.com/gohugoio/hugo)](https://goreportcard.com/report/github.com/gohugoio/hugo)
## Overview
@@ -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
@@ -126,71 +126,101 @@ For a complete guide to contributing code to Hugo, see the [Contribution Guide](
## 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.83.0 that list is, in lexical order:
```json
cloud.google.com/go/storage="v1.10.0"
cloud.google.com/go="v0.81.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.1"
github.com/armon/go-radix="v1.0.0"
github.com/aws/aws-sdk-go="v1.38.23"
github.com/bep/debounce="v1.2.0"
github.com/bep/gitmap="v1.1.2"
github.com/bep/godartsass="v0.12.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/danwakefield/fnmatch="v0.0.0-20160403171240-cbb64ac3d964"
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.11.16"
github.com/fsnotify/fsnotify="v1.4.9"
github.com/getkin/kin-openapi="v0.61.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.2"
github.com/gobwas/glob="v0.2.3"
github.com/gohugoio/go-i18n/v2="v2.1.3-0.20210430103248-4c28c89f8013"
github.com/golang/groupcache="v0.0.0-20200121045136-8c9f03a8e57e"
github.com/golang/protobuf="v1.5.2"
github.com/google/go-cmp="v0.5.5"
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/hashicorp/hcl="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/magiconair/properties="v1.8.1"
github.com/mailru/easyjson="v0.0.0-20190626092158-b2ccc519800e"
github.com/mattn/go-ieproxy="v0.0.1"
github.com/mattn/go-isatty="v0.0.12"
github.com/mattn/go-runewidth="v0.0.9"
github.com/miekg/mmark="v1.3.6"
github.com/mitchellh/hashstructure="v1.0.0"
github.com/mitchellh/mapstructure="v1.3.3"
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="v1.9.0"
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.0"
github.com/shurcooL/sanitized_anchor_name="v1.0.0"
github.com/spf13/afero="v1.6.0"
github.com/spf13/cast="v1.3.1"
github.com/spf13/cobra="v1.1.3"
github.com/spf13/fsync="v0.9.0"
github.com/spf13/jwalterweatherman="v1.1.0"
github.com/spf13/pflag="v1.0.5"
github.com/spf13/viper="v1.7.1"
github.com/subosito/gotenv="v1.2.0"
github.com/tdewolff/minify/v2="v2.9.16"
github.com/tdewolff/parse/v2="v2.5.14"
github.com/yuin/goldmark-highlighting="v0.0.0-20200307114337-60d527fdb691"
github.com/yuin/goldmark="v1.3.5"
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-20210316092652-d523dce5a7f4"
golang.org/x/oauth2="v0.0.0-20210413134643-5e61552d6c78"
golang.org/x/sync="v0.0.0-20210220032951-036812b2e83c"
golang.org/x/sys="v0.0.0-20210412220455-f1c623a9e750"
golang.org/x/text="v0.3.6"
golang.org/x/xerrors="v0.0.0-20200804184101-5ec99f83aff1"
google.golang.org/api="v0.45.0"
google.golang.org/genproto="v0.0.0-20210413151531-c14fb6ef47c3"
google.golang.org/grpc="v1.37.0"
google.golang.org/protobuf="v1.26.0"
gopkg.in/ini.v1="v1.51.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 |
+7
View File
@@ -0,0 +1,7 @@
## Security Policy
### Reporting a Vulnerability
Please report (suspected) security vulnerabilities to **[bjorn.erik.pedersen@gmail.com](mailto:bjorn.erik.pedersen@gmail.com)**. You will receive a response from us within 48 hours. If we can confirm the issue, we will release a patch as soon as possible depending on the complexity of the issue but historically within days.
Also see [Hugo's Security Model](https://gohugo.io/about/security-model/).
+1 -1
View File
@@ -3,7 +3,7 @@
# allow user to override go executable by running as GOEXE=xxx make ...
GOEXE="${GOEXE-go}"
# Send in a regexp mathing the benchmarks you want to run, i.e. './benchSite.sh "YAML"'.
# Send in a regexp matching the benchmarks you want to run, i.e. './benchSite.sh "YAML"'.
# Note the quotes, which will be needed for more complex expressions.
# The above will run all variations, but only for front matter YAML.
+1 -6
View File
@@ -158,7 +158,6 @@ func (c *Cache) ReadOrCreate(id string,
err = create(info, f)
return
}
// GetOrCreate tries to get the file with the given id from cache. If not found or expired, create will
@@ -220,10 +219,9 @@ func (c *Cache) GetOrCreateBytes(id string, create func() ([]byte, error)) (Item
return info, nil, err
}
return info, b, nil
}
// GetBytes gets the file content with the given id from the cahce, nil if none found.
// GetBytes gets the file content with the given id from the cache, nil if none found.
func (c *Cache) GetBytes(id string) (ItemInfo, []byte, error) {
id = cleanID(id)
@@ -276,7 +274,6 @@ func (c *Cache) getOrRemove(id string) hugio.ReadSeekCloser {
}
f, err := c.Fs.Open(id)
if err != nil {
return nil
}
@@ -299,7 +296,6 @@ func (c *Cache) getString(id string) string {
defer c.nlocker.Unlock(id)
f, err := c.Fs.Open(id)
if err != nil {
return ""
}
@@ -307,7 +303,6 @@ func (c *Cache) getString(id string) string {
b, _ := ioutil.ReadAll(f)
return string(b)
}
// Caches is a named set of caches.
+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 -6
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) {
@@ -69,7 +68,6 @@ dir = "/path/to/c3"
c3 := decoded["images"]
c.Assert(c3.MaxAge, qt.Equals, time.Duration(-1))
c.Assert(c3.Dir, qt.Equals, filepath.FromSlash("/path/to/c3/filecache/images"))
}
func TestDecodeConfigIgnoreCache(t *testing.T) {
@@ -110,7 +108,6 @@ dir = "/path/to/c3"
for _, v := range decoded {
c.Assert(v.MaxAge, qt.Equals, time.Duration(0))
}
}
func TestDecodeConfigDefault(t *testing.T) {
@@ -178,11 +175,10 @@ dir = "/"
_, err = DecodeConfig(fs, cfg)
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")
-2
View File
@@ -110,7 +110,6 @@ func (c *Cache) Prune(force bool) (int, error) {
}
func (c *Cache) pruneRootDir(force bool) (int, error) {
info, err := c.Fs.Stat(c.pruneAllRootDir)
if err != nil {
if os.IsNotExist(err) {
@@ -124,5 +123,4 @@ func (c *Cache) pruneRootDir(force bool) (int, error) {
}
return hugofs.MakeReadableAndRemoveAllModulePkgDir(c.Fs, c.pruneAllRootDir)
}
-1
View File
@@ -107,5 +107,4 @@ dir = ":resourceDir/_gen"
}
}
}
-3
View File
@@ -183,7 +183,6 @@ dir = ":cacheDir/c"
c.Assert(string(b), qt.Equals, "Hugo is great!")
}
}
func TestFileCacheConcurrent(t *testing.T) {
@@ -253,7 +252,6 @@ func TestFileCacheReadOrCreateErrorInRead(t *testing.T) {
var result string
rf := func(failLevel int) func(info ItemInfo, r io.ReadSeeker) error {
return func(info ItemInfo, r io.ReadSeeker) error {
if failLevel > 0 {
if failLevel > 1 {
@@ -347,5 +345,4 @@ func newPathsSpec(t *testing.T, fs afero.Fs, configStr string) *helpers.PathSpec
p, err := helpers.NewPathSpec(hugofs.NewFrom(fs, cfg), cfg, nil)
c.Assert(err, qt.IsNil)
return p
}
+1 -2
View File
@@ -49,13 +49,12 @@ func (c *Cache) Clear() {
c.cache = make(map[string]cacheEntry)
c.nlocker = locker.NewLocker()
}
// GetOrCreate tries to get the value with the given cache key, if not found
// create will be called and cached.
// This method is thread safe. It also guarantees that the create func for a given
// key is invoced only once for this cache.
// key is invoked only once for this cache.
func (c *Cache) GetOrCreate(key string, create func() (interface{}, error)) (interface{}, error) {
c.mu.RLock()
entry, found := c.cache[key]
+3 -15
View File
@@ -58,7 +58,7 @@ func (c *Inspector) MethodsFromTypes(include []reflect.Type, exclude []reflect.T
var methods Methods
var excludes = make(map[string]bool)
excludes := make(map[string]bool)
if len(exclude) > 0 {
for _, m := range c.MethodsFromTypes(exclude, nil) {
@@ -99,11 +99,9 @@ func (c *Inspector) MethodsFromTypes(include []reflect.Type, exclude []reflect.T
name = pkgPrefix + name
return name, pkg
}
for _, t := range include {
for i := 0; i < t.NumMethod(); i++ {
m := t.Method(i)
@@ -153,7 +151,6 @@ func (c *Inspector) MethodsFromTypes(include []reflect.Type, exclude []reflect.T
methods = append(methods, method)
}
}
sort.SliceStable(methods, func(i, j int) bool {
@@ -167,16 +164,13 @@ func (c *Inspector) MethodsFromTypes(include []reflect.Type, exclude []reflect.T
}
return wi < wj
})
return methods
}
func (c *Inspector) parseSource() {
c.init.Do(func() {
if !strings.Contains(c.ProjectRootDir, "hugo") {
panic("dir must be set to the Hugo root")
}
@@ -200,7 +194,6 @@ func (c *Inspector) parseSource() {
filenames = append(filenames, path)
return nil
})
for _, filename := range filenames {
@@ -230,7 +223,6 @@ func (c *Inspector) parseSource() {
c.methodWeight[iface] = weights
}
}
}
return true
})
@@ -247,7 +239,6 @@ func (c *Inspector) parseSource() {
}
}
}
})
}
@@ -374,7 +365,7 @@ func (m Methods) Imports() []string {
}
// ToMarshalJSON creates a MarshalJSON method for these methods. Any method name
// matchin any of the regexps in excludes will be ignored.
// matching any of the regexps in excludes will be ignored.
func (m Methods) ToMarshalJSON(receiver, pkgPath string, excludes ...string) (string, []string) {
var sb strings.Builder
@@ -385,7 +376,7 @@ func (m Methods) ToMarshalJSON(receiver, pkgPath string, excludes ...string) (st
fmt.Fprintf(&sb, "func Marshal%sToJSON(%s %s) ([]byte, error) {\n", what, r, receiver)
var methods Methods
var excludeRes = make([]*regexp.Regexp, len(excludes))
excludeRes := make([]*regexp.Regexp, len(excludes))
for i, exclude := range excludes {
excludeRes[i] = regexp.MustCompile(exclude)
@@ -450,7 +441,6 @@ func (m Methods) ToMarshalJSON(receiver, pkgPath string, excludes ...string) (st
}
return sb.String(), pkgImports
}
func collectMethodsRecursive(pkg string, f []*ast.Field) []string {
@@ -481,7 +471,6 @@ func collectMethodsRecursive(pkg string, f []*ast.Field) []string {
}
return methodNames
}
func firstToLower(name string) string {
@@ -544,5 +533,4 @@ func varName(name string) string {
}
return name
}
-4
View File
@@ -25,7 +25,6 @@ import (
)
func TestMethods(t *testing.T) {
var (
zeroIE = reflect.TypeOf((*IEmbed)(nil)).Elem()
zeroIEOnly = reflect.TypeOf((*IEOnly)(nil)).Elem()
@@ -58,7 +57,6 @@ func TestMethods(t *testing.T) {
methodsStr := fmt.Sprint(methods)
c.Assert(methodsStr, qt.Contains, "MethodEmbed3(arg0 string) string")
})
t.Run("ToMarshalJSON", func(t *testing.T) {
@@ -76,9 +74,7 @@ func TestMethods(t *testing.T) {
c.Assert(pkg, qt.Contains, "encoding/json")
fmt.Println(pkg)
})
}
type I interface {
+5 -4
View File
@@ -26,9 +26,10 @@ type checkCmd struct {
}
func newCheckCmd() *checkCmd {
return &checkCmd{baseCmd: &baseCmd{cmd: &cobra.Command{
Use: "check",
Short: "Contains some verification checks",
},
return &checkCmd{baseCmd: &baseCmd{
cmd: &cobra.Command{
Use: "check",
Short: "Contains some verification checks",
},
}}
}
+5 -4
View File
@@ -24,10 +24,11 @@ type checkCmd struct {
}
func newCheckCmd() *checkCmd {
cc := &checkCmd{baseCmd: &baseCmd{cmd: &cobra.Command{
Use: "check",
Short: "Contains some verification checks",
},
cc := &checkCmd{baseCmd: &baseCmd{
cmd: &cobra.Command{
Use: "check",
Short: "Contains some verification checks",
},
}}
cc.cmd.AddCommand(newLimitCmd().getCommand())
+10 -19
View File
@@ -16,24 +16,22 @@ package commands
import (
"bytes"
"errors"
"io/ioutil"
"os"
"path/filepath"
"regexp"
"sync"
"time"
hconfig "github.com/gohugoio/hugo/config"
"golang.org/x/sync/semaphore"
"io/ioutil"
"github.com/gohugoio/hugo/common/herrors"
"github.com/gohugoio/hugo/common/hugo"
jww "github.com/spf13/jwalterweatherman"
"os"
"path/filepath"
"regexp"
"time"
"github.com/gohugoio/hugo/common/loggers"
"github.com/gohugoio/hugo/config"
@@ -60,7 +58,7 @@ type commandeerHugoState struct {
type commandeer struct {
*commandeerHugoState
logger *loggers.Logger
logger loggers.Logger
serverConfig *config.Server
// Currently only set when in "fast render mode". But it seems to
@@ -112,7 +110,7 @@ func (c *commandeerHugoState) hugo() *hugolib.HugoSites {
}
func (c *commandeer) errCount() int {
return int(c.logger.ErrorCounter.Count())
return int(c.logger.LogCounters().ErrorCounter.Count())
}
func (c *commandeer) getErrorWithContext() interface{} {
@@ -156,7 +154,6 @@ func (c *commandeer) initFs(fs *hugofs.Fs) error {
}
func newCommandeer(mustHaveConfigFile, running bool, h *hugoBuilderCommon, f flagsToConfigHandler, cfgInit func(c *commandeer) error, subCmdVs ...*cobra.Command) (*commandeer, error) {
var rebuildDebouncer func(f func())
if running {
// The time value used is tested with mass content replacements in a fairly big Hugo site.
@@ -248,7 +245,6 @@ func (f *fileChangeDetector) PrepareNew() {
}
func (c *commandeer) loadConfig(mustHaveConfigFile, running bool) error {
if c.DepsCfg == nil {
c.DepsCfg = &deps.DepsCfg{}
}
@@ -277,7 +273,6 @@ func (c *commandeer) loadConfig(mustHaveConfigFile, running bool) error {
environment := c.h.getEnvironment(running)
doWithConfig := func(cfg config.Provider) error {
if c.ftch != nil {
c.ftch.flagsToConfig(cfg)
}
@@ -308,8 +303,8 @@ func (c *commandeer) loadConfig(mustHaveConfigFile, running bool) error {
WorkingDir: dir,
Filename: c.h.cfgFile,
AbsConfigDir: c.h.getConfigDir(dir),
Environ: os.Environ(),
Environment: environment},
Environment: environment,
},
cfgSetAndInit,
doWithConfig)
@@ -389,7 +384,7 @@ func (c *commandeer) loadConfig(mustHaveConfigFile, running bool) error {
}
// To debug hard-to-find path issues.
//fs.Destination = hugofs.NewStacktracerFs(fs.Destination, `fr/fr`)
// fs.Destination = hugofs.NewStacktracerFs(fs.Destination, `fr/fr`)
err = c.initFs(fs)
if err != nil {
@@ -402,7 +397,6 @@ func (c *commandeer) loadConfig(mustHaveConfigFile, running bool) error {
h, err = hugolib.NewHugoSites(*c.DepsCfg)
c.hugoSites = h
close(c.created)
})
if err != nil {
@@ -415,8 +409,5 @@ func (c *commandeer) loadConfig(mustHaveConfigFile, running bool) error {
}
config.Set("cacheDir", cacheDir)
cfg.Logger.INFO.Println("Using config file:", config.ConfigFileUsed())
return nil
}
+4 -8
View File
@@ -88,6 +88,7 @@ var _ commandsBuilderGetter = (*baseBuilderCmd)(nil)
type commandsBuilderGetter interface {
getCommandsBuilder() *commandsBuilder
}
type baseBuilderCmd struct {
*baseCmd
*commandsBuilder
@@ -138,7 +139,6 @@ func (c *nilCommand) getCommand() *cobra.Command {
}
func (c *nilCommand) flagsToConfig(cfg config.Provider) {
}
func (b *commandsBuilder) newHugoCmd() *hugoCmd {
@@ -322,16 +322,12 @@ func (cc *hugoBuilderCommon) handleFlags(cmd *cobra.Command) {
_ = cmd.Flags().SetAnnotation("theme", cobra.BashCompSubdirsInDir, []string{"themes"})
}
func checkErr(logger *loggers.Logger, err error, s ...string) {
func checkErr(logger loggers.Logger, err error, s ...string) {
if err == nil {
return
}
if len(s) == 0 {
logger.CRITICAL.Println(err)
return
}
for _, message := range s {
logger.ERROR.Println(message)
logger.Errorln(message)
}
logger.ERROR.Println(err)
logger.Errorln(err)
}
+11 -15
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,13 +31,11 @@ import (
"github.com/gohugoio/hugo/common/types"
"github.com/spf13/cobra"
"github.com/spf13/viper"
qt "github.com/frankban/quicktest"
)
func TestExecute(t *testing.T) {
c := qt.New(t)
createSite := func(c *qt.C) (string, func()) {
@@ -90,7 +90,7 @@ func TestExecute(t *testing.T) {
defer clean()
resp := Execute([]string{"deploy", "-s=" + dir, "-e=staging", "--target=mydeployment", "--dryRun"})
c.Assert(resp.Err, qt.Not(qt.IsNil))
c.Assert(resp.Err.Error(), qt.Contains, `no provider registered for "hugocloud"`)
c.Assert(resp.Err.Error(), qt.Contains, `no driver registered for "hugocloud"`)
})
c.Run("list", func(c *qt.C) {
@@ -124,7 +124,6 @@ func TestExecute(t *testing.T) {
c.Assert(config, qt.Contains, "baseURL = \"http://example.org/\"")
checkNewSiteInited(c, siteDir)
})
}
func checkNewSiteInited(c *qt.C, basepath string) {
@@ -168,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)
},
@@ -178,14 +177,15 @@ 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/**")
},
},
{
name: "Persistent flags",
args: []string{"server",
args: []string{
"server",
"--config=myconfig.toml",
"--configDir=myconfigdir",
"--contentDir=mycontent",
@@ -217,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")
@@ -235,12 +235,12 @@ func TestFlags(t *testing.T) {
// The flag is named i18n-warnings
c.Assert(cfg.GetBool("logI18nWarnings"), qt.Equals, true)
}}}
},
},
}
for _, test := range tests {
c.Run(test.name, func(c *qt.C) {
b := newCommandsBuilder()
root := b.addAll().build()
@@ -257,11 +257,9 @@ func TestFlags(t *testing.T) {
test.check(c, b.commands[0].(*serverCmd))
})
}
}
func TestCommandsExecute(t *testing.T) {
c := qt.New(t)
dir, clean, err := createSimpleTestSite(t, testSiteConfig{})
@@ -330,7 +328,6 @@ func TestCommandsExecute(t *testing.T) {
}
}
}
type testSiteConfig struct {
@@ -399,7 +396,6 @@ Environment: {{ hugo.Environment }}
`)
return d, clean, nil
}
func writeFile(t *testing.T, filename, content string) {
+3 -2
View File
@@ -22,13 +22,14 @@ import (
"sort"
"strings"
"github.com/gohugoio/hugo/common/maps"
"github.com/gohugoio/hugo/parser"
"github.com/gohugoio/hugo/parser/metadecoders"
"github.com/gohugoio/hugo/modules"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
var _ cmder = (*configCmd)(nil)
@@ -81,7 +82,7 @@ func (c *configCmd) printConfig(cmd *cobra.Command, args []string) error {
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.
+7 -10
View File
@@ -16,6 +16,7 @@ package commands
import (
"bytes"
"fmt"
"path/filepath"
"strings"
"time"
@@ -34,14 +35,10 @@ import (
"github.com/gohugoio/hugo/hugolib"
"path/filepath"
"github.com/spf13/cobra"
)
var (
_ cmder = (*convertCmd)(nil)
)
var _ cmder = (*convertCmd)(nil)
type convertCmd struct {
outputDir string
@@ -123,7 +120,7 @@ func (cc *convertCmd) convertContents(format metadecoders.Format) error {
site := h.Sites[0]
site.Log.FEEDBACK.Println("processing", len(site.AllPages()), "content files")
site.Log.Println("processing", len(site.AllPages()), "content files")
for _, p := range site.AllPages() {
if err := cc.convertAndSavePage(p, site, format); err != nil {
return err
@@ -147,19 +144,19 @@ func (cc *convertCmd) convertAndSavePage(p page.Page, site *hugolib.Site, target
errMsg := fmt.Errorf("Error processing file %q", p.Path())
site.Log.INFO.Println("Attempting to convert", p.File().Filename())
site.Log.Infoln("Attempting to convert", p.File().Filename())
f := p.File()
file, err := f.FileInfo().Meta().Open()
if err != nil {
site.Log.ERROR.Println(errMsg)
site.Log.Errorln(errMsg)
file.Close()
return nil
}
pf, err := pageparser.ParseFrontMatterAndContent(file)
if err != nil {
site.Log.ERROR.Println(errMsg)
site.Log.Errorln(errMsg)
file.Close()
return err
}
@@ -179,7 +176,7 @@ func (cc *convertCmd) convertAndSavePage(p page.Page, site *hugolib.Site, target
var newContent bytes.Buffer
err = parser.InterfaceToFrontMatter(pf.FrontMatter, targetFormat, &newContent)
if err != nil {
site.Log.ERROR.Println(errMsg)
site.Log.Errorln(errMsg)
return err
}
+2
View File
@@ -11,6 +11,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// +build !nodeploy
package commands
import (
+28 -12
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"
)
@@ -27,18 +29,32 @@ type envCmd struct {
}
func newEnvCmd() *envCmd {
return &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.`,
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())
return &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.
return nil
},
}),
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
},
}),
}
}
+33 -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,44 +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)
}
err := cmd.Root().GenBashCompletionFile(cc.autocompleteTarget)
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")
}
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
}
+1 -3
View File
@@ -22,9 +22,7 @@ import (
"github.com/spf13/cobra"
)
var (
_ cmder = (*genChromaStyles)(nil)
)
var _ cmder = (*genChromaStyles)(nil)
type genChromaStyles struct {
style string
+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.")
+1 -4
View File
@@ -23,9 +23,7 @@ import (
"github.com/spf13/cobra"
)
var (
_ cmder = (*genDocsHelper)(nil)
)
var _ cmder = (*genDocsHelper)(nil)
type genDocsHelper struct {
target string
@@ -70,5 +68,4 @@ func (g *genDocsHelper) generate() error {
fmt.Println("Done!")
return nil
}
+37 -56
View File
@@ -19,10 +19,16 @@ import (
"context"
"fmt"
"io/ioutil"
"os"
"os/signal"
"path/filepath"
"runtime"
"runtime/pprof"
"runtime/trace"
"strings"
"sync/atomic"
"syscall"
"time"
"github.com/gohugoio/hugo/hugofs"
@@ -31,21 +37,14 @@ 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"
"syscall"
"github.com/gohugoio/hugo/hugolib/filesystems"
"golang.org/x/sync/errgroup"
"os"
"path/filepath"
"runtime"
"strings"
"time"
"github.com/gohugoio/hugo/config"
flag "github.com/spf13/pflag"
@@ -82,7 +81,6 @@ func (r Response) IsUserError() bool {
// Execute adds all child commands to the root command HugoCmd and sets flags appropriately.
// The args are usually filled with os.Args[1:].
func Execute(args []string) Response {
hugoCmd := newCommandsBuilder().addAll().build()
cmd := hugoCmd.getCommand()
cmd.SetArgs(args)
@@ -120,17 +118,15 @@ func initializeConfig(mustHaveConfigFile, running bool,
h *hugoBuilderCommon,
f flagsToConfigHandler,
cfgInit func(c *commandeer) error) (*commandeer, error) {
c, err := newCommandeer(mustHaveConfigFile, running, h, f, cfgInit)
if err != nil {
return nil, err
}
return c, nil
}
func (c *commandeer) createLogger(cfg config.Provider, running bool) (*loggers.Logger, error) {
func (c *commandeer) createLogger(cfg config.Provider, running bool) (loggers.Logger, error) {
var (
logHandle = ioutil.Discard
logThreshold = jww.LevelWarn
@@ -246,7 +242,6 @@ func initializeFlags(cmd *cobra.Command, cfg config.Provider) {
setValueFromFlag(cmd.Flags(), "destination", cfg, "publishDir", false)
setValueFromFlag(cmd.Flags(), "i18n-warnings", cfg, "logI18nWarnings", false)
setValueFromFlag(cmd.Flags(), "path-warnings", cfg, "logPathWarnings", false)
}
func setValueFromFlag(flags *flag.FlagSet, key string, cfg config.Provider, targetKey string, force bool) {
@@ -282,7 +277,6 @@ func isTerminal() bool {
}
func (c *commandeer) fullBuild() error {
var (
g errgroup.Group
langCount map[string]uint64
@@ -290,6 +284,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)
@@ -298,7 +293,6 @@ func (c *commandeer) fullBuild() error {
}
copyStaticFunc := func() error {
cnt, err := c.copyStatic()
if err != nil {
return errors.Wrap(err, "Error copying static files")
@@ -346,7 +340,6 @@ func (c *commandeer) fullBuild() error {
}
return nil
}
func (c *commandeer) initCPUProfile() (func(), error) {
@@ -374,12 +367,12 @@ func (c *commandeer) initMemProfile() {
f, err := os.Create(c.h.memprofile)
if err != nil {
c.logger.ERROR.Println("could not create memory profile: ", err)
c.logger.Errorf("could not create memory profile: ", err)
}
defer f.Close()
runtime.GC() // get up-to-date statistics
if err := pprof.WriteHeapProfile(f); err != nil {
c.logger.ERROR.Println("could not write memory profile: ", err)
c.logger.Errorf("could not write memory profile: ", err)
}
}
@@ -419,7 +412,6 @@ func (c *commandeer) initMutexProfile() (func(), error) {
pprof.Lookup("mutex").WriteTo(f, 0)
f.Close()
}, nil
}
func (c *commandeer) initMemTicker() func() {
@@ -429,7 +421,6 @@ func (c *commandeer) initMemTicker() func() {
var m runtime.MemStats
runtime.ReadMemStats(&m)
fmt.Printf("\n\nAlloc = %v\nTotalAlloc = %v\nSys = %v\nNumGC = %v\n\n", formatByteCount(m.Alloc), formatByteCount(m.TotalAlloc), formatByteCount(m.Sys), m.NumGC)
}
go func() {
@@ -442,7 +433,6 @@ func (c *commandeer) initMemTicker() func() {
printMem()
return
}
}
}()
@@ -452,7 +442,6 @@ func (c *commandeer) initMemTicker() func() {
}
func (c *commandeer) initProfiling() (func(), error) {
stopCPUProf, err := c.initCPUProfile()
if err != nil {
return nil, err
@@ -518,7 +507,7 @@ func (c *commandeer) build() error {
if createCounter, ok := c.destinationFs.(hugofs.DuplicatesReporter); ok {
dupes := createCounter.ReportDuplicates()
if dupes != "" {
c.logger.WARN.Println("Duplicate target paths:", dupes)
c.logger.Warnln("Duplicate target paths:", dupes)
}
}
}
@@ -532,13 +521,13 @@ func (c *commandeer) build() error {
baseWatchDir := c.Cfg.GetString("workingDir")
rootWatchDirs := getRootWatchDirsStr(baseWatchDir, watchDirs)
c.logger.FEEDBACK.Printf("Watching for changes in %s%s{%s}\n", baseWatchDir, helpers.FilePathSeparator, rootWatchDirs)
c.logger.FEEDBACK.Println("Press Ctrl+C to stop")
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...)
checkErr(c.Logger, err)
defer watcher.Close()
var sigs = make(chan os.Signal, 1)
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
<-sigs
@@ -584,13 +573,12 @@ func (c *commandeer) copyStatic() (map[string]uint64, error) {
}
func (c *commandeer) doWithPublishDirs(f func(sourceFs *filesystems.SourceFilesystem) (uint64, error)) (map[string]uint64, error) {
langCount := make(map[string]uint64)
staticFilesystems := c.hugo().BaseFs.SourceFilesystems.Static
if len(staticFilesystems) == 0 {
c.logger.INFO.Println("No static directories found to sync")
c.logger.Infoln("No static directories found to sync")
return langCount, nil
}
@@ -662,13 +650,13 @@ func (c *commandeer) copyStaticTo(sourceFs *filesystems.SourceFilesystem) (uint6
syncer.Delete = c.Cfg.GetBool("cleanDestinationDir")
if syncer.Delete {
c.logger.INFO.Println("removing all files from destination that don't exist in static dirs")
c.logger.Infoln("removing all files from destination that don't exist in static dirs")
syncer.DeleteFilter = func(f os.FileInfo) bool {
return f.IsDir() && strings.HasPrefix(f.Name(), ".")
}
}
c.logger.INFO.Println("syncing static files to", publishDir)
c.logger.Infoln("syncing static files to", publishDir)
// because we are using a baseFs (to get the union right).
// set sync src to root
@@ -689,7 +677,7 @@ func (c *commandeer) firstPathSpec() *helpers.PathSpec {
func (c *commandeer) timeTrack(start time.Time, name string) {
elapsed := time.Since(start)
c.logger.FEEDBACK.Printf("%s in %v ms", name, int(1000*elapsed.Seconds()))
c.logger.Printf("%s in %v ms", name, int(1000*elapsed.Seconds()))
}
// getDirList provides NewWatcher() with a list of directories to watch for changes.
@@ -698,7 +686,7 @@ func (c *commandeer) getDirList() ([]string, error) {
walkFn := func(path string, fi hugofs.FileMetaInfo, err error) error {
if err != nil {
c.logger.ERROR.Println("walker: ", err)
c.logger.Errorln("walker: ", err)
return nil
}
@@ -712,7 +700,6 @@ func (c *commandeer) getDirList() ([]string, error) {
}
return nil
}
watchFiles := c.hugo().PathSpec.BaseFs.WatchDirs()
@@ -724,7 +711,7 @@ func (c *commandeer) getDirList() ([]string, error) {
w := hugofs.NewWalkway(hugofs.WalkwayConfig{Logger: c.logger, Info: fi, WalkFn: walkFn})
if err := w.Walk(); err != nil {
c.logger.ERROR.Println("walker: ", err)
c.logger.Errorln("walker: ", err)
}
}
@@ -740,8 +727,8 @@ func (c *commandeer) buildSites() (err error) {
func (c *commandeer) handleBuildErr(err error, msg string) {
c.buildErr = err
c.logger.ERROR.Print(msg + ":\n\n")
c.logger.ERROR.Println(helpers.FirstUpper(err.Error()))
c.logger.Errorln(msg + ":\n")
c.logger.Errorln(helpers.FirstUpper(err.Error()))
if !c.h.quiet && c.h.verbose {
herrors.PrintStackTraceFromErr(err)
}
@@ -753,7 +740,6 @@ func (c *commandeer) rebuildSites(events []fsnotify.Event) error {
c.buildErr = nil
visited := c.visitedURLs.PeekAllSet()
if c.fastRenderMode {
// Make sure we always render the home pages
for _, l := range c.languages {
langPath := c.hugo().PathSpec.GetLangSubDir(l.Lang)
@@ -763,7 +749,6 @@ func (c *commandeer) rebuildSites(events []fsnotify.Event) error {
home := c.hugo().PathSpec.PrependBasePath("/"+langPath, false)
visited[home] = true
}
}
return c.hugo().Build(hugolib.BuildCfg{RecentlyVisited: visited, ErrRecovery: c.wasError}, events...)
}
@@ -793,13 +778,11 @@ func (c *commandeer) fullRebuild(changeType string) {
c.fullRebuildSem.Acquire(context.Background(), 1)
go func() {
defer c.fullRebuildSem.Release(1)
c.printChangeDetected(changeType)
defer func() {
// Allow any file system events to arrive back.
// This will block any rebuild on config changes for the
// duration of the sleep.
@@ -822,13 +805,13 @@ func (c *commandeer) fullRebuild(changeType string) {
if !c.paused {
_, err := c.copyStatic()
if err != nil {
c.logger.ERROR.Println(err)
c.logger.Errorln(err)
return
}
err = c.buildSites()
if err != nil {
c.logger.ERROR.Println(err)
c.logger.Errorln(err)
} else if !c.h.buildWatch && !c.Cfg.GetBool("disableLiveReload") {
livereload.ForceRefresh()
}
@@ -848,7 +831,6 @@ func (c *commandeer) newWatcher(dirList ...string) (*watcher.Batcher, error) {
}
watcher, err := watcher.New(1 * time.Second)
if err != nil {
return nil, err
}
@@ -862,7 +844,7 @@ func (c *commandeer) newWatcher(dirList ...string) (*watcher.Batcher, error) {
// Identifies changes to config (config.toml) files.
configSet := make(map[string]bool)
c.logger.FEEDBACK.Println("Watching for config changes in", strings.Join(c.configFiles, ", "))
c.logger.Println("Watching for config changes in", strings.Join(c.configFiles, ", "))
for _, configFile := range c.configFiles {
watcher.Add(configFile)
configSet[configFile] = true
@@ -879,7 +861,7 @@ func (c *commandeer) newWatcher(dirList ...string) (*watcher.Batcher, error) {
}
case err := <-watcher.Errors:
if err != nil {
c.logger.ERROR.Println("Error while watching:", err)
c.logger.Errorln("Error while watching:", err)
}
}
}
@@ -895,9 +877,9 @@ func (c *commandeer) printChangeDetected(typ string) {
}
msg += " detected, rebuilding site."
c.logger.FEEDBACK.Println(msg)
c.logger.Println(msg)
const layout = "2006-01-02 15:04:05.000 -0700"
c.logger.FEEDBACK.Println(time.Now().Format(layout))
c.logger.Println(time.Now().Format(layout))
}
const (
@@ -909,7 +891,6 @@ func (c *commandeer) handleEvents(watcher *watcher.Batcher,
staticSyncer *staticSyncer,
evs []fsnotify.Event,
configSet map[string]bool) {
defer func() {
c.wasError = false
}()
@@ -950,7 +931,6 @@ func (c *commandeer) handleEvents(watcher *watcher.Batcher,
time.Sleep(100 * time.Millisecond)
}
}
}
// Config file(s) changed. Need full rebuild.
@@ -979,14 +959,16 @@ func (c *commandeer) handleEvents(watcher *watcher.Batcher,
return
}
c.logger.INFO.Println("Received System Events:", evs)
c.logger.Infoln("Received System Events:", evs)
staticEvents := []fsnotify.Event{}
dynamicEvents := []fsnotify.Event{}
// Special handling for symbolic links inside /content.
filtered := []fsnotify.Event{}
for _, ev := range evs {
if c.hugo().ShouldSkipFileChangeEvent(ev) {
continue
}
// Check the most specific first, i.e. files.
contentMapped := c.hugo().ContentChanges.GetSymbolicLinkMappings(ev.Name)
if len(contentMapped) > 0 {
@@ -1059,7 +1041,7 @@ func (c *commandeer) handleEvents(watcher *watcher.Batcher,
walkAdder := func(path string, f hugofs.FileMetaInfo, err error) error {
if f.IsDir() {
c.logger.FEEDBACK.Println("adding created directory to watchlist", path)
c.logger.Println("adding created directory to watchlist", path)
if err := watcher.Add(path); err != nil {
return err
}
@@ -1091,15 +1073,15 @@ func (c *commandeer) handleEvents(watcher *watcher.Batcher,
c.printChangeDetected("Static files")
if c.Cfg.GetBool("forceSyncStatic") {
c.logger.FEEDBACK.Printf("Syncing all static files\n")
c.logger.Printf("Syncing all static files\n")
_, err := c.copyStatic()
if err != nil {
c.logger.ERROR.Println("Error copying static files to publish dir:", err)
c.logger.Errorln("Error copying static files to publish dir:", err)
return
}
} else {
if err := staticSyncer.syncsStaticEvents(staticEvents); err != nil {
c.logger.ERROR.Println("Error syncing static files to publish dir:", err)
c.logger.Errorln("Error syncing static files to publish dir:", err)
return
}
}
@@ -1192,7 +1174,6 @@ func partitionDynamicEvents(sourceFs *filesystems.SourceFilesystems, events []fs
}
}
return
}
func pickOneWriteOrCreatePath(events []fsnotify.Event) string {
-1
View File
@@ -44,5 +44,4 @@ contentDir = "thisdoesnotexist"
_, err = cmd.ExecuteC()
c.Assert(err, qt.IsNil)
}
+5 -7
View File
@@ -74,11 +74,9 @@ Import from Jekyll requires two paths, e.g. ` + "`hugo import jekyll jekyll_root
cc.cmd.AddCommand(importJekyllCmd)
return cc
}
func (i *importCmd) importFromJekyll(cmd *cobra.Command, args []string) error {
if len(args) < 2 {
return newUserError(`import from jekyll requires two paths, e.g. ` + "`hugo import jekyll jekyll_root_path target_path`.")
}
@@ -255,13 +253,11 @@ func (i *importCmd) loadJekyllConfig(fs afero.Fs, jekyllRoot string) map[string]
defer f.Close()
b, err := ioutil.ReadAll(f)
if err != nil {
return nil
}
c, err := metadecoders.Default.UnmarshalToMap(b, metadecoders.YAML)
if err != nil {
return nil
}
@@ -338,8 +334,10 @@ func (i *importCmd) copyJekyllFilesAndFolders(jekyllRoot, dest string, jekyllPos
}
} else {
lowerEntryName := strings.ToLower(entry.Name())
exceptSuffix := []string{".md", ".markdown", ".html", ".htm",
".xml", ".textile", "rakefile", "gemfile", ".lock"}
exceptSuffix := []string{
".md", ".markdown", ".html", ".htm",
".xml", ".textile", "rakefile", "gemfile", ".lock",
}
isExcept := false
for _, suffix := range exceptSuffix {
if strings.HasSuffix(lowerEntryName, suffix) {
@@ -602,8 +600,8 @@ func replaceImageTag(match string) string {
}
result.WriteString(">}}")
return result.String()
}
func replaceOptionalPart(buffer *bytes.Buffer, partName string, part string) {
if len(part) > 0 {
buffer.WriteString(partName + "=\"" + part + "\" ")
+78 -38
View File
@@ -53,25 +53,41 @@ func TestConvertJekyllMetadata(t *testing.T) {
draft bool
expect string
}{
{map[interface{}]interface{}{}, "testPost", time.Date(2015, 10, 1, 0, 0, 0, 0, time.UTC), false,
`{"date":"2015-10-01T00:00:00Z"}`},
{map[interface{}]interface{}{}, "testPost", time.Date(2015, 10, 1, 0, 0, 0, 0, time.UTC), true,
`{"date":"2015-10-01T00:00:00Z","draft":true}`},
{map[interface{}]interface{}{"Permalink": "/permalink.html", "layout": "post"},
{
map[interface{}]interface{}{},
"testPost", time.Date(2015, 10, 1, 0, 0, 0, 0, time.UTC), false,
`{"date":"2015-10-01T00:00:00Z","url":"/permalink.html"}`},
{map[interface{}]interface{}{"permalink": "/permalink.html"},
`{"date":"2015-10-01T00:00:00Z"}`,
},
{
map[interface{}]interface{}{},
"testPost", time.Date(2015, 10, 1, 0, 0, 0, 0, time.UTC), true,
`{"date":"2015-10-01T00:00:00Z","draft":true}`,
},
{
map[interface{}]interface{}{"Permalink": "/permalink.html", "layout": "post"},
"testPost", time.Date(2015, 10, 1, 0, 0, 0, 0, time.UTC), false,
`{"date":"2015-10-01T00:00:00Z","url":"/permalink.html"}`},
{map[interface{}]interface{}{"category": nil, "permalink": 123},
`{"date":"2015-10-01T00:00:00Z","url":"/permalink.html"}`,
},
{
map[interface{}]interface{}{"permalink": "/permalink.html"},
"testPost", time.Date(2015, 10, 1, 0, 0, 0, 0, time.UTC), false,
`{"date":"2015-10-01T00:00:00Z"}`},
{map[interface{}]interface{}{"Excerpt_Separator": "sep"},
`{"date":"2015-10-01T00:00:00Z","url":"/permalink.html"}`,
},
{
map[interface{}]interface{}{"category": nil, "permalink": 123},
"testPost", time.Date(2015, 10, 1, 0, 0, 0, 0, time.UTC), false,
`{"date":"2015-10-01T00:00:00Z","excerpt_separator":"sep"}`},
{map[interface{}]interface{}{"category": "book", "layout": "post", "Others": "Goods", "Date": "2015-10-01 12:13:11"},
`{"date":"2015-10-01T00:00:00Z"}`,
},
{
map[interface{}]interface{}{"Excerpt_Separator": "sep"},
"testPost", time.Date(2015, 10, 1, 0, 0, 0, 0, time.UTC), false,
`{"Others":"Goods","categories":["book"],"date":"2015-10-01T12:13:11Z"}`},
`{"date":"2015-10-01T00:00:00Z","excerpt_separator":"sep"}`,
},
{
map[interface{}]interface{}{"category": "book", "layout": "post", "Others": "Goods", "Date": "2015-10-01 12:13:11"},
"testPost", time.Date(2015, 10, 1, 0, 0, 0, 0, time.UTC), false,
`{"Others":"Goods","categories":["book"],"date":"2015-10-01T12:13:11Z"}`,
},
}
for _, data := range testDataList {
@@ -90,44 +106,68 @@ func TestConvertJekyllContent(t *testing.T) {
content string
expect string
}{
{map[interface{}]interface{}{},
"Test content\r\n<!-- more -->\npart2 content", "Test content\n<!--more-->\npart2 content"},
{map[interface{}]interface{}{},
"Test content\n<!-- More -->\npart2 content", "Test content\n<!--more-->\npart2 content"},
{map[interface{}]interface{}{"excerpt_separator": "<!--sep-->"},
{
map[interface{}]interface{}{},
"Test content\r\n<!-- more -->\npart2 content", "Test content\n<!--more-->\npart2 content",
},
{
map[interface{}]interface{}{},
"Test content\n<!-- More -->\npart2 content", "Test content\n<!--more-->\npart2 content",
},
{
map[interface{}]interface{}{"excerpt_separator": "<!--sep-->"},
"Test content\n<!--sep-->\npart2 content",
"---\nexcerpt_separator: <!--sep-->\n---\nTest content\n<!--more-->\npart2 content"},
"---\nexcerpt_separator: <!--sep-->\n---\nTest content\n<!--more-->\npart2 content",
},
{map[interface{}]interface{}{}, "{% raw %}text{% endraw %}", "text"},
{map[interface{}]interface{}{}, "{%raw%} text2 {%endraw %}", "text2"},
{map[interface{}]interface{}{},
{
map[interface{}]interface{}{},
"{% highlight go %}\nvar s int\n{% endhighlight %}",
"{{< highlight go >}}\nvar s int\n{{< / highlight >}}"},
{map[interface{}]interface{}{},
"{{< highlight go >}}\nvar s int\n{{< / highlight >}}",
},
{
map[interface{}]interface{}{},
"{% highlight go linenos hl_lines=\"1 2\" %}\nvar s string\nvar i int\n{% endhighlight %}",
"{{< highlight go \"linenos=table,hl_lines=1 2\" >}}\nvar s string\nvar i int\n{{< / highlight >}}"},
"{{< highlight go \"linenos=table,hl_lines=1 2\" >}}\nvar s string\nvar i int\n{{< / highlight >}}",
},
// Octopress image tag
{map[interface{}]interface{}{},
{
map[interface{}]interface{}{},
"{% img http://placekitten.com/890/280 %}",
"{{< figure src=\"http://placekitten.com/890/280\" >}}"},
{map[interface{}]interface{}{},
"{{< figure src=\"http://placekitten.com/890/280\" >}}",
},
{
map[interface{}]interface{}{},
"{% img left http://placekitten.com/320/250 Place Kitten #2 %}",
"{{< figure class=\"left\" src=\"http://placekitten.com/320/250\" title=\"Place Kitten #2\" >}}"},
{map[interface{}]interface{}{},
"{{< figure class=\"left\" src=\"http://placekitten.com/320/250\" title=\"Place Kitten #2\" >}}",
},
{
map[interface{}]interface{}{},
"{% img right http://placekitten.com/300/500 150 250 'Place Kitten #3' %}",
"{{< figure class=\"right\" src=\"http://placekitten.com/300/500\" width=\"150\" height=\"250\" title=\"Place Kitten #3\" >}}"},
{map[interface{}]interface{}{},
"{{< figure class=\"right\" src=\"http://placekitten.com/300/500\" width=\"150\" height=\"250\" title=\"Place Kitten #3\" >}}",
},
{
map[interface{}]interface{}{},
"{% img right http://placekitten.com/300/500 150 250 'Place Kitten #4' 'An image of a very cute kitten' %}",
"{{< figure class=\"right\" src=\"http://placekitten.com/300/500\" width=\"150\" height=\"250\" title=\"Place Kitten #4\" alt=\"An image of a very cute kitten\" >}}"},
{map[interface{}]interface{}{},
"{{< figure class=\"right\" src=\"http://placekitten.com/300/500\" width=\"150\" height=\"250\" title=\"Place Kitten #4\" alt=\"An image of a very cute kitten\" >}}",
},
{
map[interface{}]interface{}{},
"{% img http://placekitten.com/300/500 150 250 'Place Kitten #4' 'An image of a very cute kitten' %}",
"{{< figure src=\"http://placekitten.com/300/500\" width=\"150\" height=\"250\" title=\"Place Kitten #4\" alt=\"An image of a very cute kitten\" >}}"},
{map[interface{}]interface{}{},
"{{< figure src=\"http://placekitten.com/300/500\" width=\"150\" height=\"250\" title=\"Place Kitten #4\" alt=\"An image of a very cute kitten\" >}}",
},
{
map[interface{}]interface{}{},
"{% img right /placekitten/300/500 'Place Kitten #4' 'An image of a very cute kitten' %}",
"{{< figure class=\"right\" src=\"/placekitten/300/500\" title=\"Place Kitten #4\" alt=\"An image of a very cute kitten\" >}}"},
{map[interface{}]interface{}{"category": "book", "layout": "post", "Date": "2015-10-01 12:13:11"},
"{{< figure class=\"right\" src=\"/placekitten/300/500\" title=\"Place Kitten #4\" alt=\"An image of a very cute kitten\" >}}",
},
{
map[interface{}]interface{}{"category": "book", "layout": "post", "Date": "2015-10-01 12:13:11"},
"somecontent",
"---\nDate: \"2015-10-01 12:13:11\"\ncategory: book\nlayout: post\n---\nsomecontent"},
"---\nDate: \"2015-10-01 12:13:11\"\ncategory: book\nlayout: post\n---\nsomecontent",
},
}
for _, data := range testDataList {
result, err := convertJekyllContent(data.metadata, data.content)
-5
View File
@@ -46,7 +46,6 @@ func (lc *listCmd) buildSites(config map[string]interface{}) (*hugolib.HugoSites
}
sites, err := hugolib.NewHugoSites(*c.DepsCfg)
if err != nil {
return nil, newSystemError("Error creating sites", err)
}
@@ -77,7 +76,6 @@ List requires a subcommand, e.g. ` + "`hugo list drafts`.",
Long: `List all of the drafts in your content directory.`,
RunE: func(cmd *cobra.Command, args []string) error {
sites, err := cc.buildSites(map[string]interface{}{"buildDrafts": true})
if err != nil {
return newSystemError("Error building sites", err)
}
@@ -97,7 +95,6 @@ List requires a subcommand, e.g. ` + "`hugo list drafts`.",
Long: `List all of the posts in your content directory which will be posted in the future.`,
RunE: func(cmd *cobra.Command, args []string) error {
sites, err := cc.buildSites(map[string]interface{}{"buildFuture": true})
if err != nil {
return newSystemError("Error building sites", err)
}
@@ -126,7 +123,6 @@ List requires a subcommand, e.g. ` + "`hugo list drafts`.",
Long: `List all of the posts in your content directory which has already expired.`,
RunE: func(cmd *cobra.Command, args []string) error {
sites, err := cc.buildSites(map[string]interface{}{"buildExpired": true})
if err != nil {
return newSystemError("Error building sites", err)
}
@@ -159,7 +155,6 @@ List requires a subcommand, e.g. ` + "`hugo list drafts`.",
"buildDrafts": true,
"buildFuture": true,
})
if err != nil {
return newSystemError("Error building sites", err)
}
-2
View File
@@ -91,7 +91,6 @@ Also note that if you configure a positive maxAge for the "modules" file cache,
}
func (b *commandsBuilder) newModCmd() *modCmd {
c := &modCmd{}
const commonUsage = `
@@ -264,7 +263,6 @@ If a module is vendored, that is where Hugo will look for it's dependencies.
c.baseBuilderCmd = b.newBuilderCmd(cmd)
return c
}
func (c *modCmd) withModsClient(failOnMissingConfig bool, f func(*modules.Client) error) error {
-2
View File
@@ -20,7 +20,6 @@ import (
)
func newModNPMCmd(c *modCmd) *cobra.Command {
cmd := &cobra.Command{
Use: "npm",
Short: "Various npm helpers.",
@@ -47,7 +46,6 @@ removed from Hugo, but we need to test this out in "real life" to get a feel of
so this may/will change in future versions of Hugo.
`,
RunE: func(cmd *cobra.Command, args []string) error {
return c.withHugo(func(h *hugolib.HugoSites) error {
return npm.Pack(h.BaseFs.SourceFs, h.BaseFs.Assets.Dirs)
})
-1
View File
@@ -72,7 +72,6 @@ func (n *newCmd) newContent(cmd *cobra.Command, args []string) error {
}
c, err := initializeConfig(true, false, &n.hugoBuilderCommon, n, cfgInit)
if err != nil {
return err
}
+2 -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)
@@ -58,7 +58,6 @@ Use ` + "`hugo new [contentPath]`" + ` to create new content.`,
cc.baseBuilderCmd = b.newBuilderBasicCmd(cmd)
return cc
}
func (n *newSiteCmd) doNewSite(fs *hugofs.Fs, basepath string, force bool) error {
@@ -124,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) {
+1 -3
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.`,
@@ -53,7 +53,6 @@ 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)
if err != nil {
return err
}
@@ -145,7 +144,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
}
func (n *newThemeCmd) createThemeMD(fs *hugofs.Fs, inpath string) (err error) {
by := []byte(`# theme.toml template for a Hugo theme
# See https://github.com/gohugoio/hugoThemes#themetoml for an example
+50
View File
@@ -0,0 +1,50 @@
// Copyright 2019 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// +build nodeploy
package commands
import (
"errors"
"github.com/spf13/cobra"
)
var _ cmder = (*deployCmd)(nil)
// deployCmd supports deploying sites to Cloud providers.
type deployCmd struct {
*baseBuilderCmd
}
func (b *commandsBuilder) newDeployCmd() *deployCmd {
cc := &deployCmd{}
cmd := &cobra.Command{
Use: "deploy",
Short: "Deploy your site to a Cloud provider.",
Long: `Deploy your site to a Cloud provider.
See https://gohugo.io/hosting-and-deployment/hugo-deploy/ for detailed
documentation.
`,
RunE: func(cmd *cobra.Command, args []string) error {
return errors.New("build without HUGO_BUILD_TAGS=nodeploy to use this command")
},
}
cc.baseBuilderCmd = b.newBuilderBasicCmd(cmd)
return cc
}
-1
View File
@@ -61,7 +61,6 @@ func (c *releaseCommandeer) getCommand() *cobra.Command {
}
func (c *releaseCommandeer) flagsToConfig(cfg config.Provider) {
}
func (r *releaseCommandeer) release() error {
+20 -15
View File
@@ -31,6 +31,8 @@ import (
"syscall"
"time"
"github.com/gohugoio/hugo/common/paths"
"github.com/pkg/errors"
"github.com/gohugoio/hugo/livereload"
@@ -185,7 +187,7 @@ func (sc *serverCmd) server(cmd *cobra.Command, args []string) error {
// port set explicitly by user -- he/she probably meant it!
err = newSystemErrorF("Server startup failed: %s", err)
}
c.logger.FEEDBACK.Println("port", sc.serverPort, "already in use, attempting to use an available port")
c.logger.Println("port", sc.serverPort, "already in use, attempting to use an available port")
sp, err := helpers.FindAvailablePort()
if err != nil {
err = newSystemError("Unable to find alternative port to use:", err)
@@ -228,7 +230,6 @@ func (sc *serverCmd) server(cmd *cobra.Command, args []string) error {
}
return err
}
if err := memStats(); err != nil {
@@ -262,7 +263,6 @@ func (sc *serverCmd) server(cmd *cobra.Command, args []string) error {
jww.FEEDBACK.Printf("Watching for changes in %s\n", group)
}
watcher, err := c.newWatcher(watchDirs...)
if err != nil {
return err
}
@@ -272,13 +272,12 @@ func (sc *serverCmd) server(cmd *cobra.Command, args []string) error {
}
return c.serve(sc)
}
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)), ",")
@@ -301,7 +300,6 @@ func (f *fileServer) rewriteRequest(r *http.Request, toPath string) *http.Reques
r2.Header.Set("X-Rewrite-Original-URI", r.URL.RequestURI())
return r2
}
func (f *fileServer) createEndpoint(i int) (*http.ServeMux, string, string, error) {
@@ -350,14 +348,16 @@ func (f *fileServer) createEndpoint(i int) (*http.ServeMux, string, string, erro
w.WriteHeader(500)
r, err := f.errorTemplate(err)
if err != nil {
f.c.logger.ERROR.Println(err)
f.c.logger.Errorln(err)
}
port = 1313
if !f.c.paused {
port = f.c.Cfg.GetInt("liveReloadPort")
}
fmt.Fprint(w, injectLiveReloadScript(r, port))
lr := *u
lr.Host = fmt.Sprintf("%s:%d", lr.Hostname(), port)
fmt.Fprint(w, injectLiveReloadScript(r, lr))
return
}
@@ -391,7 +391,6 @@ func (f *fileServer) createEndpoint(i int) (*http.ServeMux, string, string, erro
} else {
doRedirect = false
}
}
}
@@ -411,7 +410,6 @@ func (f *fileServer) createEndpoint(i int) (*http.ServeMux, string, string, erro
}
if f.c.fastRenderMode && f.c.buildErr == nil {
if strings.HasSuffix(requestURI, "/") || strings.HasSuffix(requestURI, "html") || strings.HasSuffix(requestURI, "htm") {
if !f.c.visitedURLs.Contains(requestURI) {
// If not already on stack, re-render that single page.
@@ -451,8 +449,8 @@ var logErrorRe = regexp.MustCompile(`(?s)ERROR \d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{
func removeErrorPrefixFromLog(content string) string {
return logErrorRe.ReplaceAllLiteralString(content, "")
}
func (c *commandeer) serve(s *serverCmd) error {
func (c *commandeer) serve(s *serverCmd) error {
isMultiHost := c.hugo().IsMultihost()
var (
@@ -494,21 +492,26 @@ func (c *commandeer) serve(s *serverCmd) error {
livereload.Initialize()
}
var sigs = make(chan os.Signal, 1)
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
for i := range baseURLs {
mu, serverURL, endpoint, err := srv.createEndpoint(i)
if doLiveReload {
mu.HandleFunc("/livereload.js", livereload.ServeJS)
mu.HandleFunc("/livereload", livereload.Handler)
u, err := url.Parse(helpers.SanitizeURL(baseURLs[i]))
if err != nil {
return err
}
mu.HandleFunc(u.Path+"/livereload.js", livereload.ServeJS)
mu.HandleFunc(u.Path+"/livereload", livereload.Handler)
}
jww.FEEDBACK.Printf("Web Server is available at %s (bind address %s)\n", serverURL, s.serverInterface)
go func() {
err = http.ListenAndServe(endpoint, mu)
if err != nil {
c.logger.ERROR.Printf("Error: %s\n", err.Error())
c.logger.Errorf("Error: %s\n", err.Error())
os.Exit(1)
}
}()
@@ -525,6 +528,8 @@ func (c *commandeer) serve(s *serverCmd) error {
<-sigs
}
c.hugo().Close()
return nil
}
+3 -2
View File
@@ -16,6 +16,7 @@ package commands
import (
"bytes"
"io"
"net/url"
"github.com/gohugoio/hugo/transform"
"github.com/gohugoio/hugo/transform/livereloadinject"
@@ -82,9 +83,9 @@ var buildErrorTemplate = `<!doctype html>
</html>
`
func injectLiveReloadScript(src io.Reader, port int) string {
func injectLiveReloadScript(src io.Reader, baseURL url.URL) string {
var b bytes.Buffer
chain := transform.Chain{livereloadinject.New(port)}
chain := transform.Chain{livereloadinject.New(baseURL)}
chain.Apply(&b, src)
return b.String()
+2 -4
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) {
@@ -73,7 +73,6 @@ func TestServer(t *testing.T) {
// Stop the server.
stop <- true
}
func TestFixURL(t *testing.T) {
@@ -102,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
@@ -127,7 +126,6 @@ ERROR 2018/10/07 13:11:12 Rebuild failed: logged 1 error(s)
withoutError := removeErrorPrefixFromLog(content)
c.Assert(strings.Contains(withoutError, "ERROR"), qt.Equals, false)
}
func isWindowsCI() bool {
+6 -7
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
@@ -79,9 +79,9 @@ func (s *staticSyncer) syncsStaticEvents(staticEvents []fsnotify.Event) error {
fromPath := ev.Name
relPath := sourceFs.MakePathRelative(fromPath)
relPath, found := sourceFs.MakePathRelative(fromPath)
if relPath == "" {
if !found {
// Not member of this virtual host.
continue
}
@@ -107,10 +107,10 @@ func (s *staticSyncer) syncsStaticEvents(staticEvents []fsnotify.Event) error {
logger.Println("Syncing", relPath, "to", publishDir)
if err := syncer.Sync(filepath.Join(publishDir, relPath), relPath); err != nil {
c.logger.ERROR.Println(err)
c.logger.Errorln(err)
}
} else {
c.logger.ERROR.Println(err)
c.logger.Errorln(err)
}
continue
@@ -119,7 +119,7 @@ func (s *staticSyncer) syncsStaticEvents(staticEvents []fsnotify.Event) error {
// For all other event operations Hugo will sync static.
logger.Println("Syncing", relPath, "to", publishDir)
if err := syncer.Sync(filepath.Join(publishDir, relPath), relPath); err != nil {
c.logger.ERROR.Println(err)
c.logger.Errorln(err)
}
}
@@ -128,5 +128,4 @@ func (s *staticSyncer) syncsStaticEvents(staticEvents []fsnotify.Event) error {
_, err := c.doWithPublishDirs(syncFn)
return err
}
-1
View File
@@ -51,7 +51,6 @@ func Append(to interface{}, from ...interface{}) (interface{}, error) {
} else if !fromt.AssignableTo(tot) {
// Fall back to a []interface{} slice.
return appendToInterfaceSliceFromValues(tov, fromv)
}
}
}
+29 -14
View File
@@ -36,28 +36,44 @@ func TestAppend(t *testing.T) {
{nil, []interface{}{"a", "b"}, []string{"a", "b"}},
{nil, []interface{}{nil}, []interface{}{nil}},
{[]interface{}{}, []interface{}{[]string{"c", "d", "e"}}, []string{"c", "d", "e"}},
{tstSlicers{&tstSlicer{"a"}, &tstSlicer{"b"}},
{
tstSlicers{&tstSlicer{"a"}, &tstSlicer{"b"}},
[]interface{}{&tstSlicer{"c"}},
tstSlicers{&tstSlicer{"a"}, &tstSlicer{"b"}, &tstSlicer{"c"}}},
{&tstSlicers{&tstSlicer{"a"}, &tstSlicer{"b"}},
tstSlicers{&tstSlicer{"a"}, &tstSlicer{"b"}, &tstSlicer{"c"}},
},
{
&tstSlicers{&tstSlicer{"a"}, &tstSlicer{"b"}},
[]interface{}{&tstSlicer{"c"}},
tstSlicers{&tstSlicer{"a"},
tstSlicers{
&tstSlicer{"a"},
&tstSlicer{"b"},
&tstSlicer{"c"}}},
{testSlicerInterfaces{&tstSlicerIn1{"a"}, &tstSlicerIn1{"b"}},
&tstSlicer{"c"},
},
},
{
testSlicerInterfaces{&tstSlicerIn1{"a"}, &tstSlicerIn1{"b"}},
[]interface{}{&tstSlicerIn1{"c"}},
testSlicerInterfaces{&tstSlicerIn1{"a"}, &tstSlicerIn1{"b"}, &tstSlicerIn1{"c"}}},
testSlicerInterfaces{&tstSlicerIn1{"a"}, &tstSlicerIn1{"b"}, &tstSlicerIn1{"c"}},
},
//https://github.com/gohugoio/hugo/issues/5361
{[]string{"a", "b"}, []interface{}{tstSlicers{&tstSlicer{"a"}, &tstSlicer{"b"}}},
[]interface{}{"a", "b", &tstSlicer{"a"}, &tstSlicer{"b"}}},
{[]string{"a", "b"}, []interface{}{&tstSlicer{"a"}},
[]interface{}{"a", "b", &tstSlicer{"a"}}},
{
[]string{"a", "b"},
[]interface{}{tstSlicers{&tstSlicer{"a"}, &tstSlicer{"b"}}},
[]interface{}{"a", "b", &tstSlicer{"a"}, &tstSlicer{"b"}},
},
{
[]string{"a", "b"},
[]interface{}{&tstSlicer{"a"}},
[]interface{}{"a", "b", &tstSlicer{"a"}},
},
// Errors
{"", []interface{}{[]string{"a", "b"}}, false},
// No string concatenation.
{"ab",
{
"ab",
[]interface{}{"c"},
false},
false,
},
} {
result, err := Append(test.start, test.addend...)
@@ -71,5 +87,4 @@ func TestAppend(t *testing.T) {
c.Assert(err, qt.IsNil)
c.Assert(result, qt.DeepEquals, test.expected)
}
}
+7 -7
View File
@@ -20,11 +20,13 @@ import (
qt "github.com/frankban/quicktest"
)
var _ Slicer = (*tstSlicer)(nil)
var _ Slicer = (*tstSlicerIn1)(nil)
var _ Slicer = (*tstSlicerIn2)(nil)
var _ testSlicerInterface = (*tstSlicerIn1)(nil)
var _ testSlicerInterface = (*tstSlicerIn1)(nil)
var (
_ Slicer = (*tstSlicer)(nil)
_ Slicer = (*tstSlicerIn1)(nil)
_ Slicer = (*tstSlicerIn2)(nil)
_ testSlicerInterface = (*tstSlicerIn1)(nil)
_ testSlicerInterface = (*tstSlicerIn1)(nil)
)
type testSlicerInterface interface {
Name() string
@@ -54,7 +56,6 @@ func (p *tstSlicerIn1) Slice(in interface{}) (interface{}, error) {
default:
return nil, errors.New("invalid type")
}
}
return result, nil
}
@@ -120,5 +121,4 @@ func TestSlice(t *testing.T) {
c.Assert(test.expected, qt.DeepEquals, result, errMsg)
}
}
+4
View File
@@ -18,4 +18,8 @@ package constants
const (
ErrIDAmbigousDisableKindTaxonomy = "error-disable-taxonomy"
ErrIDAmbigousOutputKindTaxonomy = "error-output-taxonomy"
// IDs for remote errors in tpl/data.
ErrRemoteGetJSON = "error-remote-getjson"
ErrRemoteGetCSV = "error-remote-getcsv"
)
-1
View File
@@ -125,5 +125,4 @@ E`, offsetMatcher)
c.Assert(location.Lines, qt.DeepEquals, []string{"A", "B", "C", "D"})
c.Assert(location.Position().LineNumber, qt.Equals, 2)
c.Assert(location.LinesPos, qt.Equals, 1)
}
+1 -3
View File
@@ -21,9 +21,7 @@ import (
"github.com/pkg/errors"
)
var (
_ causer = (*fileError)(nil)
)
var _ causer = (*fileError)(nil)
// FileError represents an error when handling a file: Parsing a config file,
// execute a template etc.
-1
View File
@@ -52,5 +52,4 @@ func TestToLineNumberError(t *testing.T) {
c.Assert(pos.ColumnNumber, qt.Equals, test.columnNumber, errMsg)
c.Assert(errors.Cause(got), qt.Not(qt.IsNil))
}
}
+45
View File
@@ -0,0 +1,45 @@
// Copyright 2020 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package hexec
import (
"context"
"os/exec"
"github.com/cli/safeexec"
)
// SafeCommand is a wrapper around os/exec Command which uses a LookPath
// implementation that does not search in current directory before looking in PATH.
// See https://github.com/cli/safeexec and the linked issues.
func SafeCommand(name string, arg ...string) (*exec.Cmd, error) {
bin, err := safeexec.LookPath(name)
if err != nil {
return nil, err
}
return exec.Command(bin, arg...), nil
}
// SafeCommandContext wraps CommandContext
// See SafeCommand for more context.
func SafeCommandContext(ctx context.Context, name string, arg ...string) (*exec.Cmd, error) {
bin, err := safeexec.LookPath(name)
if err != nil {
return nil, err
}
return exec.CommandContext(ctx, bin, arg...), nil
}
+1 -2
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)
}
@@ -67,7 +67,6 @@ func IsTruthful(in interface{}) bool {
default:
return IsTruthfulValue(reflect.ValueOf(in))
}
}
var zeroType = reflect.TypeOf((*types.Zeroer)(nil)).Elem()
+1 -1
View File
@@ -32,7 +32,7 @@ type ReadSeekCloser interface {
}
// ReadSeekerNoOpCloser implements ReadSeekCloser by doing nothing in Close.
// TODO(bep) rename this and simila to ReadSeekerNopCloser, naming used in stdlib, which kind of makes sense.
// TODO(bep) rename this and similar to ReadSeekerNopCloser, naming used in stdlib, which kind of makes sense.
type ReadSeekerNoOpCloser struct {
ReadSeeker
}
+53 -2
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 == "" {
@@ -100,3 +109,45 @@ func GetExecEnviron(workDir string, cfg config.Provider, fs afero.Fs) []string {
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 -1
View File
@@ -32,8 +32,8 @@ 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)
}
+10 -4
View File
@@ -16,7 +16,6 @@ package hugo
import (
"fmt"
"io"
"runtime"
"strings"
@@ -128,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
@@ -145,8 +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.76,
PatchLevel: 2,
Number: 0.84,
PatchLevel: 0,
Suffix: "",
}
+21 -8
View File
@@ -19,25 +19,31 @@ import (
)
// IgnorableLogger is a logger that ignores certain log statements.
type IgnorableLogger struct {
logger *Logger
type IgnorableLogger interface {
Logger
Errorsf(statementID, format string, v ...interface{})
Apply(logger Logger) IgnorableLogger
}
type ignorableLogger struct {
Logger
statements map[string]bool
}
// NewIgnorableLogger wraps the given logger and ignores the log statement IDs given.
func NewIgnorableLogger(logger *Logger, statements ...string) IgnorableLogger {
func NewIgnorableLogger(logger Logger, statements ...string) IgnorableLogger {
statementsSet := make(map[string]bool)
for _, s := range statements {
statementsSet[strings.ToLower(s)] = true
}
return IgnorableLogger{
logger: logger,
return ignorableLogger{
Logger: logger,
statements: statementsSet,
}
}
func (l IgnorableLogger) Errorf(statementID, format string, v ...interface{}) {
// Errorsf logs statementID as an ERROR if not configured as ignoreable.
func (l ignorableLogger) Errorsf(statementID, format string, v ...interface{}) {
if l.statements[statementID] {
// Ignore.
return
@@ -48,5 +54,12 @@ ignoreErrors = [%q]`, statementID)
format += ignoreMsg
l.logger.ERROR.Printf(format, v...)
l.Errorf(format, v...)
}
func (l ignorableLogger) Apply(logger Logger) IgnorableLogger {
return ignorableLogger{
Logger: logger,
statements: l.statements,
}
}
+124 -34
View File
@@ -1,4 +1,4 @@
// Copyright 2018 The Hugo Authors. All rights reserved.
// Copyright 2020 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -29,10 +29,8 @@ import (
jww "github.com/spf13/jwalterweatherman"
)
var (
// Counts ERROR logs to the global jww logger.
GlobalErrorCounter *jww.Counter
)
// Counts ERROR logs to the global jww logger.
var GlobalErrorCounter *jww.Counter
func init() {
GlobalErrorCounter = &jww.Counter{}
@@ -56,39 +54,132 @@ func (w prefixWriter) Write(p []byte) (n int, err error) {
return len(p), nil
}
// Logger wraps a *loggers.Logger and some other related logging state.
type Logger struct {
type Logger interface {
Printf(format string, v ...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{})
Warn() *log.Logger
Warnf(format string, v ...interface{})
Warnln(v ...interface{})
Error() *log.Logger
Errorf(format string, v ...interface{})
Errorln(v ...interface{})
Errors() string
Out() io.Writer
Reset()
// Used in tests.
LogCounters() *LogCounters
}
type LogCounters struct {
ErrorCounter *jww.Counter
WarnCounter *jww.Counter
}
type logger struct {
*jww.Notepad
// The writer that represents stdout.
// Will be ioutil.Discard when in quiet mode.
Out io.Writer
out io.Writer
ErrorCounter *jww.Counter
WarnCounter *jww.Counter
logCounters *LogCounters
// This is only set in server mode.
errors *bytes.Buffer
}
func (l *logger) Printf(format string, v ...interface{}) {
l.FEEDBACK.Printf(format, v...)
}
func (l *logger) Println(v ...interface{}) {
l.FEEDBACK.Println(v...)
}
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...)
}
func (l *logger) Infoln(v ...interface{}) {
l.INFO.Println(v...)
}
func (l *logger) Info() *log.Logger {
return l.INFO
}
func (l *logger) Warnf(format string, v ...interface{}) {
l.WARN.Printf(format, v...)
}
func (l *logger) Warnln(v ...interface{}) {
l.WARN.Println(v...)
}
func (l *logger) Warn() *log.Logger {
return l.WARN
}
func (l *logger) Errorf(format string, v ...interface{}) {
l.ERROR.Printf(format, v...)
}
func (l *logger) Errorln(v ...interface{}) {
l.ERROR.Println(v...)
}
func (l *logger) Error() *log.Logger {
return l.ERROR
}
func (l *logger) LogCounters() *LogCounters {
return l.logCounters
}
func (l *logger) Out() io.Writer {
return l.out
}
// PrintTimerIfDelayed prints a time statement to the FEEDBACK logger
// if considerable time is spent.
func (l *Logger) PrintTimerIfDelayed(start time.Time, name string) {
func (l *logger) PrintTimerIfDelayed(start time.Time, name string) {
elapsed := time.Since(start)
milli := int(1000 * elapsed.Seconds())
if milli < 500 {
return
}
l.FEEDBACK.Printf("%s in %v ms", name, milli)
l.Printf("%s in %v ms", name, milli)
}
func (l *Logger) PrintTimer(start time.Time, name string) {
func (l *logger) PrintTimer(start time.Time, name string) {
elapsed := time.Since(start)
milli := int(1000 * elapsed.Seconds())
l.FEEDBACK.Printf("%s in %v ms", name, milli)
l.Printf("%s in %v ms", name, milli)
}
func (l *Logger) Errors() string {
func (l *logger) Errors() string {
if l.errors == nil {
return ""
}
@@ -96,45 +187,45 @@ func (l *Logger) Errors() string {
}
// Reset resets the logger's internal state.
func (l *Logger) Reset() {
l.ErrorCounter.Reset()
func (l *logger) Reset() {
l.logCounters.ErrorCounter.Reset()
if l.errors != nil {
l.errors.Reset()
}
}
// NewLogger creates a new Logger for the given thresholds
func NewLogger(stdoutThreshold, logThreshold jww.Threshold, outHandle, logHandle io.Writer, saveErrors bool) *Logger {
func NewLogger(stdoutThreshold, logThreshold jww.Threshold, outHandle, logHandle io.Writer, saveErrors bool) Logger {
return newLogger(stdoutThreshold, logThreshold, outHandle, logHandle, saveErrors)
}
// NewDebugLogger is a convenience function to create a debug logger.
func NewDebugLogger() *Logger {
func NewDebugLogger() Logger {
return NewBasicLogger(jww.LevelDebug)
}
// NewWarningLogger is a convenience function to create a warning logger.
func NewWarningLogger() *Logger {
func NewWarningLogger() Logger {
return NewBasicLogger(jww.LevelWarn)
}
// NewInfoLogger is a convenience function to create a info logger.
func NewInfoLogger() *Logger {
func NewInfoLogger() Logger {
return NewBasicLogger(jww.LevelInfo)
}
// NewErrorLogger is a convenience function to create an error logger.
func NewErrorLogger() *Logger {
func NewErrorLogger() Logger {
return NewBasicLogger(jww.LevelError)
}
// NewBasicLogger creates a new basic logger writing to Stdout.
func NewBasicLogger(t jww.Threshold) *Logger {
func NewBasicLogger(t jww.Threshold) Logger {
return newLogger(t, jww.LevelError, os.Stdout, ioutil.Discard, false)
}
// NewBasicLoggerForWriter creates a new basic logger writing to w.
func NewBasicLoggerForWriter(t jww.Threshold, w io.Writer) *Logger {
func NewBasicLoggerForWriter(t jww.Threshold, w io.Writer) Logger {
return newLogger(t, jww.LevelError, w, ioutil.Discard, false)
}
@@ -170,7 +261,6 @@ func (a labelColorizer) Write(p []byte) (n int, err error) {
// bytes, so we lie a little.
_, err = a.w.Write([]byte(replaced))
return len(p), err
}
// InitGlobalLogger initializes the global logger, used in some rare cases.
@@ -181,7 +271,6 @@ func InitGlobalLogger(stdoutThreshold, logThreshold jww.Threshold, outHandle, lo
jww.SetLogOutput(logHandle)
jww.SetLogThreshold(logThreshold)
jww.SetStdoutThreshold(stdoutThreshold)
}
func getLogWriters(outHandle, logHandle io.Writer) (io.Writer, io.Writer) {
@@ -196,7 +285,6 @@ func getLogWriters(outHandle, logHandle io.Writer) (io.Writer, io.Writer) {
}
return outHandle, logHandle
}
type fatalLogWriter int
@@ -219,7 +307,7 @@ var fatalLogListener = func(t jww.Threshold) io.Writer {
return new(fatalLogWriter)
}
func newLogger(stdoutThreshold, logThreshold jww.Threshold, outHandle, logHandle io.Writer, saveErrors bool) *Logger {
func newLogger(stdoutThreshold, logThreshold jww.Threshold, outHandle, logHandle io.Writer, saveErrors bool) *logger {
errorCounter := &jww.Counter{}
warnCounter := &jww.Counter{}
outHandle, logHandle = getLogWriters(outHandle, logHandle)
@@ -239,11 +327,13 @@ func newLogger(stdoutThreshold, logThreshold jww.Threshold, outHandle, logHandle
listeners = append(listeners, errorCapture)
}
return &Logger{
Notepad: jww.NewNotepad(stdoutThreshold, logThreshold, outHandle, logHandle, "", log.Ldate|log.Ltime, listeners...),
Out: outHandle,
ErrorCounter: errorCounter,
WarnCounter: warnCounter,
errors: errorBuff,
return &logger{
Notepad: jww.NewNotepad(stdoutThreshold, logThreshold, outHandle, logHandle, "", log.Ldate|log.Ltime, listeners...),
out: outHandle,
logCounters: &LogCounters{
ErrorCounter: errorCounter,
WarnCounter: warnCounter,
},
errors: errorBuff,
}
}
+4 -5
View File
@@ -26,12 +26,11 @@ func TestLogger(t *testing.T) {
c := qt.New(t)
l := NewWarningLogger()
l.ERROR.Println("One error")
l.ERROR.Println("Two error")
l.WARN.Println("A warning")
c.Assert(l.ErrorCounter.Count(), qt.Equals, uint64(2))
l.Errorln("One error")
l.Errorln("Two error")
l.Warnln("A warning")
c.Assert(l.LogCounters().ErrorCounter.Count(), qt.Equals, uint64(2))
}
func TestLoggerToWriterWithPrefix(t *testing.T) {
+63 -34
View File
@@ -14,56 +14,86 @@
package maps
import (
"fmt"
"strings"
"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.
// See PrepareParams.
func ToParamsAndPrepare(in interface{}) (Params, bool) {
m, err := ToStringMapE(in)
if err != nil {
return nil, false
}
PrepareParams(m)
return m, true
}
// 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{}:
return v, nil
case []interface{}:
var s []map[string]interface{}
for _, entry := range v {
if vv, ok := entry.(map[string]interface{}); ok {
s = append(s, vv)
}
}
return s, nil
default:
return nil, fmt.Errorf("unable to cast %#v of type %T to []map[string]interface{}", in, in)
}
}
type keyRename struct {
pattern glob.Glob
newKey string
@@ -109,9 +139,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{}) {
+34 -2
View File
@@ -67,7 +67,7 @@ func TestToLower(t *testing.T) {
for i, test := range tests {
t.Run(fmt.Sprint(i), func(t *testing.T) {
// ToLower modifies input.
ToLower(test.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)
}
@@ -75,6 +75,39 @@ func TestToLower(t *testing.T) {
}
}
func TestToSliceStringMap(t *testing.T) {
c := qt.New(t)
tests := []struct {
input interface{}
expected []map[string]interface{}
}{
{
input: []map[string]interface{}{
{"abc": 123},
},
expected: []map[string]interface{}{
{"abc": 123},
},
}, {
input: []interface{}{
map[string]interface{}{
"def": 456,
},
},
expected: []map[string]interface{}{
{"def": 456},
},
},
}
for _, test := range tests {
v, err := ToSliceStringMap(test.input)
c.Assert(err, qt.IsNil)
c.Assert(v, qt.DeepEquals, test.expected)
}
}
func TestRenameKeys(t *testing.T) {
c := qt.New(t)
@@ -121,5 +154,4 @@ func TestRenameKeys(t *testing.T) {
if !reflect.DeepEqual(expected, m) {
t.Errorf("Expected\n%#v, got\n%#v\n", expected, m)
}
}
+153 -2
View File
@@ -14,6 +14,7 @@
package maps
import (
"fmt"
"strings"
"github.com/spf13/cast"
@@ -29,6 +30,95 @@ 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
}
}
}
}
// Merge transfers values from pp to p for new keys.
// This is done recursively.
func (p Params) Merge(pp Params) {
p.merge("", 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
@@ -37,7 +127,11 @@ func getNested(m map[string]interface{}, indices []string) (interface{}, string,
first := indices[0]
v, found := m[strings.ToLower(cast.ToString(first))]
if !found {
if len(indices) == 1 {
return nil, first, m
}
return nil, "", nil
}
if len(indices) == 1 {
@@ -76,11 +170,10 @@ func GetNestedParam(keyStr, separator string, candidates ...Params) (interface{}
}
return nil, nil
}
func GetNestedParamFn(keyStr, separator string, lookupFn func(key string) interface{}) (interface{}, string, map[string]interface{}, error) {
keySegments := strings.Split(strings.ToLower(keyStr), separator)
keySegments := strings.Split(keyStr, separator)
if len(keySegments) == 0 {
return nil, "", nil, nil
}
@@ -105,3 +198,61 @@ 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{} 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 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
}
}
if retyped || k != lKey {
delete(m, k)
m[lKey] = v
}
}
}
+108 -1
View File
@@ -20,7 +20,6 @@ import (
)
func TestGetNestedParam(t *testing.T) {
m := map[string]interface{}{
"string": "value",
"first": 1,
@@ -47,5 +46,113 @@ func TestGetNestedParam(t *testing.T) {
c.Assert(must("nested_color", "_", m), qt.Equals, "blue")
c.Assert(must("nested.nestednested.color", ".", m), qt.Equals, "green")
c.Assert(must("string.name", ".", m), qt.IsNil)
c.Assert(must("nested.foo", ".", m), qt.IsNil)
}
// https://github.com/gohugoio/hugo/issues/7903
func TestGetNestedParamFnNestedNewKey(t *testing.T) {
c := qt.New(t)
nested := map[string]interface{}{
"color": "blue",
}
m := map[string]interface{}{
"nested": nested,
}
existing, nestedKey, owner, err := GetNestedParamFn("nested.new", ".", func(key string) interface{} {
return m[key]
})
c.Assert(err, qt.IsNil)
c.Assert(existing, qt.IsNil)
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",
})
}
+11 -1
View File
@@ -51,7 +51,6 @@ func NewScratcher() Scratcher {
//
// If the first add for a key is an array or slice, then the next value(s) will be appended.
func (c *Scratch) Add(key string, newAddend interface{}) (string, error) {
var newVal interface{}
c.mu.RLock()
existingAddend, found := c.values[key]
@@ -130,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 -3
View File
@@ -53,7 +53,6 @@ func TestScratchAdd(t *testing.T) {
if err == nil {
t.Errorf("Expected error from invalid arithmetic")
}
}
func TestScratchAddSlice(t *testing.T) {
@@ -96,7 +95,6 @@ func TestScratchAddTypedSliceToInterfaceSlice(t *testing.T) {
_, err := scratch.Add("slice", []int{1, 2})
c.Assert(err, qt.IsNil)
c.Assert(scratch.Get("slice"), qt.DeepEquals, []int{1, 2})
}
// https://github.com/gohugoio/hugo/issues/5361
@@ -110,7 +108,6 @@ func TestScratchAddDifferentTypedSliceToInterfaceSlice(t *testing.T) {
_, err := scratch.Add("slice", []int{1, 2})
c.Assert(err, qt.IsNil)
c.Assert(scratch.Get("slice"), qt.DeepEquals, []interface{}{"foo", 1, 2})
}
func TestScratchSet(t *testing.T) {
@@ -191,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()
+9 -4
View File
@@ -16,13 +16,14 @@ package para
import (
"context"
"runtime"
"sort"
"sync"
"sync/atomic"
"testing"
"time"
"github.com/gohugoio/hugo/htesting"
qt "github.com/frankban/quicktest"
)
@@ -31,6 +32,10 @@ func TestPara(t *testing.T) {
t.Skipf("skip para test, CPU count is %d", runtime.NumCPU())
}
if !htesting.IsCI() {
t.Skip("skip para test when not running on CI")
}
c := qt.New(t)
c.Run("Order", func(c *qt.C) {
@@ -60,7 +65,6 @@ func TestPara(t *testing.T) {
c.Assert(sort.IntsAreSorted(result), qt.Equals, false, qt.Commentf("Para does not seem to be parallel"))
sort.Ints(result)
c.Assert(result, qt.DeepEquals, ints)
})
c.Run("Time", func(c *qt.C) {
@@ -83,8 +87,9 @@ func TestPara(t *testing.T) {
c.Assert(r.Wait(), qt.IsNil)
c.Assert(counter, qt.Equals, int64(n))
c.Assert(time.Since(start) < n/2*time.Millisecond, qt.Equals, true)
since := time.Since(start)
limit := n / 2 * time.Millisecond
c.Assert(since < limit, qt.Equals, true, qt.Commentf("%s >= %s", since, limit))
})
}
+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(""))
}
+1 -2
View File
@@ -50,12 +50,11 @@ func (pos Position) IsValid() bool {
var positionStringFormatfunc func(p Position) string
func createPositionStringFormatter(formatStr string) func(p Position) string {
if formatStr == "" {
formatStr = "\":file::line::col\""
}
var identifiers = []string{":file", ":line", ":col"}
identifiers := []string{":file", ":line", ":col"}
var identifiersFound []string
for i := range formatStr {
-1
View File
@@ -29,5 +29,4 @@ func TestPositionStringFormatter(t *testing.T) {
c.Assert(createPositionStringFormatter("好::col")(pos), qt.Equals, "好:13")
c.Assert(createPositionStringFormatter("")(pos), qt.Equals, "\"/my/file.txt:12:13\"")
c.Assert(pos.String(), qt.Equals, "\"/my/file.txt:12:13\"")
}
-1
View File
@@ -25,5 +25,4 @@ func TestRemoveAccents(t *testing.T) {
c.Assert(string(RemoveAccents([]byte("Resumé"))), qt.Equals, "Resume")
c.Assert(string(RemoveAccents([]byte("Hugo Rocks!"))), qt.Equals, "Hugo Rocks!")
c.Assert(string(RemoveAccentsString("Resumé")), qt.Equals, "Resume")
}
+36 -5
View File
@@ -15,21 +15,52 @@ package types
import (
"encoding/json"
"fmt"
"html/template"
"reflect"
"github.com/spf13/cast"
)
// ToStringSlicePreserveString converts v to a string slice.
// If v is a string, it will be wrapped in a string slice.
// 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.
+2 -2
View File
@@ -24,9 +24,10 @@ 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)
}
func TestToString(t *testing.T) {
@@ -34,5 +35,4 @@ func TestToString(t *testing.T) {
c.Assert(ToString([]byte("Hugo")), qt.Equals, "Hugo")
c.Assert(ToString(json.RawMessage("Hugo")), qt.Equals, "Hugo")
}
+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
View File
@@ -61,5 +61,4 @@ func TestLexicographicSort(t *testing.T) {
})
c.Assert(s, qt.DeepEquals, []string{"A", "b", "Ba", "ba", "ba", "Bz"})
}
+7 -7
View File
@@ -14,12 +14,12 @@
package config
import (
"github.com/pkg/errors"
"sort"
"strings"
"sync"
"github.com/pkg/errors"
"github.com/gohugoio/hugo/common/types"
"github.com/gobwas/glob"
@@ -34,13 +34,17 @@ var DefaultBuild = Build{
WriteStats: false,
}
// Build holds some build related condfiguration.
// Build holds some build related configuration.
type Build struct {
UseResourceCacheWhen string // never, fallback, always. Default is fallback
// When enabled, will collect and write a hugo_stats.json with some build
// related aggregated data (e.g. CSS class names).
WriteStats bool
// Can be used to toggle off writing of the intellinsense /assets/jsconfig.js
// file.
NoJSConfigInAssets bool
}
func (b Build) UseResourceCache(err error) bool {
@@ -84,7 +88,6 @@ type Sitemap struct {
}
func DecodeSitemap(prototype Sitemap, input map[string]interface{}) Sitemap {
for key, value := range input {
switch key {
case "changefreq":
@@ -112,7 +115,6 @@ type Server struct {
}
func (s *Server) init() {
s.compiledInit.Do(func() {
for _, h := range s.Headers {
s.compiledHeaders = append(s.compiledHeaders, glob.MustCompile(h.For))
@@ -146,7 +148,6 @@ func (s *Server) MatchHeaders(pattern string) []types.KeyValueStr {
})
return matches
}
func (s *Server) MatchRedirect(pattern string) Redirect {
@@ -172,7 +173,6 @@ func (s *Server) MatchRedirect(pattern string) Redirect {
}
return Redirect{}
}
type Headers struct {
+5 -7
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",
})
@@ -57,7 +55,6 @@ func TestBuild(t *testing.T) {
c.Assert(b.UseResourceCache(herrors.ErrFeatureNotAvailable), qt.Equals, false)
c.Assert(b.UseResourceCache(errors.New("err")), qt.Equals, false)
c.Assert(b.UseResourceCache(nil), qt.Equals, false)
}
func TestServer(t *testing.T) {
@@ -98,7 +95,8 @@ status = 301
c.Assert(s.MatchHeaders("/foo.jpg"), qt.DeepEquals, []types.KeyValueStr{
{Key: "X-Content-Type-Options", Value: "nosniff"},
{Key: "X-Frame-Options", Value: "DENY"},
{Key: "X-XSS-Protection", Value: "1; mode=block"}})
{Key: "X-XSS-Protection", Value: "1; mode=block"},
})
c.Assert(s.MatchRedirect("/foo/bar/baz"), qt.DeepEquals, Redirect{
From: "/foo/**",
@@ -122,7 +120,8 @@ status = 301
c.Assert(s.MatchRedirect("/default/index.html"), qt.DeepEquals, Redirect{})
c.Assert(s.MatchRedirect("/default/"), qt.DeepEquals, Redirect{})
for _, errorCase := range []string{`[[server.redirects]]
for _, errorCase := range []string{
`[[server.redirects]]
from = "/**"
to = "/file"
status = 301`,
@@ -138,5 +137,4 @@ status = 301`,
c.Assert(err, qt.Not(qt.IsNil))
}
}
+113
View File
@@ -0,0 +1,113 @@
// 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) 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)
})
}
+103 -22
View File
@@ -14,13 +14,17 @@
package config
import (
"os"
"path/filepath"
"strings"
"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,15 +47,11 @@ 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.
@@ -60,15 +60,7 @@ func FromFile(fs afero.Fs, filename string) (Provider, error) {
if err != nil {
return nil, err
}
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
@@ -86,7 +78,6 @@ func readConfig(format metadecoders.Format, data []byte) (map[string]interface{}
RenameKeys(m)
return m, nil
}
func loadConfigFromFile(fs afero.Fs, filename string) (map[string]interface{}, error) {
@@ -98,6 +89,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() {
@@ -117,9 +204,3 @@ func init() {
func RenameKeys(m map[string]interface{}) {
keyAliases.Rename(m)
}
func newViper() *viper.Viper {
v := viper.New()
return v
}
+5
View File
@@ -14,6 +14,7 @@
package config
import (
"github.com/gohugoio/hugo/common/maps"
"github.com/gohugoio/hugo/common/types"
)
@@ -22,11 +23,15 @@ 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{})
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"}
+372
View File
@@ -0,0 +1,372 @@
// 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.
// TODO(bep) use this for something (docs etc.)
ConfigRootKeysSet = map[string]bool{
"build": true,
"caches": 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 {
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{}:
var p maps.Params = vv
v = p
maps.PrepareParams(p)
}
key, m := c.getNestedKeyAndMap(k, true)
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
}
func (c *defaultConfigProvider) Merge(k string, v interface{}) {
c.mu.Lock()
defer c.mu.Unlock()
k = strings.ToLower(k)
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.
for kk, vv := range p {
if pp, ok := vv.(maps.Params); ok {
if ppp, ok := c.root[kk]; ok {
ppp.(maps.Params).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)
if len(np) > 0 {
c.root[kk] = np
}
}
}
}
// Merge the rest.
c.root.Merge(p)
} else {
panic(fmt.Sprintf("unsupported type %T received in Merge", v))
}
return
}
switch vv := v.(type) {
case map[string]interface{}:
var p maps.Params = vv
v = p
maps.PrepareParams(p)
}
key, m := c.getNestedKeyAndMap(k, true)
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
}
}
current = next.(maps.Params)
}
return parts[len(parts)-1], current
}
+315
View File
@@ -0,0 +1,315 @@
// 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",
"b": "bv2",
})
})
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",
},
})
})
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 -3
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) {
@@ -69,7 +68,6 @@ simple = true
}
c.Assert(got, qt.All(qt.Equals), true)
}
func TestDecodeConfigFromTOMLCaseInsensitive(t *testing.T) {
@@ -95,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 -3
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")
@@ -65,5 +65,4 @@ func TestUseSettingsFromRootIfSet(t *testing.T) {
c.Assert(config.Disqus.Shortname, qt.Equals, "root_short")
c.Assert(config.GoogleAnalytics.ID, qt.Equals, "ga_root")
}
+11 -11
View File
@@ -16,15 +16,16 @@ package create
import (
"bytes"
"github.com/pkg/errors"
"io"
"os"
"os/exec"
"path/filepath"
"strings"
"github.com/gohugoio/hugo/common/paths"
"github.com/pkg/errors"
"github.com/gohugoio/hugo/common/hexec"
"github.com/gohugoio/hugo/hugofs/files"
"github.com/gohugoio/hugo/hugofs"
@@ -40,7 +41,7 @@ import (
func NewContent(
sites *hugolib.HugoSites, kind, targetPath string) error {
targetPath = filepath.Clean(targetPath)
ext := helpers.Ext(targetPath)
ext := paths.Ext(targetPath)
ps := sites.PathSpec
archetypeFs := ps.BaseFs.SourceFilesystems.Archetypes.Fs
sourceFs := ps.Fs.Source
@@ -105,7 +106,11 @@ func NewContent(
if editor != "" {
jww.FEEDBACK.Printf("Editing %s with %q ...\n", targetPath, editor)
cmd := exec.Command(editor, contentPath)
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
@@ -130,7 +135,6 @@ func newContentFromDir(
sites *hugolib.HugoSites,
targetFs afero.Fs,
cm archetypeMap, name, targetPath string) error {
for _, f := range cm.otherFiles {
meta := f.Meta()
filename := meta.Path()
@@ -195,11 +199,9 @@ func mapArcheTypeDir(
ps *helpers.PathSpec,
fs afero.Fs,
archetypeDir string) (archetypeMap, error) {
var m archetypeMap
walkFn := func(path string, fi hugofs.FileMetaInfo, err error) error {
if err != nil {
return err
}
@@ -307,7 +309,6 @@ func resolveContentPath(sites *hugolib.HugoSites, fs afero.Fs, targetPath string
}
if siteContentDir == "" {
}
if siteContentDir != "" {
@@ -323,7 +324,6 @@ func resolveContentPath(sites *hugolib.HugoSites, fs afero.Fs, targetPath string
}
return s.PathSpec.AbsPathify(filepath.Join(contentDir, targetPath)), s
}
}
// FindArchetype takes a given kind/archetype of content and returns the path

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