Compare commits

...

743 Commits

Author SHA1 Message Date
hugoreleaser a301f6b2ae releaser: Add release notes to /docs for release of 0.71.1
[ci skip]
2020-05-25 09:08:55 +00:00
hugoreleaser 646bc85088 releaser: Bump versions for release of 0.71.1
[ci skip]
2020-05-25 09:08:55 +00:00
hugoreleaser 5c0d10045d releaser: Add release notes for 0.71.1
[ci skip]
2020-05-25 09:08:55 +00:00
Bjørn Erik Pedersen 81f5633245 Add some more date test cases
See #7310
2020-05-24 14:35:49 +02:00
Bjørn Erik Pedersen 9698b0dab1 Fix RenderString vs render hooks
Fixes #7265
2020-05-24 13:20:57 +02:00
Bjørn Erik Pedersen 32344fe3db Prevent WARNINGs in RenderString 2020-05-24 12:49:45 +02:00
Bjørn Erik Pedersen 4d7fa9f114 Fix IsAncestor/IsDescendant for taxonomies
Fixes #7305
2020-05-24 12:35:45 +02:00
Bjørn Erik Pedersen a985efcecf Fix GetPage on section/bundle name overlaps
In the internal Radix we stored the directory based nodes without a traling slash, e.g. `/blog`.

The original motivation was probably to make it easy to do prefix searching: Give me all ancestors.

This, however have lead to some ambigouty with overlapping directory names.

This particular problem was, however, not possible to work around in an easy way, so from now we store these as `/blog/`.

Fixes #7301
2020-05-24 12:35:45 +02:00
Bjørn Erik Pedersen 6c3c6686f5 Fix Go template script escaping
Fixes #6695
2020-05-23 22:00:34 +02:00
Bjørn Erik Pedersen c34bf48560 Add a test helper 2020-05-22 10:57:25 +02:00
hugoreleaser 833d16d467 releaser: Prepare repository for 0.72.0-DEV
[ci skip]
2020-05-18 16:18:12 +00:00
hugoreleaser 06150c87be releaser: Add release notes to /docs for release of 0.71.0
[ci skip]
2020-05-18 16:05:47 +00:00
hugoreleaser 330e52ebe6 releaser: Bump versions for release of 0.71.0
[ci skip]
2020-05-18 16:05:47 +00:00
Bjørn Erik Pedersen 9e78235374 Release 0.71 2020-05-18 17:57:12 +02:00
hugoreleaser 7cd66c53b9 releaser: Add release notes for 0.71.0
Rename to *-ready.md to continue.
[ci skip]
2020-05-18 15:47:00 +00:00
Bjørn Erik Pedersen 723ec555e7 Fix Babel on Windows
Fixes #7251
2020-05-18 16:57:13 +02:00
Bjørn Erik Pedersen 518d149646 commands: Use WARN log level also for the early initialization
Fixes #7285
2020-05-18 16:52:45 +02:00
Bjørn Erik Pedersen e0e81b280f Merge commit 'c9403cbceaaeff53ff4833561f4eefe1dc1a405e' 2020-05-18 15:25:26 +02:00
Bjørn Erik Pedersen c9403cbcea Squashed 'docs/' changes from ec0abe052..6c2195936
6c2195936 Update featured.png
109a0fcca add len function to navigation side menu
39a356bc5 Revert "Add some rickrolls redirects"
b8393b1b5 Add some rickrolls redirects
2ce21c34b Update configuration-markup.md (add rel="noopener")
95bd7974e Disambiguate global and page resources
5e233dc4b Update base.md
959b9dc3a Fix typo on "where" page
aff8059a1 Release 0.70.0
44a172ac0 releaser: Add release notes to /docs for release of 0.70.0
1b01c8988 Release 0.70.0
5ece21c6c Merge commit '89044b8f8795f17c36396c67823183a20fc88139'
0894aec5b Rename transpileJS to babel
5da27c7a6 resources: Add JavaScript transpiling solution

git-subtree-dir: docs
git-subtree-split: 6c21959360
2020-05-18 15:24:58 +02:00
Bjørn Erik Pedersen 3cc41523be Update to Go 1.14.3 and Go 1.13.11 2020-05-16 23:25:45 +02:00
Bjørn Erik Pedersen 2fd0a5a678 Improve error message when no Babel installed 2020-05-16 12:51:35 +02:00
Cameron Little 6e051c053e Add test for headings render hook 2020-05-15 21:12:43 +02:00
Eli W. Hunter 423b8f2fb8 Add render template hooks for headings
This commit also

* Renames previous types to be non-specific. (e.g. hookedRenderer rather
  than linkRenderer)

Resolves #6713
2020-05-15 21:12:43 +02:00
Joe Mooring 991934497e Add math.Pow
Closes #7266
2020-05-14 10:00:31 +02:00
John Weldon 558c09305e deploy: Do not suppress .well-known/ directory
Deployments ignore directories with a leading `.`, but should not ignore
certain well known 'hidden' directories like `.well-known/`

Fixes #6691
2020-05-14 09:56:53 +02:00
Anthony Fok b69a36140f snap: Quote "@babel/cli" to solve build error
Cannot parse snapcraft.yaml from ~gohugoio/hugo/+git/hugo:master:
  while scanning for the next token found character ‘@’ that cannot
  start any token in “”, line 70, column 34: node-packages:
  [postcss-cli, @babel/cli] ^

Also:

- Upgrade to snapcraft 3.x by adding "base: core"
- Add "license: Apache-2.0"
2020-05-12 14:29:57 -06:00
Anthony Fok a0103864ab snap: Remove custom x-nodejs plugin
My changes have been merged into snapcraft upstream.

https://bugs.launchpad.net/snapcraft/+bug/1795531
https://bugs.launchpad.net/snapcraft/+bug/1797374

Revert "snap: Add custom x-nodejs plugin to support ppc64el and s390x"

This reverts commit 91f49c0700.
2020-05-12 14:27:57 -06:00
Cameron Little b342e8fbdb Upgrade chroma to 0.7.3 to fix invalid css
The new version of chroma includes a fix to not emit styles for tokens
without a class (which is invalid).

Fixes #7207
2020-05-09 17:05:14 +02:00
Daniel Tipping 6205d56b85 Use .Lastmod for og:updated_time
.Lastmod is the time at which the website was most recently updated,
rather than .Date which is the time at which the website content file
was created.
2020-05-07 18:42:20 +02:00
hugoreleaser a5039dddaf releaser: Prepare repository for 0.71.0-DEV
[ci skip]
2020-05-06 11:29:18 +00:00
hugoreleaser 7f47b99ea9 releaser: Add release notes to /docs for release of 0.70.0
[ci skip]
2020-05-06 11:16:40 +00:00
hugoreleaser b98e2f66b0 releaser: Bump versions for release of 0.70.0
[ci skip]
2020-05-06 11:16:40 +00:00
Bjørn Erik Pedersen 57ebab7c23 Release 0.70.0 2020-05-06 13:06:10 +02:00
hugoreleaser 0e314925fb releaser: Add release notes for 0.70.0
Rename to *-ready.md to continue.
[ci skip]
2020-05-06 10:24:22 +00:00
Bjørn Erik Pedersen e4621446ce Merge commit '89044b8f8795f17c36396c67823183a20fc88139' 2020-05-06 12:12:57 +02:00
Bjørn Erik Pedersen 89044b8f87 Squashed 'docs/' changes from 19f44e150..ec0abe052
ec0abe052 Update index.md
ed44339cd Update bio.md
cef04eb95 Minor edits
4d45dcc8d Submitting Digital.gov to the Hugo Showcase
d35126af7 Azure uses storage containers, not buckets; edited accordingly. (#1078)
9c249cc89 fix grammatical error
9728699a3 Release Hugo 0.69.2
cccabed0c Merge branch 'temp692'
3d0a740c4 releaser: Add release notes to /docs for release of 0.69.2
b760aceb1 HTTPS external links in docs
49e4631b0 Release 0.69.1
01f3da870 Merge branch 'temp691'
8280d85aa releaser: Add release notes to /docs for release of 0.69.1
40ea44d24 fix typo (#1088)
725f53643 Rebuild cache
80ee1efd9 Add KeyCDN Showcase
f253e906e docs: Fix typo in Hugo's Security Model
b3ffd1ad3 Mentioning a range is equivalent to foreach (#1086)
0c396911f Update jsonify function docs
376befc9a Fix typo (#1084)
4bdc9bc72 Mark .Page.UniqueID as deprecated and add .File.UniqueID
30a7b7bf2 Update hosting-on-github.md
c5db4ba2b Update postprocess.md
1121f74a5 Update install guide with Scoop extended
8988aa6fa Merge branch 'postprocess'
225d3f9c7 Release Hugo 0.69.0
4caf7a89a releaser: Add release notes to /docs for release of 0.69.0
664b2a0fa Document resources.PostProcess and buildStats
9737b34e9 docs: Regen docs helper
0fab3ba24 Merge commit 'da3c3e5fbd0de65f956618cd2e35401460a3cd02'
96dad83b1 Update hosting-on-aws-amplify.md
57eb27897 Merge commit 'c494c37a4523fbf2db6274dc87e0877fd5bec24b'
dcc7afef7 fix typo in getting started

git-subtree-dir: docs
git-subtree-split: ec0abe052b
2020-05-06 12:12:21 +02:00
Piotr Perzyna 01befcce35 deps: Update minify to v2.6.2
Fixes #6699
2020-05-03 17:29:26 +02:00
Tom 04b1a6d997 Add support for sort by boolean 2020-05-02 11:57:34 +02:00
Bjørn Erik Pedersen dd31e80007 deps: Update to Libsass 3.6.4
Fixes #7231
2020-05-01 19:14:04 +02:00
Bjørn Erik Pedersen 6add6d77b4 Rename transpileJS to babel
And add a test.

Updates #5764
2020-04-29 10:51:33 +02:00
Niek de Wit 2a171ff1c5 resources: Add JavaScript transpiling solution
Add a new pipe called TranspileJS which uses the Babel cli. This makes it possible for users to write ES6 JavaScript code and transpile it to ES5 during website generation so that the code still works with older browser versions.

Fixes #5764
2020-04-29 10:51:33 +02:00
Bjørn Erik Pedersen 67f920419a Disable a test locally
It has started to fail in LiteIDE for some reason (works from the shell and on CI).
2020-04-28 12:24:02 +02:00
Bjørn Erik Pedersen c03ea2b660 Fix some missing JS class collector cases
Fixes #7216
2020-04-27 19:06:29 +02:00
Michael Lynch fe60b7d9e4 Add diagnostic hints to init timeout message
Expand the text in the init timeout message to give the reader more hints as to what may be causing the issue.

The current error sent me on a wild goose chase trying to debug my shortcodes, but it turned out that the issue was just that I wasn't caching my resources/ directory on my build server. Once I found this blog post, I solved the issue in minutes:

https://www.henriksommerfeld.se/hugo-timeout-not-a-circular-loop-in-shortcode/

Googling the error message yields several additional posts from users who focus on loops in their shortcode when the problem seems to be overly-expensive builds.
2020-04-27 13:23:35 +02:00
hugoreleaser c2d9fd1ebe releaser: Prepare repository for 0.70.0-DEV
[ci skip]
2020-04-24 08:00:48 +00:00
hugoreleaser ec9dcf3048 releaser: Add release notes to /docs for release of 0.69.2
[ci skip]
2020-04-24 07:48:07 +00:00
hugoreleaser 03802ff3cb releaser: Bump versions for release of 0.69.2
[ci skip]
2020-04-24 07:48:07 +00:00
hugoreleaser 5e31198c98 releaser: Add release notes for 0.69.2
[ci skip]
2020-04-24 07:48:07 +00:00
Takayama Fumihiko 8d5766d417 Fix IsAncestor and IsDescendant when the same page is passed 2020-04-23 20:23:42 +02:00
SatowTakeshi 5c41f41ad4 deps: Update goldmark-highlighting
Recreate #7027
Fixes #6596
2020-04-23 18:48:52 +02:00
Takayama Fumihiko 27a4c4410c Fix IsAncestor and IsDescendant under subsection 2020-04-23 18:12:13 +02:00
hugoreleaser ade27699e5 releaser: Prepare repository for 0.70.0-DEV
[ci skip]
2020-04-22 08:07:03 +00:00
hugoreleaser 17661debb6 releaser: Add release notes to /docs for release of 0.69.1
[ci skip]
2020-04-22 07:55:01 +00:00
hugoreleaser 8549189e8e releaser: Bump versions for release of 0.69.1
[ci skip]
2020-04-22 07:55:01 +00:00
hugoreleaser c2c7a4ce5b releaser: Add release notes for 0.69.1
[ci skip]
2020-04-22 07:55:01 +00:00
Panagiotis Koursaris 49e6c8cb4e hugolib/filesystems: Fix typo in test suite 2020-04-21 23:16:36 +02:00
Bjørn Erik Pedersen f37e77f2d3 Fix class collector when running with --minify
Also add a related stresstest.

Fixes #7161
2020-04-21 21:00:52 +02:00
Bjørn Erik Pedersen 27af5a339a related: Fix toLower
Don't change the slice.

Fixes #7198
2020-04-21 17:46:26 +02:00
Bjørn Erik Pedersen b3c825756f Fix broken test 2020-04-21 16:44:35 +02:00
BurtonQin 5146dc614f tpl/tmplimpl/template: Change defer RLock to RUnlock 2020-04-21 13:23:31 +02:00
Boqin Qin 736f84b2d5 hugolib: Add Unlock before panic 2020-04-20 17:47:34 +02:00
Onur Yaman cd4d820201 docs: Fix typo in Hugo's Security Model 2020-04-18 14:16:42 +02:00
Niklas Fasching 2b28e5a9cb deps: Update go-org to v1.1.0
- inline source blocks and exports
- result blocks and source block :exports parameter
- fix: html escaping in example blocks
- #+LINK based links
2020-04-17 22:07:52 +02:00
Steve 102ec2da7a commands: Modify gen chromastyles to output all CSS classes
Chroma was updated to include a new function to output all CSS
classes without skipping any considered redundant with the current
style.

This will modify the `hugo gen chromastyles` command to use this new
function by default, which avoids potential problems if the style is
later modified.

Also includes requires the updated Chroma (v0.7.2).

Resolves #7167
2020-04-13 18:31:33 +02:00
Bjørn Erik Pedersen feaa582cbe deps: Update to goldmark v1.1.28
Fixes #7113
2020-04-13 16:55:23 +02:00
Bjørn Erik Pedersen ee67dbeff5 Fix query parameter handling in server fast render mode
There may be a simpler way to get to the raw path, but this will have to do for now.

Fixes #7163
2020-04-12 19:18:54 +02:00
hugoreleaser 4a3f2427ed releaser: Prepare repository for 0.70.0-DEV
[ci skip]
2020-04-10 09:19:20 +00:00
hugoreleaser 4205844bce releaser: Add release notes to /docs for release of 0.69.0
[ci skip]
2020-04-10 09:08:37 +00:00
hugoreleaser 9b55d13589 releaser: Bump versions for release of 0.69.0
[ci skip]
2020-04-10 09:08:37 +00:00
Bjørn Erik Pedersen 6f56a636f6 Update 0.69.0-relnotes.md 2020-04-10 10:58:36 +02:00
hugoreleaser 5ec7fa343a releaser: Add release notes for 0.69.0
Rename to *-ready.md to continue.
[ci skip]
2020-04-10 08:25:47 +00:00
Bjørn Erik Pedersen b7ff4dc23e docs: Regen docs helper 2020-04-10 09:07:41 +02:00
Bjørn Erik Pedersen da3c3e5fbd Squashed 'docs/' changes from 20d77860b..19f44e150
19f44e150 fix typo (#1077)
b66478084 Fix build listing improvements version

git-subtree-dir: docs
git-subtree-split: 19f44e150f
2020-04-10 09:06:04 +02:00
Bjørn Erik Pedersen 30748decf1 Merge commit 'da3c3e5fbd0de65f956618cd2e35401460a3cd02' 2020-04-10 09:06:04 +02:00
Bjørn Erik Pedersen 095bf64c99 Collect HTML elements during the build to use in PurgeCSS etc.
The main use case for this is to use with resources.PostProcess and resources.PostCSS with purgecss.

You would normally set it up to extract keywords from your templates, doing it from the full /public takes forever for bigger sites.

Doing the template thing misses dynamically created class names etc., and it's hard/impossible to set up in when using themes.

You can enable this in your site config:

```toml
[build]
  writeStats = true
```

It will then write a `hugo_stats.json` file to the project root as part of the build.

If you're only using this for the production build, you should consider putting it below `config/production`.

You can then set it up with PostCSS like this:

```js
const purgecss = require('@fullhuman/postcss-purgecss')({
    content: [ './hugo_stats.json' ],
    defaultExtractor: (content) => {
        let els = JSON.parse(content).htmlElements;
        return els.tags.concat(els.classes, els.ids);
    }
});

module.exports = {
    plugins: [
        require('tailwindcss'),
        require('autoprefixer'),
        ...(process.env.HUGO_ENVIRONMENT === 'production' ? [ purgecss ] : [])
    ]
};
```

Fixes #6999
2020-04-09 22:57:26 +02:00
Elliott Sales de Andrade 7791a804e2 deps: Update to latest emoji package 2020-04-08 12:56:14 +02:00
Helicer c774b230e9 Update hosting-on-aws-amplify.md
AWS Amplify now supports a GUI method for using the latest `hugo` version. Please feel free to modify my wording here, etc.
2020-04-07 22:48:55 +02:00
Bjørn Erik Pedersen 2f721f8ec6 Add basic "post resource publish support"
Fixes #7146
2020-04-07 21:59:20 +02:00
Cameron Moore 8568928aa8 tpl: Extend Jsonify to support options map
Add support for prefix and indent options used by json.MarshalIndent
from the Go stdlib.
2020-04-07 20:01:57 +02:00
Cameron Moore 1bc93021e3 tpl: Extend Jsonify to support optional indent parameter
Fixes #5040
2020-04-07 20:01:57 +02:00
Robert Fekete 7eba37ae9b Typo correction 2020-04-07 19:47:44 +02:00
Jay Williams efc61d6f3b commands: Use semver for min_version per recommendations
See https://github.com/gohugoio/hugoThemes#themetoml
2020-04-07 19:42:45 +02:00
Bjørn Erik Pedersen d8d6a25b57 modules: Fix hugo mod vendor for regular file mounts
Fixes #7140
2020-04-07 10:13:55 +02:00
Bjørn Erik Pedersen 9f12be54ee Revert "Revert "common/herrors: Fix typos in comments""
OK, I'm getting tired. Sorry for the noise.

This reverts commit 4437e918cd.
2020-04-06 01:07:57 +02:00
Bjørn Erik Pedersen 4437e918cd Revert "common/herrors: Fix typos in comments"
This reverts commit 1123711b09.
2020-04-06 01:06:27 +02:00
Shubham Shahare 4de3ecdc26 deps: Updateto gitmap v1.1.2
Fixes #6985
2020-04-04 23:24:33 +02:00
rnazmo 1123711b09 common/herrors: Fix typos in comments 2020-04-02 22:06:22 +02:00
Bjørn Erik Pedersen 3d84ef9720 Merge commit 'c494c37a4523fbf2db6274dc87e0877fd5bec24b' 2020-03-31 22:11:54 +02:00
Bjørn Erik Pedersen c494c37a45 Squashed 'docs/' changes from 2a0ea423d..20d77860b
20d77860b Remove the calibre image action
58f53654d Improve image metadata formatting (#1067)
c569f3657 Update theme
80e6d362e Update theme
d5806cca5 Update theme
efc5cb227 Remove broken link on "where" page (#1058)
443266076 Comments Alternatives (#1036)
9b480ebb7 Fix typo
1402365ee Fix included typo in build-options.md
3b5a76de1 Update index.md
1196c7695 Update index.md
1887ea1ed Update index.md
d0666e74e Hugo 0.68.3
d514cfac9 Merge branch 'temp683'
49e57362b releaser: Add release notes to /docs for release of 0.68.3
fa0ac3bf1 Merge branch 'temp682'
46993c209 Release 0.68.2
4c8d6d242 releaser: Add release notes to /docs for release of 0.68.2
9694f4d36 Update index.md
368a03754 Update index.md
0d997010c Merge branch 'temp681'
24138a9cd releaser: Add release notes to /docs for release of 0.68.1
7dd6cc788 Update index.md
b6125b4a8 Update build-options.md
a2dead37a Release 0.68.0
7cff41348 Merge branch 'temp680'
b3b37959c releaser: Add release notes to /docs for release of 0.68.0
0f98184b0 Some minify configuration adjustments
02219f787 Add minify config
efeea7be0 Allow headless bundles to list pages via $page.Pages and $page.RegularPages
7950d0ad1 Mention `resources` folder in the "Directory structure"  docs.

git-subtree-dir: docs
git-subtree-split: 20d77860b2
2020-03-31 22:10:45 +02:00
SatowTakeshi 9c9987535f helpers: Fix TrimShortHTML
Where some tags are siblings of p tag.

Fixes #7081
2020-03-28 11:10:25 +01:00
Bjørn Erik Pedersen 4a39564efe Fix IsDescendant/IsAncestor for overlapping section names
Fixes #7096
2020-03-26 16:11:36 +01:00
Stéphane Wirtel b6e097cfe6 fix typo in getting started 2020-03-24 17:31:37 +01:00
hugoreleaser 19a8accc9f releaser: Prepare repository for 0.69.0-DEV
[ci skip]
2020-03-24 12:16:13 +00:00
hugoreleaser 157669a0e6 releaser: Add release notes to /docs for release of 0.68.3
[ci skip]
2020-03-24 12:04:27 +00:00
hugoreleaser 8f49df946a releaser: Bump versions for release of 0.68.3
[ci skip]
2020-03-24 12:04:27 +00:00
hugoreleaser 1a68ad4e31 releaser: Add release notes for 0.68.3
[ci skip]
2020-03-24 12:04:27 +00:00
Bjørn Erik Pedersen 523d51948f Fix _build.list.local logic
Fixes #7089
2020-03-24 12:47:42 +01:00
hugoreleaser 971b28904b releaser: Prepare repository for 0.69.0-DEV
[ci skip]
2020-03-24 08:33:02 +00:00
hugoreleaser 63bbb40dfb releaser: Add release notes to /docs for release of 0.68.2
[ci skip]
2020-03-24 08:21:09 +00:00
hugoreleaser 73ae6d581d releaser: Bump versions for release of 0.68.2
[ci skip]
2020-03-24 08:21:09 +00:00
hugoreleaser e18a2ad3f4 releaser: Add release notes for 0.68.2
[ci skip]
2020-03-24 08:21:09 +00:00
Bjørn Erik Pedersen cfa73050a4 Fix cache reset for a page's collections on server live reload
Fixes #7085
2020-03-23 23:14:39 +01:00
hugoreleaser 244e49c0ea releaser: Prepare repository for 0.69.0-DEV
[ci skip]
2020-03-22 10:47:54 +00:00
hugoreleaser 98dc46e1a9 releaser: Add release notes to /docs for release of 0.68.1
[ci skip]
2020-03-22 10:36:42 +00:00
hugoreleaser 87dd5725de releaser: Bump versions for release of 0.68.1
[ci skip]
2020-03-22 10:36:42 +00:00
hugoreleaser 8c6a03a92b releaser: Add release notes for 0.68.1
[ci skip]
2020-03-22 10:36:42 +00:00
Bjørn Erik Pedersen 1ce3e7d521 releaser: Include "Revert" commits in change log 2020-03-21 18:51:29 +01:00
Bjørn Erik Pedersen c9dc316ad1 Revert "resources: Add data context to the key in ExecuteAsTemplate"
This reverts commit 18cb21ff2e.

Fixes #7064
2020-03-21 18:38:19 +01:00
hugoreleaser 1664a0e893 releaser: Prepare repository for 0.69.0-DEV
[ci skip]
2020-03-21 11:59:39 +00:00
hugoreleaser 1e67854b1a releaser: Add release notes to /docs for release of 0.68.0
[ci skip]
2020-03-21 11:47:37 +00:00
hugoreleaser e1b609af9b releaser: Bump versions for release of 0.68.0
[ci skip]
2020-03-21 11:47:37 +00:00
Bjørn Erik Pedersen 8e5566af6e Release 0.68.0 2020-03-21 12:41:25 +01:00
Bjørn Erik Pedersen 1005f754e0 Update 0.68.0-relnotes.md
[ci skip]
2020-03-21 12:40:46 +01:00
hugoreleaser efde7078ed releaser: Add release notes for 0.68.0
Rename to *-ready.md to continue.
[ci skip]
2020-03-21 11:33:28 +00:00
Bjørn Erik Pedersen 2ebb9f5484 Fix Go build version 2020-03-21 12:25:03 +01:00
Bjørn Erik Pedersen 7204b354a9 Some minify configuration adjustments 2020-03-20 20:35:57 +01:00
SatowTakeshi 574c2959b8 Add minify config
Fixes #6750
Updates #6892
2020-03-20 20:35:57 +01:00
Bjørn Erik Pedersen 99958f90fe Allow headless bundles to list pages via $page.Pages and $page.RegularPages
Fixes #7075
2020-03-20 18:28:55 +01:00
Bjørn Erik Pedersen 1d91d8e14b Update to Go 1.14.1 and 1.13.9
Fixes #7078
2020-03-20 18:25:54 +01:00
Carl Johnson 95f492114e Fix GetTerms nil pointer
Fixes #7061
2020-03-20 14:35:41 +01:00
Bjørn Erik Pedersen c947351d7c Merge commit 'aa54803a84208816e9c678359bd3f86760484ce0' 2020-03-20 09:19:29 +01:00
Bjørn Erik Pedersen aa54803a84 Squashed 'docs/' changes from 988f7d5c2..2a0ea423d
2a0ea423d Wrap cascade ex in code toggle
841573e3e Correcting reference for YouTube shortcode (#1055)
8f9378f93 Release 0.67.1
178759468 Merge branch 'temp671'
1b5ae9cb1 releaser: Add release notes to /docs for release of 0.67.1
a87aa44ec Don't set GOPATH when building from source
bd35dfbd8 Update hugo-deploy.md
527cf3b2b Adding a commercial search service
709844459 Add languageDirection to language configuration
523be23eb Fix include typo on v67 Release Notes
fdd7cc66c Adjust relase notes
613ba75e8 releaser: Add release notes to /docs for release of 0.67.0
3fb1376d1 docs: Doument the server config
6408a9b4e Merge commit '14e369b961943a0b977776899e24e8bea63834df'
10457ca46 deploy: Add include and exclude support for remote

git-subtree-dir: docs
git-subtree-split: 2a0ea423d7
2020-03-20 09:18:47 +01:00
Evan Anderson cc2a5d52a4 Pass directory name to filters in LstatIfPossible in the same way as Readdir 2020-03-19 20:09:34 +01:00
Elliott Sales de Andrade 52c159c452 Update to goldmark 1.1.25.
This fixes a bug, so there's a small change to tests.
2020-03-19 12:26:19 +01:00
Bjørn Erik Pedersen c7b6d74e89 resources: Fix scss vs css import regexp
Fixes #7063
2020-03-17 08:03:25 +01:00
Bjørn Erik Pedersen 1a8af7d4f0 Add workaround for regular CSS imports in SCSS
Fixes #7059
2020-03-16 23:21:44 +01:00
Bjørn Erik Pedersen 03b93bb988 Add .RegularPagesRecursive
Fixes #6411
2020-03-16 17:37:36 +01:00
hugoreleaser 94fb4dc3dd releaser: Prepare repository for 0.68.0-DEV
[ci skip]
2020-03-15 19:41:55 +00:00
hugoreleaser 4f44227bd8 releaser: Add release notes to /docs for release of 0.67.1
[ci skip]
2020-03-15 19:30:34 +00:00
hugoreleaser 99d36237c0 releaser: Bump versions for release of 0.67.1
[ci skip]
2020-03-15 19:30:33 +00:00
hugoreleaser e371162c3f releaser: Add release notes for 0.67.1
[ci skip]
2020-03-15 19:30:33 +00:00
Bjørn Erik Pedersen 5eadc4c0a8 metrics: Fix --templateMetricsHints
Also improve non-string comparisons.

Fixes #7048
2020-03-12 19:26:19 +01:00
Bjørn Erik Pedersen 18cb21ff2e resources: Add data context to the key in ExecuteAsTemplate
Fixes #7046
2020-03-11 22:21:16 +01:00
Bjørn Erik Pedersen df298558a5 Improve Tailwind/PostCSS error messages
Fixes #7041
Fixes #7042
2020-03-11 14:13:03 +01:00
Bjørn Erik Pedersen b1106f8715 deps: Update Blackfriday
Fixes #7039
2020-03-10 13:06:23 +01:00
Bjørn Erik Pedersen c0177fe2b2 resources: Try to fix a Go 1.15 go vet error 2020-03-10 12:29:09 +01:00
Tan Yuanhong 5914f91b6c Add languageDirection to language configuration
Fixes #6550
2020-03-10 10:10:58 +01:00
hugoreleaser 5b4659fa0b releaser: Prepare repository for 0.68.0-DEV
[ci skip]
2020-03-09 20:47:30 +00:00
hugoreleaser 7f1da3efcd releaser: Add release notes to /docs for release of 0.67.0
[ci skip]
2020-03-09 20:35:43 +00:00
hugoreleaser f7d4b01c6d releaser: Bump versions for release of 0.67.0
[ci skip]
2020-03-09 20:35:43 +00:00
Bjørn Erik Pedersen b809b9680d Update 0.67.0-relnotes.md 2020-03-09 21:26:43 +01:00
hugoreleaser a9c91361c2 releaser: Add release notes for 0.67.0
Rename to *-ready.md to continue.
[ci skip]
2020-03-09 20:11:33 +00:00
Bjørn Erik Pedersen 63393230c9 docs: Doument the server config 2020-03-09 20:36:00 +01:00
Bjørn Erik Pedersen 6b61f2a5bb Merge commit '14e369b961943a0b977776899e24e8bea63834df' 2020-03-09 20:21:17 +01:00
Bjørn Erik Pedersen 14e369b961 Squashed 'docs/' changes from 341ecabb2..988f7d5c2
988f7d5c2 Document default `enableInlineShortcodes` value
0f604a345 Fix typo in 0.66.0 release note
26fc74fe3 How to access individual EXIF data tags
d5d3bad9a Fix localhost links
fa6921213 Update index.md
5bf558f78 Release 0.66.0
74ccdaaf5 Merge branch 'temp660'
75faa478b releaser: Add release notes to /docs for release of 0.66.0
c4a4a9922 docs: Regen CLI docs
0624ac198 Add build.UseResourceCacheWhen
58a8d7cd1 Add build options documentation
d926c595e fix typo
99713d44b resources: Add basic @import support to resources.PostCSS
224b96cf7 deploy: Implement include/exclude filters for deploy
eb1a00050 Adjusting description; WordPress with capitalized P
91d8efa22 Add another tool for migration from the Wordpress
a6938a4ac Adjust showcase description
a9c0a0a69 Adjust showcase
e5af08aa6 Adding Aether as a proposed showcase item.
0013daa34 Add hugo.IsProduction function
34c419ef3 tpl: Add math.Sqrt
5bdab0ebd Update minification.md
9039332e2 Hugo 0.65.3
1400caf3a Merge branch 'temp653'
9796bb337 releaser: Add release notes to /docs for release of 0.65.3
65b26598f Fix typo
23aa57d80 Fix crashes for 404 in IsAncestor etc.
42c54bc6c 0.65.2
67fd5c1f6 Merge branch 'temp652'
d820ac017 releaser: Add release notes to /docs for release of 0.65.2
51f0888ff Release 0.65.1
91e95260c releaser: Add release notes to /docs for release of 0.65.1
1880ebf05 fix broken link on internal.md
ffaa33889 Update migrations.md
de4d64675 Another tool for migration from Medium platform
90b178d77 releaser: Add release notes to /docs for release of 0.65.1
6925cda30 Handle corner case with rendering text as code in URL
3cb4b19dd Release 0.65.0
7a600cb99 Merge branch 'temp650'
ef9531ff6 releaser: Add release notes to /docs for release of 0.65.0
9bc19606f docs: Regenerate CLI docs
d4a886ed2 Add Page.GetTerms
a3bf273a5 fix broken link on use-modules.md
001f52f4e Fix mage URL in development.md
eef72e887 Merge commit '4b670bc8cc38103c2c60e5090c2f56bf30832b8d'
b18a76631 commands: Support "hugo mod get -u ./..."

git-subtree-dir: docs
git-subtree-split: 988f7d5c2d
2020-03-09 20:19:32 +01:00
Bjørn Erik Pedersen 6cceef65c2 Fix ambigous error on site.GetPage
Fixes #7016
2020-03-09 16:11:50 +01:00
Bjørn Erik Pedersen ffcb4aeb8e Fix handling of HTML files without front matter
This means that any HTML file inside /content will be treated as a regular file.

If you want it processes with shortcodes and a layout, add front matter.

The defintion of an HTML file here is:

* File with extension .htm or .html
* With first non-whitespace character "<" that isn't a HTML comment.

This is in line with the documentation.

Fixes #7030
Fixes #7028
See #6789
2020-03-09 15:01:55 +01:00
satotake 8279d2e227 Support unComparable args of uniq/complement/in
Fixes #6105
2020-03-09 13:32:38 +01:00
Sam Smith c4fa2f0799 tpl: Fix error with unicode in file paths
Add url.QueryUnescape before reading file which allows files with
unicode in their paths to be read.

Fixes #6996
2020-03-09 13:31:04 +01:00
Bjørn Erik Pedersen 108314444b Add HTTP header support for the dev server
Fixes #7031
2020-03-08 19:57:30 +01:00
David Jones 51e178a6a2 deploy: Add include and exclude support for remote 2020-03-08 17:35:32 +01:00
hugoreleaser cb12f41a96 releaser: Prepare repository for 0.67.0-DEV
[ci skip]
2020-03-03 15:31:19 +00:00
hugoreleaser 78c3c78fca releaser: Add release notes to /docs for release of 0.66.0
[ci skip]
2020-03-03 15:19:36 +00:00
hugoreleaser 713132cd4b releaser: Bump versions for release of 0.66.0
[ci skip]
2020-03-03 15:19:36 +00:00
Bjørn Erik Pedersen bbaefd7e3e Update 0.66.0-relnotes.md 2020-03-03 16:10:42 +01:00
hugoreleaser cc1a718860 releaser: Add release notes for 0.66.0
Rename to *-ready.md to continue.
[ci skip]
2020-03-03 14:55:26 +00:00
Bjørn Erik Pedersen 6a34f88dcc Skip some tests on CircleCI 2020-03-03 15:45:13 +01:00
Carl Johnson ae383f04c8 {{ in }} should work with html.Template type
Fixes #7002
2020-03-03 13:37:42 +01:00
Bjørn Erik Pedersen ee31e61fb0 docs: Regen CLI docs 2020-03-03 13:36:35 +01:00
Bjørn Erik Pedersen 760a87a45a commands: Add --all flag to hugo mod clean 2020-03-03 13:29:58 +01:00
Bjørn Erik Pedersen 3d3fa5c3fe Add build.UseResourceCacheWhen
Fixes #6993
2020-03-03 13:29:58 +01:00
Anthony Fok ee3d02134d Update dependency list in README.md
to include only runtime dependencies,
i.e. what is in the released binary.
2020-03-02 22:51:20 -07:00
Bjørn Erik Pedersen 8947c3fa0b Fix ref/relref short lookup for pages in sub-folder
Fixes #6952
2020-03-02 21:08:28 +01:00
Sam Smith d7798906d8 tpl: Change error message on missing resource
Fixes #6942
2020-03-02 18:46:14 +01:00
Bjørn Erik Pedersen 305ce1c9ec resources: Add full filename to image when processing fails
Fixes #7000
2020-03-02 12:39:26 +01:00
Bjørn Erik Pedersen 3e9db2ad95 hugolib: Fix error handling in page collector
Fixes #6988
2020-03-02 11:07:09 +01:00
Anthony Fok 449deb7f9c Update dependency list in README 2020-03-02 01:10:42 -07:00
Bjørn Erik Pedersen 1746e8a9b2 Fix ref/relRef regression for relative refs from bundles
Fixes #6952
2020-02-29 18:32:06 +01:00
Bjørn Erik Pedersen 6f48146e75 identity: Fix potential infinite recursion in server change detection
Fixes #6986
2020-02-29 15:12:56 +01:00
Bjørn Erik Pedersen b0d850321e Fix rebuild logic when editing template using a base template
We have been doing too much work in that case.

Fixes #6968
2020-02-28 14:14:55 +01:00
Bjørn Erik Pedersen b66d38c419 resources: Add basic @import support to resources.PostCSS
This commit also makes the HUGO_ENVIRONMENT environment variable available to Node.

Fixes #6957
Fixes #6961
2020-02-27 11:47:24 +01:00
Robert van Gent 05a74eaec0 deploy: Implement include/exclude filters for deploy
Fixes #6922
2020-02-27 07:26:05 +01:00
Bjørn Erik Pedersen 33ae621083 Update to Go 1.14 and 1.13.8
Fixes #6958
2020-02-26 17:33:11 +01:00
Joshua Wong 1352bc880d Add hugo.IsProduction function
Fixes #6873
2020-02-25 17:58:07 +01:00
Chris Dennis d184e5059c tpl: Add math.Sqrt
Fixes #6941
2020-02-24 23:45:04 +01:00
hugoreleaser 322c285ba2 releaser: Prepare repository for 0.66.0-DEV
[ci skip]
2020-02-23 10:09:29 +00:00
hugoreleaser 211ba42a95 releaser: Add release notes to /docs for release of 0.65.3
[ci skip]
2020-02-23 09:58:31 +00:00
hugoreleaser 0ac528d746 releaser: Bump versions for release of 0.65.3
[ci skip]
2020-02-23 09:58:31 +00:00
hugoreleaser d8bde266c1 releaser: Add release notes for 0.65.3
[ci skip]
2020-02-23 09:58:31 +00:00
Bjørn Erik Pedersen 0bd6356c6d Fix panic when home page is drafted
Fixes #6927
2020-02-23 00:11:10 +01:00
satotake ca68abf0bc Fix goldmark toc rendering
Previously gordmark-based TOC renderes only `KindText` and `KindString`

This commit expands target node with Goldmark's renderer

I am not sure of what are expected results as TOC contents in some (rare) cases
but Blackfriday's behaviours are fundamentally respected.

For example,
- image `[image text](link)` is rendered as `<img>` tag
- GFM AutoLink `gohugo.io` is rendered as text

* Render AutoLink as <a> tag as Blackfriday does

Fixes #6736
Fixes #6809
2020-02-22 18:06:30 +01:00
Bjørn Erik Pedersen a524124beb Fix crashes for 404 in IsAncestor etc.
Fixes #6931
2020-02-22 13:36:04 +01:00
hugoreleaser c1eb625124 releaser: Add release notes to /docs for release of 0.65.2
[ci skip]
2020-02-21 10:10:11 +00:00
hugoreleaser 1510f07780 releaser: Bump versions for release of 0.65.2
[ci skip]
2020-02-21 10:10:11 +00:00
hugoreleaser aa2ef45421 releaser: Add release notes for 0.65.2
[ci skip]
2020-02-21 10:10:11 +00:00
Bjørn Erik Pedersen 76b2afe642 Apply missing go fmt 2020-02-21 10:12:33 +01:00
Bjørn Erik Pedersen f460530347 Fix panic on no output formats
A page needs its output formats even if it should not be rendered or its resources should not be published.

Fixes #6924
2020-02-21 09:41:39 +01:00
Bjørn Erik Pedersen 4c2a0de412 Fix panic in 404.Parent
Fixes #6924
2020-02-21 08:14:08 +01:00
hugoreleaser 6be6684cc5 releaser: Add release notes to /docs for release of 0.65.1
[ci skip]
2020-02-20 13:42:26 +00:00
hugoreleaser dbaa15d40f releaser: Bump versions for release of 0.65.1
[ci skip]
2020-02-20 13:42:26 +00:00
hugoreleaser a449e87da7 releaser: Add release notes for 0.65.1
[ci skip]
2020-02-20 13:42:26 +00:00
Bjørn Erik Pedersen 7ef5a4c83e hugolib: Fix 2 Paginator.Pages taxonomy regressions
Fixes #6921
Fixes #6918
2020-02-20 14:13:04 +01:00
Bjørn Erik Pedersen a70bbd0696 hugolib: Fix deletion of orphaned sections
Avoid deleting inside the recursive walk.

Fixes #6920
2020-02-20 13:40:16 +01:00
hugoreleaser 24afe2b822 releaser: Add release notes to /docs for release of 0.65.0
[ci skip]
2020-02-20 08:11:06 +00:00
hugoreleaser 9fd7d3957e releaser: Bump versions for release of 0.65.0
[ci skip]
2020-02-20 08:11:06 +00:00
hugoreleaser c45025cb90 releaser: Add release notes for 0.65.0 2020-02-20 09:01:06 +01:00
Bjørn Erik Pedersen a5ebdf7d17 docs: Regenerate CLI docs 2020-02-19 22:28:06 +01:00
Bjørn Erik Pedersen 9bdedb251c Fix lazy publishing with publishResources=false
Fixes #6914
2020-02-19 18:22:41 +01:00
Bjørn Erik Pedersen dce210ab56 modules: Improve "hugo mod clean"
* Only clean project modules
* Optional glob pattern of module paths to clean

Closes #6907
2020-02-19 17:14:35 +01:00
Bjørn Erik Pedersen 0b96aba022 commands: Add "hugo mod verify"
See #6907
2020-02-19 17:14:35 +01:00
Bjørn Erik Pedersen fa520a2d98 Add Page.GetTerms
Fixes #6905
2020-02-19 14:52:23 +01:00
Bjørn Erik Pedersen 4b670bc8cc Squashed 'docs/' changes from 16753a78d..341ecabb2
341ecabb2 Update lookup-order.md
bfabd8ce8 Update homepage.md
7a1e0b742 Update shortcodes.md
e8bf22497 HTTPS links to Vimeo embeds
a9d0e7c68 Revise the wildly inaccurate types doc
af33bb724 netlify: Bump version
f4251583e Merge branch 'temp641'
4dcda861d releaser: Add release notes to /docs for release of 0.64.1
92bd0b1f5 Update errorf.md

git-subtree-dir: docs
git-subtree-split: 341ecabb29
2020-02-19 09:16:56 +01:00
Bjørn Erik Pedersen 82029c1ec9 Merge commit '4b670bc8cc38103c2c60e5090c2f56bf30832b8d' 2020-02-19 09:16:56 +01:00
Bjørn Erik Pedersen 7489a86459 Add a list terms benchmark
See #6905
2020-02-19 09:08:32 +01:00
Bjørn Erik Pedersen da54787cfa Handle disabled RSS even if it's defined in outputs
See https://github.com/gohugoio/hugo/issues/6897#issuecomment-587947078
2020-02-19 09:08:31 +01:00
Elliott Sales de Andrade c7975b48b6 Fix goMinorVersion on non-final Go releases
This should work for alpha/beta/rc releases.
2020-02-19 08:46:21 +01:00
Bjørn Erik Pedersen b2dcd53e3c Use the tree for taxonomy.Pages() 2020-02-18 19:47:45 +01:00
Bjørn Erik Pedersen 36983e6189 Add some cagegories to the site collections benchmarks 2020-02-18 18:52:35 +01:00
Bjørn Erik Pedersen d73e37387c tpl: Adjust the RSS taxonomy logic
See #6909
2020-02-18 17:29:46 +01:00
Bjørn Erik Pedersen aa3e183056 tpl: Fix RSS template for the terms listing
Fixes #6909
2020-02-18 16:55:30 +01:00
Bjørn Erik Pedersen 1b7acfe763 Fix taxonomy
Recently introduced in master.

See https://github.com/gohugoio/hugo/issues/6897#issuecomment-587499907
2020-02-18 16:43:36 +01:00
Bjørn Erik Pedersen 19e12caf8c Fix RenderString for pages without content
Fixes #6882
2020-02-18 14:08:59 +01:00
Bjørn Erik Pedersen 20f2211fce modules: Do not try to get local themes in "hugo mod get"
Fixes #6893
2020-02-18 14:08:58 +01:00
satotake a21a9373e0 deps: Update goldmark-highlighting
See  #6901
2020-02-18 14:08:46 +01:00
Bjørn Erik Pedersen 775c7c2474 commands: Support "hugo mod get -u ./..."
Fixes #6828
2020-02-18 12:17:16 +01:00
Bjørn Erik Pedersen eada236f87 Introduce a tree map for all content
This commit introduces a new data structure to store pages and their resources.

This data structure is backed by radix trees.

This simplies tree operations, makes all pages a bundle,  and paves the way for #6310.

It also solves a set of annoying issues (see list below).

Not a motivation behind this, but this commit also makes Hugo in general a little bit faster and more memory effective (see benchmarks). Especially for partial rebuilds on content edits, but also when taxonomies is in use.

```
name                                   old time/op    new time/op    delta
SiteNew/Bundle_with_image/Edit-16        1.32ms ± 8%    1.00ms ± 9%  -24.42%  (p=0.029 n=4+4)
SiteNew/Bundle_with_JSON_file/Edit-16    1.28ms ± 0%    0.94ms ± 0%  -26.26%  (p=0.029 n=4+4)
SiteNew/Tags_and_categories/Edit-16      33.9ms ± 2%    21.8ms ± 1%  -35.67%  (p=0.029 n=4+4)
SiteNew/Canonify_URLs/Edit-16            40.6ms ± 1%    37.7ms ± 3%   -7.20%  (p=0.029 n=4+4)
SiteNew/Deep_content_tree/Edit-16        56.7ms ± 0%    51.7ms ± 1%   -8.82%  (p=0.029 n=4+4)
SiteNew/Many_HTML_templates/Edit-16      19.9ms ± 2%    18.3ms ± 3%   -7.64%  (p=0.029 n=4+4)
SiteNew/Page_collections/Edit-16         37.9ms ± 4%    34.0ms ± 2%  -10.28%  (p=0.029 n=4+4)
SiteNew/Bundle_with_image-16             10.7ms ± 0%    10.6ms ± 0%   -1.15%  (p=0.029 n=4+4)
SiteNew/Bundle_with_JSON_file-16         10.8ms ± 0%    10.7ms ± 0%   -1.05%  (p=0.029 n=4+4)
SiteNew/Tags_and_categories-16           43.2ms ± 1%    39.6ms ± 1%   -8.35%  (p=0.029 n=4+4)
SiteNew/Canonify_URLs-16                 47.6ms ± 1%    47.3ms ± 0%     ~     (p=0.057 n=4+4)
SiteNew/Deep_content_tree-16             73.0ms ± 1%    74.2ms ± 1%     ~     (p=0.114 n=4+4)
SiteNew/Many_HTML_templates-16           37.9ms ± 0%    38.1ms ± 1%     ~     (p=0.114 n=4+4)
SiteNew/Page_collections-16              53.6ms ± 1%    54.7ms ± 1%   +2.09%  (p=0.029 n=4+4)

name                                   old alloc/op   new alloc/op   delta
SiteNew/Bundle_with_image/Edit-16         486kB ± 0%     430kB ± 0%  -11.47%  (p=0.029 n=4+4)
SiteNew/Bundle_with_JSON_file/Edit-16     265kB ± 0%     209kB ± 0%  -21.06%  (p=0.029 n=4+4)
SiteNew/Tags_and_categories/Edit-16      13.6MB ± 0%     8.8MB ± 0%  -34.93%  (p=0.029 n=4+4)
SiteNew/Canonify_URLs/Edit-16            66.5MB ± 0%    63.9MB ± 0%   -3.95%  (p=0.029 n=4+4)
SiteNew/Deep_content_tree/Edit-16        28.8MB ± 0%    25.8MB ± 0%  -10.55%  (p=0.029 n=4+4)
SiteNew/Many_HTML_templates/Edit-16      6.16MB ± 0%    5.56MB ± 0%   -9.86%  (p=0.029 n=4+4)
SiteNew/Page_collections/Edit-16         16.9MB ± 0%    16.0MB ± 0%   -5.19%  (p=0.029 n=4+4)
SiteNew/Bundle_with_image-16             2.28MB ± 0%    2.29MB ± 0%   +0.35%  (p=0.029 n=4+4)
SiteNew/Bundle_with_JSON_file-16         2.07MB ± 0%    2.07MB ± 0%     ~     (p=0.114 n=4+4)
SiteNew/Tags_and_categories-16           14.3MB ± 0%    13.2MB ± 0%   -7.30%  (p=0.029 n=4+4)
SiteNew/Canonify_URLs-16                 69.1MB ± 0%    69.0MB ± 0%     ~     (p=0.343 n=4+4)
SiteNew/Deep_content_tree-16             31.3MB ± 0%    31.8MB ± 0%   +1.49%  (p=0.029 n=4+4)
SiteNew/Many_HTML_templates-16           10.8MB ± 0%    10.9MB ± 0%   +1.11%  (p=0.029 n=4+4)
SiteNew/Page_collections-16              21.4MB ± 0%    21.6MB ± 0%   +1.15%  (p=0.029 n=4+4)

name                                   old allocs/op  new allocs/op  delta
SiteNew/Bundle_with_image/Edit-16         4.74k ± 0%     3.86k ± 0%  -18.57%  (p=0.029 n=4+4)
SiteNew/Bundle_with_JSON_file/Edit-16     4.73k ± 0%     3.85k ± 0%  -18.58%  (p=0.029 n=4+4)
SiteNew/Tags_and_categories/Edit-16        301k ± 0%      198k ± 0%  -34.14%  (p=0.029 n=4+4)
SiteNew/Canonify_URLs/Edit-16              389k ± 0%      373k ± 0%   -4.07%  (p=0.029 n=4+4)
SiteNew/Deep_content_tree/Edit-16          338k ± 0%      262k ± 0%  -22.63%  (p=0.029 n=4+4)
SiteNew/Many_HTML_templates/Edit-16        102k ± 0%       88k ± 0%  -13.81%  (p=0.029 n=4+4)
SiteNew/Page_collections/Edit-16           176k ± 0%      152k ± 0%  -13.32%  (p=0.029 n=4+4)
SiteNew/Bundle_with_image-16              26.8k ± 0%     26.8k ± 0%   +0.05%  (p=0.029 n=4+4)
SiteNew/Bundle_with_JSON_file-16          26.8k ± 0%     26.8k ± 0%   +0.05%  (p=0.029 n=4+4)
SiteNew/Tags_and_categories-16             273k ± 0%      245k ± 0%  -10.36%  (p=0.029 n=4+4)
SiteNew/Canonify_URLs-16                   396k ± 0%      398k ± 0%   +0.39%  (p=0.029 n=4+4)
SiteNew/Deep_content_tree-16               317k ± 0%      325k ± 0%   +2.53%  (p=0.029 n=4+4)
SiteNew/Many_HTML_templates-16             146k ± 0%      147k ± 0%   +0.98%  (p=0.029 n=4+4)
SiteNew/Page_collections-16                210k ± 0%      215k ± 0%   +2.44%  (p=0.029 n=4+4)
```

Fixes #6312
Fixes #6087
Fixes #6738
Fixes #6412
Fixes #6743
Fixes #6875
Fixes #6034
Fixes #6902
Fixes #6173
Fixes #6590
2020-02-18 09:49:42 +01:00
Bjørn Erik Pedersen e5329f13c0 Another benchmark rename 2020-02-18 09:48:36 +01:00
Bjørn Erik Pedersen 5b145ddc4c Rename the Edit benchmarks
To make them easier to filter out.
2020-02-18 09:45:21 +01:00
satotake 3c568ad013 markup/highlight: Fix chroma highlight
* Use chroma.Coalesce
* Escape code strings if lexer is nil

Fixes #6877
Fixes #6856
2020-02-17 14:59:26 +01:00
Bjørn Erik Pedersen 54bdcaacae Refactor a benchmark to make it runnable as test 2020-02-17 09:24:15 +01:00
Bjørn Erik Pedersen 1622510a5c Add benchmark for content edits 2020-02-17 09:05:37 +01:00
Bjørn Erik Pedersen 56d0b65887 Add "go mod verify" to build scripts 2020-02-16 00:15:58 +01:00
Jaymo Kang 75c3787fc2 Add git to Dockerfile
Needed for GitInfo.
2020-02-14 16:49:20 +01:00
Bjørn Erik Pedersen 9babb1f0c4 deps: Update go.sum 2020-02-14 10:18:56 +01:00
Mark Rosemaker 8a5124d6b3 commands: Rename doWithCommandeer to cfgInit/cfgSetAndInit
This will make it clearer what it does and make the code more consistent.
2020-02-13 00:37:49 +01:00
Bjørn Erik Pedersen 898a0a96af deps: Update golibsass
Fixes #6885
2020-02-12 18:56:47 +01:00
Bjørn Erik Pedersen 3b721110d5 Shuffle test files before insertion 2020-02-10 12:03:41 +01:00
Bjørn Erik Pedersen 40ba7e6d63 Update to LibSass v3.6.3
Fixes #6862
2020-02-10 10:42:05 +01:00
hugoreleaser 4f43c9022a releaser: Prepare repository for 0.65.0-DEV
[ci skip]
2020-02-09 20:53:18 +00:00
hugoreleaser c327e75d05 releaser: Add release notes to /docs for release of 0.64.1
[ci skip]
2020-02-09 20:44:34 +00:00
hugoreleaser 8bd8d4fe9a releaser: Bump versions for release of 0.64.1
[ci skip]
2020-02-09 20:44:34 +00:00
hugoreleaser ad7c38cd66 releaser: Add release notes for 0.64.1
[ci skip]
2020-02-09 20:44:34 +00:00
Bjørn Erik Pedersen b78576fd38 hugofs: Fix mount with hole regression
Fixes #6854
2020-02-09 21:35:39 +01:00
Bjørn Erik Pedersen 18888e09bb Fix bundle resource ordering regression
Introduced in Hugo 0.64.0

Fixes #6851
2020-02-09 21:35:39 +01:00
Bjørn Erik Pedersen 1e5eb8679e Merge commit '3c0036805d64fdd8290f1c4a31371780ff3ea365' 2020-02-06 13:03:30 +01:00
Bjørn Erik Pedersen 3c0036805d Squashed 'docs/' changes from bd0e15bb6..16753a78d
16753a78d remove kaiju from comments.md
25906f6ad Hugo 0.64.0
aacc7a130 releaser: Add release notes to /docs for release of 0.64.0
2243afe90 Explain Ace/Amber support has been removed
293c9496a Document the hugo function
479890f9b Update comments.md
ceab41097 Update theme
9a95876c7 Remove note
696543e13 Update usage.md
a04bab2b9 Release 0.63.2
ccaed74b5 Merge branch 'temp632'
623b363c5 releaser: Add release notes to /docs for release of 0.63.2
39ce6f50e releaser: Add release notes to /docs for release of 0.63.2
9175ac2ca Another theme fix
88c264251 Rebuild _vendor
e739dc3a8 Release 0.63.1
129ecac84 Merge branch 'temp631'
bcd7c1154 releaser: Add release notes to /docs for release of 0.63.1
e4f0d9285 releaser: Add release notes to /docs for release of 0.63.1
6a40124d6 Update theme
c486747de Params cleanup
c408c4334 netlify: Bump to 0.63.0
7e8a48be8 Adjust base template docs
a5920e9aa Adjust release notes
d4d25c524 Merge branch 'temp63'
16d981721 releaser: Add release notes to /docs for release of 0.63.0
08ab681d1 releaser: Add release notes to /docs for release of 0.63.0
90feaac39 docs, output: Add base template lookup variant to docs.json
afe2b4399 docs, output: Add base template lookup variant to docs.json
1f7466a76 docs: Regen docs helper
7ceefb94a docs: Regen docs helper
ee14087cd Remove typo from RenderString.md
6daf333d3 Remove the calibreapp action
682f710d7 docs: Updating 'submodule add' command in "Host on GitHub" to use https instead of ssh.
ef57b2dae Improve documentation on slug behavior
835ddd9c2 Fix broken link
137a32f90 Fixed typo in content-management/page-resources
936633e25 Fixed spelling error, "wich" -> "which"
a559d41e3 Using a Different Version of Hugo in AWS Amplify
2ee83402d Update rss.md
f900a2ce0 Add render-image code example and edit wording
bd0a0207c Change wording on Page Resources documentation
d213b4599 linuxbrew was renamed to homebrew (#1004)
dcb0925f8 Update index.md
789416a08 Release 0.62.2
2dc66f13c releaser: Add release notes to /docs for release of 0.62.2
813fbc865 releaser: Add release notes to /docs for release of 0.62.2
ed5b07df3 docs: Document the new autoHeadingIDType setting
02d4747e5 docs: Document the new autoHeadingIDType setting
406a8a9a6 docs: Regenerate docshelper
065319786 docs: Regenerate docshelper
61d540021 Merge commit '26f1458a2df6b55eee3a5de46f5fec23a43a7c7d'
7cac5909b releaser: Add release notes to /docs for release of 0.62.1
6e30e01a2 releaser: Add release notes to /docs for release of 0.62.0
2694dcdd8 Merge commit '8a4005cf2b0ef34265ff8051a6b76226685fc226'
115dd6782 docs: More on hooks
f4460fd54 tpl: Do not return any value in errorf
3587d2998 tpl: Add a warnf template func
7c9b02e30 docs: Regen docshelper
a7bfdeb24 Fix incorrect MIME type from image/jpg to image/jpeg
1a6089cfe Preserve HTML Text for link render hooks
4544a998c docs: Footnote
c42733258 Add render template hooks for links and images
0d8bec78a Merge commit '2e711a28c71e8667258e5ab824f9b9a71c261b0a'
3974c326c markup/tableofcontents: Add config option for ordered list
8c2bd1a62 releaser: Add release notes to /docs for release of 0.61.0
f00b2d507 releaser: Add release notes to /docs for release of 0.60.1
9a5109838 releaser: Add release notes to /docs for release of 0.60.0
d2c222f71 Add Goldmark as the new default markdown handler
df96f9efa Update homepage.md
f17e67b4b tpl/collections: Allow dict to create nested structures
5f923768a Merge commit 'efc0b1bb6c6564f54d596467dbc6a18cb206954e'
8a861bf16 Support Go time format strings in permalinks
bbb8c4fea releaser: Add release notes to /docs for release of 0.59.1
9d9070dda releaser: Add release notes to /docs for release of 0.59.0
98716176b Merge commit '5ac0f751aa47e52625662215f66efa99a6abfc2e'
2057ba4c5 Merge commit '5070ba6c9e6c492deade3c30cfe769b9dbf7151d'
c98bcff07 Merge commit 'b9bd35d72e14932fb6588ff62b90cddef0a060fc' as 'docs'

git-subtree-dir: docs
git-subtree-split: 16753a78d8
2020-02-06 13:02:49 +01:00
Cameron Moore 7f0ebd4a3c CONTRIBUTING: Fix note about CGO 2020-02-06 09:09:08 +01:00
Bjørn Erik Pedersen 23ea43180b Update Go version requirement
We run tests on current + (current -1) (we also test on the latest Go source), which means that the current supported Go versions are Go 1.12 and 1.13.

Closes #6853
2020-02-04 23:48:31 +01:00
hugoreleaser 6a74cbe916 releaser: Prepare repository for 0.65.0-DEV
[ci skip]
2020-02-04 09:16:38 +00:00
hugoreleaser 241db8f78a releaser: Add release notes to /docs for release of 0.64.0
[ci skip]
2020-02-04 09:07:21 +00:00
hugoreleaser 7624ab0281 releaser: Bump versions for release of 0.64.0
[ci skip]
2020-02-04 09:07:21 +00:00
Bjørn Erik Pedersen 8490a0aa9d Update 0.64.0-relnotes.md 2020-02-04 09:59:09 +01:00
hugoreleaser bd731d27be releaser: Add release notes for 0.64.0
Rename to *-ready.md to continue.
[ci skip]
2020-02-04 08:45:30 +00:00
Bjørn Erik Pedersen 80dd6ddde2 Fix module mount in sub folder
This addresses a specific issue, but is a also a major simplification of the filesystem file mounts.

Fixes #6730
2020-02-04 00:17:10 +01:00
Bjørn Erik Pedersen 2997310124 Mention a "no CGO rule"
See #6842
2020-02-01 10:27:26 +01:00
Bjørn Erik Pedersen 2bbc865f7b commands: Fix config environment handling
Fixes #6503
Fixes #6824
2020-01-31 16:36:36 +01:00
Bjørn Erik Pedersen 0792cfa9fa Update to Go 1.13.7 and Go 1.12.16
Fixes #6830
2020-01-31 14:18:48 +01:00
Bjørn Erik Pedersen b3f0674b80 transform/livereloadinject: Add defer to livereload script tag
In #6821 we moved the loading from end of body to head to make Turbolinks and similar work.

This commit adds a defer attribute to avoid page parse blocking.
2020-01-31 08:15:22 +01:00
Bjørn Erik Pedersen ef78a0d18a transform/livereloadinject: Don't use document.write to inject livereload
I suspect the person who originally implemented it saw examples using location.host etc. to build the URL.

We have all that information ready at build (static) time.

Fixes #6507
2020-01-31 08:02:53 +01:00
Bjørn Erik Pedersen 5859586453 hubolig: Add a render hook whitespace test
See #6832
2020-01-31 07:51:05 +01:00
Bjørn Erik Pedersen 2d159e9cc7 Do not render alias paginator pages for non-HTML outputs
Update #6797
2020-01-30 23:45:19 +01:00
Bjørn Erik Pedersen f45cb31728 Fix base template handling with preceding comments
Fixes #6816
2020-01-30 23:44:42 +01:00
Bjørn Erik Pedersen 49ef647203 modules: Fix "hugo mod get -u" with no arguments
Fixes #6826
Closes #6825
2020-01-30 17:15:35 +01:00
Bjørn Erik Pedersen 8f08cdd0ac transform/livereloadinject: Inject livereload script right after head if possible
We used to insert the livereload script right before the closing body.

This dord  not work when combined with tools such as Turbolinks.

This commit changes it So we try to inject the script as early as possible.

Fixes #6821
2020-01-29 21:12:07 +01:00
Bhavin Gandhi 281abb18ee deps: Update goldmark to v1.1.22
v1.1.22 has a fix for issue where links with newline in the title
don't get parsed correctly. Reference:
https://github.com/yuin/goldmark/issues/94

Signed-off-by: Bhavin Gandhi <bhavin7392@gmail.com>
2020-01-29 19:48:33 +01:00
hugoreleaser d8e685154d releaser: Prepare repository for 0.64.0-DEV
[ci skip]
2020-01-27 12:22:47 +00:00
hugoreleaser 934ee21fac releaser: Add release notes to /docs for release of 0.63.2
[ci skip]
2020-01-27 12:13:04 +00:00
hugoreleaser c7427a50ed releaser: Bump versions for release of 0.63.2
[ci skip]
2020-01-27 12:13:04 +00:00
hugoreleaser 49e2931eb2 releaser: Add release notes for 0.63.2
[ci skip]
2020-01-27 12:13:04 +00:00
Bjørn Erik Pedersen e8831a056b hubolib: Revert to .Type = "page" when empty
This was changed with good intentions in 0.63.0.

This behaviour was not documented, but it was of course in use.

This commit rolls back to how it behaved before:

For `Page.Type` you will get:

* `type` from front matter if set.
* `.Section`
* If none of the above returns anything, return "page"

Fixes #6805
2020-01-27 12:33:33 +01:00
Bjørn Erik Pedersen 74b6c4e5ff And now finally fix the 404 templates
Fixes #6795
2020-01-27 12:30:31 +01:00
Bjørn Erik Pedersen 8df5d76e70 Fix 404 with base template regression
Fixes #6795
2020-01-26 13:14:08 +01:00
hugoreleaser 8ae2c9c3d6 releaser: Prepare repository for 0.64.0-DEV
[ci skip]
2020-01-23 20:17:44 +00:00
hugoreleaser ce9aceb749 releaser: Add release notes to /docs for release of 0.63.1
[ci skip]
2020-01-23 20:08:10 +00:00
hugoreleaser fd32849bfe releaser: Bump versions for release of 0.63.1
[ci skip]
2020-01-23 20:08:10 +00:00
hugoreleaser 417f9ddf55 releaser: Add release notes for 0.63.1
[ci skip]
2020-01-23 20:08:10 +00:00
Bjørn Erik Pedersen 0df7bd62df deps: Make the build flags shared between sites
Updates #6789
2020-01-23 20:11:53 +01:00
Bjørn Erik Pedersen f441f67512 Fix baseof with regular define regression
Fixes #6790
2020-01-23 19:54:06 +01:00
Bjørn Erik Pedersen 7ed22e9fb6 Revert to minify v2.6.1
Closes #6791
2020-01-23 17:03:23 +01:00
hugoreleaser fb974ae87f releaser: Prepare repository for 0.64.0-DEV
[ci skip]
2020-01-23 12:48:39 +00:00
hugoreleaser 745ddcbbab releaser: Add release notes to /docs for release of 0.63.0
[ci skip]
2020-01-23 12:39:31 +00:00
hugoreleaser 3b3f5a2596 releaser: Bump versions for release of 0.63.0
[ci skip]
2020-01-23 12:39:31 +00:00
Bjørn Erik Pedersen d10ed683c5 Release 0.63.0 2020-01-23 13:30:04 +01:00
hugoreleaser 19e387d181 releaser: Add release notes for 0.63.0
Rename to *-ready.md to continue.
[ci skip]
2020-01-23 11:12:11 +00:00
Bjørn Erik Pedersen cafb1d53c0 docs, output: Add base template lookup variant to docs.json 2020-01-23 11:59:52 +01:00
Bjørn Erik Pedersen 4f466db666 docs: Regen docs helper 2020-01-23 11:55:08 +01:00
Bjørn Erik Pedersen 17af79a03e Fix 0.62.1 server rebuild slowdown regression
Fixes #6784
2020-01-23 11:50:02 +01:00
Bjørn Erik Pedersen 2fefc01606 tpl/compare: Fix eq when > 2 args
Fixes #6786
2020-01-23 10:48:28 +01:00
Tan Yuanhong 0c251be66b Allow multiple arguments in ne/ge/gt/le/lt functions
Treat op arg1 arg2 arg3 ... as (arg1 op arg2) && (arg1 op arg3)
and so on for ne/ge/gt/le/lt.

Closes #6619
2020-01-23 10:36:35 +01:00
Bjørn Erik Pedersen 836c24261f hugolib: Disable a test assertion on ARM
See #6655
2020-01-22 11:44:29 +01:00
Bjørn Erik Pedersen c6d650c8c8 tpl/tplimpl: Rework template management to get rid of concurrency issues
This more or less completes the simplification of the template handling code in Hugo started in v0.62.

The main motivation was to fix a long lasting issue about a crash in HTML content files  without front matter.

But this commit also comes with a big functional improvement.

As we now have moved the base template evaluation to the build stage we now use the same lookup rules for `baseof` as for `list` etc. type of templates.

This means that in this simple example you can have a `baseof` template for the `blog` section without having to duplicate the others:

```
layouts
├── _default
│   ├── baseof.html
│   ├── list.html
│   └── single.html
└── blog
    └── baseof.html
```

Also, when simplifying code, you often get rid of some double work, as shown in the "site building" benchmarks below.

These benchmarks looks suspiciously good, but I have repeated the below with ca. the same result. Compared to master:

```
name                              old time/op    new time/op    delta
SiteNew/Bundle_with_image-16        13.1ms ± 1%    10.5ms ± 1%  -19.34%  (p=0.029 n=4+4)
SiteNew/Bundle_with_JSON_file-16    13.0ms ± 0%    10.7ms ± 1%  -18.05%  (p=0.029 n=4+4)
SiteNew/Tags_and_categories-16      46.4ms ± 2%    43.1ms ± 1%   -7.15%  (p=0.029 n=4+4)
SiteNew/Canonify_URLs-16            52.2ms ± 2%    47.8ms ± 1%   -8.30%  (p=0.029 n=4+4)
SiteNew/Deep_content_tree-16        77.9ms ± 1%    70.9ms ± 1%   -9.01%  (p=0.029 n=4+4)
SiteNew/Many_HTML_templates-16      43.0ms ± 0%    37.2ms ± 1%  -13.54%  (p=0.029 n=4+4)
SiteNew/Page_collections-16         58.2ms ± 1%    52.4ms ± 1%   -9.95%  (p=0.029 n=4+4)

name                              old alloc/op   new alloc/op   delta
SiteNew/Bundle_with_image-16        3.81MB ± 0%    2.22MB ± 0%  -41.70%  (p=0.029 n=4+4)
SiteNew/Bundle_with_JSON_file-16    3.60MB ± 0%    2.01MB ± 0%  -44.20%  (p=0.029 n=4+4)
SiteNew/Tags_and_categories-16      19.3MB ± 1%    14.1MB ± 0%  -26.91%  (p=0.029 n=4+4)
SiteNew/Canonify_URLs-16            70.7MB ± 0%    69.0MB ± 0%   -2.40%  (p=0.029 n=4+4)
SiteNew/Deep_content_tree-16        37.1MB ± 0%    31.2MB ± 0%  -15.94%  (p=0.029 n=4+4)
SiteNew/Many_HTML_templates-16      17.6MB ± 0%    10.6MB ± 0%  -39.92%  (p=0.029 n=4+4)
SiteNew/Page_collections-16         25.9MB ± 0%    21.2MB ± 0%  -17.99%  (p=0.029 n=4+4)

name                              old allocs/op  new allocs/op  delta
SiteNew/Bundle_with_image-16         52.3k ± 0%     26.1k ± 0%  -50.18%  (p=0.029 n=4+4)
SiteNew/Bundle_with_JSON_file-16     52.3k ± 0%     26.1k ± 0%  -50.16%  (p=0.029 n=4+4)
SiteNew/Tags_and_categories-16        336k ± 1%      269k ± 0%  -19.90%  (p=0.029 n=4+4)
SiteNew/Canonify_URLs-16              422k ± 0%      395k ± 0%   -6.43%  (p=0.029 n=4+4)
SiteNew/Deep_content_tree-16          401k ± 0%      313k ± 0%  -21.79%  (p=0.029 n=4+4)
SiteNew/Many_HTML_templates-16        247k ± 0%      143k ± 0%  -42.17%  (p=0.029 n=4+4)
SiteNew/Page_collections-16           282k ± 0%      207k ± 0%  -26.55%  (p=0.029 n=4+4)
```

Fixes #6716
Fixes #6760
Fixes #6768
Fixes #6778
2020-01-22 09:39:49 +01:00
Niklas Fasching 8585b388d2 deps: Update go-org
Not really a new major version but it's used in production and apparently that
means it should be a 1+. Will try to follow semver better from now on.

Changes:

- `#+OPTIONS: toc:1` now supports not just true/false but numbers to limit
  headline levels included in table of conents
- bug fix latex fragment parsing
2020-01-21 10:21:57 +01:00
Jonathan Ling d61bee5e09 examples: Fix blog not building
The example blog had not been updated for some time and I had to restructure it a little bit.

Fixes #6752

Changed tag and category directory structure
2020-01-19 14:42:27 +01:00
Joshua Wong 21ca2e9ce4 Add support for newline characters in raw string shortcode 2020-01-18 11:24:10 +01:00
Ghislain Bourgeois 3efa1d8121 deps: Update github.com/alecthomas/chroma
This new release improves YAML syntax highlighting.
2020-01-16 20:57:02 +01:00
Bjørn Erik Pedersen 65ec8fe827 deps: Update minify to v2.7.2
Fixes #6756
2020-01-15 16:04:44 +01:00
Matt Riggott d3e8ab2e39 deps: Update Goldmark to v1.1.21
This is the first version of Goldmark that supports all the
Smartypants-style typographic punctuation transformations. Now, a
straight single quote in the middle of a word is translated into a curly
quote (e.g. "that's" becomes "that&rsquo;s"). Earlier versions leave
them untouched. This brings Goldmark in line with Blackfriday.

Fixes #6571.
2020-01-15 12:07:25 +01:00
Joshua Wong da81455656 Allow raw string literals in shortcode params 2020-01-15 09:27:19 +01:00
Bjørn Erik Pedersen 0c0bb37285 deps: Update github.com/gohugoio/testmodBuilder 2020-01-14 17:09:11 +01:00
Bjørn Erik Pedersen ddd75f2121 hugolib: Some more benchmark adjustments 2020-01-13 16:47:10 +01:00
Bjørn Erik Pedersen 4ed6ebef4c hugolib: Adjust site benchmarks 2020-01-13 16:39:33 +01:00
Bjørn Erik Pedersen 94cfdf6bef deps: Update direct dependencies
Closes #6719
2020-01-07 20:12:20 +01:00
Bjørn Erik Pedersen 4513801778 minifiers: Update to new CSS config
Update #6719
2020-01-07 18:06:22 +01:00
Bjørn Erik Pedersen 56354a63bb deps: Update to Minify v2.7.0
Updates ##6719
2020-01-07 16:13:38 +01:00
Bjørn Erik Pedersen b9b73a2f63 Revert "Add support for freebsd/arm64"
golang.org/x/sys is an indirect dependency and needs to be updates as such.

This reverts commit aead8108b8.
2020-01-07 13:42:43 +01:00
Dmitri Goutnik aead8108b8 Add support for freebsd/arm64
Update #6719 6719
2020-01-07 13:21:19 +01:00
Bjørn Erik Pedersen 1cf235412f tpl: Put Go's internal template funcs in Hugo's map
```
name                            old time/op    new time/op    delta
SiteNew/Many_HTML_templates-16    43.4ms ± 0%    42.7ms ± 0%  -1.71%  (p=0.016 n=4+5)

name                            old alloc/op   new alloc/op   delta
SiteNew/Many_HTML_templates-16    17.5MB ± 0%    17.5MB ± 0%    ~     (p=0.690 n=5+5)

name                            old allocs/op  new allocs/op  delta
SiteNew/Many_HTML_templates-16      247k ± 0%      247k ± 0%    ~     (p=0.310 n=5+5)
```

Fixes #6717
2020-01-07 13:18:19 +01:00
Bjørn Erik Pedersen df6e9efd8f Update releasenotes_writer.go 2020-01-07 13:15:22 +01:00
Bjørn Erik Pedersen ea05c0e845 hugolib: Add a benchmark with lots of templates 2020-01-07 10:48:17 +01:00
hugoreleaser 273047b5ba releaser: Prepare repository for 0.63.0-DEV
[ci skip]
2020-01-05 18:58:55 +00:00
hugoreleaser 83e501849e releaser: Add release notes to /docs for release of 0.62.2
[ci skip]
2020-01-05 18:50:35 +00:00
hugoreleaser 12230b6897 releaser: Bump versions for release of 0.62.2
[ci skip]
2020-01-05 18:50:35 +00:00
hugoreleaser afdb180e23 releaser: Add release notes for 0.62.2
[ci skip]
2020-01-05 18:50:35 +00:00
Bjørn Erik Pedersen 196a9df585 hugolib: Fix relative .Page.GetPage from bundle
Fixes #6705
2020-01-05 19:41:53 +01:00
Bjørn Erik Pedersen 9b6e61464b markup/goldmark: Adjust auto ID space handling
GitHub does not consider tabs as delimiter, see https://github.com/bep/portable-hugo-links/blob/master/blog/p2.md

Closes #6710
2020-01-05 15:58:14 +01:00
Bjørn Erik Pedersen d62ede8e9e docs: Document the new autoHeadingIDType setting
See #6707
See #6616
2020-01-05 12:10:12 +01:00
Bjørn Erik Pedersen 81b7e48a55 docs: Regenerate docshelper
See #6707
See #6616
2020-01-05 11:57:49 +01:00
Bjørn Erik Pedersen 16e7c11203 markup/goldmark: Add an optional Blackfriday auto ID strategy
Fixes #6707
2020-01-05 11:56:05 +01:00
Bjørn Erik Pedersen 8f071fc159 markup/goldmark: Make the autoID type config a string
To potentially make room for one more.

See #6707
2020-01-05 11:29:22 +01:00
Bjørn Erik Pedersen 469351d5b6 Merge commit '26f1458a2df6b55eee3a5de46f5fec23a43a7c7d' 2020-01-05 11:14:51 +01:00
Bjørn Erik Pedersen 26f1458a2d Squashed 'docs/' changes from 54f0e8776..bd0e15bb6
bd0e15bb6 Optimised images with calibre/image-actions
59830ea44 Remove comments from quickstart code samples
348821b5d Remove image-actions
1cbbd26a9 Update index.md
bcf3de764 Update index.md
fcf17e6ef Release 0.62.1
0956bde21 Merge branch 'temp621'
28d604756 releaser: Add release notes to /docs for release of 0.62.1
c895f12e7 Fix statement about version installed with apt-get (#854)
e96928e38 Updated quickstart to split theme download and theme config add into separate blocks (#967)
e099c1ad6 changed ".Title" to ".URL" (#972)
bea71280d Fix small typing error (#1001)
9c28c422e Correct hyperlink for 'markdownify' function
cf3844a06 Corrected small conjugation mistake (#996)
8b9c1d4f2 Added remarks about additional parameters in ref/relref (#995)
ca06c9a56 Fix illegal character in render-link.html example
7a85c789b Update RenderString.md
69df3b17e Update configuration-markup.md
43e9222a2 Revert "Add shortcodes to note comparing with `markdownify`"
2bd5bc2d7 Add shortcodes to note comparing with `markdownify`
ddfee60b7 Update configuration-markup.md
f87c35fe2 docs: Remove extra double quotation
5ca5cc15f Update index.md
6e457f5ec Update configuration-markup.md
12df3c0fc Update configuration-markup.md
91977fd96 Update configuration-markup.md
377b8954a Update configuration-markup.md
99d691b5e Update hosting-on-render.md
ccf855b22 Update index.md
a945acc42 Update index.md
7d4f308d6 Fix Netlify config
f4caa07f5 Release 0.62.0
79d18276f releaser: Add release notes to /docs for release of 0.62.0
9db1a08d1 Merge commit '8a4005cf2b0ef34265ff8051a6b76226685fc226'
79e556223 docs: More on hooks
5088c54df tpl: Do not return any value in errorf
98c8c8638 tpl: Add a warnf template func
4a9d76cea docs: Regen docshelper
626e53b55 Fix incorrect MIME type from image/jpg to image/jpeg
f92f77c5d Preserve HTML Text for link render hooks
6db9c52b1 docs: Footnote
16801db3b Add render template hooks for links and images
0facb823c Merge commit '2e711a28c71e8667258e5ab824f9b9a71c261b0a'
79bf8ed4c markup/tableofcontents: Add config option for ordered list

git-subtree-dir: docs
git-subtree-split: bd0e15bb60
2020-01-05 11:13:09 +01:00
Bjørn Erik Pedersen 5ee1f0876f markup/goldmark: Simplify code 2020-01-04 23:58:23 +01:00
Bjørn Erik Pedersen a82d2700fc markup/goldmark: Make auto IDs GitHub compatible
You can turn off this behaviour:

```toml
[markup]
  [markup.goldmark]
    [markup.goldmark.parser]
      autoHeadingIDAsciiOnly = true
```
Note that the `anchorize` now adapts its behaviour depending on the default Markdown handler.

Fixes #6616
2020-01-04 19:46:01 +01:00
hugoreleaser ae816452b1 releaser: Prepare repository for 0.63.0-DEV
[ci skip]
2020-01-01 17:46:46 +00:00
hugoreleaser a1518704a7 releaser: Add release notes to /docs for release of 0.62.1
[ci skip]
2020-01-01 17:38:22 +00:00
hugoreleaser 3a21a1708d releaser: Bump versions for release of 0.62.1
[ci skip]
2020-01-01 17:38:22 +00:00
hugoreleaser 451746ddd7 releaser: Add release notes for 0.62.1
[ci skip]
2020-01-01 17:38:22 +00:00
Bjørn Erik Pedersen ff6253bc7c Support files in content mounts
This commit is a general improvement of handling if single file mounts.

Fixes #6684
Fixes #6696
2020-01-01 18:19:49 +01:00
Remco de Man aa4ccb8a1e Update alpine base image in Dockerfile to 3.11
When building the extended version of Hugo using the Dockerfile and
`--build-arg HUGO_BUILD_TAGS=extended`, the obtained Docker container is
broken, because the source is build under alpine 3.11 and the compiled
binary is copied to an image based on alpine 3.10. This problem was most
likely introduced due to an update of the golang base image.

This commit changes the base image from alpine:3.10 to alpine:3.11,
fixing extended version builds.
2019-12-30 13:56:58 +01:00
Bjørn Erik Pedersen 5509954c7e hugolib: Fix inline shortcode regression
Fixes #6677
2019-12-28 14:31:51 +01:00
hugoreleaser 6b59b64f02 releaser: Prepare repository for 0.63.0-DEV
[ci skip]
2019-12-23 10:32:39 +00:00
hugoreleaser 6608f15570 releaser: Add release notes to /docs for release of 0.62.0
[ci skip]
2019-12-23 10:23:27 +00:00
hugoreleaser b361d9a462 releaser: Bump versions for release of 0.62.0
[ci skip]
2019-12-23 10:23:27 +00:00
Bjørn Erik Pedersen 592a7d104d Release 0.62.0 2019-12-23 10:49:08 +01:00
hugoreleaser 93216fda72 releaser: Add release notes for 0.62.0
Rename to *-ready.md to continue.
[ci skip]
2019-12-23 08:57:02 +00:00
Bjørn Erik Pedersen 8a4005cf2b Squashed 'docs/' changes from af4b7ac5b..54f0e8776
54f0e8776 Update image-actions.yml
94e5cad02 Update image-actions.yml
0ad20d226 Add a page about Hugo's Security Model
0dee16d11 Link to Régis Full Partials series
138782808 Update partialCached.md

git-subtree-dir: docs
git-subtree-split: 54f0e87767
2019-12-22 22:51:45 +01:00
Bjørn Erik Pedersen 740b72558b Merge commit '8a4005cf2b0ef34265ff8051a6b76226685fc226' 2019-12-22 22:51:45 +01:00
Bjørn Erik Pedersen 1fb17be9a0 deps: Update Goldmark to v1.1.18
Fixes #6649
2019-12-22 18:14:04 +01:00
Niklas Fasching 51d89dab18 deps: Update go-org
- export #+TITLE (front-matter title) as `<h1>` and demote all normal headlines
  by 1 accordingly (i.e. a normal top level headline now becomes a `<h2>`
  rather than a `<h1>`)
- preserve whitespace in paragraphs - this allows rendering meaningful
  whitespace when wished for using e.g. css `white-space: pre;` (e.g. in verse
  / quote blocks)
2019-12-22 16:18:55 +01:00
Bjørn Erik Pedersen c8bfe47c6a docs: More on hooks 2019-12-21 11:59:36 +01:00
Bjørn Erik Pedersen 50cc7fe545 tpl: Do not return any value in errorf
Fixes #6653
2019-12-21 10:26:14 +01:00
Bjørn Erik Pedersen 1773d71d5b tpl: Add a warnf template func
Fixes #6628
2019-12-21 10:23:00 +01:00
Bjørn Erik Pedersen 8a58ebb311 hugolib: Improve error and reload handling of hook templates in server mode
Fixes #6635
2019-12-20 11:38:44 +01:00
Bjørn Erik Pedersen 0453683816 deps: Update to Goldmark v1.1.17
Fixes #6641
2019-12-20 08:00:37 +01:00
Bjørn Erik Pedersen 55c29d4de3 docs: Regen docshelper 2019-12-19 23:48:01 +01:00
Bjørn Erik Pedersen ccb1bf1abb tpl/collections: Some more params merge adjustments
* If the end result is maps.Params, we need to lower the keys
* Also make sure to handle nested maps of different type

Update #6633
2019-12-19 20:50:30 +01:00
Bjørn Erik Pedersen a67d95fe1a Preserve HTML Text for image render hooks
Fixes #6639
2019-12-19 19:02:03 +01:00
Bjørn Erik Pedersen ad6504e6b5 Fix abs path handling in module mounts
Fixes #6622
2019-12-19 18:51:59 +01:00
John Zaitseff 158e7ec204 Fix incorrect MIME type from image/jpg to image/jpeg
According to multiple sources, both official ([IANA] and [RFC2046]) and
otherwise (eg, [Mozilla] and [Wikipedia]), the official MIME type for
JPEG images is `image/jpeg`, not `image/jpg`.  Change Hugo to match.

[IANA]: https://www.iana.org/assignments/media-types/media-types.xhtml#image
[RFC2046]: https://tools.ietf.org/html/rfc2046
[Mozilla]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types
[Wikipedia]: https://en.wikipedia.org/wiki/JPEG
2019-12-19 18:02:11 +01:00
Bjørn Erik Pedersen eef934ae7e deps: Update Goldmark
Fixes #6626
2019-12-19 09:05:35 +01:00
Bjørn Erik Pedersen 00954c5d1f Preserve HTML Text for link render hooks
The context now have two text methods:

* Text - rendered
* PlainText

Fixes #6629
2019-12-18 22:55:19 +01:00
Bjørn Erik Pedersen 1b785a7a6d tpl/collections: Fix merge vs Params
Fixes #6633
2019-12-18 21:31:34 +01:00
Bjørn Erik Pedersen d20ca37005 tpl: Get rid of the custom template truth logic
Fixes #6615
2019-12-18 20:05:22 +01:00
Bjørn Erik Pedersen 3e316155c5 docs: Footnote 2019-12-18 16:37:43 +01:00
Bjørn Erik Pedersen e625088ef5 Add render template hooks for links and images
This commit also

* revises the change detection for templates used by content files in server mode.
* Adds a Page.RenderString method

Fixes #6545
Fixes #4663
Closes #6043
2019-12-18 11:44:40 +01:00
Bjørn Erik Pedersen 67f3aa72cf Merge commit '2e711a28c71e8667258e5ab824f9b9a71c261b0a' 2019-12-15 10:37:36 +01:00
Bjørn Erik Pedersen 2e711a28c7 Squashed 'docs/' changes from 51c4f3184..af4b7ac5b
af4b7ac5b Remove mention of Amber and Ace
c841e9207 Exif docs corrections (#978)
0f82420b8 Change cache assets default example to 1 year
676dc6e12 Release 0.61.0
a1d9fb18a Merge commit '79c5d7053486f540b6219e693d5590f2c4c3937a'
1b9e675cd releaser: Add release notes to /docs for release of 0.61.0
5b95cbc8a Fixed suffixIsRemoved error in code samples (#975)
59b2c245b Fix Usage section in toc.md to consider Goldmark TOC settings
fd3828673 Add link on how to configure TOC w/ Goldmark
ea339f2d6 Added external learning resources including Hugo In Action book.
fab502d5d Adjust release notes
269a025ef Release 0.60.1
6bff50bea Merge branch 'temp601'
e15251c43 releaser: Add release notes to /docs for release of 0.60.1
690b864b9 Update use-modules.md
345ca8c36 Update syntax-highlighting.md
be64af9f5 Update syntax-highlighting.md
df9dead83 Update syntax-highlighting.md
1c6e6d238 Fix relnotes
0ea6b2012 Update homepagetweets.toml
2c465625d Update index.md
0025bba09 Update index.md
7417f1c05 Update index.md
9eeb8ce57 Release 0.60.0
25a711023 Merge branch 'temp60'
0c4faab0e releaser: Add release notes to /docs for release of 0.60.0
779e5108e Update installing.md
2ef1c386a Minor text improvements in README.md
41ec5a19a Reword sentence for clarity search.md
ded74f098 Add Goldmark as the new default markdown handler
cb55cdbb0 Update introduction.md
fcaad653a Update homepage.md
7427a1fc5 Update configuration.md
8cc2c72ca tpl/collections: Allow dict to create nested structures
4538c092c Merge commit 'efc0b1bb6c6564f54d596467dbc6a18cb206954e'
90f908e7b Support Go time format strings in permalinks

git-subtree-dir: docs
git-subtree-split: af4b7ac5b4
2019-12-15 10:35:09 +01:00
Shohei Ueda 0947cf9583 Enhance accessibility to issues
Add links to the Hugo issues, Hugo docs issues, and Hugo website theme issues.

Close #6233
2019-12-14 18:47:23 +01:00
Bjørn Erik Pedersen 3c24ae030f hugolib: Fix test 2019-12-12 14:48:59 +01:00
Bjørn Erik Pedersen 03d6960a15 deps: Re-introduce the correct version of Goldmark
It was accidently pulled back to an old version earlier today.
2019-12-12 14:45:46 +01:00
Bjørn Erik Pedersen 92c7f7ab85 tpl: Add some comments 2019-12-12 11:44:36 +01:00
Bjørn Erik Pedersen a03c631c42 Rework template handling for function and map lookups
This is a big commit, but it deletes lots of code and simplifies a lot.

* Resolving the template funcs at execution time means we don't have to create template clones per site
* Having a custom map resolver means that we can remove the AST lower case transformation for the special lower case Params map

Not only is the above easier to reason about, it's also faster, especially if you have more than one language, as in the benchmark below:

```
name                          old time/op    new time/op    delta
SiteNew/Deep_content_tree-16    53.7ms ± 0%    48.1ms ± 2%  -10.38%  (p=0.029 n=4+4)

name                          old alloc/op   new alloc/op   delta
SiteNew/Deep_content_tree-16    41.0MB ± 0%    36.8MB ± 0%  -10.26%  (p=0.029 n=4+4)

name                          old allocs/op  new allocs/op  delta
SiteNew/Deep_content_tree-16      481k ± 0%      410k ± 0%  -14.66%  (p=0.029 n=4+4)
```

This should be even better if you also have lots of templates.

Closes #6594
2019-12-12 10:04:35 +01:00
Bjørn Erik Pedersen 167c01530b Create lightweight forks of text/template and html/template
This commit also removes support for Ace and Amber templates.

Updates #6594
2019-12-12 09:59:34 +01:00
Gavin D. Howard 4c804319f6 markup/tableofcontents: Add config option for ordered list 2019-12-12 07:48:40 +01:00
hugoreleaser 186a5ebfca releaser: Prepare repository for 0.62.0-DEV
[ci skip]
2019-12-11 08:35:04 +00:00
hugoreleaser 9b445b9da2 releaser: Add release notes to /docs for release of 0.61.0
[ci skip]
2019-12-11 08:26:33 +00:00
hugoreleaser 3af783966d releaser: Bump versions for release of 0.61.0
[ci skip]
2019-12-11 08:26:33 +00:00
Bjørn Erik Pedersen 31f322a610 Release 0.61.0 2019-12-11 09:14:48 +01:00
hugoreleaser 38c60f2be4 releaser: Add release notes for 0.61.0
Rename to *-ready.md to continue.
[ci skip]
2019-12-11 07:55:37 +00:00
Bjørn Erik Pedersen 3cc217a650 deps: Update Goldmark 2019-12-11 08:41:57 +01:00
Bjørn Erik Pedersen 5f8c2818f1 Deprecate Ace and Amber
Fixes #6609
2019-12-11 08:08:42 +01:00
Daniel Tang c5f2f5837f markup: Add typographic chars from goldmark to toc
Fixes #6592
2019-12-10 23:48:44 +01:00
Bjørn Erik Pedersen 0efb00c2a8 tpl/partials: Allow any key type in partialCached
Fixes #6572
2019-12-03 00:13:47 +01:00
Bjørn Erik Pedersen 40a092b068 markup: Reimplement pygmentsCodefencesGuessSyntax
Fixes #6565
2019-12-02 14:12:23 +01:00
Bjørn Erik Pedersen d534ce9424 deps: Update Goldmark
Fixes #6557
2019-12-01 22:07:31 +01:00
hugoreleaser a6b6b135a4 releaser: Prepare repository for 0.61.0-DEV
[ci skip]
2019-11-29 15:05:19 +00:00
hugoreleaser 960667561f releaser: Add release notes to /docs for release of 0.60.1
[ci skip]
2019-11-29 14:56:16 +00:00
hugoreleaser 6c05563082 releaser: Bump versions for release of 0.60.1
[ci skip]
2019-11-29 14:56:16 +00:00
hugoreleaser f5250ec09d releaser: Add release notes for 0.60.1
[ci skip]
2019-11-29 14:56:16 +00:00
MeiK 86a5b59f64 deps: Update minify
Fixes #6475
2019-11-29 14:37:32 +01:00
Bjørn Erik Pedersen bb80fff69a Fix headless regression
Fixes #6552
2019-11-29 13:46:29 +01:00
Bjørn Erik Pedersen 347cfb0c17 deps: Update Goldmark
Fixes #6549
Fixes #6551
2019-11-29 13:44:29 +01:00
Bjørn Erik Pedersen b60ae35b97 hugolib: Fix timeout number parsing for YAML/JSON config
Where numbers are all floats.

Fixes #6555
2019-11-29 10:50:36 +01:00
hugoreleaser 003ba5b10f releaser: Prepare repository for 0.61.0-DEV
[ci skip]
2019-11-27 10:19:00 +00:00
hugoreleaser f2dea9b036 releaser: Add release notes to /docs for release of 0.60.0
[ci skip]
2019-11-27 10:09:46 +00:00
hugoreleaser 763b0dcb97 releaser: Bump versions for release of 0.60.0
[ci skip]
2019-11-27 10:09:46 +00:00
Bjørn Erik Pedersen b2969b7a77 Release 0.60.0 2019-11-27 11:01:50 +01:00
hugoreleaser 60fea562c4 releaser: Add release notes for 0.60.0
Rename to *-ready.md to continue.
[ci skip]
2019-11-27 11:01:23 +01:00
Bjørn Erik Pedersen 14a1de14fb modules: Add some more output if modules download takes time
Closes #6519
2019-11-27 09:51:47 +01:00
Bjørn Erik Pedersen dcde8af8c6 Add some internal template image tests
Closes #6542
2019-11-27 09:24:08 +01:00
Max Arnold c91970c08d tpl/tplimpl: Featured and Site.Params image support for Schema 2019-11-26 23:53:43 +01:00
Bjørn Erik Pedersen dd1e5fc0b4 hugolib: Disable test assertion on Windows 2019-11-26 23:51:31 +01:00
Bjørn Erik Pedersen b0c7749fa1 deps: Update Goldmark
Closes https://github.com/yuin/goldmark/issues/36#event-2832923993
2019-11-26 23:51:31 +01:00
Max Arnold 25a6b33693 tpl/tplimpl: Add support for featured and global image to OpenGraph template 2019-11-26 20:11:53 +01:00
Bjørn Erik Pedersen 0176643924 hugolib: Fix cascade in server mode
Fixes #6538
2019-11-26 17:04:39 +01:00
Bjørn Erik Pedersen da53523599 hugolib: Fix .Sections vs siblings
Fixes #6365
2019-11-26 13:12:44 +01:00
Bjørn Erik Pedersen 96f09659ce Fix language handling in ExecuteAsTemplate
Fixes #6331
2019-11-26 12:55:00 +01:00
Bjørn Erik Pedersen 03b369e672 hugolib: Adjust .Site.Permalinks deprecation level 2019-11-25 20:19:41 +01:00
Bjørn Erik Pedersen 69fd1c60d8 hugolib: Remove .Site.Ref/RelRef 2019-11-25 20:17:59 +01:00
Bjørn Erik Pedersen 33d733300a Deprecate mmark
Fixes #6486
2019-11-25 20:14:20 +01:00
Bjørn Erik Pedersen e3451371bd hugolib: Fix recently broken timeout config 2019-11-25 20:13:29 +01:00
Bjørn Erik Pedersen 5c5231e09e commands: Use HUGO_ENV if set
Fixes #6456
2019-11-25 19:12:14 +01:00
Bjørn Erik Pedersen d6f7a9e28d resources/images: Make the image cache more robust
Also allow timeout to be set as a duration string, e.g. `30s`.

Fixes #6501
2019-11-25 18:59:06 +01:00
Bjørn Erik Pedersen 031f948f87 Update to Go 1.13.4 and Go 1.12.13 2019-11-25 18:59:06 +01:00
Bjørn Erik Pedersen 71597bd1ad mage: Restore -v behaviour 2019-11-25 18:59:06 +01:00
Bjørn Erik Pedersen a8e9f8389a hugolib: Increase default timeout value to 30s
Fixes #6502
2019-11-25 18:59:06 +01:00
Bjørn Erik Pedersen 03e2d7462d hubolig: Fix potential data race
Fixes #6478
2019-11-25 18:59:06 +01:00
Bjørn Erik Pedersen ea96e1dc55 Revert "deps: Update Goldmark"
See https://github.com/yuin/goldmark/issues/36

This reverts commit 8221912869.
2019-11-25 16:58:37 +01:00
Bjørn Erik Pedersen 8221912869 deps: Update Goldmark 2019-11-25 12:50:45 +01:00
Chris Trimble 8beaa4c25e mage: Fix mage check on darwin and add debugging output
Darwin no longer supports 386 builds after Catalina. Also add
debugging output when running test suites from mage.
2019-11-25 09:48:26 +01:00
Chris Trimble 8a89b8582f commands: Fix jekyll metadata import on individual posts
Prior refactor had eliminated writing FrontMatter for Jekyll imports. This
fixes that bug as well as adds a regression test.

Also removed unused site var, replaced some raw strings, and added regression
test for \r\n removal.

Fixes #5576
2019-11-25 09:46:44 +01:00
jasdeepgill e1175ae83a Improve grammar in README.md 2019-11-25 09:45:21 +01:00
Bjørn Erik Pedersen a2d77f4a80 markup/highlight: Replace the temp for with a dependency 2019-11-24 13:59:16 +01:00
Bjørn Erik Pedersen b546417a27 deps: Update Chroma 2019-11-24 12:29:55 +01:00
Bjørn Erik Pedersen 4175b04686 deps: Update Goldmark 2019-11-24 12:28:57 +01:00
Bjørn Erik Pedersen 55f951cbba markup/tableofcontents: GoDoc etc. 2019-11-23 16:59:43 +01:00
Cameron Moore 20f351ee4c Minor cleanups
Use fmt.Fprint were appropriate instead of Fprintf.  Remove some unused
code.
2019-11-23 16:38:02 +01:00
Bjørn Erik Pedersen bfb9613a14 Add Goldmark as the new default markdown handler
This commit adds the fast and CommonMark compliant Goldmark as the new default markdown handler in Hugo.

If you want to continue using BlackFriday as the default for md/markdown extensions, you can use this configuration:

```toml
[markup]
defaultMarkdownHandler="blackfriday"
```

Fixes #5963
Fixes #1778
Fixes #6355
2019-11-23 14:12:24 +01:00
Bjørn Erik Pedersen a3fe5e5e35 Fix Params case handling in the index, sort and where func
This means that you can now do:

```
{{ range where .Site.Pages "Params.MYPARAM" "foo" }}
```
2019-11-22 18:41:50 +01:00
Bjørn Erik Pedersen cd07e6d57b Fix GetPage Params case issue
Fixes #5946
2019-11-22 18:41:40 +01:00
Bjørn Erik Pedersen 628efd6e29 common/para: Add parallel task executor helper
Usage of this will come later.
2019-11-21 18:38:14 +01:00
Bjørn Erik Pedersen 2dcc1318d1 Add some more output if loading modules takes time
Also include the time to collect modules etc. in the "Total in ..." time reported for the `hugo` command.

Fixes #6519
2019-11-21 18:11:07 +01:00
Bjørn Erik Pedersen 14a985f8ab Update homepage.md
Fixes https://github.com/gohugoio/hugo/issues/6510
2019-11-18 09:17:49 +01:00
Bjørn Erik Pedersen 0cf85c071a hugolib: Add a benchmark 2019-11-17 17:22:32 +01:00
Bjørn Erik Pedersen 20ec9fa2bb modules: Do not check for remote modules if main project is vendored
Fixes #6506
2019-11-14 12:24:55 +01:00
Bjørn Erik Pedersen 812688fc2f hugolib: Fix emoji handling inside shortcodes
Fixes #6504
2019-11-14 10:00:06 +01:00
Bjørn Erik Pedersen a2670bf460 tpl/collections: Allow dict to create nested structures
Fixes #6497
2019-11-11 21:55:16 +01:00
reuben honigwachs 1a36ce9b09 commands: Add hint when dir not empty
Many users seem to stumble over creating new sites in existing non-empty directories. And that `--force` is the necessary option. So I added *See --force* as a hint to the error.

Fixes #4825.
2019-11-11 21:38:10 +01:00
Bjørn Erik Pedersen 90d0cdf236 tpl/collections: Add collections.Reverse
Fixes #6499
2019-11-11 18:33:22 +01:00
Bjørn Erik Pedersen 95ef93be66 tpl/collections: Make index work with slice as the last arg
Fixes #6496
2019-11-11 13:54:57 +01:00
Bjørn Erik Pedersen 79355043e8 Merge commit 'efc0b1bb6c6564f54d596467dbc6a18cb206954e' 2019-11-11 11:46:22 +01:00
Bjørn Erik Pedersen efc0b1bb6c Squashed 'docs/' changes from 723da4a37..51c4f3184
51c4f3184 update figure shortcode docs
2e9c8200d Fix mediatype table
040355013 Rework the index doc
6f0c67c08 Release 0.59.1
a1add2ad0 Merge branch 'temp591'
e0ad971c0 releaser: Add release notes to /docs for release of 0.59.1
c03eb16e7 Fix automatic typo
a623ccfd1 Update quick-start.md
de36e6f8f Clarify that `print` takes 1+ arguments
de439ab84 correct the themes url www.themes.gohugo.io > themes.gohugo.io
806102d10 Remove homepage Tweet (Account no longer exists)
fc4c88513 Add extended version choco instructions (#703)
1b1e8b33c Fix environment typo (#950)
76932cb49 HTTPS relevant search link URLs (#951)
2ef6bdfa4 Update theme
336a6468a Fix consecutive typo (#949)
f44183ddb Fix corresponding typo (#948)
995bf0048 Update index.md
e99758f79 Release 0.59.0
36517d198 releaser: Add release notes to /docs for release of 0.59.0
3acb75f89 Merge commit '5ac0f751aa47e52625662215f66efa99a6abfc2e'
8b3cb611a Merge commit '5070ba6c9e6c492deade3c30cfe769b9dbf7151d'
fd0127841 Merge commit 'b9bd35d72e14932fb6588ff62b90cddef0a060fc' as 'docs'
39121de4d docs: Replace /docs
180195aa3 cache/filecache: Recover from file corruption
4b286b9d2 resources/images: Allow to set background fill colour
689f647ba media: Add common video media types
46cafdbac examples: Replace .RSSLink
653e6856e resources/page: Use binary search in Pages.Prev/Next if possible
f4f566edf Make Pages.Prev/Next work like the other Prev/Next methods
7b3edc293 tpl: Add optional "title" attribute to iframe in Vimeo shortcode
65b7d4221 tpl: Modify error messages of after, first, and last
0e75af74d tpl: Last now accepts 0 as limit
5f1aafafb Update feature_request.md
a9762b5c4 common: Fix elements are doubling when append a not assignable type
096a4b67b tpl: After now accepts 0 as index
bc70f2bf1 helpers: Fix data race in global logger init
0d7b05be4 tpl: Make getJSON/getCVS accept non-string args
71b18a078 Update to Go 1.12.10 and 1.13.1
339ee3714 Simplify test output to simplify diffing
f10db101a hugofs: Add FileMeta.String
b401858eb deps: Update minify to v2.5.2
39ed33fce resources: Fix image test error on s390x, ppc64* and arm64
020a6fbd7 Add BaseFs to RenderingContext
b152216d5 deps: Update go-org
64ec8c890 media: Use + to create the Type string
c466b88c9 deps: Upgrade to latest version of emoji dependency
2df5d202c Revert "deps: Upgrade to latest version of emoji dependency"
170f18d93 deps: Upgrade to latest version of emoji dependency
15a0364d3 readme: Update Architectures
674e81ae8 deploy: Add ability to invalidate Google Cloud CDN
298092d51 resources: Ensure same dirinfos sort order in TestImageOperationsGolden
019ae3848 Update bug_report.md
329e88db1 Support typed bool, int and float in shortcode params
e073f4efb deps: Update Chroma
454a033dc github: Add issue templates and action
e5856e61d resources: Support output image format in image operations
34dc06b03 tpl: Add `rel="noopener"` for external links
2b1814ee5 tpl: Remove unneeded space
8cb7a0d4d releaser: Prepare repository for 0.59.0-DEV
4aac02d49 releaser: Add release notes to /docs for release of 0.58.3
85376a757 releaser: Bump versions for release of 0.58.3
0fd30f832 releaser: Add release notes for 0.58.3 [ci skip]
c262a95a5 Add some more resource transform tests
6dec671fb Fix cache key transformed resources
c0d7188ec deploy: Do not compile in Azure on Solaris
13768c3c5 releaser: Prepare repository for 0.59.0-DEV
253e5fdc6 releaser: Add release notes to /docs for release of 0.58.2
7bc1270ec releaser: Bump versions for release of 0.58.2
d4c98e580 releaser: Add release notes for 0.58.2 [ci skip]
c0d757367 Fix cache keys for bundled resoures in transform.Unmarshal
fcfa6f33b filecache: Ignore "does not exist" errors in prune
77b23fe3d releaser: Prepare repository for 0.59.0-DEV
24277b920 releaser: Add release notes to /docs for release of 0.58.1
8bc478d3f releaser: Bump versions for release of 0.58.1
609a9afbe releaser: Add release notes for 0.58.1 [ci skip]
9442937d8 Avoid writing the same processed image to /public twice
901077c03 hugolib: Fix broken bundle live reload logic
24ad42957 deps: Update github.com/bep/gitmap
3be2c2535 Fix concat with fingerprint regression
5e6609477 tpl: Remove eq argument limitation
f4e1cb8d0 releaser: Prepare repository for 0.59.0-DEV
64d8bf1ee releaser: Add release notes to /docs for release of 0.58.0
10c0baddf releaser: Bump versions for release of 0.58.0
9d3ae81b9 Release 0.58.0
bb894ceaf Allow slices in the image Filter funcs, not just varargs
529c7f109 Update 0.58.0-relnotes.md
57a54d19d releaser: Add release notes for 0.58.0
dc3f3df29 hugolib: Adjust Go version specific test
b43130115 Update to Go 1.13
28501ceb9 hugolib: Remove the old and slow site benchmarks
8624b9fe9 Cache processed images by their source path
018494f36 Remove test artifact
43298f028 Make the "is this a Hugo Module" logic more lenient
1b5c7e327 hugolib: Add a Sass includePaths test
05d83b6c0 Update to Go 1.11.13 and 1.12.9
4898fb3d6 Make home.Pages work like any other section
45d7988f2 Add some fingerprint tests
ce47c21a2 resources: Cache Exif data to disk
de9cbf619 Remove metaDataFormat setting
4f5011692 resources: Make the Exif benchmark filenames distinct
3becba7a9 resources: Add Exif benchmark
20bdc69a4 resources: Remove unused map type
28143397d Add image.Exif
8a8d4a6d9 deps: Update go-org (fix descriptive lists)
00297085d tpl: Migrate last shortcodes (YouTube and Vimeo) to HTTPS embeds
823f53c86 Add a set of image filters
f9978ed16 Image resource refactor
58d4c0a8b deps: Update go-org (fix footnotes in headlines)
c5319db9f Discrepancy typo fix
ad1d6d640 source: Remove debug check left during development
fd3d90ced hugolib: Change to output non-panic error message if missing shortcode template
3ae4b3e19 releaser: Prepare repository for 0.58.0-DEV
a849cb2d9 releaser: Add release notes to /docs for release of 0.57.2
01fbb4635 releaser: Bump versions for release of 0.57.2
9958e5e91 releaser: Add release notes for 0.57.2 [ci skip]
f77a4a2f4 Revert "Update to Go 1.11.13 and 1.12.9"
88d699361 tpl: Use RegularPages for RSS template
ea6816030 hugolib: Don't use the global warning logger
564cf1bb1 tpl: Avoid "home page warning" in RSS template
4b4bdcfe7 hugolib: Allow index.md inside bundles
18836a71c Adjust the default paginator for sections
ab40ce679 Revert the 0.57 home.Pages change
416493b54 hugolib: Add a site benchmark
f28efd358 Update to Go 1.11.13 and 1.12.9
36d749f4e releaser: Prepare repository for 0.58.0-DEV
58c56e9de releaser: Add release notes to /docs for release of 0.57.1
484106cfa releaser: Bump versions for release of 0.57.1
4d60a920f releaser: Add release notes for 0.57.1 [ci skip]
6ccf50ea7 hugolib: Fix draft etc. handling of _index.md pages
67524c993 Fix mainSections logic
952a31949 Fix live reload mount logic with sub paths
321418f22 modules: Disable "auto tidy" for now
7f3aab5ac hugolib: Recover and log panics in content init
028b99261 hugolib: Add some outputs tests
9475f61a3 hugolib: Fix taxonomies vs expired
ea9261e85 commands: Make sure the hugo field is always initialized before it's used
37f592980 releaser: Prepare repository for 0.58.0-DEV
9b00e6476 releaser: Add release notes to /docs for release of 0.57.0
ab849fcc9 releaser: Bump versions for release of 0.57.0
8a4c080cc Add release notes for 0.57.0
4644b95bd hugolib: Remove temporary warning
1089cfe4e Add FileInfo to resources created with resources.Match etc.
cd575023a Improve the server assets cache invalidation logic
631509810 modules: Do not fail build on errors in theme.toml
b64617fe4 Add resources.Match and resources.GetMatch
17ca8f0c4 commands: Fix faulty -h logic in hugo mod get
9e5718270 tests: Convert from testify to quicktest
6027ee110 Avoid unnecessary conversions
c577a9ed2 Fixed ineffectual assignments
a93cbb0d6 Simplify code
bd98182db Implement cascading front matter
e88d79899 Fixed tautological error conditions
c0eef3b40 Use the SVG logo in README.md
166a394a2 Fix static sync issue with virtual mounts
824395204 Add a branch bundle test case
7ff0a8ee9 Simplify page tree logic
df374851a hugolib: Add some more site benchmarks
a843ca53b  transform/urlreplacers: Cache the next position of `urlreplacer.prefix`
02397e76c postcss: Fix no-map vs noMap discrepancy
de8762424 hugolib: Fix output format handling of mix cased page kinds
9ef4dca36 hugolib: Fix broken test
2d1d33673 tpl: Regenerate templates
be0d4efc3 tpl: Always load GitHub Gists over HTTPS
f7f549e3a Fix assorted typos
6512d128c common/collections: Fix typo
b8758de19 examples: Fix multilingual example compatibility with latest version
53077b0da Merge pull request #6149 from bep/sort-caseinsensitive
a4f96a9d8 releaser: Prepare repository for 0.57.0-DEV
f637a1eac releaser: Add release notes to /docs for release of 0.56.3
9433c3c70 releaser: Bump versions for release of 0.56.3
7b448340c releaser: Add release notes for 0.56.3 [ci skip]
0e086785f hugolib: Fix bundle header clone logic
02b947eaa docs: Regenerate CLI docs
d7c233afe commands: Add "hugo config mounts" command
45ee8a7a5 commands: Cleanup the hugo config command
4b6c5eba3 Move the mount duplicate filter to the modules package
edf9f0a35 Allow overlap in module mounts
36220851e Fix self-mounts on the main project
53ade40ba releaser: Prepare repository for 0.57.0-DEV
5f033a7fc releaser: Add release notes to /docs for release of 0.56.2
2e6da0067 releaser: Bump versions for release of 0.56.2
06f29068f releaser: Add release notes for 0.56.2 [ci skip]
84bc8d84e Add some more content language test assertions
6eca0a3de commands: Fix config reloading in Vim and similar
e28bd4c0f Fix Jekyll import
2c7c36109 releaser: Create a proper automated title for patch releases
c62bbf7b1 Fix image format detection for upper case extensions, e.g. JPG
00a238e32 Fix i18n project vs theme order
e5f960245 Add proper error message when receiving nil in Resource transformation
9f497e7b5 Merge branch 'release-0.56.1'
3ad16af6f releaser: Prepare repository for 0.57.0-DEV
56908509e deps: Update go-org to v0.1.2
0ad218afc releaser: Add release notes to /docs for release of 0.56.1
b5fda703f releaser: Bump versions for release of 0.56.1
447700228 releaser: Add release notes for 0.56.1 [ci skip]
544f826dd releaser: Make it a one click release for patch releases
e393c6290 common/maps: Do not return error on params dot access on incompatible types
93d02aabe resources: Fix image Width/Height regression
508db1906 Revert "cache/filecache: Skip resource cache init if the fs is missing"
e5fe37892 modules: Set GO111MODULE=on
da4c4a778 cache/filecache: Skip resource cache init if the fs is missing
b4827fbb1 releaser: Prepare repository for 0.57.0-DEV
45f4eb984 releaser: Add release notes to /docs for release of 0.56.0
263f86d45 releaser: Bump versions for release of 0.56.0
bed75108e Update release notes
8d7006d85 releaser: Add release notes draft for 0.56.0
e5b6e2085 resources: Fix test on Windows
77bf2991b docs: Add Hugo Modules docs
e5f229974 Block symlink dir traversal for /static
87a07282a modules: Gofmt
882d678bb modules: Rename disabled => disable in config
fa28df105 hugolib: Fix broken test
072aa7f11 hugolib: Add a symdiff test
215d2ed88 docs: Regenerate CLI docs
23adc0c2d docs: Regenerate data helpers
461b0e066 Merge commit '5cb4e46cfa65bddae8ac5344540e3dd1e4c266b2'
5cb4e46cf Squashed 'docs/' changes from 540aeddc7..41aae7abb
9f5a92078 Add Hugo Modules
47953148b deps: Tidy
2fc0abd22 Fix livereload for @import case
53da3881d releaser: Remove unused function
ac101aba4 deps: Update xerrors
58a47ccde travis: Ignore errors in go mod download
95b1d3013 deps: Update Chroma
a5604e18b resource/postcss: Change postcss to check for local installation under node_modules/.bin
05d0eddd2 Merge commit '35febb2e2a3780c3338a2665fddea7dda28a17f4'
35febb2e2 Squashed 'docs/' changes from 0c3c04fd6..540aeddc7
c624a7799 tpl/collections: Add Merge function
020086cb2 Add org to front matter formats
8524baee1 deps: Update go-org
90b0127f6 Fix typo s/Meny/Menu/
7611078da hugolib: Add testfile to .gitignore
b2a3d4644 tpl/tplimpl: Regenerate templates
88c8a15be Pagination - do not render href if no next item
59c4bc52e Include path to source page in non-relative ref/relref warning
dc1d4a920 hugolib: Add another site benchmark
de7b9475c commands: Remove comma after URL in new site output
d6ca728ff deps: Revert to an older version of Blackfriday
ff10aa522 examples: Update link to prevent redirect
9f258d2b8 examples: Update URLs
31c9c690f releaser: Update Go Releaser and consolidate the 2 configs
e8a716b23 tpl/collections: Fix slice type handling in sort
3e6cb2cb7 hugolib: Fix bundle path when slug is set
8d898ad66 tpl/collections: Unwrap any interface value in sort and where
fad183c4a Refactor Org mode front matter: Introduce '#+KEY[]:' array notation
b6867bf80 Improve Org mode support: Replace goorgeous with go-org
9df57154e deploy: Default --target to the first deployment target
35abce27c Add safety barrier between concatenated javascript resources
8914fe7ed Update CLI doc for "long" form
b0f536fb2 Drop dashes in http header matcher attributes; other changes from code review
1384d77a0 docs: Add documentation for "hugo deploy"
5e83f4256 deploy: remove TODO comment about subfolders; handled by GoCDK blob URLs
b376b2685 deps: Update gocloud.dev to v0.15.0.
fb007e9ae tpl/collections: Convert numeric values to float64 and compare them
4c560020b resources: Return nil when not found in resources.Get
d44d3ea89 deps: Update Viper
d1cf53f5f Remove references to Google+
811ee996a Update gitmap to get CommitDate field
4f61a926f Merge commit 'be04ece8590f775a52ea167fbe4555753e8c5211'
be04ece85 Squashed 'docs/' changes from 50c02516c..0c3c04fd6
5b4b8bb3c commands: Create new 'hugo list all' command
2278b0eb0 Medium -> Hugo exporting tool
41974303f dockerfile:  Switch base image for final build
6b3f1a100 Merge branch 'release-0.55.6'
fa8e334da releaser: Prepare repository for 0.56.0-DEV
a5d4c82d2 releaser: Add release notes to /docs for release of 0.55.6
32f4b3833 releaser: Bump versions for release of 0.55.6
9b48c5d6b Release 0.55.6
8a1873a2d releaser: Add release notes draft for 0.55.6
95ce2a40e hugolib: Prevent parallel server rebuilds
e22b3f54c tpl: Fix internal templates usage of safeHTMLAttr
71b8d8b6a Update to Go 1.12.5 and Go 1.11.10
5dc6d0df9 deploy: Add tests; fix Windows
527cf1ab0 deploy: Support configuration of upload order
f4956d9aa deploy: Support invalidating a CloudFront CDN cache
2838d58b1 i18n: Move the package below /langs
f330e869e deploy: compute MD5 by reading if List didn't provide one
f2b5d4de3 Revert docs/config.toml changes
0091b1f89 travis: Use proxy.golang.org
c7165589b Add a "deploy" command
ad5703a91 hugolib: Disable racy test
f94a388ad releaser: Prepare repository for 0.56.0-DEV
a83256b9c releaser: Add release notes to /docs for release of 0.55.5
77ad1336d releaser: Bump versions for release of 0.55.5
e33ed29b7 Release 0.55.5
2fb708d3d releaser: Add release notes draft for 0.55.5
cee181c3a docs: Regenerate docs helper
b1d438ea2 Merge commit 'f147b5c53eda15982e0fe762847532eeddb7485f'
f147b5c53 Squashed 'docs/' changes from 13097daf2..50c02516c
6b76841b0 output: Fix permalink in sitemap etc. when multiple permalinkable output formats
bcbed4ebd hugolib: Fix PrevInSection/NextInSection for nested sections
009076e5e lazy: Fix concurrent initialization order
1cbb501be Update blackfriday to v1.5.2
66b143a01 tpl/compare: Fix nil compare in eq/ne for interface values
4f93f8c67 tpl: Fix hugo package name and add godocs
f76e50118 tpl: Provide more detailed errors in Where
f84df16fe releaser: Prepare repository for 0.56.0-DEV
579004178 releaser: Add release notes to /docs for release of 0.55.4
f2fbca23a releaser: Bump versions for release of 0.55.4
1707f1a5f Release 0.55.4
211d66797 releaser: Add release notes draft for 0.55.4
33c738116 hugolib: Fix shortcode version=1 logic
69a56420a hugolib: Avoid recloning of shortcode templates
4756ec3cd i18n: Avoid rebuilding the Translations map for every lookup
4c3c51203 commands: Init mem profile at the end
0775c98e6 hugolib: No links for bundled pages
1477fb33c releaser: Prepare repository for 0.56.0-DEV
993b84333 releaser: Add release notes to /docs for release of 0.55.3
a9ee2ab58 releaser: Bump versions for release of 0.55.3
c85b726f8 Release 0.55.3
89cf7a3f4 releaser: Add release notes draft for 0.55.3
75b16e30e docs: Regenerate docs helper
0508ca185 Merge commit 'a0c28c943c2f4714fa340b22a583b96f5013090b'
a0c28c943 Squashed 'docs/' changes from 0f2bf195e..13097daf2
c7dd66bfe Fix links for non-HTML output formats
7aeeb60d7 hugolib: Add some OutputFormats.Get tests
ea529c847 Fix menu URL when multiple permalinkable output formats
6c80acbd5 hugolib: Add some integration tests for in/uniq using Pages
7fbfedf01 tpl/collections: Return error on invalid input in in
06f56fc98 tpl/collections: Make Pages etc. work with the in func
d7a67dcb5 tpl/collections: Make Pages etc. work in uniq
3e421bd47 commands: Replace IsDraft with Draft in list command
102876033 releaser: Prepare repository for 0.56.0-DEV
9d0203488 releaser: Add release notes to /docs for release of 0.55.2
ccfbb63d1 releaser: Bump versions for release of 0.55.2
fcd63a865 Release 0.55.2
7ace59d5b releaser: Add release notes draft for 0.55.2
35f41834e hugolib: Add more tests for Permalinkable
9b17cbb62 hugolib: Fix Pages reinitialization on rebuilds
2957795f5 tpl/tplimpl: Handle late transformation of templates
56550d1e4 hugolib: Fix shortcode namespace issue
7881b0965 hugolib: Fix false WARNINGs in lang prefix check
49d0a8264 hugolib: Fix bundle resource publishing when multiple output formats
b799b12f4 hugolib: Fix panic for unused taxonomy content files
701486728 hugolib: Fix dates for sections with dates in front matter
f2795d4d2 Fix WeightedPages in union etc.
e85c057f9 releaser: Prepare repository for 0.56.0-DEV
223b3c2ee releaser: Add release notes to /docs for release of 0.55.1
7ca15c7dd releaser: Bump versions for release of 0.55.1
adb776b22 Release 0.55.1
5efdd14eb releaser: Add release notes draft for 0.55.1
8d7607aed hugolib: Add a test for parent's resources in shortcode
4d425a86f Fix
9e9a1f92b hugolib: Fix simple menu config
f7375c497 Fix paginator refresh on server change
7966c0b5b Remove the space in `. RelPermalink`
cc98fc8ad Merge commit '8b73644d81a81e82851b7f7c90aa8ab5524fbe93'
8b73644d8 Squashed 'docs/' changes from acf70cdd9..0f2bf195e
3b86b4a9f resources/page: Fix .RSSLinke deprecation message
27a8049da tpl/tplimpl: Replace deprecated .GetParam usage
ee4274244 releaser: Prepare repository for 0.56.0-DEV
4333cc77f releaser: Add release notes to /docs for release of 0.55.0
452cdcd7c releaser: Bump versions for release of 0.55.0
05d614e13 Release 0.55.0
018cd0c9d releaser: Add release notes draft for 0.55.0
612a06f06 Misc paginator adjustments
3db4a1cf7 Update to Go 1.12.2 and Go 1.11.7
f34e6172c hugolib: Log warning on relative front matter url with lang
708d4ceeb Adjust rlimit logic
ed65bda3b docs: Add information about summary front matter variable
3a62d5474 hugolib: Consider summary in front matter for .Summary
ebab291c0 resources/page: Regenerate JSON wrapper
75467cd78 resources/page: Add missing GitInfo to Page
d1553b4b0 integrity: Add support for sha384
1d9dde82a hugolib: Fix default date assignment for sections
87b16abd9 Add HUGO_NUMWORKERMULTIPLIER
415ca9673 hugolib: Fix the GOMAXPROCS env get
8559f5c29 Use YAML for the benchmark compare
e2dc432fe hugolib: Fix benchmark for YAML front matter
950295516 hugolib: Buffer the render pages chan
032e6802d deps: Update to imaging v1.6.0
d0d661dff hugolib: Re-work "fast render" logic in the new flow
4494a01b7 metrics: Adjust the howSimilar logic vs strings
e91e222cd resources/page: Implement compare.ProbablyEqer for the core slices
5185fb065 hugolib: Allow relative URLs in front matter
92baa14fd hugolib: Allow page-relative aliases
a55640de8 tpl: Allow the partial template func to return any type
9225db636 releaser: Remove version replacement in docs config
f7ef7d376 releaser: Adjust patch vs images logic
f9d6feca0 hugolib: Fix alias path for AMP and similar
439ab0339 resources: Fix image publish ordering issue
b6a60f718 output: Add missing JSON tag
bfdc44964 docs: Regenerate docshelper data
cc8515f18 deps: Update Chroma
8bfd3a54a hugolib: Add a simple test for jsonify of Site
bb533ca5e docs: Regenerate CLI docs
876e5f67b Merge commit 'c2037f0c9a3a35b9db9c404f6b5f94ec8b690a53'
c2037f0c9 Squashed 'docs/' changes from 4f4d1f48c..acf70cdd9
9bc6187b8 hugolib: Do not fall back to site title if not set in content file
10bb614a7 deps: Update Afero
bceda1b28 hugolib: Add a test for home page with no title
4dae52af6 Avoid nilpointer on no File on Page
794d4052b herrors/errors: Improve the "feature not available" error
a7ee9b0bb hugolib: Add String() to fileInfo
91ef9655a resources/page: Re-introduce .Page.Page
b5f39d23b all: Apply staticcheck recommendations
3011f36c2 hugolib: Remove unused slice
d30e84548 Run gofmt -s
597e418cb Make Page an interface
44f5c1c14 List future and expired dates in CSV format
984a73af9 Update to Go 1.12.1 and Go 1.11.6
e54213f52 tpl/tplimpl: Fix mutex unlock
4a2a8afff commands: Fix doLiveReload logic
79d517d86 deps: Update Viper
34c49d788 hugolib: Adjust site benchmark
b9e75afd6 Update to Go 1.12
dfc72d61a Remove Gitter dev chat link
02eaddc2f tpl/tplimpl: Fix template truth logic
bdf47e8da Update Travis config to work for forked builds
75904332f Add skipHTML option to blackfriday config
60c0eb4e8 Update stretchr/testify to 1.3.0.
c154c2f7b Rewrite relative action URLS
075b17ee1 Support Docker args TAGS, WORKDIR, CGO; speed up repetitive builds
b4148cd1d hugolib: Adjust test for Go 1.12
908692fae Support nested keys/fields with missing values with the `where` function
7e4b18c5a commands: Update debouncer version
483cf19d5 common/herrors: Fix args order in strings.TrimPrefix
720104294 tpl: Fix strings.HasPrefix args order
5383fe458 releaser: Prepare repository for 0.55.0-DEV
b1a82c61a releaser: Add release notes to /docs for release of 0.54.0
6fe6b9c17 releaser: Bump versions for release of 0.54.0
52cec0fb2 Release 0.54.0
23e52ea4c releaser: Add release notes draft for 0.54.0
9b619dc02 releaser: Adjust patch logic
fab41f42d common/hugo: Use official semver even for main releases
f27faf9af Squashed 'docs/' changes from 49809a038..4f4d1f48c
c7c66e664 Merge commit 'f27faf9afd0a8db768a21954b8755f1bf1a14f1b'
5e078383a Squashed 'docs/' changes from 785e375f..49809a03
ddc15ed41 Merge commit '5e078383a787e8b5ec3ba73f05ea4130840afbe2'
ddc6d4e30 tpl/data: Adjust tests
6a2bfcbec tpl/data: Prevent getJSON and getCSV fetch failure from aborting build
59d87044a commands: Add test for --configDir
3244cb3b3 Ignore unknown config files in config dir
d9282cf98 Store supported config formats in a variable
c52045bbb Fix some inline shortcode issues
8ed2a1caa Bump to Go 1.11.5
e85961390 Update Afero
2a9060a85 hugolib: Expand TestPageWithEmoji to cover '+', '-' and '_' too
3038464ea Accept hyphen and plus sign in emoji detection
526b5b1c4 Fix OpenGraph image fallback to site params
26f75edb7 Support numeric sort in ByParam
e1a66c734 Fix Params case handling in the new site global
db3c49d04 Make hugo server -t work again
e3cb8e6c7 Add configFile(s) back to the watch list after RENAME event too
55251aa89 Remove historical rssURI config
843fcd19d Use subtests with server_test.go
ce8a09a4c resources: Move resource interfaces into its own package
669ada436 resource: Move resource processors into sub-packages
507451229 Update _index.md
40ffb0484 hugolib: Restore 0.48 slash handling in taxonomies
4bae8b04a Revert " Fix handling of taxonomy terms containing slashes"
0584432b0 Update go.sum
65fa06927 Revert "hugolib: Restore taxonomy term path separation"
9e4f9e0bb tpl: Fix reflect
3f3187de0 cache/namedmemcache: Fix data race
cc351958e Update Chroma
c24f3ae22 Make docshelper run again
214e9745b releaser: Use Git short commit in release binaries
ecc892275 releaser: Bump Goreleaser version
22afe2804 Merge commit '978856e2ad12d2bcaf37bb9e31f806b30a4c42f4'
978856e2a Squashed 'docs/' changes from bd91d1cfd..785e375f5
843187120 releaser: Prepare repository for 0.54-DEV
8fc339dc2 releaser: Add release notes to /docs for release of 0.53
5236cb8e9 releaser: Bump versions for release of 0.53
a28865cfc release: Fix goreleaser config
cb6c77b81 Release 0.53
be58c7b9c tpl/transform: Include options in cache key
62d031aed docs: Adjust CSV example
ce06bdb16 Rename CSV option from comma to delimiter
2efc1a64c docs: Document transform.Unmarshal
25ddbb09f hugolib: Adjust test
e691c48a5 docs: Regenerate CLI docs
094709e10 tpl/transform: Simplify transform.Unmarshal func
a57446979 Add CSV support to transform.Unmarshal
822dc627a tpl/transform: Add transform.Unmarshal func
43f9df019 Prevent resource publishing for transformed inline resources
102171444 hugolib: Add .Name as a shortcode variable
5a83bf314 Squashed 'docs/' changes from d1cf9adc4..bd91d1cfd
6f069e549 Merge commit '5a83bf314f4c0ce1d61341e0a1df21c9998e8154'
0483299bc hugolib: Improve logic of output path trimming
27b62a546 snap: Revert build-snap to 1.11/stable channel for go
35bfca3b1 commands: Remove the benchmark command
9cd54cab2 Move the emoji parsing to pageparser
a8853f1c5 parser/pageparser: Split the page lexer into some more files
4d93aca27 hugolib: Enable Emoji in site benchmark
f2167de83 parser/pageparser: Add a benchmark
64b6b2907 tpl: Fix case handling in cast params
bb9c2988f Update to Go 1.11.4
c04030b14 releaser: Get ldflags for build date etc. in line for all builds
f7691fe96 transform/urlreplacers: Simplify implementation
efe0b4e5c transform/urlreplacers: Support unquoted URLs in canonifyURLs replacer
d5a0b6bbb hugolib: Remove "double layout" lookup
5178cd13a Fix "failed to create file caches from configuration: file exists" on Windows
9ce0a1fb7 hugolib: Restore taxonomy term path separation
ab9214768 importer: fix jekyll import highlight options
506868170 docs: Regenerate CLI docs
b17a61a60 Merge commit 'eb16165694f868d73e57b6aed5c26ba5e98229de'
eb1616569 Squashed 'docs/' changes from 37095d540..d1cf9adc4
782947408 Add /config dir support
256418917 resource/image: Fix "always false" condition
c84f506f8 tpl: Add reflect namespace
4b5f74395 minifiers: Fixx CSS2 color code handling
931a13245 tpl/hugo: Use the correct Hugo var
837835885 hugolib: Add .Site.Sites
831d23cb4 Add tpl/site and tpl/hugo
514e18dc2 cache/filecache: Simplify test
b804a7088 cache/filecache: Use OS fs for test
30a7c9ea3 tpl: Add godoc packages comments
834684810 common/collections: Fix defines typo
54ecade02 releaser: Prepare repository for 0.53-DEV
9433cf5a9 releaser: Add release notes to /docs for release of 0.52
3c909eb3f releaser: Bump versions for release of 0.52
724b3e673 Release 0.52
056c75477 releaser: Add release notes draft for 0.52
a9a93d082 hugolib: Fall back to title in ByLinkTitle sort
b09a40333 hugolib: Improve nil handling in IsDescendant and IsAncestor
7540a6283 parser/pageparser: Fix handling of commented out front matter
7e75aeca8 Remove duplicate mapstructure depdendency
e14e0b192 Add dependency list to README
ed698e94c tpl/path: Add tests
89e2716d2 tpl: Regenerate templates
aba2647c1 tpl: Fix whitespace issue
f37c5a256 tpl: Add "param" shortcode
aded0f25f docs: Document inline shortcodes
bc337e6ab Add inline shortcode support
112461fde tpl/collections: Add float64 support to where
94ab125b2 parser/pageparser: Fix when only shortcode and then summary
dcfeed35c commands: Include drafts in convert command
f9b4eb4f3 Handle themes in the new file cache (for images, assets)
e82b2dc8c Fix ignored --config flag with 'new' command
5df2b79dd Fix Permalink for resource, baseURL with path and canonifyURLs set
12742bac7 Add tests for permalink on Resource with baseURL with path
fabf026f4 helpers: Add a comment about file mode for new files
94f0f7e59 cache/filecache: Add a :project placeholder
3c29c5af8 cache/filecache: Add a cache prune func
33502667f cache/filecache: Add a filecache root dir
d3489eba5 cache/filecache: Use time.Duration for maxAge
17d7ecde2 cache/filecache: Split implementation and config into separate files
e4b257288 Update to LibSASS 3.5.5
782dd1585 More spelling corrections
aff9c0916 cache/filecache: Spelling corrections
fdd4a768f Remove appveyor
abeeff132 docs: Document the new file cache
f7aeaa612 Add a consolidated file cache
7d78a2afd Add Windows build config to Travis
5570a6e47 Revert "Add Elasticsearch/bonsai.io to services doc."
c0b3a1af0 Add Elasticsearch/bonsai.io to services doc.
a8cb1b07b tpl: Fix test to pass with gccgo
2900801ac releaser: Prepare repository for 0.52-DEV
f3d519079 releaser: Add release notes to /docs for release of 0.51
1ccc0b79a releaser: Bump versions for release of 0.51
cbed50e22 Release 0.51
05ecd8111 releaser: Add release notes draft for 0.51
e456e34bd docs: Document shortcode error handling
5d14d04ac docs: Document symdiff
ddcb40285 docs: Document complement
3a44920e7 hugolib: Improve error message on duplicate menu items
79a06aa4b tpl/collections: Properly handle pointer types in complement/symdiff
d212f6094 deps: Update minify
488776b64 tpl/collections: Add collections.SymDiff
b8b8436fc hugolib: Fix changing paginators in lazy render
42d8dfc8c tpl/collections: Add collections.Complement
47506d164 commands: Fix spelling
2998fa0cd docs: Re-generate CLI docs
d16a7a33f Fix shortcode directly following a shortcode delimiter
5b1edd281 commands: Add --minify to hugo server
2bd9d9099 commands: Fix recently broken error template
4b7d3e57a Make WARN the new default log log level
4f3c09596 Revert "tpl: Update Jsonify to return pretty-print output"
486bc46a5 docs: Regenerate the docs helper
61f210dd7 tpl: Fix the docshelper
f8446188d Skip watcher event files if matched in ignoreFiles
d523aa4bb deps: Update Chroma
b8725f518 Fix ANSI character output regression on Windows
0bc4b0246 hugolib: Remove deprecated useModTimeAsFallback
faeb55c1d hugolib: Bump to ERROR for the deprecated Pages.Sort
6c6a6c87e hugolib: Deprecate .Site.Ref and .Site.RelRef
1d18eb057 Add file (line/col) info to ref/relref errors
33a7b36fd hugolib: Add .Position to shortcode
6180c85fb hugolib: Fix REF_NOT_FOUND logging to include page path
d3a98325c common/loggers: Improve log color regexp
b2a676f5f hugolib: Fix broken manual summary handling
3a786a248 tpl: Fix BOM issue in templates
729593c84 hugolib: Fix deadlock when content building times out
e65268f2c Correct minor typo (#5372)
f863b6a07 releaser: Prepare repository for 0.51-DEV
f5be59920 releaser: Add release notes to /docs for release of 0.50
b14c11b0e releaser: Bump versions for release of 0.50
0addb2add Release 0.50
8bba85601 releaser: Add release notes draft for 0.50
7082a5d14 Update go.sum
aa281b513 mod: Update minify
325019872 docs: Regenerate CLI docs
d6a4af701 Squashed 'docs/' changes from 084804447..37095d540
27569275b Merge commit 'd6a4af7018e8618944a6471ceeb7aae1d4df6afa'
4b2738d87 Merge commit '74309fe5699a595080fdb3a14711e0869babce99'
74309fe56 Squashed 'docs/' changes from e5e98b950..084804447
9c88a8a55 common/loggers: Make sure the global logger also gets colored labels
95e72f5e8 i18n: Avoid using the global logger
1c7b7b4ef common/loggers: Add color to ERROR and WARN
1ad117cbe common/herrors: Make the file error log format configurable
dac7092a9 common/collections: Allow a mix of slice types in append/Scratch.Add
b27ccf34b resource: Allow .Data.Integrity to be accessed on its own
286d0b7dc Revert "mod: Update minify"
83c873ff3 mod: Update minify
a2440dc0e mod: Update cast
1e9ac3dcc commands: Truncate the error log on repeated config errors
40e99672b docs: Regenerate CLI docs
3a3badfd1 resource: Serialize image processing
df021317a commands: Only show Ansi escape codes if in a terminal
78578632f Fix archetype handling of directories in theme
6b78b3810 Revert "commands: Read disableFastRender from flag even if it's not changed"
78a4c2e32 commands: Read disableFastRender from flag even if it's not changed
d4ebfea1f comamnds: Use overflow-x: auto; for browser errors
93aa6261b common/loggers: Remove the ANSI color for the browser error version
acc14b464 hugolib: Adjust error test to make it pass on Go tip
2d7709d15 tpl: Handle truncated identifiers in Go template errors
deff9e154 Add some color to the relevant filenames in terminal log
889aca054 Run gofmt -s
e3ed4a83b hugolib: Rename some page_* files
6636cf1be Resolve error handling/parser related TODOs
f669ef6be herrors: Improve handling of JSON errors
ed7b3e261 commands, hugolib: Get file context in "config parse failed" errors
2bf686ee2 hugolib: Improve errors in /i18n handlling
9f74dc2a5 hugolib: Improve errors in /data handlling
d1661b823 hugolib: Continue the file context/line number errors work
7930d2132 hugolib: Remove the now superflous Source struct
eb038cfa0 Convert the rest to new page parser code paths
129c27ee6 parser/metadecoders: Consolidate the metadata decoders
44da60d86 hugolib: Redo the summary delimiter logic
1e3e34002 hugolib: Integrate new page parser
1b7ecfc2e hugolib: Use []byte in shortcode parsing
27f5a906a parser/pageparser: Use []byte in page lexer
2fdc4a24d parser/pageparser: Add front matter etc. support
f6863e1ef parser/pageparser: File renames and splitting
d6c16afde Move the shortcode parser to the new pageparser package
6f3716dc2 commands: Avoid panic in error handler on config errors
5a52cd5f9 tpl: Update Jsonify to return pretty-print output
4a366fcfe Prevent stale content in Fast Render Mode
083311d03 hugolib: Fix test on Windows
0fe4ff187 tpl: Improve the Execute panic error message
1f42e47e4 Allow date and slug from filename for leaf bundles
35fbfb19a commands: Show server error info in browser
3a3089121 Simple doc fix in CONTRIBUTING.md
c21e5179c tpl: Use .Lastmod in embedded schema template
a205f24ba Revert "commands: Add .gitignore "hugo new site""
92979d928 commands: Add .gitignore "hugo new site"
0a3340e95 resource: Optimize integrity string generation
6b21ac3e6 commands: Add help text to "hugo new"
d14420539 snap: Set "extended" tag based on build_url on Launchpad
3d4a9882b helpers: Call rst2html directly on *nix
bdca97279 Update URLs to stop 301 redirects
604ddb90c Merge branch 'release-0.49.2'
b09e495a7 releaser: Prepare repository for 0.50-DEV
42cde6666 releaser: Add release notes to /docs for release of 0.49.2
ad60948c4 releaser: Bump versions for release of 0.49.2
c397f2c08 Release 0.49.2
b9e18e20c releaser: Add release notes draft for 0.49.2
2159d77f3 common/collections: Fix type checking in Append
535755e4f common/collections: Fix type checking in Append
3583dd6d7 Merge branch 'release-0.49.1'
e5b4cb241 releaser: Prepare repository for 0.50-DEV
821adf3ae releaser: Add release notes to /docs for release of 0.49.1
8ba9a2736 releaser: Bump versions for release of 0.49.1
235acf223 Relase 0.49.1
ac0fac934 releaser: Add release notes draft for 0.49.1
23f48c300 common/maps: Improve append in Scratch
e2201ef15 tpl/collections: Fix handling of different interface types in Slice
b5e17f7c8 Add GOPATH Hugo building tip
31a8bb8c0 common/maps: Improve append in Scratch
8e825ddf5 Revert "tpl: Fix baseof.html in error message"
646a52a5c tpl: Fix baseof.html in error message
e421696d0 helpers: Consolidate MakeSegment vs MakePathSanitized
4b4af2c52 hugolib: Use stdlib context package
fae48d745 hugolib: Normalize permalink path segments
06d28a464 hugolib: Fix FuzzyWordCount test error message
681817030 Render Markdown in figure shortcode "caption" and "attr" params
c5279064d Re-organize the figure shortcode for better readability
152cffb13 Update README & CONTRIBUTING
0d5110d03 tpl: Cast IsSet key to int for indexed types
d3b81ee58 hugolib: Improve error message for bad taxonomy weights
1fd30d462 hugolib: Cast taxonomy weight parameters to int
498d62995 hugolib: Allow nil to be unwrapped as *Page
10ac2ec44 tpl/collections: Fix handling of different interface types in Slice
ce264b936 tpl: Add a delimiter parameter to lang.NumFmt
91f49c070 snap: Add custom x-nodejs plugin to support ppc64el and s390x
a475bf125 snap: Fetch mage with GO111MODULE=off
f1dede370 snap: Revert 'Skip "mage -v test" due to build failure on Launchpad'
fa873a6cb snap: Use build-snaps instead of building go from source
fb732d532 hugolib: Be a litle more specific in NextPage TODO
ad705aac0 hugolib: Introduce Page.NextPage and Page.PrevPage
52ac85fbc snap: Skip "mage -v test" due to build failure on Launchpad
048a64be1 releaser: Update path to snap/snapcraft.yaml
3033a9a37 snap: Fix go plugin build failure by renaming go.mod
27d421118 snap: Move snapcraft.yaml to snap/snapcraft.yaml
4730a78a7 snapcraft: Try installing postcss again
b7706d6ae snapcraft: Set GO111MODULE=on in override-build script
48413d76f build: Update the temp docker script
66b9e2bff releaser: Prepare repository for 0.50-DEV
398996e8b releaser: Add release notes to /docs for release of 0.49
7f005f5e9 releaser: Bump versions for release of 0.49
011e3aaa9 Release 0.49
369744845 docs: Document directory based archetypes
2638b04c6 releaser: Add release notes draft for 0.49
cf47f43ff ci: Add "go mod download" to CI scripts
3b6bd1210 docs: Regenerate CLI docs
8388cd90e docs: Document group
807c55192 Squashed 'docs/' changes from 6b00298bb..e5e98b950
bc57f5c36 Merge commit '807c551922707fc5ae0eb26e8f01638c0c63fdb3'
fe6a6f273 resource/integrity: Make Data.Integrity be of type template.HTMLAttr
2650fa772 Add directory based archetypes
ef525b15d Build on CircleCI outside of GOPATH
f91681469 Prevent symbolic links from themes
cae07ce84 tpl/collections: Allow first function to return an empty slice
4f9c109dc tpl/opengraph: Use safeHTMLAttr instead of safeHTML for HTML attributes
f1a00b206 hugolib: Remove deprecated rssURI
df4cbbd3b commands: Remove deprecated flags
2e2e34a93 hugolib: Deprecate Pages.Sort
2eed35c82 hugolib: Minor cleaning in the sorting code
dd692c710 hugolib: Clear the page cache per render
ed4f1edbd hugolib: Compare every element in pages cache
058cc6c2c Revert "hugolib: Normalize permalink path segments"
4b82f7484 Update releasenotes_writer.go
06976ebb8 hugolib: Normalize permalink path segments
555a5612b hugolib: Do not set RSS as Kind in RSS output
75e54345f hugolib: Make sure ambiguous lookups in GetPage gets an error
df50c108b docs: Add docs for append
e27fd4c1b tpl/collections: Add collections.Append
b7ca3e1b3 Merge commit '13e64d72763bf8d6d92d4cdfc15ed45ee9debfab'
13e64d727 Squashed 'docs/' changes from 9b494a58c..6b00298bb
9b26b5487 minifiers: Set minifier to KeepEndTags
3dafe206e minifiers: Make JSON minification more generic
37d646347 Update Mage
43d446522 tpl/data: Revise error handling in getJSON and getCSV
4f72e7912 tpl: Show error on union or intersect of uncomparable types
fe6676c77 tpl/collections: Improve type handling in collections.Slice
7a97d3e6b tpl/collections: Allow pointer receiver in Group
6667c6d74 tpl/collections: Add group template func
cfda13b36 hugolib: Allow creating page groups from any page collection
bb2fe814c Update dependencies
e5d66074c tpl/strings: Add strings.FirstUpper
d970327d7 hugofs: Fix filepath issue in test
0013bea90 resource: Fix golint issues
30bc4ed0a Improve some godoc comments
f6f22ad94 tpl: Fix golint godoc issues
400fe96ae media: Fix golint issues
3f45e729f output: Fix golint godoc issues
ffaa73dc8 publisher: Fix golint godoc issue
f8d8c8542 langs: Fix golint godoc issue
10dc87bf8 i18n: Fix golint issue
7231869ba related: Fix golint issues
ccd328548 releaser: Fix golint issues
600047ff1 source: Fix golint godoc issues
5f2e1cb89 hugofs: Fix golint issues
c8ce65046 helpers: Fix golint issues
a53f96231 deps: Fix most golint issues
daffeec30 config: Fix golint issues
b8b91f550 common: Fix golint errors
f0effac80 commands: Fix golint issues
be3ae3ec9 hugolib: Do not FirstUpper taxonomy titles
2cf8fe2ea Fix broken Travis config
3b103cb7b Update to latest Mage
0cc936583 resource: Fix broken build
c15c7da42 resource: Remove some duplicate code
bcbe57c6e Update Dockerfile to Go 1.11
e38e88124 hugolib: Simplify some code
0665a3951 hugolib: Add missing error checks
1ed8c3633 hugolib: Remove extraneous createStaticFs call
e03eb90a3 hugolib: Fix godoc comment
c915d0d32 hugolib: Fix typo in private func name
47d4edce6 Fix error message for go vet
ea8ef573c mage: Init packages once
293e12355 appveyor: Update script to Go 1.11
fdf3c3b82 build: Remove the remains of Go Dep
312d2252b Update CONTRIBUTING.md
f627903ef Update README.md
a2f0f9d47 snapcraft: Update to work with Go Modules
1ff54ab3d releaser: Prepare repository for 0.49-DEV
456f5476c releaser: Add release notes to /docs for release of 0.48
09811d0be releaser: Bump versions for release of 0.48
d351ac2e6 Release 0.48
59f57900a releaser: Add release notes draft for 0.48
59cdad325 release: Fix CircleCI script
6022f219f hugolib: Only run variable variable overwrite test on Go 1.11
0c8a41548 hugolib: Add a test for template variable overwrite
f4675fa0f helpers: Fix permissions when creating new folders
ebb56e8bd Improve minifier MIME type resolution
6b9934a26 circleci: Update to Go 1.11
c7f057797 travis: Set GO111MODULE=on for mage install
08d14113b resource: Add instruction to install PostCSS when missing
94d6d6780 Update snapcraft build config to Go 1.11
45c9c45d1 Use Go 1.11 modules with Mage
fce32c07f Add go.mod
d32ff16fd Update Travis to Go 1.11 and Go 1.10.4
e6eda2a37 minfiers: Keep end tags
66f688f71 snap: Skip installing postcss due to failure on build server
2c934be8a snap: Refactor, fix bin/node, and add bin/postcss
94d0e79d3 hugolib: Include language code in REF_NOT_FOUND errors
b9a503feb tpl/tplimpl: Make the autogenerated templates collapsed in PRs
fff132537  Fix handling of taxonomy terms containing slashes
8999de193 Fix build on armv7
a81c64e43 releaser: Prepare repository for 0.48-DEV
7ef509625 releaser: Add release notes to /docs for release of 0.47.1
16b691a87 releaser: Bump versions for release of 0.47.1
aefd9a80a Release 0.47.1
57ace857a releaser: Add release notes draft for 0.47.1
fdff0d3af tpl/tplimpl: Fix .Site.Params case regression
834617f9f snap: Remove unused files from Git, Perl, etc.
ef20ec1fb snap: Add nodejs to allow PostCSS to work
5a0ee2b93 minifiers: Do not strip IE conditional statements
674682668 releaser: Prepare repository for 0.48-DEV
caf608d56 releaser: Add release notes to /docs for release of 0.47
6711dacde releaser: Bump versions for release of 0.47
de2329348 releaser: Work around a Goreleaser bug
918177ac2 Release  0.47
83a980d29 releaser: Add release notes draft for 0.47
4a16b5f4b docs: Regenerate CLI docs
a95896878 Squashed 'docs/' changes from d88477eb3..9b494a58c
873f8805c Merge commit 'a95896878f4b4a79448b39ce93a4e0d3258b4a43'
374387577 tpl/tplimpl: Fix compiling Amber templates that import other templates
baa62d0ab hugolib: Adjust tests for shortcode p-issue
78c99463f hugolib: Fix shortcode output wrapped in p
abc54080e Add configFile(s) back to the watch list after REMOVE event
a655e00d7 commands: Gracefully handle typos in server config when running the server
9d973004f hugolib: Fix image cache-clearing for sub-languages
224754601 hugolib: Force render of any changed page, even in Fast Render Mode
d139a037d hugoblib: Fix "adding a bundle" in server mode
0a88741fe hugolib: Fix error when deleting a bundle in server mode
d999b4e82 Revert "releaser: Revert to the old versions of the release pipeline"
20148345a releaser: Fix goreleaser config
e5052f4e0 commands: Include theme name in version mismatch error
c81fbf462 minifiers: Make the JS minifier matcher less specific
a6f199f7a hugolib: Use the interface value when doing Related search
0dd06bdac hugolib: Fix Related when called from shortcode
5c5384916 tpl/tplimpl: Reimplement the ".Params tolower" template transformer
56c61559b Only duplicate resource output in multihost mode
78f8475a0 Fix Resource output in multihost setups
c09ee78fd tpl: Suppress blank lines from opengraph internal template
f6ae436c5 publisher: Close file when done
2182ecfd3 hugolib: Fix GitInfo when multiple content dirs
e85833d86 hugolib: Add multiple content dirs to GitInfo test site
43a5aaa77 Fix broken tests
1639fd20d Merge commit '3a44bf182fed5f34621f450114083a6dd7e88a07'
3a44bf182 Squashed 'docs/' changes from 81847981f..d88477eb3
c2a674139 readme: https links to 3rd party sites
06bd01364 Update alias.go
755d1ffe7 tpl/tmplimpl: Add MIME type to embedded JS
fb3cb05cc resource: Remove test debug
d07882dfb Update dependencies
7f5356717 Update Chroma
789ef8c63 Add support for minification of final output
71931b30b Remove alias of os.Stat
d40116e5f Renmae FileStat Stat
c362634b7 Fix typo
d71120852 Add fileStat to tpl/os/os
a6b1eb1e9 transform: Reduce allocation in the benchmark itself
27110133f transform: Simplify the 0 transformer case
31faf98ce releaser: Prepare repository for 0.47-DEV
f14d77384 releaser: Add release notes to /docs for release of 0.46
3aa838cf2 releaser: Bump versions for release of 0.46
a3a26597c Release 0.46
92d776b0d releaser: Add release notes draft for 0.46
e6dd54943 Merge commit '766085c2dc6fc95ac30fda2a9ebde2355fc12554'
766085c2d Squashed 'docs/' changes from a4fa0d1d6..81847981f
b5d13ca16 Update Chroma
6b02f5c0f Make resources fetched via resources.Get and similar language agnostic
88e447c44 tocss/scss: Improve _ prefix handling in SCSS imports
b718d743b Fix file paths for uncached transformed images
0ba19c57f tpl/partials: Add templates.Exists
0afa2897a tpl/partials: Remove superflous loop
f219ac09f tocss/scss: Improve SCSS project vs themes import resolution
786f72302 Fix image cache eviction for sites with subdir in baseURL
0cae1cf82 releaser: Prepare repository for 0.46-DEV
3b18042ee releaser: Add release notes to /docs for release of 0.45.1
e38843f4b releaser: Bump versions for release of 0.45.1
87f0dc14a Release 0.45.1
b7d9ab136 releaser: Add release notes draft for 0.45.1
04d4c08db hugolib: Fix .Site.GetPage regression
016dd4a69 Add Page.FirstSection
c6b599a06 hugolib: Fix "borrow content from another language" issue
3a6784b16 releaser: Prepare repository for 0.46-DEV
48d7a641d releaser: Add release notes to /docs for release of 0.45
2c5a036de releaser: Bump versions for release of 0.45
592c5b307 Update release notes 0.45
a0c4a3660 releaser: Add release notes draft for 0.45
062510cf1 Get rid of the utils package
4e1d0cd9f Update hugo_windows.go
a451c49fd hugolib: Print a WARNING about relative non-relative ref/relref matches
ff16c42ed hugolib: Allow untyped nil to be merged in lang.Merge
166483fe1 resource/scss: Add IncludePaths config option
f01505c91 resource/scss: Fix source maps on Windows
8278384b9 Increase refLinker test coverage
65e610e16 hugolib: Avoid nilpointer in absoluteSourceRef
b56d9a129 Fix typo-logic bug in GetPage
d6fde8fa1 Enable test case fixed by commit 501543d4
2bac37154 Add test coverage for recent ref overhaul
9b4b97a72 hugolib: Create an adapter from old to new getPage
501543d4b hugolib: Only do page-relative getPage for relative paths
6ffa88234 hugolib: Improve error handling in refLink
1eb8b36b3 docs: Update ref, relref, GetPage docs
00c74ee7f docs: Document refLinksErrorLevel and refLinksNotFoundURL
e25aa655f Add configurable ref/relref error handling and notFoundURL
12679b408 hugolib: Mark shortcode changes as content changes in server mode
c39ac5738 Revert "hugolib: Fix potential server panic with drafts/future enabled"
a3535c848 Squashed 'docs/' changes from cfe89ecbc..a4fa0d1d6
9da617912 Merge commit 'a3535c8486b2ce762b1a8a9c30b03985c3e02cee'
1ab4658c0 hugolib: Fix potential server panic with drafts/future enabled
75acff5f2 hugolib: Avoid server panic on TOML mistake in i18n
5c9d5413a hugolib/filesystems: Fix theme config for Work Fs
59ebc83d7 Merge commit 'b6b37a1f00f808f3c0d2715f65ca2d3091f36495'
b6b37a1f0 Squashed 'docs/' changes from f59b3ab06..cfe89ecbc
ebe4d39f1 resource/postcss: Try node_modules/postcss-cli/bin/postcss first
1b0aeeaaf commands: Disable flaky server tests on Windows CI
a4c513cae commands: Increase sleep in server teset to make it less shaky on Windows
d741064be Add optional lang as argument to rel/relref
3eb313fef Simplify .Site.GetPage etc.
b93417aa1 Unify page lookups
fd1f4a786 Fix addkit link to account for i18n
4c240800a resource/bundler: Improve error message
38204c4ab hugolib: Only set 'allThemes' if there are themes in the config file
2f2bc7ff7 resource/integrity: Remove unused code
242b297f5 releaser: Remove flag on Windows build
f44c9ab9c releaser: Prepare repository for 0.45-DEV
9f9695cf7 releaser: Add release notes to /docs for release of 0.44
0831d8cca releaser: Bump versions for release of 0.44
1d4ff024c Finish release notes 0.44
521e63ac7 releaser: Add release notes draft for 0.44
47d38628e resource: Clean up the in-memory Resource reader usage
0024dcfe3 resource: Move opening of the transformed resources after cache check
beec1fc98 resource: Fix resources.Concat for transformed resources
306573def Improve type support in resources.Concat
80c8f3b81 hugolib: Fix static filesystem for themed multihost sites
6b6dcb44a Flush partialCached cache on rebuilds
d96f2a460 resource: Include the transformation step in the error message
ac5303503 media: Only show deprecation warning when needed
b874a1ba7 media: Allow multiple file suffixes per media type
410870593 hugolib: Remove empty resources/ dir after TestNewSiteDefaultLang
9c1e82085 .gitattributes: Exclude *.svg from CRLF/LF conversion
2b73e89d6 tpl: Set permission of embedded templates to 0644
febf0aec8 Build a fully static Windows extended binary
a4fad5be6 Adjust release notes
6084f0433 releaser: Prepare repository for 0.44-DEV
cbb7214b6 releaser: Add release notes to /docs for release of 0.43
e6136b36f releaser: Bump versions for release of 0.43
659917a00 releaser: Revert to the old versions of the release pipeline
9d194ab90 releaser: Add release for 0.43
a305609e1 snap: Migrate from deprecated keywords to "override-build"
179de5f5b Revert "Consider root and current section's content type if set in front matter"
5dc1f95b6 Revert "Restrict the new type layout resolution to page and section kinds"
6bc892fc2 Revert "output: gofmt -l -w output/layout.go"
5f06dbf77 Revert "snap: Build both hugo and hugo.extended for 0.43"
0850e9798 Revert "Revert "Add Goreleaser extended config""
a3b4b10f6 Revert "Add Goreleaser extended config"
e3df6478f Bump CircleCI image
626afc982 Add Goreleaser extended config
e1027c584 snap: Build both hugo and hugo.extended for 0.43
e1a052ecb fix: nfpm replacements
bfc3488b8 Add temporary build script
ce84b524f Add "extended" to "hugo version"
3cea2932e Fix typos
0efd37480 Merge commit '98293eaa1570b5aff4452021c8b6d6c8560b3f06'
98293eaa1 Squashed 'docs/' changes from 501c6e233..f59b3ab06
2b8d907ab Add a newScratch template func
43338c3a9 hugolib: Do not create paginator pages for the other output formats
dea71670c Add Hugo Piper with SCSS support and much more
a5d0a57e6 output: Fix the shortcodes/partials vs base template detection
f465571b3 output: gofmt -l -w output/layout.go
f8212d200 tpl/collections: Return en empty slice in after instead of error
78e8a744b Restrict the new type layout resolution to page and section kinds
c790029e1 Consider root and current section's content type if set in front matter
554553c09 circleci: Update docker image
de37455ec hugolib: Allow forward slash in shortcode names
282f6035e Merge branch 'release-0.42.2'
360fa1221 releaser: Prepare repository for 0.43-DEV
02aa32003 releaser: Add release notes to /docs for release of 0.42.2
d2640fbc1 releaser: Bump versions for release of 0.42.2
1637d12e3 Release 0.42.2
3a7706b06 commands: Fix broken server-reload on config changes
2955f93fc commands: Fix broken server-reload on config changes
1f0c4e1fb Update GoReleaser config
91ab455d8 tpl: Remove some "debug info"
ca1e46efb tpl: Update internal pagination template to support Bootstrap 4
fd71fa89b Create missing head.html partial on new theme generation
b5a3aa708 Add html doctype to baseof.html template for new themes
3d5928889 Revert "tpl: Support text/template/parse API change in go1.11"
dc7bc7b4d appveyor: Disable asciidoctor for now
42ed60258 hugolib: Replace deprecated {Get,}ByPrefix with {Get,}Match
6a2968fd5 Adds .gitattributes to force Go files to LF
23d5fc82e Update to Go 1.9.7 and Go 1.10.3
8531ec7ca Update Dockerfile to a multi-stage build
9f27091e1 tpl: Support text/template/parse API change in go1.11
187621ae2 releaser: Prepare repository for 0.43-DEV
4172a835e releaser: Add release notes to /docs for release of 0.42.1
fc9738896 releaser: Bump versions for release of 0.42.1
d67e843c1 Release 0.42.1
6e33c557b releaser: Add release notes draft for 0.42.1
128f14efa hugolib: Reset the global pages cache on server rebuilds
34ee27a78 commands: Do not fail server build when /static is missing
0f1fc01ef releaser: Prepare repository for 0.43-DEV
f32ccd018 Merge tag 'v0.42'
ffb609f4a releaser: Add release notes to /docs for release of 0.42
19d91abc9 releaser: Bump versions for release of 0.42
f5c0a2b4b Release 0.42
31828026a releaser: Add release notes draft for 0.42
c74b0f8f9 docs: Update theme documentation
80949dc73 docs: Remove some files now moved
e02629f81 Merge commit 'b239595af5a9fc1fc9a1ccc666c3ab06ccc32f04'
b239595af Squashed 'docs/' changes from 0fd7b4169..501c6e233
ed4a345ef commands: Create LICENSE rather than LICENSE.md in "new theme"
9717ac7dc commands: Create _default/baseof.html in "new theme"
692ec0087 commands: Make "new theme" feedback more intuitive
d3dd74fd6 commands: Move nextStepsText() to new_site.go
80230f26a Add support for theme composition and inheritance
6464981ad hugolib: Make sure that .Site.Taxonomies is always set on rebuilds
2e6712e28 tpl: Always load GA script over HTTPS
65deb72dc tplimpl: Remove speakerdeck shortcode
dc4226a8b hugolib: Reset Page's main output on server rebuilds
bf5f10faa Reset the "distinct error logger" on rebuilds
019bd5576 tpl/strings: strings.RuneCount
c3115292a tpl: Prevent isBaseTemplate() from matching "baseof" in dir
0c6c98e40 tpl/strings: Remove overflow check in strings.Repeat
90c774908 tpl/strings: Adjust the overflow validation in strings.Repeat
13435a6f6 tpl: Add strings.Repeat
07b96d16e Fixes #4798
ceaff7caf tpl: Remove frameborder attr YT iframe + CSS fixes
b84389c5e Fix vimeo_simple thumb scaling
8de532447 Add vimeo_simple
20cbc2c78 Add a BlackFriday option for rel="noreferrer" on external links
2174525ce hugolib: A little more on shortcode ordinal
7a6192647 Add a BlackFriday option for rel="nofollow" on external links
d68367cbe fix typo instagram_simple
5241f0bae releaser: Prepare repository for 0.42-DEV
b5b36e320 dep: Update Chroma
4f0665f47 Enhance Page and Resource String()
fc8c5ad82 Merge tag 'v0.41'
171caf28a releaser: Add release notes to /docs for release of 0.41
0e77f5d4e releaser: Bump versions for release of 0.41
9e7e322de Release 0.41
06827398f releaser: Add release notes draft for 0.41
cfc5096e8 releaser: Put release notes below /en
ab02594e0 create: Provide the correct .Site object to archetype templates
c71f201fd docs: Document the GDPR Privacy Config
4ed1228d5 Fix GA anonymizeIp order
a51945ea4 Add no-cookie variants of the Google Analytics templates
7b9dbef41 Merge commit 'd2b1030060d3c91d5f9ffa3456418da16bd74f1d'
d2b103006 Squashed 'docs/' changes from e161ea09d..0fd7b4169
0bf0e1972 tpl: Remove the shortcode assets for now
1f244b802 tpl: Adjust instagram_simple margins
448081b84 Remove youtube_simple for now
1f1d955b5 Add anonymizeIP to GA privacy config
ffcf26e68 Fix broken test
9753cb59f Support DNT in Twitter shortcode for GDPR
3bfe8f4be tpl: Alias tweet shortode to twitter
6aa2c3850 Regenerate embedded templates
6d69dac9d Fix youtube_simple thumb scaling
9ad46a203 Add instagram_simple shortcode
4256de339 deps: Go fmt
bed7a0faf Remove the id from youtube_simple
35ccf06da Fix some recently broken embedded templates
4ddcf52cc Add an unified .Site.Config with a services section
353148c2b Move the privacy config into a parent
568b4335c commands: Avoid ANSI character output on Windows
14705ecea tpl: Add another class and an id to youtube_simple
69ee6b41e Make the simple mode YouTube links schemaless
88e356868 Add YouTube shortcode simple mode
2f17f9378 Do not return error on .Get "class" and vice versa in shortcodes
0a7027e2a Create SUPPORT.md
5f24a2c04 Add PrivacyEnhanced mode for YouTube to the GDPR Policy
710142016 Add RespectDoNotTrack to GDPR privacy policy for Google Analytics
f45b522eb tpl/tplimpl: Adjust GA templates
678920734 tpl/tplimpl/embedded: Wrap the relevant templates with the privacy policy disable check
0bbdef986 config: Add the foundation for GDPR privacy configuration
9bd4236e1 Show site build warning in TestPageBundlerSiteRegular
4eedb377b commands: Do not show empty BuildDate in version
b2b500f56 hugolib: Use double quotes instead of back quotes
2fb9af59c Improve markup determination logic
00e36a416 Merge branch 'release-0.40.3'
bfb774490 releaser: Prepare repository for 0.41-DEV
ecae2106b releaser: Add release notes to /docs for release of 0.40.3
315a73c9f releaser: Bump versions for release of 0.40.3
46dc006f1 Release 0.40.3
d089e9d45 releaser: Add release notes draft for 0.40.3
90d0d8309 hugolib: Fix possible .Content cut
086ae81a9 hugolib: Fix possible .Content cut
c2bb62d63 tpl/tplimpl: Move README one level up
34ad9a4f1 tpl/tplimpl: Extract internal templates
914cc85e2 Merge commit '83bef6955e014d40c0f00db9cebe09113154e999'
83bef6955 Squashed 'docs/' changes from 896bad9f4..e161ea09d
a6816db77 Fix typo
b6ededf05 Update CONTRIBUTING.md
8b03c51ea releaser: Prepare repository for 0.41-DEV
5a9d1324d releaser: Add release notes to /docs for release of 0.40.2
f1269a6d0 releaser: Bump versions for release of 0.40.2
669b3d3a9 Release 0.40.2
317d81ec4 releaser: Add release notes draft for 0.40.2
655983a22 Reset .Page.Scratch on live-reload
001a28c2f Fix .WordCount, .FuzzyWordCount, .ReadingTime when summary marker is set
391f59f99 releaser: Prepare repository for 0.41-DEV
459935b29 releaser: Add release notes to /docs for release of 0.40.1
b5dafb0f2 releaser: Bump versions for release of 0.40.1
88cb2697e Release 0.40.1
6fb2d30d2 releaser: Add release notes draft for 0.40.1
288c39643 hugolib: Fix some shortcode vs .Content corner cases
44e47478d releaser: Prepare repository for 0.41-DEV
c7e59367d releaser: Add release notes to /docs for release of 0.40
3aed26837 releaser: Bump versions for release of 0.40
7ef118392 Release 0.40
2e77cc07a releaser: Add release notes draft for 0.40
402f6788e hugolib: Add .Page.BundleType
3decf4a32 hugolib: Add zero-based Ordinal to shortcode
24c662ce6 hugolib: Defer the unlock in orderedMap.Add
a215abf70 Squashed 'docs/' changes from 76e881257..896bad9f4
474bad34c Merge commit 'a215abf70e018f4bf40d6c09d8bd148d8684b33d'
85535084d hugolib: Process and render shortcodes in their order of appearance
19084eaf7 hugolib: Init the content and shortcodes early
47e7788b3 tpl/path: Add path.Ext, path.Dir and path.Base
51af1d2ea tpl/os: Make fileExist use the same filesystem as readFile
1b9dc52ef Merge commit 'd2ec1a06df8ab6b17ad05cb008d5701b40327d47'
d2ec1a06d Squashed 'docs/' changes from f9a5dc59b..76e881257
4d26ab33d Make .Content (almost) always available in shortcodes
d6a2024e6 Revert "Improve .Content vs shortcodes"
d6982ac0a Revert "hugolib: Prepare child page resources before the page itself"
3238e14fd hugolib: Prepare child page resources before the page itself
47c05c47e Add language merge support for Pages in resource.Resources
e590cc26e Improve .Content vs shortcodes
74520d2cf Improve .Get docs
e2b277bba Update missing positional parameter test for .Get
236f0c840 .Get doesn't crash on missing positional param fixes #4619
cd6a26124 .Get function: fix syntax signature
d681ea55a Improve error message in metadata parse
a96ad5c21 hugolib: Fix broken test
159bed34c parser: Add some context to front matter parse error
5cc944ffd Updated GetCSV error message (#4636)
89d2cf49a releaser: Prepare repository for 0.40-DEV
933a16b10 releaser: Add release notes to /docs for release of 0.39
60845a5a0 releaser: Bump versions for release of 0.39
9a39146ed releaser: Fix LICENSE vs LICENSE.md
1a6a0fa6f Release 0.39
936fc76ad releaser: Add release notes draft for 0.39
f21b827f7 commands: Re-add the missing releaser command
7c597c7d7 Merge commit '047c4188dfc854f658d16f1e4a9501f9c97a31c7'
047c4188d Squashed 'docs/' changes from d9c8fc220..f9a5dc59b
e136c26d0 Remove old LICENSE.md
dd4827749 Add a GitHub compatible Apache 2 license text
4dba6ce15 tpl/urls: Add anchorize template func
880ca19f2 tpl/path: Add path.Join
01b72eb59 tpl: Add path.Split template func
61d52f146 hugolib: Do not reset .Page.Scratch on rebuilds
0e7716a42 resource: Implement Resource.Content
417c5e2b6 Make Page.Content a method that returns interface{}
94c8b29c3 source: Remove deprecated File.Bytes
1b4e0c416 commands: Remove accidental and breaking space in baseURL flag
27a524b09 commands: Properly handle CLI slice arguments
bede93de0 commands: Correctly handle destination and i18n-warnings
2aab6dee8 commands: Fix handling of persistent CLI flags
f3775877c hugolib: Fix livereload of bundled pages
9c782d514 commands: Fix failing Travis server test
14c35c8a5 Allow "*/" inside commented out shortcodes
96689a5c3 commands: Make commands.Execute return a Response object
e7010c1b6 commands: Remove some TODOs
f396cffa2 commands: Fix the config command
24d5c2194 commands: Fix some flag diff
a7d00fc39 commands: Add basic server test
1e233b1c4 commands: Fix TestFixURL
b110d0ae0 commands: Remove the Hugo global
73825cfc1 commands: Make the limit command work again
a8f7fbbb1 commands: Move the commands related logic to its own file
e8d6ca953 commands: Add CLI tests
4d32f2fa8 commands: Make the hugo command non-global
018602c46 commands: Extract some common types into its own file
2f0d98a19 commands: Make the server command non-global
e0621d207 commands: Make the gen commands non-global
e26a8b242 commands: Make the list commands non-global
2a2c98386 commands: Make the import commands non-global
15b1e269a comands: Make the config command non-global
56a130804 commands: Make the new commands non-global
4b780ca77 commands: Make convert command non-global
7bc5e89fb commands: Make more commands non-global
fdf1d94eb commands: Make benchmark non-global
1157fef85 commands: Start of flag cleaning
e614d8a57 commands: Use short date format in CLI docs
fca49d6c6 Update README.md
0e8b3cbcd Sync dependencies
230f2b8c4 Bump Go versions
d7f47b780 releaser: Prepare repository for 0.39-DEV
712c0fdfe releaser: Add release notes to /docs for release of 0.38.2
62e758826 releaser: Bump versions for release of 0.38.2
47da0dca5 Release 0.38.2
8d87bfd5e releaser: Add release notes draft for 0.38.2
719251c1a Bump the debouncer dependency
8b2ef83bb Use a versioned debounce dependency
080302eb8 Fix handling of --contentDir etc. flag
094ec1714 travis: Disable shallow clone to fix TestPageWithLastmodFromGitInfo
e84b7ade6 Revert "Disable failing test on Travis"
2817e8424 Fix handling of content files with "." in them
623c9afa8  And now really disable failing test on Travis
2170943ae Disable failing test on Travis
9cd4d3597 Revert "Try an older GitMap version"
3a3261a3b Try an older GitMap version
6792d86ad hugolib: Set .Parent in bundled pages to its owner
e7d87e241 releaser: Prepare repository for 0.39-DEV
c475eab47 releaser: Add release notes to /docs for release of 0.38.1
3a96fa40b releaser: Bump versions for release of 0.38.1
c356f1d41 Release 0.38.1
30c2c2f8e releaser: Add release notes draft for 0.38.1
f87239e4c Fix livereload for the home page bundle
db0633c1a snap: Revert to "mage test" because "mage check" fails
874159b54 snap: Add bash completion
294c0f800 snap: Fix empty BuildDate in "hugo version"
a4deaeff0 Fix some livereload content regressions
4d115c56f Update github.com/bep/gitmap to fix snap build
26f34fd59 Fix two tests that are broken on Windows
730b66b65 commands: Handle mass content etc. edits in server mode
4f639d6bd releaser: Prepare repository for 0.39-DEV
f7bc28c52 releaser: Add release notes to /docs for release of 0.38
20e9c08e1 releaser: Bump versions for release of 0.38
37140a093 Release 0.38
da80163c7 releaser: Add release notes draft for 0.38
60e66d12e travis: Clean up and increase verbosity
ed8bf081f Squashed 'docs/' changes from 3068989b9..d9c8fc220
558825cc2 Merge commit 'ed8bf081fdbf336e026517b7e1b123c039014ab5'
10c33c17c docs: Generate docshelper data
2c54f1ad4 docshelper: List Chroma lexers
eb15ac37e travis: Run "gem install" without sudo
eb42774e5 Add support for a content dir set per language
f27977809 Update stale.yml
7a634898c Update Chroma
1823c053c Add .Site.IsServer
511d5d3b7 travis: Move to Ubuntu Trusty image
8299fa885 snap: Remove "make" from build-packages because we use mage now
06495f713 snapcraft.yaml: Call mage with "-v" for debugging
93e24a03c hugolib: Fix freeze in invalid front matter error case
e9c7b6205 Allow themes to define output formats, media types and params
3d1a6e109 hugolib: Add ConfigSourceDescriptor
b6798ee86 Bump some deprecations
0a23baa6a Squashed 'docs/' changes from 211a3c613..3068989b9
84f4b731d Merge commit '0a23baa6a90901f772c234107c4f12c16c76f4aa'
61f6e9f63 tpl/transform: Add a comments test for Remarshal
904a3d9dd Update Chroma to get Go template support
f0052b6d0 commands: Recover from error in server
da8801577 Spring test cleaning, take 2
debd3663d hugolib: Test cleaning #1
af67ad8af hugolib: Trim some now superflous tests
e46ab29bd hugolib: Add Reset method to delete key from Scratch
10fef32de releaser: Adjust the "thank you" section
70005364a docs: Add docs for lang.Merge
ffaec4ca8 Add a way to merge pages by language
3886fc1fe Squashed 'docs/' changes from 4e7e1815b..211a3c613
91fb8f1b5 Merge commit '3886fc1fef6ac19d58b9ba1bb642d0c6c9a54031'
ac12d51e7 create: Remove archetype title/date warning
3fbc75534 resource: Fix path duplication/flattening in processed images
e427ba426 hugolib: Remove superflous debug file
79dd7cb31 hugolib: Simplify Prev/Next
0dbf79c2f docs: Add docs on the new front matter configuration
f12ad7d56 hugolib: Adjust GitInfo author date test
ce6e4310f Refactor the GitInfo into the date handlers
95d62004a Merge commit 'c0290655825e7bb36e13fb39f89d85b392cf1adc'
c02906558 Squashed 'docs/' changes from 715741f73..4e7e1815b
68bf1511f hugolib: Extract date and slug from filename
f8dc47eef Allow partial redefinition of the ouputs config
ae3fa349d output: Fix build
64cec0729 outputs: Adjust the layout examples
9ac620658 releaser: Prepare repository for 0.38-DEV
f414966b9 releaser: Add release notes to /docs for release of 0.37.1
c29a2ed2f releaser: Bump versions for release of 0.37.1
dfb6484a4 Release 0.37.1
8a0296839 releaser: Add release notes draft for 0.37.1
e7fda289b Remove defaultLayout config
50a03a5ac commands: Do not print build total when --quiet is set
ba94abbf5 resource: Fix SVG and similar resource handling
55fb0eac2 releaser: Remove suplerflous release notes slug
06e5ee652 releaser: Prepare repository for 0.38-DEV
956a2dce8 releaser: Add release notes to /docs for release of 0.37
1f1c562b9 releaser: Bump versions for release of 0.37
3e1a6ebc1 Release 0.37
8915cb83f releaser: Add release notes draft for 0.37
900b5f6cf Squashed 'docs/' changes from 1dc05a16b..715741f73
57637d89e Merge commit '900b5f6cfe5a377ef369d26cd700201be4cf6b06'
13ea1e7c3 resource: Use Floyd-Steinberg dithering for PNGs
9f740b37c hugolib: Fix paginator URL for sections with URL in front matter
e39797fa7 hugolib: Avoid scanning entire site to find the home
00868081f Fix bug in Site.assembleSections method
e9750d831 hugolib: Continue GitInfo lookup on error
19d9a46f6 Properly handle -DEV suffix when comparing Hugo versions
0602135fd Make ge, le etc. work with the Hugo Version number
55bd46a63 commands: Remove ERROR on missing baseURL
8dc77b84a releaser: Create bundles for the release notes
4560261b5 Merge commit '374d184e6747678364fd61f5faf328ec9205eb6b'
374d184e6 Squashed 'docs/' changes from f97826a17..1dc05a16b
772128485 Run gofmt -s with Go 1.10
c2c4cb1f9 hugolib: Fix broken footnote test
492fea7cd Update Blackfriday to fix footnote HTML5 validation error
5ed11edf5 releaser: Update to Go 1.10
799c654b0 resource: Preserve color palette for PNG images
faa3159e5 Fix typos in development contribution doc
eaf573a27 Update dependencies
3ced6f8d4 magefile: Disable Go 1.10 gofmt check for now
a3f26e563 Second try: Update to Go 1.10 (!)
0c452c6e7 Revert "Update to Go 1.10 (!)"
ff10c15a9 Update to Go 1.10 (!)
efd506314 Merge branch 'release-0.36.1'
8de91da74 releaser: Prepare repository for 0.37-DEV
25e88ccab releaser: Add release notes to /docs for release of 0.36.1
19228ed83 releaser: Bump versions for release of 0.36.1
a1f40084f Release 0.36.1
d7bf9d4da releaser: Add release notes draft for 0.36.1
53e661e7c releaser: Update to Go 1.9.4
fc23a80ff Bump Travis/Snapcraft to Go 1.9.4
d8fdffb55 resource: Fix multi-threaded image processing issue
2851af022 resource: Improve error processing error message
08521dac8 hugolib: Improve error message in .Render
58382e957 resource: Fix multi-threaded image processing issue
53dac9a50 resource: Improve error processing error message
4edb4bcc6 hugolib: Improve error message in .Render
0816a97a4 parser: Add WARNING for integer YAML keys
10a917dfd parser: Tune stringifyMapKeys
d4beef0d2 parser: Rename stringifyYAMLMapKeys to stringifyMapKeys
51213e0be parser: Add benchmarks for stringifyYAMLMapKeys
1fa241777 Add support for YAML array data files
bb549a0d5 Account for array type data in data dir merge/override logic
82eefded1 hugolib: Refactor tests for JSON, YAML and TOML equivalency, add coverage
e17283499 hugolib: Re-enable YAML data tests disabled in f554503f
b5cb8866e Merge commit '9cc9bab46288d8d5f9fda7009c5f746258cec1b4'
9cc9bab46 Squashed 'docs/' changes from 2fc775dec..f97826a17
d382502d6 tpl/transform: Add template func for TOML/JSON/YAML docs examples conversion
2e95ec684 Add "target" and "rel" parameters to figure shortcode
76d38d5e5 Use more canonical "twitter:image" property, not "twitter:image:src"
f554503fe hugolib: Temp. disable some YAML data tests
16a5c7451 parser: Fix YAML maps key type
49b98975b releaser: Update to Go 1.9.4
0de375a7e Bump Travis/Snapcraft to Go 1.9.4
e02ee7d6a releaser: Prepare repository for 0.37-DEV
18e3657a2 releaser: Add release notes to /docs for release of 0.36
4bc8727fc releaser: Bump versions for release of 0.36
a9a0190b1 Release 0.336
742deaa3d releaser: Add release notes draft for 0.36
694c0fd76 docs: Add documentation for smart cropping etc.
15ff07657 Merge commit 'c305e44f5f081e4436195923a4593e396f07cd49'
c305e44f5 Squashed 'docs/' changes from dce236ad1..2fc775dec
722086b4e resource: Add smart cropping
084cf4191 tpl: Ensure site templates can override theme templates
fc06d5c18 hugolib: Add additional test to TestTemplateLookupOrder
9a367d9d0 hugolib: Fix broken TestTemplateLookupOrder
4402c0777 Fix JSON array-based data file handling regression
4743de0d3 Increase data directory test coverage
19e26cb4e releaser: Prepare repository for 0.36-DEV
0283db6c6 releaser: Add release notes to /docs for release of 0.35
58188807a releaser: Bump versions for release of 0.35
51d5c5421 Release 0.35
a9a5b1e09 docs: Regenerate CLI docs
cf5c2df81 releaser: Add release notes draft for 0.35
158e1151c Merge commit '337d0c5f516ee085205e8abefdb7f87e6d33ca05'
337d0c5f5 Squashed 'docs/' changes from 56c34962c..dce236ad1
f0c0ece44 Add "removable-media" interface to snapcraft.yaml
a34213f0b Fix Docker build
fe40823de readme: Update list of "builders" to include myself
ae742cb1b Fix language params handling
feeed073c commands: Remove some now superflous Fast Render Mode code
94e736c5e hugolib: Extract the Fast Render Mode logic into a method
1707dae8d hugolib: Handle newly created files in Fast Render Mode
2fa70c934 command: Remove undraft command
b6f3f087a commands: Mark deprecated flags in the CLI help
adfd4370b hugolib: Deprecate useModTimeAsFallback
25d691daf tpl: Update Twitter card to also consider images in .Resources
df20b0546 resource: Make resource counters for name and title independent
863a812e0 create: Provide .Name to the archetype templates
f08ea02d2 commands: Deprecate CLI flags canonifyURLs, pluralizeListTitles, preserveTaxonomyNames, uglyURLs
016398ffe hugolib: Fix --uglyURLs from comand line regression
3752348ef Only set 'url' if permalink in metadata and remove duplicate confirm msg
4eb2fec67 Fix handling of top-level page bundles
83c761b71 tpl/collections: Seed random on init only
ed4a00e46 commands: Fix baseURL server regression for multilingual sites
7b472e460 resource: Start Resources :counter first time they're used
96e3fbcf2 travis: Re-enable macOS builds
a91aba1c1 Update to Go 1.9.3
6413559f7 Add a way to disable one or more languages
322c56722 Fix "date" page param
91bb774ae Support pages without front matter
3f0379adb Add page metadata dates tests
ae5a45be6 hugolib: Remove unused code
4d912e2aa hugolib, output: Fix robots.txt in multihost mode
1e27d0589 docs: Re-generate CLI docs
d418c2c2e Remove and update deprecation status
b2fcbb1f9 output: Remove duplicate layout lookup layouts
3446fe9b8 hugolib: Add the last lookup variant for the GetPage index
4a7c2b369 github: Shorten the stale setup
912147ab8 resource: Fix typo in comment
517b6b623 hugolib: Simplify bundle lookup via .Site.GetPage, ref, relref
a19563910 Add a GetPage to the site benchmarks
0432c64dd Add headless bundle support
5a0819b9b Merge matching resources params maps
78c863305 Add some general code contribution criterias
22ad1ebdb travis: Disable macOS builds for now
ebdd8cba3 helpers: Avoid unescape in highlight
8125b4b03 Tighten page kind logic, introduce tests
87217d1d0 releaser: Prepare repository for 0.35-DEV
ffd7dc396 releaser: Add release notes to /docs for release of 0.34
2228d3e28 releaser: Bump versions for release of 0.34
5903a9ce1 Release 0.34
4d644c9d6 releaser: Add release notes draft for 0.34
34a216fe6 resource: Avoid some strings.ToLower in globbing
adee04f4b releaser: Fix BuildDate in release binaries
942138016 resource: Add Match and GetMatch
5d0308698 hugolib: Fix handling of pages bundled in sub-folders in ByPrefix etc.
07700aab0 output: Add some more layout docshelper variants
4d5e4f379 hugolib: Add validation for defaultContentLanguage
cd7796828 releaser: Prepare repository for 0.34-DEV
c7b9347be releaser: Add release notes to /docs for release of 0.33
c6b903729 releaser: Bump versions for release of 0.33
09a934b32 Release 0.33
e6cc2a655 releaser: Add release notes draft for 0.33
a39ae4bb0 output: Redo the docshelper layouts examples
b3eeb9764 Merge commit '3cf4300097610bb8b5bd0686d96d1df5db641895'
3cf430009 Squashed 'docs/' changes from ddb7d8fae..56c34962c
9409bc0f7 Improve .Site.GetPage for regular translated pages
4eb1650be resource: Use path.Match instead of filepath.Match
20c9b6ec8 resource: Add front matter metadata to Resource
f8a119b60 Update Afero to avoid panic on "file name is too long"
ecaf14514 resource: Fix handling of very long image file names
d4f8f88e6 commands: And now really fix the server watch logic
4e524ffcf commands: Fix server without watch
64f0e9d1c Update Chroma and other third-party deps
13d53b31f commands: Remove superflous BuildDate logic
51dd462c3 layout: Respect Type and Layout for list template selection
b6ea6d07d Run benchmarks 3 times
4dac1781e resource: Add some GoDoc
8a409894b hugolib: Allow url in front matter for list type pages
46db900da resource: Implement Resources.ByPrefix
60c9f3b1c resource: Make GetByPrefix work for Page resources
57e10f174 Support uglyURLs per section
db85e8340 resource: Make .Resources.GetByPrefix case insensitive
1046e9363 Update CONTRIBUTING.md
d5803da1b Support offline builds
27c77e1ab releaser: Prepare repository for 0.33-DEV
218773a82 releaser: Add release notes to /docs for release of 0.32.4
a97ef61ba releaser: Bump versions for release of 0.32.4
4aaf27dc5 Release 0.32.4
f7d0b05f9 releaser: Add release notes draft for 0.32.4
f82428d2e releaser: Git info bounds checking
50fb49c3d resource: Remove superflous comment
5235a5bf5 Correct fix for --cleanDestinationDir flag
1921a70ab Revert "Remove the --cleanDestinationDir flag", there is a better fix.
f0eecc6a4 Fix non-ASCII path handling for Page resources
768ec5df9 Remove the --cleanDestinationDir flag
238e7f7fb releaser: Prepare repository for 0.33-DEV
0aaa38544 releaser: Add release notes to /docs for release of 0.32.3
fdec5e308 releaser: Bump versions for release of 0.32.3
71abb53ff Release 0.32.2
db5d79862 releaser: Add release notes draft for 0.32.3
2d3189b22 hugolib: Fix handling of mixed-case taxonomy folders with content file
4b04db0f0 resource: Avoid processing and storing same image for each language
97c1866e3 resource: Resources.ByType should return Resources
8969331f5 Fix multihost detection for sites without language definition
6feb13878 commands: Report build time on config.toml change
059e8458d Fix hugo benchmark --renderToMemory
ab82a27d0 Fix URLs for bundle resources in multihost mode
f25d8a9e1 Fix sub-folder baseURL handling for Page resources
54a89cde6 releaser: Prepare repository for 0.33-DEV
2cd962233 releaser: Add release notes to /docs for release of 0.32.2
865877cd0 releaser: Bump versions for release of 0.32.2
1ff80a8bb Release 0.32.2
956ef4097 releaser: Add release notes draft for 0.32.2
196da49c9 resource: Handle publish to /public on fresh build
2aa4c009e Merge commit 'eb738cd35cca1ffc68c5ed688dbe2a19108e8761'
eb738cd35 Squashed 'docs/' changes from fc61378a3..ddb7d8fae
3dd8c1c02 releaser: Prepare repository for 0.33-DEV
fd301c3c0 releaser: Add release notes to /docs for release of 0.32.1
54ef60b03 releaser: Bump versions for release of 0.32.1
14a758ff2 Release Hugo 0.32.1
e64eb5ec2 releaser: Add release notes draft for 0.32.1
d36d71edd commands: Fix broken hugo --renderToMemory
a54fd7df2 resource: Use the correct Destination FS
16e1d99c6 resource: Create target dir if not exists
bf8a61fde hugolib: Add test for image processing from shortcodes
72158ab2e releaser: Prepare repository for 0.33-DEV
cb359a75c releaser: Add release notes to /docs for release of 0.32
82db03943 releaser: Bump versions for release of 0.32
2d2289c79 Release v0.32
6894f121b releaser: Add release notes draft for 0.32
245212a5b Merge commit 'f3cd083961f36dc96d05e98aaf67f650102bc757'
f3cd08396 Squashed 'docs/' changes from 3e663efb2..fc61378a3
407c24020 hugolib: Add test for homepage content for all rendering engines
c067f3455 tpl/transform: Do not unescape input to highlight
72903be58 commands: Make sure all language homes are always re-rendered in fast render mode
1c114d539 hugolib: Do not tolower result from Page.GetParam
e14129461 resource: Avoid potential case issue in image names
612dcc194 helpers: Avoid writing the last MD5 buff part twice
e50a8c7a1 resource: Use MD5 to identify image files
7e76a6fd3 source: Fix test on Windows
1b0780dbe source: Make sure .File.Dir() ends with a slash
3cdf19e9b  Implement Page bundling and image handling
02f2735f6 tpl/strings: Fix broken test
22cd89adc Make chomp return the type it receives
db4b7a5c6 Reuse the BlackFriday instance when possible
251149860 livereload: Fix host comparison when ports aren't present
9df3736fe Add .Title and .Page to MenuEntry
243694102 Remove the goroutines from the shortcode lexer
315352616 mage: Do not run Go Fmt check on Go tip
fdbef2a81 Adjust the stale setup
426ac9c18 Add Github stale bot config
84805a68c Use StopTimer in site benchmarks
a2d81ce98 Add output formats definition to benchmarks
051fa343d Improve site benchmarks
23f69efb3 Fix context of opengraph video range
e69da7a4c Add Pandoc support, refactor external helpers
e7652180a vendor: Fix Humanize for multi-byte runes
798921012 vendor: Update Chroma to v0.2.0
7f2ae3ef3 vendor: update goorgeous@v1.1.0
8a8ba63c7 releaser: Prepare repository for 0.32-DEV
c1c04d74a releaser: Add release notes to /docs for release of 0.31.1
aa68205d1 releaser: Bump versions for release of 0.31.1
94115888e Release 0.31.1
bf8aa4ac5 releaser: Add release notes draft for 0.31.1
6d79beb5f tpl/images: Close image file
8afd7d9ce commands: Fix broken --appendPort=false
42fbf15fb releaser: Prepare repository for 0.32-DEV
288723a04 releaser: Add release notes to /docs for release of 0.31
f4b416bbe releaser: Bump versions for release of 0.31
058f25146 Release 0.31
3dd7e8b7a releaser: Add release notes draft for 0.31
30c0d485e Squashed 'docs/' changes from a042b67b5..3e663efb2
14786c4d8 Merge commit '30c0d485eaff6d70df1be0353911ddca485d52bf'
089fe4930 hugolib: Make sure everything ends up in its lang root in multihost mode
118b83d74 helpers: Properly handle []interface{} as staticDir
adbd5bc47 source: Enable disabled test
c1d325934 helpers: Remove (now) unused GetStaticDir
d99db71ab livereload: Fix recently broken window.location.reload logic
503ca6de6 Fix broken shortcodes for Ace and Amber
b3daa1f4b hugolib: Fix .IsTranslated  with identical filenames
df1677a6e Merge commit '05e42bc643f1840ed2ad9c2eff82a269d1381683'
05e42bc64 Squashed 'docs/' changes from e65df1059..a042b67b5
0a81a6b4b output: Fall back to unstranslated base template
60dfb9a6e Add support for multiple staticDirs
2e0465764 Add multilingual multihost support
6233ddf9d tpl/partials: Fix the lock contention in cached partial
e66d813bc gopkg: Update Chroma to get SVG support
f5ed04bd4 tpl/partials: Fix cache locking
7730d683e tplimpl: Make partial benchmarks use RunParallel
bb048d811 Use ms precision for static change logging
9299a16c9 circleci: Bump to Go 1.9.2
a9be687b8 hugolib: Pre-allocate some slices
b32ffed6a Update Chroma to get the latest SASS lexer
77cbd001f Update Travis and snapcraft to Go 1.9.2
764f1304e hugolib: Add some more taxonomy permalinks test cases
d9a78b61a Handle Taxonomy permalinks
23ba779fa i18n: Support unknown language codes
550cec0b1 gopkg: Bump go-i18n version
b88a105a7 Revert "i18n: Allow custom language codes"
b3443b3d0 Revert "i18n: Prevent data race in lang code handling"
c97216e4f i18n: Prevent data race in lang code handling
bb04010cb i18n: Allow custom language codes
76dc811c6 tpl/math: Refactor Mod with cast
488631fe0 Add support for height argument to figure shortcode
fdd62eb4c Add linebreak to README.md for better readability
b6f2e3b43 Update toml dependency revision in Gopkg.lock too
c61998d3a Update toml dep to fetch its latest master branch instead of v0.3.0
45ad8ac38 vendor: Lock mage to v1
133cfd171 mage: Skip Check on Go 1.8
db1a5af15 Gopk.toml cleanup
9ccc958ce Update Dockerfile and Snap build to reflect move to dep
30e471b8c Update CONTRIBUTING to reflect Go Dep
f711b170e Update magefile to use Go Dep
9536f7cd0 Adjust some deps versions
1ac47cd88 Run dep init
ba0b22ef4 vendor: Remove to prepare for dep
c9c19d794 Fix error handling in mage build
1d52bfbb4 releaser: Prepare repository for 0.31-DEV
142ebba2c releaser: Add release notes to /docs for release of 0.30.2
bf633ea2f releaser: Bump versions for release of 0.30.2
6faf47e8d 0.30.2 Release
7954bc0f0 releaser: Add release notes draft for 0.30.2
c4bf03a55 releaser: Improve release notes front matter
316410331 commands: Support Fast Render mode with sub-path in baseURL
6a5170116 Merge commit '325009c3fd4ac90021897b7e3e025c14e70ce162'
325009c3f Squashed 'docs/' changes from 4628b9ec2..e65df1059
bc53cd7b1 releaser: Prepare repository for 0.31-DEV
4e07b4144 releaser: Add release notes to /docs for release of 0.30.1
89a3f47a2 releaser: Bump versions for release of 0.30.1
35be07f7c Release 0.30.1
6f84570d8 releaser: Add release notes draft for 0.30.1
896416257 circleci: Must go get mage
e939aaed8 releaser: Correctly set final version on patch releases
d2b3f00df Bump Snap to go1.9.1
fa53b13ca Fix hugo -w
c3c10f2c7 Simplify Site benchmarks
ad5ef4383 Fix mage vs make issues
5109ed520 Revert "tplimpl: Output xmlns:xhtml only if there are translations available"
45e0908b8 releaser: Prepare repository for 0.31-DEV
41180c51e releaser: Add release notes to /docs for release of 0.30
811f381e2 releaser: Bump versions for release of 0.30
7d783a1c0 Release Hugo 0.30
49d5e7da4 Use Make for the release for now
190508ae1 releaser: Add release notes draft for 0.30
04bdb596a Fix CircleCI build issue
fe71cb6f5 Replace make with mage in CircleCI build
68ace4343 Update CircleCI build to use Mage
ecf5e081b Squashed 'docs/' changes from 000ab7c42..4628b9ec2
5c31e0c34 Merge commit 'ecf5e081b5540e69f4af330233f39a07baf53846'
7c30e2cbb Add table linenos support for Chroma highlighter
60bd332c1 Only re-render the view(s) you're working on
6a30874f1 Make sure Date and PublishDate is always set to a value if one is available
15ec031d9 Add correct config file name to verbose server log
01e54609e metrics: Reset benchmark timer
5800a20a2 metrics: Detect partialCached candidates
e2e8bcbec tpl: Rework the partial test and benchmarks
66a169a24 Simplify HugoNoGitInfo in magefile
2cc476567 Add mage installation step to CONTRIBUTING.md
856fc445d Bump Go versions in Travis config
a6ed645a3 Change last 'make' statements to 'mage'
23488f874 Minor README changes
8d2580f07 Replace make with mage
06e563340 Merge commit 'dae5a7c61cceeb0de59f2d755f63e453f71dd9b2'
dae5a7c61 Squashed 'docs/' changes from 36d7e22f5..000ab7c42
a58741a17 helpers: Fix broken test
d32fd8e32 vendor: Update deps
0859d9dfe tplimpl: Output xmlns:xhtml only if there are translations available
384a6ac4b Create magefile from Makefile
4fc67fe44 tpl: Add errorf template function
47fdfd519 Clean up lint in various packages
d45e358a0 helpers: Fix broken Chroma test
24fab9984 hugolib: Fix broken hightlighter smoke test
6a986b7c0 vendor: Update dependencies
8cf55aff0 vendor: Update Chroma
8717a60cc Change SummaryLength to be configurable (#3924)
281887899 tpl: Add os.fileExists template function
b6a30283f Merge commit '9d68f695e782c6a83c77aff13317c7a22c694c98'
9d68f695e Squashed 'docs/' changes from 20959c7b..36d7e22f
57adc539f tpl: Add float template function
b277cb33e hugolib: Move metrics output to the end of the site build
a354d130d examples: Fix `now` usage in footer
f806e951f releaser: Prepare repository for 0.30-DEV
524c67107 releaser: Add release notes to /docs for release of 0.29
396759a09 releaser: Bump versions for release of 0.29
e6079a9c0 releaser: Add release notes for 0.29
b5e1dc589 tpl: Set Metrics at creation time
d3681f51c metrics: Fix sort order
4f576e1c0 Revert "vendor: Update Chroma"
b4a14c25f metrics: Add simple template metrics feature
cb8eb4726 vendor: Update Chroma
e94d4f017 commands: Make noHTTPCache default false
8a69d2356 tpl: Add math.Ceil, Floor, and Round to method mappings
d9697e275 Split go build in Dockerfile
09d960f17 Update Dockerfile to benefit build cache
a3a3f5b86 snap: Add git to snap package for GitInfo
404e2994e releaser: Prepare repository for 0.29-DEV
2a7f6dda1 releaser: Add release notes to /docs for release of 0.28
9e850c1f6 releaser: Bump versions for release of 0.28
ab86851a1 releaser: Add final 0.28 release notes
53b6235bb releaser: Add release notes draft for 0.28
61c27b58b Squashed 'docs/' changes from 1662b9d0..20959c7b
932ae5270 Merge commit '61c27b58b353c73772aae572c7d822fdfdf7791b'
30694a133 Squashed 'docs/' changes from 5be6fef0..1662b9d0
23ba0edf7 Merge commit '30694a133a88d5f76a51d0372646e10cbeca7691'
fb33d8286 Use Chroma as new default syntax highlighter
81ed56479 tpl: Add urls.Parse function
19c591048 tpl: Add math.Ceil, Floor, and Round
80c7ea60a Make noHTTPCache default on
0d29a0f78 Trim newlines in the hightlight shortcode
b8fabce21 vendor: Update goorgeous
b18047763 Add liveReloadPort flag to server
c31e083ea Fix the docs helper tool
9436f0b0c Allow the pull-docs script to pull other than master
7a89dce53 Squashed 'docs/' changes from 32356e4e..5be6fef0
f8fd5796b Merge commit '7a89dce53bfbd67a17442a8f9be8fa895fc4f9b1'
173b54498 commands: Remove superflous space
df411ec81 commands: Rename noHttpCache to noHTTPCache
0b34af216 Add noHttpCache to hugo server
c0370e0ee Merge commit 'ba45da9d03056447e4873de13d4e0f8d658a769b'
ba45da9d0 Squashed 'docs/' changes from 44fe0285..32356e4e
5c3b21036 releaser: Prepare repository for 0.28-DEV
5a4002bc8 releaser: Add release notes to /docs for release of 0.27.1
18126434f releaser: Bump versions for release of 0.27.1
dda269f17 releaser: Add release notes for 0.27.1
2d613dd90 tpl/tplimpl: Fix escaped HTML Go 1.9 multioutput issue (#3880)
642ba6cab snap: Bump to 1.9
d1d6aa634 Remove .goxc.json
0375cbd02 releaser: Prepare repository for 0.28-DEV
01fdf6d26 releaser: Add release notes to /docs for release of 0.27
828eb70fa releaser: Bump versions for release of 0.27
f4ea43398 Release of 0.27
457048634 releaser: Add release notes draft for 0.27
1b4319be6 Squashed 'docs/' changes from 1d052b16..44fe0285
58245a29d docs: Merge commit '1b4319be62ba071f79e90ef32dbe92eb893429f7'
d2249c509 Set up Hugo release flow on CircleCI
f4bf21413 tpl/time: Add time.Duration and time.ParseDuration template funcs
0462c96a5 tpl/compare: Add cond (ternary) template func
202510fdc hugolib: Fix "published" front matter handling
573deca08 hugolib: Fix typo in aquired
eeb057f22 docs: Document Related Content
3b4f17bbc hugolib: Implement "related content"
7d63a23b0 Squashed 'docs/' changes from f887bd7b..1d052b16
16c912766 docs: Merge commit '7d63a23b0c68d9cd7c7c09c2755619237bc03485'
f88fe312c output: Fix taxonomy term base template lookup
d33563b5d release: CGO_ENABLED=0
fc4a0d170 Update Travis build to Go 1.9!
7231d5a82 livereload: Maintain the scroll position if possible
88e1bca92 Update template_embedded.go
d000cf605 tpl: Prepare for template metrics
29a2da059 tpl: Cleanup strings.TrimPrefix and TrimSuffix
7674ad738 tpl: Add strings.TrimLeft and TrimRight
08f48b91d compare, hugolib, tpl: Add Eqer interface
2fc121ce2 appveyor: Simplify
2a2e69070 hugolib: Simplify Page.Eq
a7555c543 hugolib: Do not return error in Eq on type mismatch
c265c102a hugolib: Rename Page.Equals to Page.Eq
f0f49ed9b hugolib: Add Page.Equals
71ae9b453 hugolib: Rewrite replaceDivider to reduce memory allocation
199816fdd hugolib: Extract replaceDivider logic
919bc9210 Add an iFrame title to the YouTube shortcode
07f6e1499 travis: Pull docutils out into requirements.txt
e8468a985 travis: Fix docutils setup
359af563a travis: Try to fix docutils setup on Linux
0019ce002 output: Improve the base template identification
33ae10b6a tpl/transform: Only strip p tag in markdownify if only one paragraph
2d1bd876c Update docs versiona and README
ec4e6f9df Squashed 'docs/' content from commit f887bd7b
a1900826b Merge commit 'ec4e6f9df2ab9ffdc62a3f59675369096e0d3f77' as 'docs'

git-subtree-dir: docs
git-subtree-split: 51c4f31840
2019-11-11 11:45:18 +01:00
Bjørn Erik Pedersen d1d1f240a2 hubolib: Headless bundles should not be listed in .Pages
Fixes #6492
2019-11-10 18:57:31 +01:00
Luke Francl 70a1aa345b Support Go time format strings in permalinks
In the vein of an ancient TODO about supporting custom date formatting with
strftime, this allows `:`-prefixed Go time format strings in permalink segments.
This allows users to customize date-based permalinks any way they need to.

For example, with a date of 2019-11-09, the permalink `/:06/:1/:2` will render
as `/19/11/9`.

See:

https://github.com/gohugoio/hugo/commit/07978e4a4922bc21c230fee65052232b829bd1ab#diff-0688a3b65c7f5d01aa216f8d9b57fd00R111-R112
https://discourse.gohugo.io/t/implementing-additional-date-formats-for-permalinks/17860
https://github.com/gohugoio/hugo/pull/6488
2019-11-10 11:00:02 +01:00
Anthony Fok cafecca440 travis: Increase timeout to 30000 for mage -v check
The default timeout of 15000 millisecond is too short
for go test -race on arm64.

See golang/go#35308
2019-11-08 08:24:41 +01:00
Bjørn Erik Pedersen 5f6b6ec689 Prepare for Goldmark
This commmit prepares for the addition of Goldmark as the new Markdown renderer in Hugo.

This introduces a new `markup` package with some common interfaces and each implementation in its own package.

See #5963
2019-11-06 19:09:08 +01:00
Bjørn Erik Pedersen 366ee4d8da deps: Update quicktest
To make the test build on Go 1.14.
2019-11-06 17:04:58 +01:00
Bjørn Erik Pedersen c26d00db64 hugolib: Fix ref/relref anhcor handling
Fixes #6481
2019-11-06 09:29:38 +01:00
Anthony Fok 8483b53aef deps: Update to Chroma v0.6.9 for Java lexer fix
Fixes #6476
2019-11-05 08:24:41 +01:00
Bjørn Erik Pedersen 9f46a72c7e tpl/collections: Add some index map test cases
See #3974
2019-11-04 11:13:27 +01:00
Bjørn Erik Pedersen 9abd396789 helpers: Use pointer receiver for ContentSpec 2019-11-04 10:57:11 +01:00
Bjørn Erik Pedersen ad4c56b551 travis: Allow arm64 to fail
As that is what it does at the moment.
2019-11-04 09:29:12 +01:00
Bjørn Erik Pedersen 3717db1f90 minifiers: Add a JSON roundtrip test
See #6472
2019-11-03 11:34:22 +01:00
Anthony Fok ae4fde0866 Update .travis.yml for arm64 support, etc.
- Add arm64 support for Linux thanks to Travis CI’s new feature, see
  https://blog.travis-ci.com/2019-10-07-multi-cpu-architecture-support
- Force GO111MODULE=on
- Cache directories
- Switch to bionic (Ubuntu 18.04) environment
- Use "master" instead of "tip" to match the latest Travis CI docs
- Allow "mage -v check" to fail on non-AMD64 architectures
  because "go test -race ./..." currently fails on arm64 and ppc64le.
2019-11-01 11:03:06 -06:00
Anthony Fok c6d69d0c95 mage: Skip Test386 on non-AMD64 architectures
This is to allow "mage check" to run on arm64 on Travis CI.
2019-11-01 11:03:06 -06:00
Anthony Fok c3d433af56 Update past go-cmp's checkptr fix
To fix our -race test under Go 1.14.

See google/go-cmp#167
2019-11-01 02:25:11 -06:00
hugoreleaser 07a203406a releaser: Prepare repository for 0.60.0-DEV
[ci skip]
2019-10-31 15:30:12 +00:00
hugoreleaser d5dab232c2 releaser: Add release notes to /docs for release of 0.59.1
[ci skip]
2019-10-31 15:20:53 +00:00
hugoreleaser e04a22c5e4 releaser: Bump versions for release of 0.59.1
[ci skip]
2019-10-31 15:20:53 +00:00
hugoreleaser d14265da8f releaser: Add release notes for 0.59.1
[ci skip]
2019-10-31 15:20:53 +00:00
Bjørn Erik Pedersen 33c474b9b3 hugofs: Fix crash in multilingual content fs
Fixes #6463
2019-10-31 16:11:53 +01:00
Jake Jarvis ed2682325a Dockerfile: Switch to mage builds, various optimizations
- Use Alpine for both stages for consistency.
- Switch to mage from go install as dictated in the latest docs.
- Easy switch to building Hugo Extended by directly setting HUGO_BUILD_TAGS flag at image build time: `docker build --build-arg HUGO_BUILD_TAGS=extended .`
- Update to Go 1.13 and Alpine 3.10.
- The only possibly breaking change: Moved the `hugo` binary in the final stage from /hugo to /usr/bin/hugo so one can simply run `hugo` without having to search around for its location.
2019-10-31 09:53:49 +01:00
Anthony Fok 66fe68ffc9 resources/images: Add exception for new test image
in TestImageOperationsGolden due to "fused multiply and add" (FMA)
instruction on s390x, ppc64* and arm64.

See #6439
2019-10-30 12:22:13 -06:00
Bjørn Erik Pedersen c5e1e8241a Adjust benchmark templates 2019-10-28 10:56:07 +01:00
Bjørn Erik Pedersen baa975082c deps: Update to Chroma v0.6.8 to fix a crash
Also improve relevant logging.

Fixes #6450
2019-10-24 11:11:18 +02:00
Bjørn Erik Pedersen 3e8b5a5c01 deps: Update quicktest 2019-10-23 09:08:45 +02:00
Nick Krichevsky e6aa6edb4c Do not attempt to build if there is no config file
Fixes #5896
2019-10-22 00:10:36 +02:00
hugoreleaser 6bcc5ad8b2 releaser: Prepare repository for 0.60.0-DEV
[ci skip]
2019-10-21 09:47:26 +00:00
hugoreleaser 1dd0c69c7b releaser: Add release notes to /docs for release of 0.59.0
[ci skip]
2019-10-21 09:38:50 +00:00
hugoreleaser b084af4bfa releaser: Bump versions for release of 0.59.0
[ci skip]
2019-10-21 09:38:50 +00:00
Bjørn Erik Pedersen 0237d45955 Release 0.59.0 2019-10-21 11:33:11 +02:00
hugoreleaser 109ac877c2 releaser: Add release notes for 0.59.0
Rename to *-ready.md to continue.
[ci skip]
2019-10-21 11:32:54 +02:00
Bjørn Erik Pedersen 5ac0f751aa Squashed 'docs/' changes from 0584815c8..723da4a37
723da4a37 Vendor the theme

git-subtree-dir: docs
git-subtree-split: 723da4a376
2019-10-21 10:52:23 +02:00
Bjørn Erik Pedersen de8ca7e4d4 Merge commit '5ac0f751aa47e52625662215f66efa99a6abfc2e' 2019-10-21 10:52:23 +02:00
Bjørn Erik Pedersen 5070ba6c9e Squashed 'docs/' changes from fdea5430f..0584815c8
0584815c8 Add a page about Pages methods (Next, Prev)
653dc8db5 Add note about default bgColor

git-subtree-dir: docs
git-subtree-split: 0584815c8a
2019-10-21 10:49:16 +02:00
Bjørn Erik Pedersen ec5962278f Merge commit '5070ba6c9e6c492deade3c30cfe769b9dbf7151d' 2019-10-21 10:49:16 +02:00
Bjørn Erik Pedersen b9bd35d72e Squashed 'docs/' content from commit fdea5430f
git-subtree-dir: docs
git-subtree-split: fdea5430f8
2019-10-21 10:22:28 +02:00
Bjørn Erik Pedersen 27aef3f1fb Merge commit 'b9bd35d72e14932fb6588ff62b90cddef0a060fc' as 'docs' 2019-10-21 10:22:28 +02:00
Bjørn Erik Pedersen 39121de4d9 docs: Replace /docs 2019-10-21 10:21:51 +02:00
Bjørn Erik Pedersen 180195aa34 cache/filecache: Recover from file corruption
Fixes #6401
2019-10-21 09:51:51 +02:00
Bjørn Erik Pedersen 4b286b9d27 resources/images: Allow to set background fill colour
Closes #6298
2019-10-20 22:06:58 +02:00
Nicolas Martignoni 689f647baf media: Add common video media types
- See https://discourse.gohugo.io/t/resources-bytype-for-video-files/21285
2019-10-16 17:16:14 +02:00
Bjørn Erik Pedersen 46cafdbaca examples: Replace .RSSLink
Fixes #6037
2019-10-14 09:30:09 +02:00
Bjørn Erik Pedersen 653e6856ea resources/page: Use binary search in Pages.Prev/Next if possible
This is obviously much faster for lager data sets:

```bash
name                         old time/op    new time/op    delta
SearchPage/ByWeight-100-4       267ns ± 4%     272ns ± 5%     ~     (p=0.457 n=4+4)
SearchPage/ByWeight-5000-4     10.8µs ± 3%     1.2µs ± 2%  -88.99%  (p=0.029 n=4+4)
SearchPage/ByWeight-10000-4    21.1µs ± 1%     1.4µs ±11%  -93.28%  (p=0.029 n=4+4)
```

See #4500
2019-10-13 12:36:17 +02:00
Bjørn Erik Pedersen f4f566edf4 Make Pages.Prev/Next work like the other Prev/Next methods
Fixes #4500
2019-10-13 12:36:17 +02:00
Zach Bayoff 7b3edc2931 tpl: Add optional "title" attribute to iframe in Vimeo shortcode
Add an optional "title" attribute to the iframe in the vimeo shortcode. If one is not given, the title attribute will default to "vimeo video". It is imperative for iframes to have a non-empty "title" attribute in order to meet WCAG2.0 accessibility guidelines https://www.w3.org/TR/WCAG20-TECHS/H64.
2019-10-12 18:10:14 +02:00
Baibhav Vatsa 65b7d4221b tpl: Modify error messages of after, first, and last
Modified the messages functions after, first, and last threw on being passed invalid parameters (index or limit) to be more standardised and resemble what Go compiler would throw.

Fixes #6415
2019-10-12 18:07:46 +02:00
Baibhav Vatsa 0e75af74db tpl: Last now accepts 0 as limit
Modified the if conditional because of which last threw an error if 0 was passed as limit. The function now returns an empty slice if it is called with 0 as limit. The behavior of first and last is now the same when 0 is passed as limit. Also added tests to test the new behavior.

Fixes #6419
2019-10-11 20:34:51 +02:00
Bjørn Erik Pedersen 5f1aafafb4 Update feature_request.md 2019-10-11 16:43:00 +02:00
Vazrupe (HyeonGyu Lee) a9762b5c48 common: Fix elements are doubling when append a not assignable type
Fixes #6188
2019-10-11 10:38:12 +02:00
Baibhav Vatsa 096a4b67b9 tpl: After now accepts 0 as index
Modified the if conditional because of which after threw an error if called with 0 as index. The function now returns the whole original slice if 0 is passed as an index. Also added tests to test the new behavior.

Fixes #6388
2019-10-11 08:35:27 +02:00
Bjørn Erik Pedersen bc70f2bf12 helpers: Fix data race in global logger init
Fixes #6409
2019-10-10 16:07:53 +02:00
Bjørn Erik Pedersen 0d7b05be4c tpl: Make getJSON/getCVS accept non-string args
This broke for the Twitter simple shortcode now that Shortcodes accepts typed arguments.

Fixes #6382
2019-10-10 13:30:39 +02:00
Bjørn Erik Pedersen 71b18a0786 Update to Go 1.12.10 and 1.13.1
Fixes #6406
2019-10-10 09:50:44 +02:00
Bjørn Erik Pedersen 339ee37143 Simplify test output to simplify diffing 2019-10-09 10:49:52 +02:00
Bjørn Erik Pedersen f10db101a1 hugofs: Add FileMeta.String
To make the page listing easier to compare.
2019-10-09 10:30:09 +02:00
Anthony Fok b401858ebd deps: Update minify to v2.5.2
- v2.5.1 removes import comments, solving a build error with Go 1.13
  in GOPATH mode (used Debian packaging for example)
- v2.5.2 no longer converts polyline/rect/polygon/line to path
  as it has been reported to break a SVG referenced by CSS,
  see tdewolff/minify#260

The test case for Min SVG in TestResourceChains is updated accordingly.

Fixes pocc/tshark.dev#33
2019-10-09 09:01:08 +02:00
Anthony Fok 39ed33fceb resources: Fix image test error on s390x, ppc64* and arm64
In TestImageOperationsGolden, tolerate slight floating-point rounding
differences due to the use or non-use of "fused multiply and add" (FMA)
instruction on different architectures.

Special thanks to @disintegration for the solution in goldenEqual();
see https://github.com/disintegration/gift/issues/20

Fixes #6387
2019-10-07 21:52:43 +02:00
Niklas Fasching 020a6fbd7f Add BaseFs to RenderingContext
The org mode renderer supports including other files [1]. We don't want to
allow reading of arbitrary files (go-org defaults to ioutil.ReadFile [2]) but want
to make use of the FileSystem abstractions hugo provides. For starters we will
allow reading from the content directory only

[1]: e.g. `#+INCLUDE: ./foo.py src python` includes `foo.py` as a python source
block.
2019-10-07 17:30:15 +02:00
Niklas Fasching b152216d5c deps: Update go-org
- add support for latex fragments
- allow customization of ReadFile method for includes (#+INCLUDE: ...)
2019-10-07 17:30:15 +02:00
Bjørn Erik Pedersen 64ec8c8904 media: Use + to create the Type string 2019-10-06 22:20:58 +02:00
Jamie Tanna c466b88c99 deps: Upgrade to latest version of emoji dependency
To add support for new emojis in Hugo, we need to upgrade our internal
dependency on the emoji package.

Note that we also need to update our tests, as the underlying emoji that
is rendered has changed.

Follow-up to #6391. (170f18d935 and
2df5d202c6)
2019-10-05 22:58:53 +02:00
Bjørn Erik Pedersen 2df5d202c6 Revert "deps: Upgrade to latest version of emoji dependency"
This reverts commit 170f18d935.
2019-10-05 19:25:25 +02:00
Jamie Tanna 170f18d935 deps: Upgrade to latest version of emoji dependency
To add support for new emojis in Hugo, we need to upgrade our internal
dependency on the emoji package.
2019-10-05 18:47:35 +02:00
Bjørn Erik Pedersen 15a0364d39 readme: Update Architectures 2019-10-04 20:55:10 +02:00
Garret Kelly 674e81ae87 deploy: Add ability to invalidate Google Cloud CDN 2019-10-03 16:53:45 +02:00
Anthony Fok 298092d516 resources: Ensure same dirinfos sort order in TestImageOperationsGolden
Fix filename mismatch errors on Debian auto-building machines
possibly due to different directory order on ext4 vs tmpfs file systems.
2019-10-03 16:48:22 +02:00
Bjørn Erik Pedersen 019ae38483 Update bug_report.md 2019-09-30 20:09:49 +02:00
Bjørn Erik Pedersen 329e88db1f Support typed bool, int and float in shortcode params
This means that you now can do:

    {{< vidur 9KvBeKu false true 32 3.14 >}}

And the boolean and numeric values will be converted to `bool`, `int` and `float64`.

If you want these to be  strings, they must be quoted:

    {{< vidur 9KvBeKu "false" "true" "32" "3.14" >}}

Fixes #6371
2019-09-29 23:22:41 +02:00
Bjørn Erik Pedersen e073f4efb1 deps: Update Chroma
Closes #6279
2019-09-25 08:42:15 +02:00
Brian MacKinney 454a033dc5 github: Add issue templates and action 2019-09-25 08:40:04 +02:00
J. Ansorg e5856e61d8 resources: Support output image format in image operations
The image format is defined as the image extension of the known formats,
excluding the dot.
All of 'img.Resize "600x jpeg"', 'img.Resize "600x jpg"',
and 'img.Resize "600x png"' are valid format definitions.
If the target format is defined in the operation definition string,
then the converted image will be stored in this format. Permalinks and
media type are updated correspondingly.
Unknown image extensions in the operation definition have not effect.

See #6298
2019-09-21 16:50:27 +02:00
XhmikosR 34dc06b032 tpl: Add rel="noopener" for external links
This could be a security and performance issue.

See https://developers.google.com/web/tools/lighthouse/audits/noopener
2019-09-21 10:08:47 +02:00
XhmikosR 2b1814ee58 tpl: Remove unneeded space 2019-09-21 10:06:15 +02:00
hugoreleaser 8cb7a0d4db releaser: Prepare repository for 0.59.0-DEV
[ci skip]
2019-09-19 15:36:35 +00:00
hugoreleaser 4aac02d49c releaser: Add release notes to /docs for release of 0.58.3
[ci skip]
2019-09-19 15:28:26 +00:00
hugoreleaser 85376a757b releaser: Bump versions for release of 0.58.3
[ci skip]
2019-09-19 15:28:26 +00:00
hugoreleaser 0fd30f832b releaser: Add release notes for 0.58.3
[ci skip]
2019-09-19 15:28:26 +00:00
Bjørn Erik Pedersen c262a95a5c Add some more resource transform tests
See #6348
2019-09-19 16:58:14 +02:00
Bjørn Erik Pedersen 6dec671fb9 Fix cache key transformed resources
Fixes #6348
2019-09-19 12:36:01 +02:00
Fazal Majid c0d7188ec8 deploy: Do not compile in Azure on Solaris
See #6324
2019-09-13 14:53:36 +02:00
hugoreleaser 13768c3c50 releaser: Prepare repository for 0.59.0-DEV
[ci skip]
2019-09-13 08:12:38 +00:00
hugoreleaser 253e5fdc69 releaser: Add release notes to /docs for release of 0.58.2
[ci skip]
2019-09-13 08:04:20 +00:00
hugoreleaser 7bc1270ec7 releaser: Bump versions for release of 0.58.2
[ci skip]
2019-09-13 08:04:20 +00:00
hugoreleaser d4c98e5800 releaser: Add release notes for 0.58.2
[ci skip]
2019-09-13 08:04:20 +00:00
Bjørn Erik Pedersen c0d7573677 Fix cache keys for bundled resoures in transform.Unmarshal
Fixes #6327
2019-09-12 20:58:06 +02:00
Bjørn Erik Pedersen fcfa6f33bb filecache: Ignore "does not exist" errors in prune
Fixes #6326
Fixes #5745
2019-09-12 17:37:41 +02:00
hugoreleaser 77b23fe3db releaser: Prepare repository for 0.59.0-DEV
[ci skip]
2019-09-06 09:26:46 +00:00
hugoreleaser 24277b9202 releaser: Add release notes to /docs for release of 0.58.1
[ci skip]
2019-09-06 09:18:56 +00:00
hugoreleaser 8bc478d3f7 releaser: Bump versions for release of 0.58.1
[ci skip]
2019-09-06 09:18:56 +00:00
hugoreleaser 609a9afbed releaser: Add release notes for 0.58.1
[ci skip]
2019-09-06 09:18:56 +00:00
Bjørn Erik Pedersen 9442937d82 Avoid writing the same processed image to /public twice
Fixes #6307
2019-09-06 11:04:57 +02:00
Bjørn Erik Pedersen 901077c036 hugolib: Fix broken bundle live reload logic
Fixes #6315
Updates #6308
2019-09-06 11:03:23 +02:00
Bjørn Erik Pedersen 24ad429571 deps: Update github.com/bep/gitmap
Fixes #6313
2019-09-06 10:39:21 +02:00
Bjørn Erik Pedersen 3be2c25351 Fix concat with fingerprint regression
In Hugo 0.58 we optimized the transformers that only adjusted metadata, e.g. the fingerprint.

This depended on the source readers implementing `io.ReadSeeker`.

The reader produced by `concat` did that, but the implementation was buggy.

This commit fixes that.

Fixes #6309
2019-09-05 19:59:49 +02:00
Vazrupe (HyeonGyu Lee) 5e66094775 tpl: Remove eq argument limitation
Fixes #6237
2019-09-05 14:38:47 +02:00
hugoreleaser f4e1cb8d05 releaser: Prepare repository for 0.59.0-DEV
[ci skip]
2019-09-04 15:51:16 +00:00
hugoreleaser 64d8bf1ee9 releaser: Add release notes to /docs for release of 0.58.0
[ci skip]
2019-09-04 15:41:58 +00:00
hugoreleaser 10c0baddfa releaser: Bump versions for release of 0.58.0
[ci skip]
2019-09-04 15:41:58 +00:00
Bjørn Erik Pedersen 9d3ae81b91 Release 0.58.0 2019-09-04 17:33:42 +02:00
Bjørn Erik Pedersen bb894ceaf8 Allow slices in the image Filter funcs, not just varargs
[ci skip]

See #6255
2019-09-04 17:24:50 +02:00
Bjørn Erik Pedersen 529c7f1090 Update 0.58.0-relnotes.md
[ci skip]
2019-09-04 13:05:50 +02:00
hugoreleaser 57a54d19d5 releaser: Add release notes for 0.58.0
Rename to *-ready.md to continue.
[ci skip]
2019-09-04 10:39:05 +00:00
Bjørn Erik Pedersen dc3f3df29d hugolib: Adjust Go version specific test
See #6304
2019-09-04 09:50:32 +02:00
Bjørn Erik Pedersen b43130115d Update to Go 1.13
Fixes #6304
2019-09-04 00:54:41 +02:00
Bjørn Erik Pedersen 28501ceb93 hugolib: Remove the old and slow site benchmarks 2019-09-03 21:36:53 +02:00
Bjørn Erik Pedersen 8624b9fe9e Cache processed images by their source path
Fixes #6269
2019-09-03 18:38:57 +02:00
Bjørn Erik Pedersen 018494f363 Remove test artifact 2019-09-03 17:18:18 +02:00
Bjørn Erik Pedersen 43298f028c Make the "is this a Hugo Module" logic more lenient
Now we only try to load modules via Go if there is one or more modules imported in project config.

Fixes #6299
2019-09-03 15:12:33 +02:00
Bjørn Erik Pedersen 1b5c7e327c hugolib: Add a Sass includePaths test
See #6274
2019-09-03 12:25:41 +02:00
Bjørn Erik Pedersen 05d83b6c08 Update to Go 1.11.13 and 1.12.9
Fixes #6228
2019-09-03 10:05:17 +02:00
Bjørn Erik Pedersen 4898fb3d64 Make home.Pages work like any other section
Fixes #6240
2019-09-02 17:34:02 +02:00
Bjørn Erik Pedersen 45d7988f2d Add some fingerprint tests
Closes #6284
Closes #6280
2019-09-02 17:18:32 +02:00
Bjørn Erik Pedersen ce47c21a29 resources: Cache Exif data to disk
```bash
name                        old time/op    new time/op    delta
ImageExif/Cold_cache-4         312µs ±28%     355µs ± 7%     ~     (p=0.343 n=4+4)
ImageExif/Cold_cache,_10-4     479µs ± 6%     546µs ± 0%  +13.91%  (p=0.029 n=4+4)
ImageExif/Warm_cache-4         272µs ± 1%      81µs ± 5%  -70.30%  (p=0.029 n=4+4)

name                        old alloc/op   new alloc/op   delta
ImageExif/Cold_cache-4         151kB ± 0%     161kB ± 0%   +6.46%  (p=0.029 n=4+4)
ImageExif/Cold_cache,_10-4     179kB ± 0%     189kB ± 0%   +5.49%  (p=0.029 n=4+4)
ImageExif/Warm_cache-4         151kB ± 0%      13kB ± 0%  -91.52%  (p=0.029 n=4+4)

name                        old allocs/op  new allocs/op  delta
ImageExif/Cold_cache-4         1.03k ± 0%     1.21k ± 0%  +17.78%  (p=0.029 n=4+4)
ImageExif/Cold_cache,_10-4     1.65k ± 0%     1.83k ± 0%  +11.09%  (p=0.029 n=4+4)
ImageExif/Warm_cache-4         1.03k ± 0%     0.28k ± 0%  -72.40%  (p=0.029 n=4+4)
```

Fixes #6291
2019-09-02 16:37:28 +02:00
Bjørn Erik Pedersen de9cbf6195 Remove metaDataFormat setting
Not in use anymore.
2019-09-01 23:48:51 +02:00
Bjørn Erik Pedersen 4f5011692a resources: Make the Exif benchmark filenames distinct 2019-09-01 22:05:39 +02:00
Bjørn Erik Pedersen 3becba7a98 resources: Add Exif benchmark
See #6291
2019-09-01 18:02:49 +02:00
Bjørn Erik Pedersen 20bdc69a47 resources: Remove unused map type 2019-08-31 21:30:13 +02:00
Bjørn Erik Pedersen 28143397d6 Add image.Exif
Note that we will probably need to add some metadata cache for this to scale.

Fixes #4600
2019-08-31 19:04:56 +02:00
Niklas Fasching 8a8d4a6d97 deps: Update go-org (fix descriptive lists)
</dt> and </dd> closing tags were broken, see
https://github.com/niklasfasching/go-org/pull/9
2019-08-31 15:03:12 +02:00
Jake Jarvis 00297085db tpl: Migrate last shortcodes (YouTube and Vimeo) to HTTPS embeds 2019-08-30 11:55:55 +02:00
Bjørn Erik Pedersen 823f53c861 Add a set of image filters
With this you can do variants of this:

```
{{ $img := resources.Get "images/misc/3-jenny.jpg" }}
{{ $img := $img.Resize "300x" }}
{{ $g1 := $img.Filter images.Grayscale }}
{{ $g2 := $img | images.Filter (images.Saturate 30) (images.GaussianBlur 3) }}
```

Fixes #6255
2019-08-28 15:59:54 +02:00
Bjørn Erik Pedersen f9978ed164 Image resource refactor
This commit pulls most of the image related logic into its own package, to make it easier to reason about and extend.

This is also a rewrite of the transformation logic used in Hugo Pipes, mostly to allow constructs like the one below:

    {{ ($myimg | fingerprint ).Width }}

Fixes #5903
Fixes #6234
Fixes #6266
2019-08-26 15:00:44 +02:00
Niklas Fasching 58d4c0a8be deps: Update go-org (fix footnotes in headlines) 2019-08-24 13:23:42 +02:00
Christian Oliff c5319db9f1 Discrepancy typo fix 2019-08-23 17:21:37 +02:00
Bjørn Erik Pedersen ad1d6d6406 source: Remove debug check left during development
Fixes #6249
2019-08-23 07:37:56 +02:00
Vazrupe (HyeonGyu Lee) fd3d90ced8 hugolib: Change to output non-panic error message if missing shortcode template
A panic occurred when the `nested` variable was nil.
Changed to check if the `nested` variable is nil.

Fixes #6075
2019-08-22 10:40:16 +02:00
hugoreleaser 3ae4b3e19f releaser: Prepare repository for 0.58.0-DEV
[ci skip]
2019-08-17 17:59:28 +00:00
hugoreleaser a849cb2d9b releaser: Add release notes to /docs for release of 0.57.2
[ci skip]
2019-08-17 17:51:54 +00:00
hugoreleaser 01fbb46354 releaser: Bump versions for release of 0.57.2
[ci skip]
2019-08-17 17:51:54 +00:00
hugoreleaser 9958e5e911 releaser: Add release notes for 0.57.2
[ci skip]
2019-08-17 17:51:54 +00:00
Bjørn Erik Pedersen f77a4a2f4a Revert "Update to Go 1.11.13 and 1.12.9"
This reverts commit f28efd3582.
2019-08-17 19:38:12 +02:00
Bjørn Erik Pedersen 88d6993612 tpl: Use RegularPages for RSS template
This is in line with how it was in Hugo 0.56.

See #6238
2019-08-17 19:37:14 +02:00
Bjørn Erik Pedersen ea68160300 hugolib: Don't use the global warning logger
See #6238
2019-08-17 18:50:16 +02:00
Bjørn Erik Pedersen 564cf1bb11 tpl: Avoid "home page warning" in RSS template
See #6238
2019-08-17 18:50:16 +02:00
Bjørn Erik Pedersen 4b4bdcfe74 hugolib: Allow index.md inside bundles
Fixes #6208
2019-08-17 18:50:16 +02:00
Bjørn Erik Pedersen 18836a71ce Adjust the default paginator for sections
To make it in line with 0.56 for sections; only paginate regular pages.

Fixes #6231
2019-08-17 13:08:03 +02:00
Bjørn Erik Pedersen ab40ce679f Revert the 0.57 home.Pages change
In 0.57 we change the behaviour of home.Pages to be in line with the other sections. This has created a lot noise and breakage in the wild.

This commit reverts that change, but adds a warning that we will change this in 0.58 and that you should consider using .Site.RegularPages if that is what you want.
2019-08-17 13:06:39 +02:00
Bjørn Erik Pedersen 416493b548 hugolib: Add a site benchmark 2019-08-16 16:24:21 +02:00
Bjørn Erik Pedersen f28efd3582 Update to Go 1.11.13 and 1.12.9
Fixes #6228
2019-08-16 10:46:34 +02:00
hugoreleaser 36d749f4ea releaser: Prepare repository for 0.58.0-DEV
[ci skip]
2019-08-15 19:00:12 +00:00
hugoreleaser 58c56e9ded releaser: Add release notes to /docs for release of 0.57.1
[ci skip]
2019-08-15 18:52:49 +00:00
hugoreleaser 484106cfa2 releaser: Bump versions for release of 0.57.1
[ci skip]
2019-08-15 18:52:49 +00:00
hugoreleaser 4d60a920fa releaser: Add release notes for 0.57.1
[ci skip]
2019-08-15 18:52:49 +00:00
Bjørn Erik Pedersen 6ccf50ea7b hugolib: Fix draft etc. handling of _index.md pages
We will need to revisit this with a proper spec, but this commit makes sure that draft/expiryDate etc. set in front matter on _index.md content files that should disable the page will:

* Not crash
* Make the rendered page not render any `.Content`.

Fixes #6222
Fixes #6210
2019-08-15 20:41:48 +02:00
Bjørn Erik Pedersen 67524c9936 Fix mainSections logic
Fixes #6217
2019-08-15 20:21:57 +02:00
Bjørn Erik Pedersen 952a319496 Fix live reload mount logic with sub paths
Fixes #6209
2019-08-15 19:14:22 +02:00
Bjørn Erik Pedersen 321418f22a modules: Disable "auto tidy" for now
See #6115
2019-08-15 16:50:02 +02:00
Bjørn Erik Pedersen 7f3aab5ac2 hugolib: Recover and log panics in content init
See #6210
2019-08-15 10:56:49 +02:00
Bjørn Erik Pedersen 028b992611 hugolib: Add some outputs tests
See #6210
2019-08-15 10:30:37 +02:00
Bjørn Erik Pedersen 9475f61a37 hugolib: Fix taxonomies vs expired
In Hugo 0.57 we needed to delay the page metadata initialization until we had built the page graph.

This introduced a regression in that we now created taxonomy entries for expired pages.

This fixes that by moving the "should not build" filter before we assemble the taxonomies.

Fixes #6213
2019-08-15 09:52:08 +02:00
HyeonGyu Lee ea9261e856 commands: Make sure the hugo field is always initialized before it's used
Wrap the field to make it accessible after initialization.

Fixes #6193
2019-08-15 09:33:47 +02:00
hugoreleaser 37f5929803 releaser: Prepare repository for 0.58.0-DEV
[ci skip]
2019-08-14 08:13:53 +00:00
hugoreleaser 9b00e64765 releaser: Add release notes to /docs for release of 0.57.0
[ci skip]
2019-08-14 08:05:33 +00:00
hugoreleaser ab849fcc98 releaser: Bump versions for release of 0.57.0
[ci skip]
2019-08-14 08:05:33 +00:00
hugoreleaser 8a4c080cc5 Add release notes for 0.57.0 2019-08-14 09:56:35 +02:00
Bjørn Erik Pedersen 4644b95bd5 hugolib: Remove temporary warning 2019-08-14 08:11:39 +02:00
Bjørn Erik Pedersen 1089cfe4e1 Add FileInfo to resources created with resources.Match etc.
Without it, image resize fails.

See #6190
2019-08-13 18:45:08 +02:00
Bjørn Erik Pedersen cd575023af Improve the server assets cache invalidation logic
Fixes #6199
2019-08-13 18:09:46 +02:00
Bjørn Erik Pedersen 6315098104 modules: Do not fail build on errors in theme.toml
Fixes #6162
2019-08-13 18:09:11 +02:00
Bjørn Erik Pedersen b64617fe4f Add resources.Match and resources.GetMatch
Fix #6190
2019-08-13 11:44:20 +02:00
Bjørn Erik Pedersen 17ca8f0c4c commands: Fix faulty -h logic in hugo mod get
Fixes #6197
2019-08-13 11:17:19 +02:00
Bjørn Erik Pedersen 9e57182705 tests: Convert from testify to quicktest 2019-08-12 13:26:32 +02:00
Christian Muehlhaeuser 6027ee1108 Avoid unnecessary conversions
No need to convert these types.
2019-08-10 20:12:38 +02:00
Christian Muehlhaeuser c577a9ed23 Fixed ineffectual assignments
Dropped/fixed ineffectual assignments after static code analysis.
2019-08-10 20:11:51 +02:00
Christian Muehlhaeuser a93cbb0d6c Simplify code
- Use bytes.Equal instead of bytes.Compare
- Omit range's value where it's unused
2019-08-10 20:10:32 +02:00
Bjørn Erik Pedersen bd98182dbd Implement cascading front matter
Fixes #6041
2019-08-10 20:07:42 +02:00
Christian Muehlhaeuser e88d798990 Fixed tautological error conditions
Drop error & nil checks where the value can not have changed.
2019-08-10 01:04:43 +02:00
XhmikosR c0eef3b401 Use the SVG logo in README.md 2019-08-09 16:58:41 +02:00
Bjørn Erik Pedersen 166a394a2f Fix static sync issue with virtual mounts
Fixes #6165
2019-08-09 10:18:28 +02:00
Bjørn Erik Pedersen 8243952046 Add a branch bundle test case
See #6173
2019-08-09 09:44:41 +02:00
Bjørn Erik Pedersen 7ff0a8ee9f Simplify page tree logic
This is preparation for #6041.

For historic reasons, the code for bulding the section tree and the taxonomies were very much separate.

This works, but makes it hard to extend, maintain, and possibly not so fast as it could be.

This simplification also introduces 3 slightly breaking changes, which I suspect most people will be pleased about. See referenced issues:

This commit also switches the radix tree dependency to a mutable implementation: github.com/armon/go-radix.

Fixes #6154
Fixes #6153
Fixes #6152
2019-08-08 20:13:39 +02:00
Bjørn Erik Pedersen df374851a0 hugolib: Add some more site benchmarks 2019-08-08 11:04:47 +02:00
HyeonGyu Lee a843ca53b5 transform/urlreplacers: Cache the next position of urlreplacer.prefix
Improved performance due to `bytes.Index` repeated calls

Fixes #5942
2019-08-06 17:46:20 +02:00
Bjørn Erik Pedersen 02397e76ce postcss: Fix no-map vs noMap discrepancy
Fixes #6166
2019-08-05 13:48:58 +02:00
Bjørn Erik Pedersen de87624241 hugolib: Fix output format handling of mix cased page kinds
Fixes #4528
2019-08-05 11:22:03 +02:00
Bjørn Erik Pedersen 9ef4dca361 hugolib: Fix broken test 2019-08-01 22:09:58 +02:00
Bjørn Erik Pedersen 2d1d33673d tpl: Regenerate templates 2019-08-01 14:05:20 +02:00
Christian Oliff be0d4efc3d tpl: Always load GitHub Gists over HTTPS 2019-08-01 13:57:41 +02:00
XhmikosR f7f549e3a7 Fix assorted typos 2019-08-01 13:55:48 +02:00
Shawn Smith 6512d128c6 common/collections: Fix typo 2019-08-01 13:52:05 +02:00
Robin Andersson b8758de19e examples: Fix multilingual example compatibility with latest version 2019-08-01 13:49:07 +02:00
Bjørn Erik Pedersen 53077b0da5 Merge pull request #6149 from bep/sort-caseinsensitive
Implement lexicographically string sorting
2019-08-01 10:19:19 +02:00
hugoreleaser a4f96a9d8c releaser: Prepare repository for 0.57.0-DEV
[ci skip]
2019-07-31 12:56:14 +00:00
hugoreleaser f637a1eace releaser: Add release notes to /docs for release of 0.56.3
[ci skip]
2019-07-31 12:48:33 +00:00
hugoreleaser 9433c3c706 releaser: Bump versions for release of 0.56.3
[ci skip]
2019-07-31 12:48:33 +00:00
hugoreleaser 7b448340c0 releaser: Add release notes for 0.56.3
[ci skip]
2019-07-31 12:48:33 +00:00
Bjørn Erik Pedersen 0e086785fa hugolib: Fix bundle header clone logic
Fixes #6136
2019-07-31 14:20:24 +02:00
Bjørn Erik Pedersen 02b947eaa3 docs: Regenerate CLI docs 2019-07-31 12:11:22 +02:00
Bjørn Erik Pedersen d7c233afee commands: Add "hugo config mounts" command
This prints the effective file mounts in a project.

Fixes #6144
2019-07-31 12:10:05 +02:00
Bjørn Erik Pedersen 45ee8a7a52 commands: Cleanup the hugo config command
Most importantly filter out some keys not relevant for the end user.

See #6144
2019-07-31 12:10:05 +02:00
Bjørn Erik Pedersen 4b6c5eba30 Move the mount duplicate filter to the modules package
Also simplify the mount validation logic. There are plenty of ways a user can create mount configs that behaves oddly.
2019-07-31 12:10:05 +02:00
Bjørn Erik Pedersen edf9f0a354 Allow overlap in module mounts
Fixes #6146
2019-07-31 12:10:05 +02:00
Bjørn Erik Pedersen 36220851e4 Fix self-mounts on the main project
Fixes #6143
2019-07-31 12:10:05 +02:00
hugoreleaser 53ade40ba4 releaser: Prepare repository for 0.57.0-DEV
[ci skip]
2019-07-30 09:12:29 +00:00
hugoreleaser 5f033a7fcc releaser: Add release notes to /docs for release of 0.56.2
[ci skip]
2019-07-30 09:05:09 +00:00
hugoreleaser 2e6da00679 releaser: Bump versions for release of 0.56.2
[ci skip]
2019-07-30 09:05:09 +00:00
hugoreleaser 06f29068f8 releaser: Add release notes for 0.56.2
[ci skip]
2019-07-30 09:05:09 +00:00
Bjørn Erik Pedersen 84bc8d84e4 Add some more content language test assertions
See #6136
2019-07-30 09:58:58 +02:00
Bjørn Erik Pedersen 6eca0a3dee commands: Fix config reloading in Vim and similar
The config path was simplified in Hugo 0.56.0 to support more config dirs/files (go.mod etc.),
and the new code path assumed that every file change would trigger a `Write` event.

This is not true for Vim etc. which triggers a `Chmod` and then a `Rename`.

Lesson learned: Be really careful changing Os/editor specific code without proper tests.

Fixes #6139
2019-07-30 09:35:01 +02:00
Bjørn Erik Pedersen e28bd4c0f8 Fix Jekyll import
Fixes #6131
2019-07-30 09:14:14 +02:00
Bjørn Erik Pedersen 2c7c361091 releaser: Create a proper automated title for patch releases
Fixes #6126
2019-07-30 09:02:03 +02:00
Bjørn Erik Pedersen c62bbf7b11 Fix image format detection for upper case extensions, e.g. JPG
This regression was introduced in 0.56.0.

Fixes #6137
2019-07-30 08:53:50 +02:00
Bjørn Erik Pedersen 00a238e32c Fix i18n project vs theme order
Fixes #6134
2019-07-29 19:10:15 +02:00
Bjørn Erik Pedersen e5f9602459 Add proper error message when receiving nil in Resource transformation
Closes #6128
2019-07-29 09:59:39 +02:00
Bjørn Erik Pedersen 9f497e7b5f Merge branch 'release-0.56.1' 2019-07-28 17:06:46 +02:00
hugoreleaser 3ad16af6f8 releaser: Prepare repository for 0.57.0-DEV
[ci skip]
2019-07-28 15:05:28 +00:00
Niklas Fasching 56908509eb deps: Update go-org to v0.1.2
fixes superfluous whitespace around code blocks due to misuse of pre tag
2019-07-28 16:52:27 +02:00
hugoreleaser 0ad218afc5 releaser: Add release notes to /docs for release of 0.56.1
[ci skip]
2019-07-28 14:51:43 +00:00
hugoreleaser b5fda703f9 releaser: Bump versions for release of 0.56.1
[ci skip]
2019-07-28 14:51:43 +00:00
hugoreleaser 447700228c releaser: Add release notes for 0.56.1
[ci skip]
2019-07-28 14:51:43 +00:00
Bjørn Erik Pedersen 544f826dd6 releaser: Make it a one click release for patch releases 2019-07-28 15:05:15 +02:00
Bjørn Erik Pedersen e393c6290e common/maps: Do not return error on params dot access on incompatible types
This error was introduced in 0.56 and has shown some site breakage in the wild.

Fixes #6121
2019-07-28 13:03:12 +02:00
Bjørn Erik Pedersen 93d02aabe6 resources: Fix image Width/Height regression
Fixes #6120
2019-07-28 12:34:18 +02:00
Bjørn Erik Pedersen 508db1906b Revert "cache/filecache: Skip resource cache init if the fs is missing"
I need to revisit this.

This reverts commit da4c4a7789.
2019-07-26 16:29:33 +02:00
Bjørn Erik Pedersen e5fe378925 modules: Set GO111MODULE=on
Fixes #6114
2019-07-26 10:55:50 +02:00
Bjørn Erik Pedersen da4c4a7789 cache/filecache: Skip resource cache init if the fs is missing
Fixes #6113
2019-07-26 10:45:07 +02:00
hugoreleaser b4827fbb14 releaser: Prepare repository for 0.57.0-DEV
[ci skip]
2019-07-25 16:45:08 +00:00
hugoreleaser 45f4eb9846 releaser: Add release notes to /docs for release of 0.56.0
[ci skip]
2019-07-25 16:37:58 +00:00
hugoreleaser 263f86d456 releaser: Bump versions for release of 0.56.0
[ci skip]
2019-07-25 16:37:58 +00:00
Bjørn Erik Pedersen bed75108e4 Update release notes 2019-07-25 18:29:55 +02:00
hugoreleaser 8d7006d853 releaser: Add release notes draft for 0.56.0
Rename to *-ready.md to continue. [ci skip]
2019-07-25 15:58:15 +00:00
Bjørn Erik Pedersen e5b6e2085a resources: Fix test on Windows 2019-07-25 16:54:05 +02:00
Bjørn Erik Pedersen 77bf2991b1 docs: Add Hugo Modules docs 2019-07-25 13:21:30 +02:00
Bjørn Erik Pedersen e5f2299741 Block symlink dir traversal for /static
This is in line with how it behaved before, but it was lifted a little for the project mount for Hugo Modules,
but that could create hard-to-detect loops.
2019-07-25 11:27:25 +02:00
Bjørn Erik Pedersen 87a07282a2 modules: Gofmt 2019-07-24 23:31:30 +02:00
Bjørn Erik Pedersen 882d678bbf modules: Rename disabled => disable in config 2019-07-24 21:46:24 +02:00
Bjørn Erik Pedersen fa28df1058 hugolib: Fix broken test 2019-07-24 19:50:34 +02:00
Bjørn Erik Pedersen 072aa7f110 hugolib: Add a symdiff test 2019-07-24 10:05:09 +02:00
Bjørn Erik Pedersen 215d2ed883 docs: Regenerate CLI docs 2019-07-24 09:40:41 +02:00
Bjørn Erik Pedersen 23adc0c2d9 docs: Regenerate data helpers 2019-07-24 09:39:12 +02:00
Bjørn Erik Pedersen 461b0e066f Merge commit '5cb4e46cfa65bddae8ac5344540e3dd1e4c266b2' 2019-07-24 09:36:50 +02:00
Bjørn Erik Pedersen 5cb4e46cfa Squashed 'docs/' changes from 540aeddc7..41aae7abb
41aae7abb Better deploy script example

git-subtree-dir: docs
git-subtree-split: 41aae7abb3
2019-07-24 09:36:50 +02:00
Bjørn Erik Pedersen 9f5a92078a Add Hugo Modules
This commit implements Hugo Modules.

This is a broad subject, but some keywords include:

* A new `module` configuration section where you can import almost anything. You can configure both your own file mounts nd the file mounts of the modules you import. This is the new recommended way of configuring what you earlier put in `configDir`, `staticDir` etc. And it also allows you to mount folders in non-Hugo-projects, e.g. the `SCSS` folder in the Bootstrap GitHub project.
* A module consists of a set of mounts to the standard 7 component types in Hugo: `static`, `content`, `layouts`, `data`, `assets`, `i18n`, and `archetypes`. Yes, Theme Components can now include content, which should be very useful, especially in bigger multilingual projects.
* Modules not in your local file cache will be downloaded automatically and even "hot replaced" while the server is running.
* Hugo Modules supports and encourages semver versioned modules, and uses the minimal version selection algorithm to resolve versions.
* A new set of CLI commands are provided to manage all of this: `hugo mod init`,  `hugo mod get`,  `hugo mod graph`,  `hugo mod tidy`, and  `hugo mod vendor`.

All of the above is backed by Go Modules.

Fixes #5973
Fixes #5996
Fixes #6010
Fixes #5911
Fixes #5940
Fixes #6074
Fixes #6082
Fixes #6092
2019-07-24 09:35:53 +02:00
Bjørn Erik Pedersen 47953148b6 deps: Tidy 2019-07-23 00:13:46 +02:00
Bjørn Erik Pedersen 2fc0abd22a Fix livereload for @import case
Fixes #6106
2019-07-22 13:54:24 +02:00
peaceiris 53da3881de releaser: Remove unused function
gitLog function is not used
2019-07-20 12:33:30 +02:00
Bjørn Erik Pedersen ac101aba4f deps: Update xerrors
To get it to build on Go 1.13.
2019-07-19 09:09:04 +02:00
Bjørn Erik Pedersen 58a47ccde0 travis: Ignore errors in go mod download
It sometimes fails with 502 errors, but the dependency download later when tests are run.
2019-07-17 15:35:31 +02:00
Bjørn Erik Pedersen 95b1d3013b deps: Update Chroma
Fixes #6088
2019-07-16 21:08:18 +02:00
Eric Selin a5604e18b0 resource/postcss: Change postcss to check for local installation under node_modules/.bin
Fixes #5091
2019-07-16 10:02:20 +02:00
Bjørn Erik Pedersen 05d0eddd2b Merge commit '35febb2e2a3780c3338a2665fddea7dda28a17f4' 2019-07-15 23:50:56 +02:00
Bjørn Erik Pedersen 35febb2e2a Squashed 'docs/' changes from 0c3c04fd6..540aeddc7
540aeddc7 Small fixes for Open Graph internal template
47bbb3fd7 Bump lodash.template from 4.4.0 to 4.5.0 in /themes/gohugoioTheme
64c1cc3db Update title.md
36c27be37 Update configuration.md
4627cfe9a added commento.io to the list
341d9d945 Fix link to font assets
4a6876dec Small typo fix in configuration.md
736d6ddd7 Add bypasscensorship.org showcase.
de7ab636b Use actual width in image processing examples
6c88ab2da Update directory-structure.md
88f559e81 Fix spelling mistakes
7bd427141 Rephrase four points from Hosting on Github docs
bce1b1832 Fix typos for absLangURL and relLangURL functions
abab57335 Update directory-structure.md
a6716f2ed Fix metadata list
5ef61d912 Fix typo
d9e467b8b Actuall show how to generate pages in quickstart
0aadc92e7 Update link to issue theme submission
b1902faaa Remove incorrect note about Hugo snap --classic use.
d451e7362 Update documentation on page variables
ab2233c39 Update publish_to_ghpages.sh
7c120346b Fix typo in syntax highlighting page.
f01dc555d Correct some typos
be825ade9 Videos plural produces og:video
bc962fbdf Updated installing.md file to include linuxbrew installation
08c9f8fc8 Mention 1 MB file size limit in readFile doc
7145e29e2 Fixes bad URL in menus.md for .hasChildren * part of issue #814
0edbd59c4 add warning about .Hugo variable being deprecated
77f74ced5 fix: typo in output-formats.md
f71b67f34 Correct typo "RFC339" to "RFC1123Z" (#837)
424c0207a baseurl -> baseURL
f4e24a03e Render launched; no invite code needed
37e1101d3 Add Render hosting guide
01d0a6481 Bump js-yaml from 3.12.0 to 3.13.1 in /themes/gohugoioTheme
edb7b36b0 Link site hierarchy schema to larger version
af72acda0 Fixes typo in fingerprint.md
0a738467b Adding required XML tag to sample templates
52211f656 Remove note that XML declaration is not needed
a39b9ac87 Adding required XML tag to sample templates
1a44d8a50 Add configuration information for Azure
5b7c6b5a1 remove google plus
5a64301ba HTTPS link to yaml.org/spec/

git-subtree-dir: docs
git-subtree-split: 540aeddc79
2019-07-15 23:49:41 +02:00
Bjørn Erik Pedersen c624a77992 tpl/collections: Add Merge function
Merges two maps recursively and returns a new one. Merge is case-insensitive.

Fixes #5992
2019-07-15 20:47:35 +02:00
Niklas Fasching 020086cb2b Add org to front matter formats
actually it's 5, there's also csv. Afaict it's not meant to be used in that way
though so let's just add org.
2019-07-10 11:14:37 +02:00
Niklas Fasching 8524baee16 deps: Update go-org
- added support for anonymous footnotes
- changed source block html output to more closely resemble emacs org-export
  output
2019-07-10 11:14:37 +02:00
Kaushal Modi 90b0127f63 Fix typo s/Meny/Menu/ 2019-07-09 17:28:53 +02:00
Bjørn Erik Pedersen 7611078dae hugolib: Add testfile to .gitignore 2019-07-07 13:01:30 +02:00
Bjørn Erik Pedersen b2a3d4644b tpl/tplimpl: Regenerate templates 2019-06-26 22:39:32 +02:00
Mark Mandel 88c8a15be1 Pagination - do not render href if no next item
When using a html link checker with Hugo, this template consistently causes errors, as it renders `href=""` attributes when next/previous is disabled.

This change makes it so that the `href` attribute is not rendered at all if `HasNext` is false - which is better semantically, and makes link checking far easier.
2019-06-26 22:38:30 +02:00
Justin Van Patten 59c4bc52ed Include path to source page in non-relative ref/relref warning
We occasionally see warnings when building our site:

```
WARN 2019/06/25 23:07:08 make non-relative ref/relref page reference(s) in page %q absolute, e.g. {{< ref "/blog/my-post.md" >}}
```

But the `%q` value is missing, making it difficult to track down the source of the warning.

This change addresses that, by including the source path in the warning:

```
WARN 2019/06/25 23:07:31 make non-relative ref/relref page reference(s) in page "blog/my-post/index.md" absolute, e.g. {{< ref "/blog/my-post.md" >}}
```
2019-06-26 09:25:12 +02:00
Bjørn Erik Pedersen dc1d4a9200 hugolib: Add another site benchmark
Also rework test test setup so the benchmarks can also be run as tests, which
is useful when creating new benchmarks an make sure they ... work.
2019-06-26 09:09:40 +02:00
Joshua Arnott de7b9475c0 commands: Remove comma after URL in new site output
Some terminals include the comma in the URL when hyperlinking, resulting in a 404
2019-06-19 23:03:30 +02:00
Bjørn Erik Pedersen d6ca728ff3 deps: Revert to an older version of Blackfriday
See #6040
2019-06-16 22:13:23 +02:00
Christian Oliff ff10aa522d examples: Update link to prevent redirect 2019-06-12 13:56:05 +02:00
Christian Oliff 9f258d2b8f examples: Update URLs 2019-06-12 12:29:19 +02:00
Bjørn Erik Pedersen 31c9c690fd releaser: Update Go Releaser and consolidate the 2 configs
Fixes #5949
2019-06-11 00:02:06 +02:00
Bjørn Erik Pedersen e8a716b23a tpl/collections: Fix slice type handling in sort
The `sort` template func was producing a `[]page.Page` which did not work in `.Paginate`.

Fixes #6023
2019-06-10 08:32:44 +02:00
Bjørn Erik Pedersen 3e6cb2cb77 hugolib: Fix bundle path when slug is set
Fixes #4870
2019-06-09 16:55:08 +02:00
Bjørn Erik Pedersen 8d898ad667 tpl/collections: Unwrap any interface value in sort and where
Hugo `0.55.0` introduced some new interface types for `Page` etc.

This worked great in general, but there were cases where this would fail in `where` and `sort`.

One such example would be sorting by `MenuItem.Page.Date` where `Page` on `MenuItem` was a small subset of the bigger `page.Page` interface.

This commit fixes that by unwrapping such interface values.

Fixes #5989
2019-06-09 16:54:36 +02:00
Niklas Fasching fad183c4ae Refactor Org mode front matter: Introduce '#+KEY[]:' array notation
Hugo requires some front matter values to be arrays (e.g. for taxonomies).
Org mode front matter syntax (`#+KEY: VALUE`) does however not support anything
but string values normally - which is why goorgeous hardcoded the values for
the keys tags, categories & aliases to be parsed as string arrays. This causes
problems with custom taxonomies.

A simple thing we can do instead is make keywords ending in '[]' be parsed as
string arrays.
2019-06-08 10:13:00 +02:00
Niklas Fasching b6867bf806 Improve Org mode support: Replace goorgeous with go-org
Sadly, goorgeous has not been updated in over a year and still has a lot of
open issues (e.g. no support for nested lists).

go-org fixes most of those issues and supports a larger subset of Org mode
syntax.
2019-06-08 10:13:00 +02:00
Robert van Gent 9df57154ee deploy: Default --target to the first deployment target 2019-06-08 00:41:59 +02:00
Vincent Fiduccia 35abce27ca Add safety barrier between concatenated javascript resources 2019-06-02 10:23:48 +02:00
Robert van Gent 8914fe7ed7 Update CLI doc for "long" form 2019-05-31 22:08:12 +02:00
Robert van Gent b0f536fb27 Drop dashes in http header matcher attributes; other changes from code review 2019-05-31 22:08:12 +02:00
Robert van Gent 1384d77a04 docs: Add documentation for "hugo deploy" 2019-05-31 22:08:12 +02:00
Robert van Gent 5e83f42562 deploy: remove TODO comment about subfolders; handled by GoCDK blob URLs 2019-05-30 22:42:44 +02:00
Robert van Gent b376b2685a deps: Update gocloud.dev to v0.15.0. 2019-05-30 22:07:04 +02:00
Anton Harniakou fb007e9ae5 tpl/collections: Convert numeric values to float64 and compare them
Fixes #5685
2019-05-30 11:32:58 +02:00
Bjørn Erik Pedersen 4c560020bc resources: Return nil when not found in resources.Get
Fixes #5999
2019-05-29 22:33:03 +02:00
Bjørn Erik Pedersen d44d3ea898 deps: Update Viper
This will hopefully improve the dependency/install problems we have seen lately.

See #5954
2019-05-28 16:11:09 +02:00
Bruno Amaral d1cf53f5f4 Remove references to Google+
According to google, this is no longer supported and structured data should be used instead: https://support.google.com/webmasters/answer/6083347?hl=en
2019-05-26 19:24:45 +02:00
Bjørn Erik Pedersen 811ee996a6 Update gitmap to get CommitDate field 2019-05-25 10:43:09 +02:00
Bjørn Erik Pedersen 4f61a926f6 Merge commit 'be04ece8590f775a52ea167fbe4555753e8c5211' 2019-05-25 10:41:51 +02:00
Bjørn Erik Pedersen be04ece859 Squashed 'docs/' changes from 50c02516c..0c3c04fd6
0c3c04fd6 Merge pull request #827 from BCNelson/range-patch
b14dd3505 Updated link to Go Docs to more helpful page
c3d83149a Boolean Values in the Where Function
56d4cea3c hugo-extended no longer the default
e9b15c698 Update index.md
11de98e0d Release 0.55.6
d2def17f4 Merge branch 'release-0.55.6'
115457b70 releaser: Add release notes to /docs for release of 0.55.6
25855690d Fix misspelling
fc5e43db2 Update 404.md with Netlify Instructions
9f684318f Removed mentioning of removed --stepAnalysis command line option
86ba9071c Related md5 and aliases for sha1/sha256
15f48966a Added related sha function into the See Also
5e08b6930 Fix date description
908e87ab2 Revert docs/config.toml changes
c925646cf Add a "deploy" command
e765084dd Update sectionvars.md
e08be4d81 Update sectionvars.md
7c9653cbe Hugo 0.55.5
1035ff028 releaser: Add release notes to /docs for release of 0.55.5
cda21f9d4 docs: Regenerate docs helper

git-subtree-dir: docs
git-subtree-split: 0c3c04fd63
2019-05-25 10:41:23 +02:00
Ruslan Nasonov 5b4b8bb3c1 commands: Create new 'hugo list all' command
New:
- command `hugo list all`, return all posts meta in csv format

Refactoring:
- move common parts in commands/list.go to function `buildSites`
- change way to detect path to content

See #5904
2019-05-25 00:09:51 +02:00
Brice BERDAH 2278b0eb02 Medium -> Hugo exporting tool
Suggesting a simple yet powerful tool for people looking to export their Medium blog to Hugo
2019-05-24 15:35:41 +02:00
Brian 'Redbeard' Harrington 41974303f3 dockerfile: Switch base image for final build
Switching the base image for the final build to alpine as it still
provides a minimal interface, but has a mechanism for easily including
relevant CA certificates.  This is currently pinned to a tagged version,
though since none of the underlying mechanisms are used this should
balance both remaining stable, supported for a period of time, and
providing usable functionality.

Resolves #5970
Affects #5056
2019-05-23 12:49:13 -06:00
Bjørn Erik Pedersen 6b3f1a1002 Merge branch 'release-0.55.6' 2019-05-18 10:18:23 +02:00
hugoreleaser fa8e334dae releaser: Prepare repository for 0.56.0-DEV
[ci skip]
2019-05-18 07:57:50 +00:00
hugoreleaser a5d4c82d2f releaser: Add release notes to /docs for release of 0.55.6
[ci skip]
2019-05-18 07:55:28 +00:00
hugoreleaser 32f4b38338 releaser: Bump versions for release of 0.55.6
[ci skip]
2019-05-18 07:55:28 +00:00
Bjørn Erik Pedersen 9b48c5d6bd Release 0.55.6 2019-05-18 09:50:50 +02:00
hugoreleaser 8a1873a2d5 releaser: Add release notes draft for 0.55.6
Rename to *-ready.md to continue. [ci skip]
2019-05-18 07:39:23 +00:00
Bjørn Erik Pedersen 95ce2a40e7 hugolib: Prevent parallel server rebuilds
There have been reports about infrequent paginator crashes when running the Hugo server since 0.55.0.

The reason have been narrowed down to that of parallel rebuilds.

This isn't a new thing, but the changes in 0.55.0 made it extra important to serialize the page initialization.

This commit fixes that by protecting the `Build` method with a lock when running in server mode.

Fixes #5885
Fixes #5968
2019-05-18 09:01:40 +02:00
Rodolfo Carvalho e22b3f54c3 tpl: Fix internal templates usage of safeHTMLAttr
The `safeHTMLAttr` function operates on a full attribute definition, not
just within the attribute value.

Docs: https://gohugo.io/functions/safehtmlattr/

For `opengraph.html`, run the whole `content` HTML attribute through
`safeHTMLAttr`. That will preserve `+` signs in formatted dates.

For `vimeo_simple.html`, `safeHTMLAttr` was in the context of an
attribute value, thus having no effect. In this case we could replace it
with `safeURL`, but since the code is coming from an API it is safer to
just let Go's template engine sanitize the value as it already does with
`provider_url`.

Fixes #5236 (no need to change Go upstream)
Related to #5246
2019-05-17 16:00:54 +02:00
Bjørn Erik Pedersen 71b8d8b6a4 Update to Go 1.12.5 and Go 1.11.10
Fixes #5944
2019-05-15 07:49:04 +02:00
Robert van Gent 5dc6d0df94 deploy: Add tests; fix Windows 2019-05-09 22:11:23 +02:00
Robert van Gent 527cf1ab03 deploy: Support configuration of upload order 2019-05-06 22:59:07 +02:00
Robert van Gent f4956d9aae deploy: Support invalidating a CloudFront CDN cache 2019-05-06 21:09:33 +02:00
Bjørn Erik Pedersen 2838d58b1d i18n: Move the package below /langs
To get fewer top level packages.
2019-05-04 18:25:56 +02:00
Robert van Gent f330e869e4 deploy: compute MD5 by reading if List didn't provide one 2019-05-04 09:31:34 +02:00
Robert van Gent f2b5d4de34 Revert docs/config.toml changes 2019-05-03 17:58:40 +02:00
Bjørn Erik Pedersen 0091b1f893 travis: Use proxy.golang.org 2019-05-03 17:58:40 +02:00
Robert van Gent c7165589b3 Add a "deploy" command 2019-05-03 17:58:40 +02:00
Bjørn Erik Pedersen ad5703a917 hugolib: Disable racy test
See #5926
2019-05-03 09:20:39 +02:00
hugoreleaser f94a388ad3 releaser: Prepare repository for 0.56.0-DEV
[ci skip]
2019-05-02 13:06:04 +00:00
hugoreleaser a83256b9cd releaser: Add release notes to /docs for release of 0.55.5
[ci skip]
2019-05-02 13:03:34 +00:00
hugoreleaser 77ad1336d2 releaser: Bump versions for release of 0.55.5
[ci skip]
2019-05-02 13:03:34 +00:00
Bjørn Erik Pedersen e33ed29b75 Release 0.55.5 2019-05-02 14:50:04 +02:00
hugoreleaser 2fb708d3d0 releaser: Add release notes draft for 0.55.5
Rename to *-ready.md to continue. [ci skip]
2019-05-02 12:36:11 +00:00
Bjørn Erik Pedersen cee181c3a6 docs: Regenerate docs helper 2019-05-02 14:26:02 +02:00
Bjørn Erik Pedersen b1d438ea28 Merge commit 'f147b5c53eda15982e0fe762847532eeddb7485f' 2019-05-02 14:24:13 +02:00
Bjørn Erik Pedersen f147b5c53e Squashed 'docs/' changes from 13097daf2..50c02516c
50c02516c resources: Clean
380554caf Added Pharmaseal case study
bd462671d Fix typo
0522a2595 no -> fr
f2c4671db Fix broken Netlify setup
056da25f2 Release 0.55.4
2ddca746e Merge branch 'temp554'
3d6cf9967 releaser: Add release notes to /docs for release of 0.55.4
9dc637cab Minor link fix
95186103c Release 0.55.3
b2449cd25 releaser: Add release notes to /docs for release of 0.55.3
55934c3a2 docs: Regenerate docs helper

git-subtree-dir: docs
git-subtree-split: 50c02516cb
2019-05-02 14:23:40 +02:00
Bjørn Erik Pedersen 6b76841b05 output: Fix permalink in sitemap etc. when multiple permalinkable output formats
In Hugo 0.55.0 we made AMP `permalinkable`. We also render the output formats in their natural sort order, meaning `AMP` will be rendered before `HTML`. References in the sitemap would then point to the AMP version, and this is normally not what you'd want.

This commit fixes that by making `HTML` by default sort before the others.

If this is not you want, you can set `weight` on the output format configuration.

Fixes #5910
2019-05-02 14:23:16 +02:00
Bjørn Erik Pedersen bcbed4ebda hugolib: Fix PrevInSection/NextInSection for nested sections
This was broken in Hugo 0.55.0.

Fixes #5883
2019-05-01 19:34:28 +02:00
Bjørn Erik Pedersen 009076e5ee lazy: Fix concurrent initialization order
Fixes #5901
2019-05-01 16:00:31 +02:00
David Birks 1cbb501be8 Update blackfriday to v1.5.2 2019-05-01 11:56:53 +02:00
Bjørn Erik Pedersen 66b143a01d tpl/compare: Fix nil compare in eq/ne for interface values
Fixes #5905
2019-04-29 18:43:44 +02:00
Cameron Moore 4f93f8c670 tpl: Fix hugo package name and add godocs 2019-04-27 22:44:57 +02:00
Cameron Moore f76e50118b tpl: Provide more detailed errors in Where 2019-04-27 09:54:22 +02:00
hugoreleaser f84df16fea releaser: Prepare repository for 0.56.0-DEV
[ci skip]
2019-04-25 07:41:16 +00:00
hugoreleaser 579004178b releaser: Add release notes to /docs for release of 0.55.4
[ci skip]
2019-04-25 07:38:48 +00:00
hugoreleaser f2fbca23aa releaser: Bump versions for release of 0.55.4
[ci skip]
2019-04-25 07:38:48 +00:00
Bjørn Erik Pedersen 1707f1a5f5 Release 0.55.4 2019-04-25 09:28:17 +02:00
hugoreleaser 211d667979 releaser: Add release notes draft for 0.55.4
Rename to *-ready.md to continue. [ci skip]
2019-04-25 07:26:35 +00:00
Bjørn Erik Pedersen 33c738116c hugolib: Fix shortcode version=1 logic
Fixes #5831
2019-04-24 15:35:04 +02:00
Bjørn Erik Pedersen 69a56420ae hugolib: Avoid recloning of shortcode templates
```bash
benchmark                                    old ns/op     new ns/op     delta
BenchmarkSiteNew/Bundle_with_image-4         14572242      14382188      -1.30%
BenchmarkSiteNew/Bundle_with_JSON_file-4     13683922      13738196      +0.40%
BenchmarkSiteNew/Multiple_languages-4        41912231      25192494      -39.89%

benchmark                                    old allocs     new allocs     delta
BenchmarkSiteNew/Bundle_with_image-4         57496          57493          -0.01%
BenchmarkSiteNew/Bundle_with_JSON_file-4     57492          57501          +0.02%
BenchmarkSiteNew/Multiple_languages-4        242422         118809         -50.99%

benchmark                                    old bytes     new bytes     delta
BenchmarkSiteNew/Bundle_with_image-4         3845077       3844065       -0.03%
BenchmarkSiteNew/Bundle_with_JSON_file-4     3627442       3627798       +0.01%
BenchmarkSiteNew/Multiple_languages-4        13963502      7543885       -45.97%
```

Fixes #5890
2019-04-24 12:37:57 +02:00
Bjørn Erik Pedersen 4756ec3cd8 i18n: Avoid rebuilding the Translations map for every lookup
```bash
benchmark                                                    old ns/op     new ns/op     delta
BenchmarkI18nTranslate/all-present-4                         764           757           -0.92%
BenchmarkI18nTranslate/present-in-default-4                  2578          1457          -43.48%
BenchmarkI18nTranslate/present-in-current-4                  764           766           +0.26%
BenchmarkI18nTranslate/missing-4                             3362          1103          -67.19%
BenchmarkI18nTranslate/file-missing-4                        4646          3611          -22.28%
BenchmarkI18nTranslate/context-provided-4                    2013          2014          +0.05%
BenchmarkI18nTranslate/same-id-and-translation-4             1961          784           -60.02%
BenchmarkI18nTranslate/same-id-and-translation-default-4     3717          1405          -62.20%
BenchmarkI18nTranslate/unknown-language-code-4               1775          1787          +0.68%

benchmark                                                    old allocs     new allocs     delta
BenchmarkI18nTranslate/all-present-4                         6              6              +0.00%
BenchmarkI18nTranslate/present-in-default-4                  16             10             -37.50%
BenchmarkI18nTranslate/present-in-current-4                  6              6              +0.00%
BenchmarkI18nTranslate/missing-4                             20             8              -60.00%
BenchmarkI18nTranslate/file-missing-4                        27             21             -22.22%
BenchmarkI18nTranslate/context-provided-4                    15             15             +0.00%
BenchmarkI18nTranslate/same-id-and-translation-4             12             6              -50.00%
BenchmarkI18nTranslate/same-id-and-translation-default-4     22             10             -54.55%
BenchmarkI18nTranslate/unknown-language-code-4               13             13             +0.00%

benchmark                                                    old bytes     new bytes     delta
BenchmarkI18nTranslate/all-present-4                         152           152           +0.00%
BenchmarkI18nTranslate/present-in-default-4                  1144          216           -81.12%
BenchmarkI18nTranslate/present-in-current-4                  152           152           +0.00%
BenchmarkI18nTranslate/missing-4                             2008          152           -92.43%
BenchmarkI18nTranslate/file-missing-4                        1208          600           -50.33%
BenchmarkI18nTranslate/context-provided-4                    704           704           +0.00%
BenchmarkI18nTranslate/same-id-and-translation-4             1080          152           -85.93%
BenchmarkI18nTranslate/same-id-and-translation-default-4     2073          216           -89.58%
BenchmarkI18nTranslate/unknown-language-code-4               696           696           +0.00%
```

Fixes #5892
2019-04-23 21:40:50 +02:00
Bjørn Erik Pedersen 4c3c512038 commands: Init mem profile at the end
Much more useful ...
2019-04-23 17:14:02 +02:00
Bjørn Erik Pedersen 0775c98e6c hugolib: No links for bundled pages
This fixes a bug introduced in Hugo 0.55.

Fixes #5882
2019-04-22 13:22:01 +02:00
hugoreleaser 1477fb33c9 releaser: Prepare repository for 0.56.0-DEV
[ci skip]
2019-04-20 14:25:57 +00:00
1417 changed files with 81664 additions and 35991 deletions
+2 -1
View File
@@ -1,6 +1,6 @@
defaults: &defaults
docker:
- image: bepsays/ci-goreleaser:1.12-2
- image: bepsays/ci-goreleaser:1.14.3
environment:
CGO_ENABLED: "0"
@@ -17,6 +17,7 @@ jobs:
cd hugo
go mod download
sleep 5
go mod verify
go test -p 1 ./...
- persist_to_workspace:
root: .
+18
View File
@@ -0,0 +1,18 @@
---
name: 'Bug report'
labels: ''
assignees: ''
about: Create a report to help us improve
---
<!-- Please answer these questions before submitting your issue. Thanks! -->
### What version of Hugo are you using (`hugo version`)?
<pre>
$ hugo version
</pre>
### Does this issue reproduce with the latest release?
@@ -0,0 +1,8 @@
---
name: Proposal
about: Suggest an idea for Hugo
title: ''
labels: 'Proposal'
assignees: ''
---
+10
View File
@@ -0,0 +1,10 @@
---
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!
+14
View File
@@ -0,0 +1,14 @@
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 }}
+4 -1
View File
@@ -20,5 +20,8 @@ dock.sh
GoBuilds
dist
hugolib/hugo_stats.json
resources/sunset.jpg
vendor
vendor
+50 -18
View File
@@ -1,26 +1,59 @@
language: go
sudo: false
dist: xenial
dist: bionic
env:
global:
- HUGO_BUILD_TAGS="extended"
- CACHE_NAME=${TRAVIS_ARCH}
- GO111MODULE=on
- GOPROXY=https://proxy.golang.org
- HUGO_BUILD_TAGS=extended
git:
depth: false
go:
- "1.11.7"
- "1.12.2"
- tip
- "1.13.11"
- "1.14.3"
- master
arch:
- amd64
- arm64
os:
- linux
- osx
- windows
matrix:
jobs:
allow_failures:
- go: tip
- go: master
- arch: arm64
fast_finish: true
exclude:
- os: windows
go: tip
- 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
@@ -28,18 +61,17 @@ install:
- 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
- mage -v check
- 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
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
+8 -4
View File
@@ -29,12 +29,16 @@ Please don't use the GitHub issue tracker to ask questions.
## Reporting Issues
If you believe you have found a defect in Hugo or its documentation, use
the GitHub [issue tracker](https://github.com/gohugoio/hugo/issues) to report
the GitHub issue tracker to report
the problem to the Hugo maintainers. If you're not sure if it's a bug or not,
start by asking in the [discussion forum](https://discourse.gohugo.io).
When reporting the issue, please provide the version of Hugo in use (`hugo
version`) and your operating system.
- [Hugo Issues · gohugoio/hugo](https://github.com/gohugoio/hugo/issues)
- [Hugo Documentation Issues · gohugoio/hugoDocs](https://github.com/gohugoio/hugoDocs/issues)
- [Hugo Website Theme Issues · gohugoio/hugoThemesSite](https://github.com/gohugoio/hugoThemesSite/issues)
## Code Contribution
Hugo has become a fully featured static site generator, so any new functionality must:
@@ -44,15 +48,15 @@ Hugo has become a fully featured static site generator, so any new functionality
* strive not to break existing sites.
* close or update an open [Hugo issue](https://github.com/gohugoio/hugo/issues)
If it is of some complexity, the contributor is expected to maintain and support the new future (answer questions on the forum, fix any bugs etc.).
If it is of some complexity, the contributor is expected to maintain and support the new feature in the future (answer questions on the forum, fix any bugs etc.).
It is recommended to open up a discussion on the [Hugo Forum](https://discourse.gohugo.io/) to get feedback on your idea before you begin. If you are submitting a complex feature, create a small design proposal on the [Hugo issue tracker](https://github.com/gohugoio/hugo/issues) before you start.
Note that we do not accept new features that require [CGO](https://github.com/golang/go/wiki/cgo).
We have one exception to this rule which is LibSASS.
**Bug fixes are, of course, always welcome.**
## Submitting Patches
The Hugo project welcomes all contributors and contributions regardless of skill or experience level. If you are interested in helping with the project, we will help you with your contribution.
+33 -20
View File
@@ -2,31 +2,44 @@
# Twitter: https://twitter.com/gohugoio
# Website: https://gohugo.io/
FROM golang:1.11-stretch AS build
FROM golang:1.13-alpine AS build
# Optionally set HUGO_BUILD_TAGS to "extended" when building like so:
# docker build --build-arg HUGO_BUILD_TAGS=extended .
ARG HUGO_BUILD_TAGS
WORKDIR /go/src/github.com/gohugoio/hugo
RUN apt-get install \
git gcc g++ binutils
COPY . /go/src/github.com/gohugoio/hugo/
ENV GO111MODULE=on
RUN go get -d .
ARG CGO=0
ARG CGO=1
ENV CGO_ENABLED=${CGO}
ENV GOOS=linux
ENV GO111MODULE=on
# default non-existent build tag so -tags always has an arg
ARG BUILD_TAGS="99notag"
RUN go install -ldflags '-w -extldflags "-static"' -tags ${BUILD_TAGS}
WORKDIR /go/src/github.com/gohugoio/hugo
COPY . /go/src/github.com/gohugoio/hugo/
# gcc/g++ are required to build SASS libraries for extended version
RUN apk update && \
apk add --no-cache gcc g++ musl-dev && \
go get github.com/magefile/mage
RUN mage hugo && mage install
# ---
FROM scratch
COPY --from=build /go/bin/hugo /hugo
ARG WORKDIR="/site"
WORKDIR ${WORKDIR}
VOLUME ${WORKDIR}
EXPOSE 1313
ENTRYPOINT [ "/hugo" ]
CMD [ "--help" ]
FROM alpine:3.11
COPY --from=build /go/bin/hugo /usr/bin/hugo
# libc6-compat & libstdc++ are required for extended SASS libraries
# ca-certificates are required to fetch outside resources (like Twitter oEmbeds)
RUN apk update && \
apk add --no-cache ca-certificates libc6-compat libstdc++ git
VOLUME /site
WORKDIR /site
# Expose port for live server
EXPOSE 1313
ENTRYPOINT ["hugo"]
CMD ["--help"]
+42 -39
View File
@@ -1,4 +1,4 @@
![Hugo](https://raw.githubusercontent.com/gohugoio/hugoDocs/master/static/img/hugo-logo.png)
<img src="https://raw.githubusercontent.com/gohugoio/gohugoioTheme/master/static/images/hugo-logo-wide.svg?sanitize=true" alt="Hugo" width="565">
A Fast and Flexible Static Site Generator built with love by [bep](https://github.com/bep), [spf13](http://spf13.com/) and [friends](https://github.com/gohugoio/hugo/graphs/contributors) in [Go][].
@@ -29,9 +29,9 @@ Hugo is designed to work well for any kind of website including blogs, tumbles,
#### Supported Architectures
Currently, we provide pre-built Hugo binaries for Windows, Linux, FreeBSD, NetBSD, macOS (Darwin), and [Android](https://gist.github.com/bep/a0d8a26cf6b4f8bc992729b8e50b480b) for x64, i386 and ARM architectures.
Currently, we provide pre-built Hugo binaries for Windows, Linux, FreeBSD, NetBSD, DragonFly BSD, Open BSD, macOS (Darwin), and [Android](https://gist.github.com/bep/a0d8a26cf6b4f8bc992729b8e50b480b) for x64, i386 and ARM architectures.
Hugo may also be compiled from source wherever the Go compiler tool chain can run, e.g. for other operating systems including DragonFly BSD, OpenBSD, Plan 9, and Solaris.
Hugo may also be compiled from source wherever the Go compiler tool chain can run, e.g. for other operating systems including Plan 9 and Solaris.
**Complete documentation is available at [Hugo Documentation](https://gohugo.io/getting-started/).**
@@ -54,7 +54,7 @@ Use the [installation instructions in the Hugo documentation](https://gohugo.io/
#### Prerequisite Tools
* [Git](https://git-scm.com/)
* [Go (at least Go 1.11)](https://golang.org/dl/)
* [Go (we test it with the last 2 major versions)](https://golang.org/dl/)
#### Fetch from GitHub
@@ -106,7 +106,7 @@ The Hugo project welcomes all contributors and contributions regardless of skill
If you are interested in helping with the project, we will help you with your contribution.
Hugo is a very active project with many contributions happening daily.
Because we want to create the best possible product for our users and the best contribution experience for our developers,
We want to create the best possible product for our users and the best contribution experience for our developers,
we have a set of guidelines which ensure that all contributions are acceptable.
The guidelines are not intended as a filter or barrier to participation.
If you are unfamiliar with the contribution process, the Hugo team will help you and teach you how to bring your contribution in accordance with the guidelines.
@@ -124,64 +124,67 @@ Hugo stands on the shoulder of many great open source libraries, in lexical orde
| Dependency | License |
| :------------- | :------------- |
| [github.com/alecthomas/chroma](https://github.com/alecthomas/chroma) | MIT License |
| [github.com/armon/go-radix](https://github.com/armon/go-radix) | MIT License |
| [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) | Apache License 2.0 |
| [github.com/bep/debounce](https://github.com/bep/debounce) | MIT License |
| [github.com/bep/gitmap](https://github.com/bep/gitmap) | MIT License |
| [github.com/bep/golibsass](https://github.com/bep/golibsass) | MIT License |
| [github.com/bep/tmc](https://github.com/bep/tmc) | MIT License |
| [github.com/BurntSushi/locker](https://github.com/BurntSushi/locker) | The Unlicense |
| [github.com/BurntSushi/toml](https://github.com/BurntSushi/toml) | MIT License |
| [github.com/PuerkitoBio/purell](https://github.com/PuerkitoBio/purell) | BSD 3-Clause "New" or "Revised" License |
| [github.com/PuerkitoBio/urlesc](https://github.com/PuerkitoBio/urlesc) | BSD 3-Clause "New" or "Revised" License |
| [github.com/alecthomas/chroma](https://github.com/alecthomas/chroma) | MIT License |
| [github.com/bep/debounce](https://github.com/bep/debounce) | MIT License |
| [github.com/bep/gitmap](https://github.com/bep/gitmap) | MIT License |
| [github.com/bep/go-tocss](https://github.com/bep/go-tocss) | MIT License |
| [github.com/chaseadamsio/goorgeous](https://github.com/chaseadamsio/goorgeous) | MIT License |
| [github.com/cpuguy83/go-md2man](https://github.com/cpuguy83/go-md2man) | MIT License |
| [github.com/danwakefield/fnmatch](https://github.com/danwakefield/fnmatch) | BSD 2-Clause "Simplified" License |
| [github.com/disintegration/imaging](https://github.com/disintegration/imaging) | MIT License |
| [github.com/dlclark/regexp2](https://github.com/dlclark/regexp2) | MIT License |
| [github.com/eknkc/amber](https://github.com/eknkc/amber) | MIT License |
| [github.com/fsnotify/fsnotify](https://github.com/fsnotify/fsnotify) | BSD 3-Clause "New" or "Revised" License |
| [github.com/disintegration/gift](https://github.com/disintegration/gift) | MIT License |
| [github.com/dustin/go-humanize](https://github.com/dustin/go-humanize) | MIT License |
| [github.com/fsnotify/fsnotify](https://github.com/fsnotify/fsnotify) | BSD 3-Clause "New" or "Revised" License |
| [github.com/gobwas/glob](https://github.com/gobwas/glob) | MIT License |
| [github.com/gorilla/websocket](https://github.com/gorilla/websocket) | BSD 2-Clause "Simplified" License |
| [github.com/hashicorp/go-immutable-radix](https://github.com/hashicorp/go-immutable-radix) | Mozilla Public License 2.0 |
| [github.com/gorilla/websocket](https://github.com/gorilla/websocket) | BSD 2-Clause "Simplified" License |
| [github.com/hashicorp/golang-lru](https://github.com/hashicorp/golang-lru) | Mozilla Public License 2.0 |
| [github.com/hashicorp/hcl](https://github.com/hashicorp/hcl) | Mozilla Public License 2.0 |
| [github.com/jdkato/prose](https://github.com/jdkato/prose) | MIT License |
| [github.com/kyokomi/emoji](https://github.com/kyokomi/emoji) | MIT License |
| [github.com/hashicorp/hcl](https://github.com/hashicorp/hcl) | Mozilla Public License 2.0 |
| [github.com/jdkato/prose](https://github.com/jdkato/prose) | MIT License |
| [github.com/kr/pretty](https://github.com/kr/pretty) | MIT License |
| [github.com/kyokomi/emoji](https://github.com/kyokomi/emoji) | MIT License |
| [github.com/magiconair/properties](https://github.com/magiconair/properties) | BSD 2-Clause "Simplified" License |
| [github.com/markbates/inflect](https://github.com/markbates/inflect) | MIT License |
| [github.com/markbates/inflect](https://github.com/markbates/inflect) | MIT License |
| [github.com/mattn/go-isatty](https://github.com/mattn/go-isatty) | MIT License |
| [github.com/mattn/go-runewidth](https://github.com/mattn/go-runewidth) | MIT License |
| [github.com/miekg/mmark](https://github.com/miekg/mmark) | Simplified BSD License |
| [github.com/mitchellh/hashstructure](https://github.com/mitchellh/hashstructure) | MIT License |
| [github.com/mitchellh/mapstructure](https://github.com/mitchellh/mapstructure) | MIT License |
| [github.com/muesli/smartcrop](https://github.com/muesli/smartcrop) | MIT License |
| [github.com/muesli/smartcrop](https://github.com/muesli/smartcrop) | MIT License |
| [github.com/nicksnyder/go-i18n](https://github.com/nicksnyder/go-i18n) | MIT License |
| [github.com/niklasfasching/go-org](https://github.com/niklasfasching/go-org) | MIT License |
| [github.com/olekukonko/tablewriter](https://github.com/olekukonko/tablewriter) | MIT License |
| [github.com/pelletier/go-toml](https://github.com/pelletier/go-toml) | MIT License |
| [github.com/pkg/errors](https://github.com/pkg/errors) | BSD 2-Clause "Simplified" License |
| [github.com/pelletier/go-toml](https://github.com/pelletier/go-toml) | MIT License |
| [github.com/pkg/errors](https://github.com/pkg/errors) | BSD 2-Clause "Simplified" License |
| [github.com/PuerkitoBio/purell](https://github.com/PuerkitoBio/purell) | BSD 3-Clause "New" or "Revised" License |
| [github.com/PuerkitoBio/urlesc](https://github.com/PuerkitoBio/urlesc) | BSD 3-Clause "New" or "Revised" License |
| [github.com/rogpeppe/go-internal](https://github.com/rogpeppe/go-internal) | BSD 3-Clause "New" or "Revised" License |
| [github.com/russross/blackfriday](https://github.com/russross/blackfriday) | Simplified BSD License |
| [github.com/shurcooL/sanitized_anchor_name](https://github.com/shurcooL/sanitized_anchor_name) | MIT License |
| [github.com/rwcarlsen/goexif](https://github.com/rwcarlsen/goexif) | BSD 2-Clause "Simplified" License |
| [github.com/spf13/afero](https://github.com/spf13/afero) | Apache License 2.0 |
| [github.com/spf13/cast](https://github.com/spf13/cast) | MIT License |
| [github.com/spf13/cast](https://github.com/spf13/cast) | MIT License |
| [github.com/spf13/cobra](https://github.com/spf13/cobra) | Apache License 2.0 |
| [github.com/spf13/fsync](https://github.com/spf13/fsync) | MIT License |
| [github.com/spf13/jwalterweatherman](https://github.com/spf13/jwalterweatherman) | MIT License |
| [github.com/spf13/nitro](https://github.com/spf13/nitro) | Apache License 2.0 |
| [github.com/spf13/pflag](https://github.com/spf13/pflag) | BSD 3-Clause "New" or "Revised" License |
| [github.com/spf13/viper](https://github.com/spf13/viper) | MIT License |
| [github.com/tdewolff/minify](https://github.com/tdewolff/minify) | MIT License |
| [github.com/tdewolff/parse](https://github.com/tdewolff/parse) | MIT License |
| [github.com/wellington/go-libsass](https://github.com/wellington/go-libsass) | Apache License 2.0 |
| [github.com/yosssi/ace](https://github.com/yosssi/ace) | MIT License |
| [github.com/yuin/goldmark](https://github.com/yuin/goldmark) | MIT License |
| [github.com/yuin/goldmark-highlighting](https://github.com/yuin/goldmark-highlighting) | MIT License |
| [go.opencensus.io](https://go.opencensus.io) | Apache License 2.0 |
| [go.uber.org/atomic](https://go.uber.org/atomic) | MIT License |
| [gocloud.dev](https://gocloud.dev) | Apache License 2.0 |
| [golang.org/x/image](https://golang.org/x/image) | BSD 3-Clause "New" or "Revised" License |
| [golang.org/x/net](https://golang.org/x/net) | BSD 3-Clause "New" or "Revised" License |
| [golang.org/x/oauth2](https://golang.org/x/oauth2) | BSD 3-Clause "New" or "Revised" License |
| [golang.org/x/sync](https://golang.org/x/sync) | BSD 3-Clause "New" or "Revised" License |
| [golang.org/x/sys](https://golang.org/x/sys) | BSD 3-Clause "New" or "Revised" License |
| [golang.org/x/text](https://golang.org/x/text) | BSD 3-Clause "New" or "Revised" License
| [gopkg.in/yaml.v2](https://gopkg.in/yaml.v2) | Apache License 2.0 |
| [golang.org/x/text](https://golang.org/x/text) | BSD 3-Clause "New" or "Revised" License |
| [golang.org/x/xerrors](https://golang.org/x/xerrors) | BSD 3-Clause "New" or "Revised" License |
| [google.golang.org/api](https://google.golang.org/api) | BSD 3-Clause "New" or "Revised" License |
| [google.golang.org/genproto](https://google.golang.org/genproto) | Apache License 2.0 |
| [gopkg.in/ini.v1](https://gopkg.in/ini.v1) | Apache License 2.0 |
| [gopkg.in/yaml.v2](https://gopkg.in/yaml.v2) | Apache License 2.0 |
+1 -2
View File
@@ -1,2 +1 @@
gobench -package=./hugolib -bench="BenchmarkSiteBuilding/YAML,num_langs=3,num_pages=5000,tags_per_page=5,shortcodes,render" -count=3 > 1.bench
benchcmp -best 0.bench 1.bench
gobench -package=./hugolib -bench="BenchmarkSiteNew/Deep_content_tree"
+7 -3
View File
@@ -14,14 +14,18 @@
package bufferpool
import (
"github.com/stretchr/testify/assert"
"testing"
qt "github.com/frankban/quicktest"
)
func TestBufferPool(t *testing.T) {
c := qt.New(t)
buff := GetBuffer()
buff.WriteString("do be do be do")
assert.Equal(t, "do be do be do", buff.String())
c.Assert(buff.String(), qt.Equals, "do be do be do")
PutBuffer(buff)
assert.Equal(t, 0, buff.Len())
c.Assert(buff.Len(), qt.Equals, 0)
}
+46 -23
View File
@@ -15,6 +15,7 @@ package filecache
import (
"bytes"
"errors"
"io"
"io/ioutil"
"os"
@@ -31,6 +32,9 @@ import (
"github.com/spf13/afero"
)
// ErrFatal can be used to signal an unrecoverable error.
var ErrFatal = errors.New("fatal filecache error")
const (
filecacheRootDirname = "filecache"
)
@@ -44,6 +48,9 @@ type Cache struct {
// 0 is effectively turning this cache off.
maxAge time.Duration
// When set, we just remove this entire root directory on expiration.
pruneAllRootDir string
nlocker *lockTracker
}
@@ -77,11 +84,12 @@ type ItemInfo struct {
}
// NewCache creates a new file cache with the given filesystem and max age.
func NewCache(fs afero.Fs, maxAge time.Duration) *Cache {
func NewCache(fs afero.Fs, maxAge time.Duration, pruneAllRootDir string) *Cache {
return &Cache{
Fs: fs,
nlocker: &lockTracker{Locker: locker.NewLocker(), seen: make(map[string]struct{})},
maxAge: maxAge,
Fs: fs,
nlocker: &lockTracker{Locker: locker.NewLocker(), seen: make(map[string]struct{})},
maxAge: maxAge,
pruneAllRootDir: pruneAllRootDir,
}
}
@@ -121,7 +129,7 @@ func (c *Cache) WriteCloser(id string) (ItemInfo, io.WriteCloser, error) {
// If not found a new file is created and passed to create, which should close
// it when done.
func (c *Cache) ReadOrCreate(id string,
read func(info ItemInfo, r io.Reader) error,
read func(info ItemInfo, r io.ReadSeeker) error,
create func(info ItemInfo, w io.WriteCloser) error) (info ItemInfo, err error) {
id = cleanID(id)
@@ -133,7 +141,13 @@ func (c *Cache) ReadOrCreate(id string,
if r := c.getOrRemove(id); r != nil {
err = read(info, r)
defer r.Close()
return
if err == nil || err == ErrFatal {
// See https://github.com/gohugoio/hugo/issues/6401
// To recover from file corruption we handle read errors
// as the cache item was not found.
// Any file permission issue will also fail in the next step.
return
}
}
f, err := helpers.OpenFileForWriting(c.Fs, id)
@@ -307,9 +321,15 @@ func (f Caches) Get(name string) *Cache {
// NewCaches creates a new set of file caches from the given
// configuration.
func NewCaches(p *helpers.PathSpec) (Caches, error) {
dcfg, err := decodeConfig(p)
if err != nil {
return nil, err
var dcfg Configs
if c, ok := p.Cfg.Get("filecacheConfigs").(Configs); ok {
dcfg = c
} else {
var err error
dcfg, err = DecodeConfig(p.Fs.Source, p.Cfg)
if err != nil {
return nil, err
}
}
fs := p.Fs.Source
@@ -319,30 +339,33 @@ func NewCaches(p *helpers.PathSpec) (Caches, error) {
var cfs afero.Fs
if v.isResourceDir {
cfs = p.BaseFs.Resources.Fs
cfs = p.BaseFs.ResourcesCache
} else {
cfs = fs
}
var baseDir string
if !strings.HasPrefix(v.Dir, "_gen") {
// We do cache eviction (file removes) and since the user can set
// his/hers own cache directory, we really want to make sure
// we do not delete any files that do not belong to this cache.
// We do add the cache name as the root, but this is an extra safe
// guard. We skip the files inside /resources/_gen/ because
// that would be breaking.
baseDir = filepath.Join(v.Dir, filecacheRootDirname, k)
} else {
baseDir = filepath.Join(v.Dir, k)
if cfs == nil {
// TODO(bep) we still have some places that do not initialize the
// full dependencies of a site, e.g. the import Jekyll command.
// That command does not need these caches, so let us just continue
// for now.
continue
}
if err = cfs.MkdirAll(baseDir, 0777); err != nil && !os.IsExist(err) {
baseDir := v.Dir
if err := cfs.MkdirAll(baseDir, 0777); err != nil && !os.IsExist(err) {
return nil, err
}
bfs := afero.NewBasePathFs(cfs, baseDir)
m[k] = NewCache(bfs, v.MaxAge)
var pruneAllRootDir string
if k == cacheKeyModules {
pruneAllRootDir = "pkg"
}
m[k] = NewCache(bfs, v.MaxAge, pruneAllRootDir)
}
return m, nil
+42 -14
View File
@@ -19,6 +19,8 @@ import (
"strings"
"time"
"github.com/gohugoio/hugo/config"
"github.com/gohugoio/hugo/helpers"
"github.com/mitchellh/mapstructure"
@@ -32,7 +34,7 @@ const (
resourcesGenDir = ":resourceDir/_gen"
)
var defaultCacheConfig = cacheConfig{
var defaultCacheConfig = Config{
MaxAge: -1, // Never expire
Dir: ":cacheDir/:project",
}
@@ -42,9 +44,20 @@ const (
cacheKeyGetCSV = "getcsv"
cacheKeyImages = "images"
cacheKeyAssets = "assets"
cacheKeyModules = "modules"
)
var defaultCacheConfigs = map[string]cacheConfig{
type Configs map[string]Config
func (c Configs) CacheDirModules() string {
return c[cacheKeyModules].Dir
}
var defaultCacheConfigs = Configs{
cacheKeyModules: {
MaxAge: -1,
Dir: ":cacheDir/modules",
},
cacheKeyGetJSON: defaultCacheConfig,
cacheKeyGetCSV: defaultCacheConfig,
cacheKeyImages: {
@@ -57,9 +70,7 @@ var defaultCacheConfigs = map[string]cacheConfig{
},
}
type cachesConfig map[string]cacheConfig
type cacheConfig struct {
type Config struct {
// Max age of cache entries in this cache. Any items older than this will
// be removed and not returned from the cache.
// a negative value means forever, 0 means cache is disabled.
@@ -88,13 +99,18 @@ func (f Caches) ImageCache() *Cache {
return f[cacheKeyImages]
}
// ModulesCache gets the file cache for Hugo Modules.
func (f Caches) ModulesCache() *Cache {
return f[cacheKeyModules]
}
// AssetsCache gets the file cache for assets (processed resources, SCSS etc.).
func (f Caches) AssetsCache() *Cache {
return f[cacheKeyAssets]
}
func decodeConfig(p *helpers.PathSpec) (cachesConfig, error) {
c := make(cachesConfig)
func DecodeConfig(fs afero.Fs, cfg config.Provider) (Configs, error) {
c := make(Configs)
valid := make(map[string]bool)
// Add defaults
for k, v := range defaultCacheConfigs {
@@ -102,11 +118,9 @@ func decodeConfig(p *helpers.PathSpec) (cachesConfig, error) {
valid[k] = true
}
cfg := p.Cfg
m := cfg.GetStringMap(cachesConfigKey)
_, isOsFs := p.Fs.Source.(*afero.OsFs)
_, isOsFs := fs.(*afero.OsFs)
for k, v := range m {
cc := defaultCacheConfig
@@ -148,7 +162,7 @@ func decodeConfig(p *helpers.PathSpec) (cachesConfig, error) {
for i, part := range parts {
if strings.HasPrefix(part, ":") {
resolved, isResource, err := resolveDirPlaceholder(p, part)
resolved, isResource, err := resolveDirPlaceholder(fs, cfg, part)
if err != nil {
return c, err
}
@@ -176,6 +190,18 @@ func decodeConfig(p *helpers.PathSpec) (cachesConfig, error) {
}
}
if !strings.HasPrefix(v.Dir, "_gen") {
// We do cache eviction (file removes) and since the user can set
// his/hers own cache directory, we really want to make sure
// we do not delete any files that do not belong to this cache.
// We do add the cache name as the root, but this is an extra safe
// guard. We skip the files inside /resources/_gen/ because
// that would be breaking.
v.Dir = filepath.Join(v.Dir, filecacheRootDirname, k)
} else {
v.Dir = filepath.Join(v.Dir, k)
}
if disabled {
v.MaxAge = 0
}
@@ -187,15 +213,17 @@ func decodeConfig(p *helpers.PathSpec) (cachesConfig, error) {
}
// Resolves :resourceDir => /myproject/resources etc., :cacheDir => ...
func resolveDirPlaceholder(p *helpers.PathSpec, placeholder string) (cacheDir string, isResource bool, err error) {
func resolveDirPlaceholder(fs afero.Fs, cfg config.Provider, placeholder string) (cacheDir string, isResource bool, err error) {
workingDir := cfg.GetString("workingDir")
switch strings.ToLower(placeholder) {
case ":resourcedir":
return "", true, nil
case ":cachedir":
d, err := helpers.GetCacheDir(p.Fs.Source, p.Cfg)
d, err := helpers.GetCacheDir(fs, cfg)
return d, false, err
case ":project":
return filepath.Base(p.WorkingDir), false, nil
return filepath.Base(workingDir), false, nil
}
return "", false, errors.Errorf("%q is not a valid placeholder (valid values are :cacheDir or :resourceDir)", placeholder)
+34 -45
View File
@@ -20,19 +20,18 @@ import (
"testing"
"time"
"github.com/gohugoio/hugo/helpers"
"github.com/spf13/afero"
"github.com/gohugoio/hugo/config"
"github.com/gohugoio/hugo/hugofs"
qt "github.com/frankban/quicktest"
"github.com/spf13/viper"
"github.com/stretchr/testify/require"
)
func TestDecodeConfig(t *testing.T) {
t.Parallel()
assert := require.New(t)
c := qt.New(t)
configStr := `
resourceDir = "myresources"
@@ -56,30 +55,27 @@ dir = "/path/to/c3"
`
cfg, err := config.FromConfigString(configStr, "toml")
assert.NoError(err)
fs := hugofs.NewMem(cfg)
p, err := helpers.NewPathSpec(fs, cfg)
assert.NoError(err)
c.Assert(err, qt.IsNil)
fs := afero.NewMemMapFs()
decoded, err := DecodeConfig(fs, cfg)
c.Assert(err, qt.IsNil)
decoded, err := decodeConfig(p)
assert.NoError(err)
assert.Equal(4, len(decoded))
c.Assert(len(decoded), qt.Equals, 5)
c2 := decoded["getcsv"]
assert.Equal("11h0m0s", c2.MaxAge.String())
assert.Equal(filepath.FromSlash("/path/to/c2"), c2.Dir)
c.Assert(c2.MaxAge.String(), qt.Equals, "11h0m0s")
c.Assert(c2.Dir, qt.Equals, filepath.FromSlash("/path/to/c2/filecache/getcsv"))
c3 := decoded["images"]
assert.Equal(time.Duration(-1), c3.MaxAge)
assert.Equal(filepath.FromSlash("/path/to/c3"), c3.Dir)
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) {
t.Parallel()
assert := require.New(t)
c := qt.New(t)
configStr := `
resourceDir = "myresources"
@@ -104,24 +100,21 @@ dir = "/path/to/c3"
`
cfg, err := config.FromConfigString(configStr, "toml")
assert.NoError(err)
fs := hugofs.NewMem(cfg)
p, err := helpers.NewPathSpec(fs, cfg)
assert.NoError(err)
c.Assert(err, qt.IsNil)
fs := afero.NewMemMapFs()
decoded, err := DecodeConfig(fs, cfg)
c.Assert(err, qt.IsNil)
decoded, err := decodeConfig(p)
assert.NoError(err)
assert.Equal(4, len(decoded))
c.Assert(len(decoded), qt.Equals, 5)
for _, v := range decoded {
assert.Equal(time.Duration(0), v.MaxAge)
c.Assert(v.MaxAge, qt.Equals, time.Duration(0))
}
}
func TestDecodeConfigDefault(t *testing.T) {
assert := require.New(t)
c := qt.New(t)
cfg := newTestConfig()
if runtime.GOOS == "windows" {
@@ -133,34 +126,32 @@ func TestDecodeConfigDefault(t *testing.T) {
cfg.Set("cacheDir", "/cache/thecache")
}
fs := hugofs.NewMem(cfg)
p, err := helpers.NewPathSpec(fs, cfg)
assert.NoError(err)
fs := afero.NewMemMapFs()
decoded, err := decodeConfig(p)
decoded, err := DecodeConfig(fs, cfg)
assert.NoError(err)
c.Assert(err, qt.IsNil)
assert.Equal(4, len(decoded))
c.Assert(len(decoded), qt.Equals, 5)
imgConfig := decoded[cacheKeyImages]
jsonConfig := decoded[cacheKeyGetJSON]
if runtime.GOOS == "windows" {
assert.Equal("_gen", imgConfig.Dir)
c.Assert(imgConfig.Dir, qt.Equals, filepath.FromSlash("_gen/images"))
} else {
assert.Equal("_gen", imgConfig.Dir)
assert.Equal("/cache/thecache/hugoproject", jsonConfig.Dir)
c.Assert(imgConfig.Dir, qt.Equals, "_gen/images")
c.Assert(jsonConfig.Dir, qt.Equals, "/cache/thecache/hugoproject/filecache/getjson")
}
assert.True(imgConfig.isResourceDir)
assert.False(jsonConfig.isResourceDir)
c.Assert(imgConfig.isResourceDir, qt.Equals, true)
c.Assert(jsonConfig.isResourceDir, qt.Equals, false)
}
func TestDecodeConfigInvalidDir(t *testing.T) {
t.Parallel()
assert := require.New(t)
c := qt.New(t)
configStr := `
resourceDir = "myresources"
@@ -182,13 +173,11 @@ dir = "/"
}
cfg, err := config.FromConfigString(configStr, "toml")
assert.NoError(err)
fs := hugofs.NewMem(cfg)
p, err := helpers.NewPathSpec(fs, cfg)
assert.NoError(err)
c.Assert(err, qt.IsNil)
fs := afero.NewMemMapFs()
_, err = decodeConfig(p)
assert.Error(err)
_, err = DecodeConfig(fs, cfg)
c.Assert(err, qt.Not(qt.IsNil))
}
+87 -39
View File
@@ -17,6 +17,8 @@ import (
"io"
"os"
"github.com/gohugoio/hugo/hugofs"
"github.com/pkg/errors"
"github.com/spf13/afero"
)
@@ -28,49 +30,15 @@ import (
func (c Caches) Prune() (int, error) {
counter := 0
for k, cache := range c {
err := afero.Walk(cache.Fs, "", func(name string, info os.FileInfo, err error) error {
if info == nil {
return nil
}
name = cleanID(name)
count, err := cache.Prune(false)
if info.IsDir() {
f, err := cache.Fs.Open(name)
if err != nil {
// This cache dir may not exist.
return nil
}
defer f.Close()
_, err = f.Readdirnames(1)
if err == io.EOF {
// Empty dir.
return cache.Fs.Remove(name)
}
return nil
}
shouldRemove := cache.isExpired(info.ModTime())
if !shouldRemove && len(cache.nlocker.seen) > 0 {
// Remove it if it's not been touched/used in the last build.
_, seen := cache.nlocker.seen[name]
shouldRemove = !seen
}
if shouldRemove {
err := cache.Fs.Remove(name)
if err == nil {
counter++
}
return err
}
return nil
})
counter += count
if err != nil {
if os.IsNotExist(err) {
continue
}
return counter, errors.Wrapf(err, "failed to prune cache %q", k)
}
@@ -78,3 +46,83 @@ func (c Caches) Prune() (int, error) {
return counter, nil
}
// Prune removes expired and unused items from this cache.
// If force is set, everything will be removed not considering expiry time.
func (c *Cache) Prune(force bool) (int, error) {
if c.pruneAllRootDir != "" {
return c.pruneRootDir(force)
}
counter := 0
err := afero.Walk(c.Fs, "", func(name string, info os.FileInfo, err error) error {
if info == nil {
return nil
}
name = cleanID(name)
if info.IsDir() {
f, err := c.Fs.Open(name)
if err != nil {
// This cache dir may not exist.
return nil
}
defer f.Close()
_, err = f.Readdirnames(1)
if err == io.EOF {
// Empty dir.
err = c.Fs.Remove(name)
}
if err != nil && !os.IsNotExist(err) {
return err
}
return nil
}
shouldRemove := force || c.isExpired(info.ModTime())
if !shouldRemove && len(c.nlocker.seen) > 0 {
// Remove it if it's not been touched/used in the last build.
_, seen := c.nlocker.seen[name]
shouldRemove = !seen
}
if shouldRemove {
err := c.Fs.Remove(name)
if err == nil {
counter++
}
if err != nil && !os.IsNotExist(err) {
return err
}
}
return nil
})
return counter, err
}
func (c *Cache) pruneRootDir(force bool) (int, error) {
info, err := c.Fs.Stat(c.pruneAllRootDir)
if err != nil {
if os.IsNotExist(err) {
return 0, nil
}
return 0, err
}
if !force && !c.isExpired(info.ModTime()) {
return 0, nil
}
return hugofs.MakeReadableAndRemoveAllModulePkgDir(c.Fs, c.pruneAllRootDir)
}
+15 -22
View File
@@ -18,17 +18,15 @@ import (
"testing"
"time"
"github.com/gohugoio/hugo/config"
"github.com/gohugoio/hugo/helpers"
"github.com/gohugoio/hugo/hugofs"
"github.com/spf13/afero"
"github.com/stretchr/testify/require"
qt "github.com/frankban/quicktest"
)
func TestPrune(t *testing.T) {
t.Parallel()
assert := require.New(t)
c := qt.New(t)
configStr := `
resourceDir = "myresources"
@@ -54,16 +52,11 @@ maxAge = "200ms"
dir = ":resourceDir/_gen"
`
cfg, err := config.FromConfigString(configStr, "toml")
assert.NoError(err)
for _, name := range []string{cacheKeyGetCSV, cacheKeyGetJSON, cacheKeyAssets, cacheKeyImages} {
msg := fmt.Sprintf("cache: %s", name)
fs := hugofs.NewMem(cfg)
p, err := helpers.NewPathSpec(fs, cfg)
assert.NoError(err)
msg := qt.Commentf("cache: %s", name)
p := newPathsSpec(t, afero.NewMemMapFs(), configStr)
caches, err := NewCaches(p)
assert.NoError(err)
c.Assert(err, qt.IsNil)
cache := caches[name]
for i := 0; i < 10; i++ {
id := fmt.Sprintf("i%d", i)
@@ -77,21 +70,21 @@ dir = ":resourceDir/_gen"
}
count, err := caches.Prune()
assert.NoError(err)
assert.Equal(5, count, msg)
c.Assert(err, qt.IsNil)
c.Assert(count, qt.Equals, 5, msg)
for i := 0; i < 10; i++ {
id := fmt.Sprintf("i%d", i)
v := cache.getString(id)
if i < 5 {
assert.Equal("", v, id)
c.Assert(v, qt.Equals, "")
} else {
assert.Equal("abc", v, id)
c.Assert(v, qt.Equals, "abc")
}
}
caches, err = NewCaches(p)
assert.NoError(err)
c.Assert(err, qt.IsNil)
cache = caches[name]
// Touch one and then prune.
cache.GetOrCreateBytes("i5", func() ([]byte, error) {
@@ -99,17 +92,17 @@ dir = ":resourceDir/_gen"
})
count, err = caches.Prune()
assert.NoError(err)
assert.Equal(4, count)
c.Assert(err, qt.IsNil)
c.Assert(count, qt.Equals, 4)
// Now only the i5 should be left.
for i := 0; i < 10; i++ {
id := fmt.Sprintf("i%d", i)
v := cache.getString(id)
if i != 5 {
assert.Equal("", v, id)
c.Assert(v, qt.Equals, "")
} else {
assert.Equal("abc", v, id)
c.Assert(v, qt.Equals, "abc")
}
}
+157 -66
View File
@@ -14,17 +14,20 @@
package filecache
import (
"errors"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"regexp"
"strings"
"sync"
"testing"
"time"
"github.com/gohugoio/hugo/langs"
"github.com/gohugoio/hugo/modules"
"github.com/gohugoio/hugo/common/hugio"
"github.com/gohugoio/hugo/config"
"github.com/gohugoio/hugo/helpers"
@@ -32,19 +35,19 @@ import (
"github.com/gohugoio/hugo/hugofs"
"github.com/spf13/afero"
"github.com/stretchr/testify/require"
qt "github.com/frankban/quicktest"
)
func TestFileCache(t *testing.T) {
t.Parallel()
assert := require.New(t)
c := qt.New(t)
tempWorkingDir, err := ioutil.TempDir("", "hugo_filecache_test_work")
assert.NoError(err)
c.Assert(err, qt.IsNil)
defer os.Remove(tempWorkingDir)
tempCacheDir, err := ioutil.TempDir("", "hugo_filecache_test_cache")
assert.NoError(err)
c.Assert(err, qt.IsNil)
defer os.Remove(tempCacheDir)
osfs := afero.NewOsFs()
@@ -83,38 +86,33 @@ dir = ":cacheDir/c"
configStr = replacer.Replace(configStr)
configStr = strings.Replace(configStr, "\\", winPathSep, -1)
cfg, err := config.FromConfigString(configStr, "toml")
assert.NoError(err)
fs := hugofs.NewFrom(osfs, cfg)
p, err := helpers.NewPathSpec(fs, cfg)
assert.NoError(err)
p := newPathsSpec(t, osfs, configStr)
caches, err := NewCaches(p)
assert.NoError(err)
c.Assert(err, qt.IsNil)
cache := caches.Get("GetJSON")
assert.NotNil(cache)
assert.Equal("10h0m0s", cache.maxAge.String())
c.Assert(cache, qt.Not(qt.IsNil))
c.Assert(cache.maxAge.String(), qt.Equals, "10h0m0s")
bfs, ok := cache.Fs.(*afero.BasePathFs)
assert.True(ok)
c.Assert(ok, qt.Equals, true)
filename, err := bfs.RealPath("key")
assert.NoError(err)
c.Assert(err, qt.IsNil)
if test.cacheDir != "" {
assert.Equal(filepath.Join(test.cacheDir, "c/"+filecacheRootDirname+"/getjson/key"), filename)
c.Assert(filename, qt.Equals, filepath.Join(test.cacheDir, "c/"+filecacheRootDirname+"/getjson/key"))
} else {
// Temp dir.
assert.Regexp(regexp.MustCompile(".*hugo_cache.*"+filecacheRootDirname+".*key"), filename)
c.Assert(filename, qt.Matches, ".*hugo_cache.*"+filecacheRootDirname+".*key")
}
cache = caches.Get("Images")
assert.NotNil(cache)
assert.Equal(time.Duration(-1), cache.maxAge)
c.Assert(cache, qt.Not(qt.IsNil))
c.Assert(cache.maxAge, qt.Equals, time.Duration(-1))
bfs, ok = cache.Fs.(*afero.BasePathFs)
assert.True(ok)
c.Assert(ok, qt.Equals, true)
filename, _ = bfs.RealPath("key")
assert.Equal(filepath.FromSlash("_gen/images/key"), filename)
c.Assert(filename, qt.Equals, filepath.FromSlash("_gen/images/key"))
rf := func(s string) func() (io.ReadCloser, error) {
return func() (io.ReadCloser, error) {
@@ -132,55 +130,55 @@ dir = ":cacheDir/c"
return []byte("bcd"), nil
}
for _, c := range []*Cache{caches.ImageCache(), caches.AssetsCache(), caches.GetJSONCache(), caches.GetCSVCache()} {
for _, ca := range []*Cache{caches.ImageCache(), caches.AssetsCache(), caches.GetJSONCache(), caches.GetCSVCache()} {
for i := 0; i < 2; i++ {
info, r, err := c.GetOrCreate("a", rf("abc"))
assert.NoError(err)
assert.NotNil(r)
assert.Equal("a", info.Name)
info, r, err := ca.GetOrCreate("a", rf("abc"))
c.Assert(err, qt.IsNil)
c.Assert(r, qt.Not(qt.IsNil))
c.Assert(info.Name, qt.Equals, "a")
b, _ := ioutil.ReadAll(r)
r.Close()
assert.Equal("abc", string(b))
c.Assert(string(b), qt.Equals, "abc")
info, b, err = c.GetOrCreateBytes("b", bf)
assert.NoError(err)
assert.NotNil(r)
assert.Equal("b", info.Name)
assert.Equal("bcd", string(b))
info, b, err = ca.GetOrCreateBytes("b", bf)
c.Assert(err, qt.IsNil)
c.Assert(r, qt.Not(qt.IsNil))
c.Assert(info.Name, qt.Equals, "b")
c.Assert(string(b), qt.Equals, "bcd")
_, b, err = c.GetOrCreateBytes("a", bf)
assert.NoError(err)
assert.Equal("abc", string(b))
_, b, err = ca.GetOrCreateBytes("a", bf)
c.Assert(err, qt.IsNil)
c.Assert(string(b), qt.Equals, "abc")
_, r, err = c.GetOrCreate("a", rf("bcd"))
assert.NoError(err)
_, r, err = ca.GetOrCreate("a", rf("bcd"))
c.Assert(err, qt.IsNil)
b, _ = ioutil.ReadAll(r)
r.Close()
assert.Equal("abc", string(b))
c.Assert(string(b), qt.Equals, "abc")
}
}
assert.NotNil(caches.Get("getJSON"))
c.Assert(caches.Get("getJSON"), qt.Not(qt.IsNil))
info, w, err := caches.ImageCache().WriteCloser("mykey")
assert.NoError(err)
assert.Equal("mykey", info.Name)
c.Assert(err, qt.IsNil)
c.Assert(info.Name, qt.Equals, "mykey")
io.WriteString(w, "Hugo is great!")
w.Close()
assert.Equal("Hugo is great!", caches.ImageCache().getString("mykey"))
c.Assert(caches.ImageCache().getString("mykey"), qt.Equals, "Hugo is great!")
info, r, err := caches.ImageCache().Get("mykey")
assert.NoError(err)
assert.NotNil(r)
assert.Equal("mykey", info.Name)
c.Assert(err, qt.IsNil)
c.Assert(r, qt.Not(qt.IsNil))
c.Assert(info.Name, qt.Equals, "mykey")
b, _ := ioutil.ReadAll(r)
r.Close()
assert.Equal("Hugo is great!", string(b))
c.Assert(string(b), qt.Equals, "Hugo is great!")
info, b, err = caches.ImageCache().GetBytes("mykey")
assert.NoError(err)
assert.Equal("mykey", info.Name)
assert.Equal("Hugo is great!", string(b))
c.Assert(err, qt.IsNil)
c.Assert(info.Name, qt.Equals, "mykey")
c.Assert(string(b), qt.Equals, "Hugo is great!")
}
@@ -189,7 +187,7 @@ dir = ":cacheDir/c"
func TestFileCacheConcurrent(t *testing.T) {
t.Parallel()
assert := require.New(t)
c := qt.New(t)
configStr := `
resourceDir = "myresources"
@@ -207,14 +205,10 @@ dir = "/cache/c"
`
cfg, err := config.FromConfigString(configStr, "toml")
assert.NoError(err)
fs := hugofs.NewMem(cfg)
p, err := helpers.NewPathSpec(fs, cfg)
assert.NoError(err)
p := newPathsSpec(t, afero.NewMemMapFs(), configStr)
caches, err := NewCaches(p)
assert.NoError(err)
c.Assert(err, qt.IsNil)
const cacheName = "getjson"
@@ -231,16 +225,16 @@ dir = "/cache/c"
go func(i int) {
defer wg.Done()
for j := 0; j < 20; j++ {
c := caches.Get(cacheName)
assert.NotNil(c)
ca := caches.Get(cacheName)
c.Assert(ca, qt.Not(qt.IsNil))
filename, data := filenameData(i)
_, r, err := c.GetOrCreate(filename, func() (io.ReadCloser, error) {
_, r, err := ca.GetOrCreate(filename, func() (io.ReadCloser, error) {
return hugio.ToReadCloser(strings.NewReader(data)), nil
})
assert.NoError(err)
c.Assert(err, qt.IsNil)
b, _ := ioutil.ReadAll(r)
r.Close()
assert.Equal(data, string(b))
c.Assert(string(b), qt.Equals, data)
// Trigger some expiration.
time.Sleep(50 * time.Millisecond)
}
@@ -250,8 +244,105 @@ dir = "/cache/c"
wg.Wait()
}
func TestCleanID(t *testing.T) {
assert := require.New(t)
assert.Equal(filepath.FromSlash("a/b/c.txt"), cleanID(filepath.FromSlash("/a/b//c.txt")))
assert.Equal(filepath.FromSlash("a/b/c.txt"), cleanID(filepath.FromSlash("a/b//c.txt")))
func TestFileCacheReadOrCreateErrorInRead(t *testing.T) {
t.Parallel()
c := qt.New(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 {
return ErrFatal
}
return errors.New("fail")
}
b, _ := ioutil.ReadAll(r)
result = string(b)
return nil
}
}
bf := func(s string) func(info ItemInfo, w io.WriteCloser) error {
return func(info ItemInfo, w io.WriteCloser) error {
defer w.Close()
result = s
_, err := w.Write([]byte(s))
return err
}
}
cache := NewCache(afero.NewMemMapFs(), 100*time.Hour, "")
const id = "a32"
_, err := cache.ReadOrCreate(id, rf(0), bf("v1"))
c.Assert(err, qt.IsNil)
c.Assert(result, qt.Equals, "v1")
_, err = cache.ReadOrCreate(id, rf(0), bf("v2"))
c.Assert(err, qt.IsNil)
c.Assert(result, qt.Equals, "v1")
_, err = cache.ReadOrCreate(id, rf(1), bf("v3"))
c.Assert(err, qt.IsNil)
c.Assert(result, qt.Equals, "v3")
_, err = cache.ReadOrCreate(id, rf(2), bf("v3"))
c.Assert(err, qt.Equals, ErrFatal)
}
func TestCleanID(t *testing.T) {
c := qt.New(t)
c.Assert(cleanID(filepath.FromSlash("/a/b//c.txt")), qt.Equals, filepath.FromSlash("a/b/c.txt"))
c.Assert(cleanID(filepath.FromSlash("a/b//c.txt")), qt.Equals, filepath.FromSlash("a/b/c.txt"))
}
func initConfig(fs afero.Fs, cfg config.Provider) error {
if _, err := langs.LoadLanguageSettings(cfg, nil); err != nil {
return err
}
modConfig, err := modules.DecodeConfig(cfg)
if err != nil {
return err
}
workingDir := cfg.GetString("workingDir")
themesDir := cfg.GetString("themesDir")
if !filepath.IsAbs(themesDir) {
themesDir = filepath.Join(workingDir, themesDir)
}
modulesClient := modules.NewClient(modules.ClientConfig{
Fs: fs,
WorkingDir: workingDir,
ThemesDir: themesDir,
ModuleConfig: modConfig,
IgnoreVendor: true,
})
moduleConfig, err := modulesClient.Collect()
if err != nil {
return err
}
if err := modules.ApplyProjectConfigDefaults(cfg, moduleConfig.ActiveModules[len(moduleConfig.ActiveModules)-1]); err != nil {
return err
}
cfg.Set("allModules", moduleConfig.ActiveModules)
return nil
}
func newPathsSpec(t *testing.T, fs afero.Fs, configStr string) *helpers.PathSpec {
c := qt.New(t)
cfg, err := config.FromConfigString(configStr, "toml")
c.Assert(err, qt.IsNil)
initConfig(fs, cfg)
p, err := helpers.NewPathSpec(hugofs.NewFrom(fs, cfg), cfg, nil)
c.Assert(err, qt.IsNil)
return p
}
+11 -11
View File
@@ -18,12 +18,12 @@ import (
"sync"
"testing"
"github.com/stretchr/testify/require"
qt "github.com/frankban/quicktest"
)
func TestNamedCache(t *testing.T) {
t.Parallel()
assert := require.New(t)
c := qt.New(t)
cache := New()
@@ -35,24 +35,24 @@ func TestNamedCache(t *testing.T) {
for i := 0; i < 5; i++ {
v1, err := cache.GetOrCreate("a1", create)
assert.NoError(err)
assert.Equal(1, v1)
c.Assert(err, qt.IsNil)
c.Assert(v1, qt.Equals, 1)
v2, err := cache.GetOrCreate("a2", create)
assert.NoError(err)
assert.Equal(2, v2)
c.Assert(err, qt.IsNil)
c.Assert(v2, qt.Equals, 2)
}
cache.Clear()
v3, err := cache.GetOrCreate("a2", create)
assert.NoError(err)
assert.Equal(3, v3)
c.Assert(err, qt.IsNil)
c.Assert(v3, qt.Equals, 3)
}
func TestNamedCacheConcurrent(t *testing.T) {
t.Parallel()
assert := require.New(t)
c := qt.New(t)
var wg sync.WaitGroup
@@ -71,8 +71,8 @@ func TestNamedCacheConcurrent(t *testing.T) {
for j := 0; j < 100; j++ {
id := fmt.Sprintf("id%d", j)
v, err := cache.GetOrCreate(id, create(j))
assert.NoError(err)
assert.Equal(j, v)
c.Assert(err, qt.IsNil)
c.Assert(v, qt.Equals, j)
}
}()
}
+20 -20
View File
@@ -18,13 +18,13 @@ import (
"sync"
"testing"
"github.com/stretchr/testify/require"
qt "github.com/frankban/quicktest"
)
func TestNewPartitionedLazyCache(t *testing.T) {
t.Parallel()
assert := require.New(t)
c := qt.New(t)
p1 := Partition{
Key: "p1",
@@ -51,28 +51,28 @@ func TestNewPartitionedLazyCache(t *testing.T) {
cache := NewPartitionedLazyCache(p1, p2)
v, err := cache.Get("p1", "p1_1")
assert.NoError(err)
assert.Equal("p1v1", v)
c.Assert(err, qt.IsNil)
c.Assert(v, qt.Equals, "p1v1")
v, err = cache.Get("p1", "p2_1")
assert.NoError(err)
assert.Nil(v)
c.Assert(err, qt.IsNil)
c.Assert(v, qt.IsNil)
v, err = cache.Get("p1", "p1_nil")
assert.NoError(err)
assert.Nil(v)
c.Assert(err, qt.IsNil)
c.Assert(v, qt.IsNil)
v, err = cache.Get("p2", "p2_3")
assert.NoError(err)
assert.Equal("p2v3", v)
c.Assert(err, qt.IsNil)
c.Assert(v, qt.Equals, "p2v3")
v, err = cache.Get("doesnotexist", "p1_1")
assert.NoError(err)
assert.Nil(v)
c.Assert(err, qt.IsNil)
c.Assert(v, qt.IsNil)
v, err = cache.Get("p1", "doesnotexist")
assert.NoError(err)
assert.Nil(v)
c.Assert(err, qt.IsNil)
c.Assert(v, qt.IsNil)
errorP := Partition{
Key: "p3",
@@ -84,18 +84,18 @@ func TestNewPartitionedLazyCache(t *testing.T) {
cache = NewPartitionedLazyCache(errorP)
v, err = cache.Get("p1", "doesnotexist")
assert.NoError(err)
assert.Nil(v)
c.Assert(err, qt.IsNil)
c.Assert(v, qt.IsNil)
_, err = cache.Get("p3", "doesnotexist")
assert.Error(err)
c.Assert(err, qt.Not(qt.IsNil))
}
func TestConcurrentPartitionedLazyCache(t *testing.T) {
t.Parallel()
assert := require.New(t)
c := qt.New(t)
var wg sync.WaitGroup
@@ -129,8 +129,8 @@ func TestConcurrentPartitionedLazyCache(t *testing.T) {
defer wg.Done()
for j := 0; j < 10; j++ {
v, err := cache.Get("p1", "p1_1")
assert.NoError(err)
assert.Equal("p1v1", v)
c.Assert(err, qt.IsNil)
c.Assert(v, qt.Equals, "p1v1")
}
}()
}
+19 -19
View File
@@ -20,8 +20,8 @@ import (
"reflect"
"testing"
qt "github.com/frankban/quicktest"
"github.com/gohugoio/hugo/common/herrors"
"github.com/stretchr/testify/require"
)
func TestMethods(t *testing.T) {
@@ -33,47 +33,47 @@ func TestMethods(t *testing.T) {
)
dir, _ := os.Getwd()
c := NewInspector(dir)
insp := NewInspector(dir)
t.Run("MethodsFromTypes", func(t *testing.T) {
assert := require.New(t)
c := qt.New(t)
methods := c.MethodsFromTypes([]reflect.Type{zeroI}, nil)
methods := insp.MethodsFromTypes([]reflect.Type{zeroI}, nil)
methodsStr := fmt.Sprint(methods)
assert.Contains(methodsStr, "Method1(arg0 herrors.ErrorContext)")
assert.Contains(methodsStr, "Method7() interface {}")
assert.Contains(methodsStr, "Method0() string\n Method4() string")
assert.Contains(methodsStr, "MethodEmbed3(arg0 string) string\n MethodEmbed1() string")
c.Assert(methodsStr, qt.Contains, "Method1(arg0 herrors.ErrorContext)")
c.Assert(methodsStr, qt.Contains, "Method7() interface {}")
c.Assert(methodsStr, qt.Contains, "Method0() string\n Method4() string")
c.Assert(methodsStr, qt.Contains, "MethodEmbed3(arg0 string) string\n MethodEmbed1() string")
assert.Contains(methods.Imports(), "github.com/gohugoio/hugo/common/herrors")
c.Assert(methods.Imports(), qt.Contains, "github.com/gohugoio/hugo/common/herrors")
})
t.Run("EmbedOnly", func(t *testing.T) {
assert := require.New(t)
c := qt.New(t)
methods := c.MethodsFromTypes([]reflect.Type{zeroIEOnly}, nil)
methods := insp.MethodsFromTypes([]reflect.Type{zeroIEOnly}, nil)
methodsStr := fmt.Sprint(methods)
assert.Contains(methodsStr, "MethodEmbed3(arg0 string) string")
c.Assert(methodsStr, qt.Contains, "MethodEmbed3(arg0 string) string")
})
t.Run("ToMarshalJSON", func(t *testing.T) {
assert := require.New(t)
c := qt.New(t)
m, pkg := c.MethodsFromTypes(
m, pkg := insp.MethodsFromTypes(
[]reflect.Type{zeroI},
[]reflect.Type{zeroIE}).ToMarshalJSON("*page", "page")
assert.Contains(m, "method6 := p.Method6()")
assert.Contains(m, "Method0: method0,")
assert.Contains(m, "return json.Marshal(&s)")
c.Assert(m, qt.Contains, "method6 := p.Method6()")
c.Assert(m, qt.Contains, "Method0: method0,")
c.Assert(m, qt.Contains, "return json.Marshal(&s)")
assert.Contains(pkg, "github.com/gohugoio/hugo/common/herrors")
assert.Contains(pkg, "encoding/json")
c.Assert(pkg, qt.Contains, "github.com/gohugoio/hugo/common/herrors")
c.Assert(pkg, qt.Contains, "encoding/json")
fmt.Println(pkg)
+52 -41
View File
@@ -16,6 +16,11 @@ package commands
import (
"bytes"
"errors"
"sync"
hconfig "github.com/gohugoio/hugo/config"
"golang.org/x/sync/semaphore"
"io/ioutil"
@@ -27,8 +32,6 @@ import (
"os"
"path/filepath"
"regexp"
"strings"
"sync"
"time"
"github.com/gohugoio/hugo/common/loggers"
@@ -49,14 +52,16 @@ import (
type commandeerHugoState struct {
*deps.DepsCfg
hugo *hugolib.HugoSites
fsCreate sync.Once
hugoSites *hugolib.HugoSites
fsCreate sync.Once
created chan struct{}
}
type commandeer struct {
*commandeerHugoState
logger *loggers.Logger
logger *loggers.Logger
serverConfig *config.Server
// Currently only set when in "fast render mode". But it seems to
// be fast enough that we could maybe just add it for all server modes.
@@ -70,7 +75,7 @@ type commandeer struct {
visitedURLs *types.EvictingStringQueue
doWithCommandeer func(c *commandeer) error
cfgInit func(c *commandeer) error
// We watch these for changes.
configFiles []string
@@ -84,14 +89,28 @@ type commandeer struct {
doLiveReload bool
fastRenderMode bool
showErrorInBrowser bool
wasError bool
configured bool
paused bool
fullRebuildSem *semaphore.Weighted
// Any error from the last build.
buildErr error
}
func newCommandeerHugoState() *commandeerHugoState {
return &commandeerHugoState{
created: make(chan struct{}),
}
}
func (c *commandeerHugoState) hugo() *hugolib.HugoSites {
<-c.created
return c.hugoSites
}
func (c *commandeer) errCount() int {
return int(c.logger.ErrorCounter.Count())
}
@@ -115,7 +134,7 @@ func (c *commandeer) getErrorWithContext() interface{} {
if c.h.verbose {
var b bytes.Buffer
herrors.FprintStackTrace(&b, c.buildErr)
herrors.FprintStackTraceFromErr(&b, c.buildErr)
m["StackTrace"] = b.String()
}
@@ -136,7 +155,7 @@ func (c *commandeer) initFs(fs *hugofs.Fs) error {
return nil
}
func newCommandeer(mustHaveConfigFile, running bool, h *hugoBuilderCommon, f flagsToConfigHandler, doWithCommandeer func(c *commandeer) error, subCmdVs ...*cobra.Command) (*commandeer, error) {
func newCommandeer(mustHaveConfigFile, running bool, h *hugoBuilderCommon, f flagsToConfigHandler, cfgInit func(c *commandeer) error, subCmdVs ...*cobra.Command) (*commandeer, error) {
var rebuildDebouncer func(f func())
if running {
@@ -146,15 +165,21 @@ func newCommandeer(mustHaveConfigFile, running bool, h *hugoBuilderCommon, f fla
rebuildDebouncer = debounce.New(4 * time.Second)
}
out := ioutil.Discard
if !h.quiet {
out = os.Stdout
}
c := &commandeer{
h: h,
ftch: f,
commandeerHugoState: &commandeerHugoState{},
doWithCommandeer: doWithCommandeer,
commandeerHugoState: newCommandeerHugoState(),
cfgInit: cfgInit,
visitedURLs: types.NewEvictingStringQueue(10),
debounce: rebuildDebouncer,
fullRebuildSem: semaphore.NewWeighted(1),
// This will be replaced later, but we need something to log to before the configuration is read.
logger: loggers.NewLogger(jww.LevelError, jww.LevelError, os.Stdout, ioutil.Discard, running),
logger: loggers.NewLogger(jww.LevelWarn, jww.LevelError, out, ioutil.Discard, running),
}
return c, c.loadConfig(mustHaveConfigFile, running)
@@ -262,12 +287,12 @@ func (c *commandeer) loadConfig(mustHaveConfigFile, running bool) error {
return nil
}
doWithCommandeer := func(cfg config.Provider) error {
cfgSetAndInit := func(cfg config.Provider) error {
c.Cfg = cfg
if c.doWithCommandeer == nil {
if c.cfgInit == nil {
return nil
}
err := c.doWithCommandeer(c)
err := c.cfgInit(c)
return err
}
@@ -278,22 +303,20 @@ func (c *commandeer) loadConfig(mustHaveConfigFile, running bool) error {
config, configFiles, err := hugolib.LoadConfig(
hugolib.ConfigSourceDescriptor{
Fs: sourceFs,
Logger: c.logger,
Path: configPath,
WorkingDir: dir,
Filename: c.h.cfgFile,
AbsConfigDir: c.h.getConfigDir(dir),
Environ: os.Environ(),
Environment: environment},
doWithCommandeer,
cfgSetAndInit,
doWithConfig)
if err != nil {
if mustHaveConfigFile {
return err
}
if err != hugolib.ErrNoConfigFile {
return err
}
if err != nil && mustHaveConfigFile {
return err
} else if mustHaveConfigFile && len(configFiles) == 0 {
return hugolib.ErrNoConfigFile
}
c.configFiles = configFiles
@@ -310,8 +333,8 @@ func (c *commandeer) loadConfig(mustHaveConfigFile, running bool) error {
// This is potentially double work, but we need to do this one more time now
// that all the languages have been configured.
if c.doWithCommandeer != nil {
if err := c.doWithCommandeer(c); err != nil {
if c.cfgInit != nil {
if err := c.cfgInit(c); err != nil {
return err
}
}
@@ -323,6 +346,7 @@ func (c *commandeer) loadConfig(mustHaveConfigFile, running bool) error {
cfg.Logger = logger
c.logger = logger
c.serverConfig = hconfig.DecodeServer(cfg.Cfg)
createMemFs := config.GetBool("renderToMemory")
@@ -366,13 +390,15 @@ func (c *commandeer) loadConfig(mustHaveConfigFile, running bool) error {
err = c.initFs(fs)
if err != nil {
close(c.created)
return
}
var h *hugolib.HugoSites
h, err = hugolib.NewHugoSites(*c.DepsCfg)
c.hugo = h
c.hugoSites = h
close(c.created)
})
@@ -388,21 +414,6 @@ func (c *commandeer) loadConfig(mustHaveConfigFile, running bool) error {
cfg.Logger.INFO.Println("Using config file:", config.ConfigFileUsed())
themeDir := c.hugo.PathSpec.GetFirstThemeDir()
if themeDir != "" {
if _, err := sourceFs.Stat(themeDir); os.IsNotExist(err) {
return newSystemError("Unable to find theme Directory:", themeDir)
}
}
dir, themeVersionMismatch, minVersion := c.isThemeVsHugoVersionMismatch(sourceFs)
if themeVersionMismatch {
name := filepath.Base(dir)
cfg.Logger.ERROR.Printf("%s theme does not support Hugo version %s. Minimum version required is %s\n",
strings.ToUpper(name), hugo.CurrentVersion.ReleaseVersion(), minVersion)
}
return nil
}
+36 -6
View File
@@ -14,7 +14,9 @@
package commands
import (
"fmt"
"os"
"time"
"github.com/gohugoio/hugo/hugolib/paths"
@@ -45,14 +47,16 @@ func (b *commandsBuilder) addAll() *commandsBuilder {
b.newServerCmd(),
newVersionCmd(),
newEnvCmd(),
newConfigCmd(),
b.newConfigCmd(),
newCheckCmd(),
newConvertCmd(),
b.newDeployCmd(),
b.newConvertCmd(),
b.newNewCmd(),
newListCmd(),
b.newListCmd(),
newImportCmd(),
newGenCmd(),
createReleaser(),
b.newModCmd(),
)
return b
@@ -107,6 +111,12 @@ func (b *commandsBuilder) newBuilderCmd(cmd *cobra.Command) *baseBuilderCmd {
return bcmd
}
func (b *commandsBuilder) newBuilderBasicCmd(cmd *cobra.Command) *baseBuilderCmd {
bcmd := &baseBuilderCmd{commandsBuilder: b, baseCmd: &baseCmd{cmd: cmd}}
bcmd.hugoBuilderCommon.handleCommonBuilderFlags(cmd)
return bcmd
}
func (c *baseCmd) flagsToConfig(cfg config.Provider) {
initializeFlags(c.cmd, cfg)
}
@@ -144,6 +154,7 @@ built with love by spf13 and friends in Go.
Complete documentation is available at http://gohugo.io/.`,
RunE: func(cmd *cobra.Command, args []string) error {
defer cc.timeTrack(time.Now(), "Total")
cfgInit := func(c *commandeer) error {
if cc.buildWatch {
c.Set("disableLiveReload", true)
@@ -214,6 +225,14 @@ type hugoBuilderCommon struct {
logFile string
}
func (cc *hugoBuilderCommon) timeTrack(start time.Time, name string) {
if cc.quiet {
return
}
elapsed := time.Since(start)
fmt.Printf("%s in %v ms\n", name, int(1000*elapsed.Seconds()))
}
func (cc *hugoBuilderCommon) getConfigDir(baseDir string) string {
if cc.cfgDir != "" {
return paths.AbsPathify(baseDir, cc.cfgDir)
@@ -235,6 +254,11 @@ func (cc *hugoBuilderCommon) getEnvironment(isServer bool) string {
return v
}
// Used by Netlify and Forestry
if v, found := os.LookupEnv("HUGO_ENV"); found {
return v
}
if isServer {
return hugo.EnvironmentDevelopment
}
@@ -242,20 +266,26 @@ func (cc *hugoBuilderCommon) getEnvironment(isServer bool) string {
return hugo.EnvironmentProduction
}
func (cc *hugoBuilderCommon) handleCommonBuilderFlags(cmd *cobra.Command) {
cmd.PersistentFlags().StringVarP(&cc.source, "source", "s", "", "filesystem path to read files relative from")
cmd.PersistentFlags().SetAnnotation("source", cobra.BashCompSubdirsInDir, []string{})
cmd.PersistentFlags().StringVarP(&cc.environment, "environment", "e", "", "build environment")
cmd.PersistentFlags().StringP("themesDir", "", "", "filesystem path to themes directory")
cmd.PersistentFlags().BoolP("ignoreVendor", "", false, "ignores any _vendor directory")
}
func (cc *hugoBuilderCommon) handleFlags(cmd *cobra.Command) {
cc.handleCommonBuilderFlags(cmd)
cmd.Flags().Bool("cleanDestinationDir", false, "remove files from destination not found in static directories")
cmd.Flags().BoolP("buildDrafts", "D", false, "include content marked as draft")
cmd.Flags().BoolP("buildFuture", "F", false, "include content with publishdate in the future")
cmd.Flags().BoolP("buildExpired", "E", false, "include expired content")
cmd.Flags().StringVarP(&cc.source, "source", "s", "", "filesystem path to read files relative from")
cmd.Flags().StringVarP(&cc.environment, "environment", "e", "", "build environment")
cmd.Flags().StringP("contentDir", "c", "", "filesystem path to content directory")
cmd.Flags().StringP("layoutDir", "l", "", "filesystem path to layout directory")
cmd.Flags().StringP("cacheDir", "", "", "filesystem path to cache directory. Defaults: $TMPDIR/hugo_cache/")
cmd.Flags().BoolP("ignoreCache", "", false, "ignores the cache directory")
cmd.Flags().StringP("destination", "d", "", "filesystem path to write files to")
cmd.Flags().StringSliceP("theme", "t", []string{}, "themes to use (located in /themes/THEMENAME/)")
cmd.Flags().StringP("themesDir", "", "", "filesystem path to themes directory")
cmd.Flags().StringVarP(&cc.baseURL, "baseURL", "b", "", "hostname (and path) to the root, e.g. http://spf13.com/")
cmd.Flags().Bool("enableGitInfo", false, "add Git revision, date and author info to the pages")
cmd.Flags().BoolVar(&cc.gc, "gc", false, "enable to run some cleanup tasks (remove unused cache files) after the build")
+167 -52
View File
@@ -20,34 +20,139 @@ import (
"path/filepath"
"testing"
"github.com/gohugoio/hugo/htesting"
"github.com/spf13/afero"
"github.com/gohugoio/hugo/hugofs"
"github.com/gohugoio/hugo/common/types"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/stretchr/testify/require"
qt "github.com/frankban/quicktest"
)
func TestExecute(t *testing.T) {
assert := require.New(t)
c := qt.New(t)
dir, err := createSimpleTestSite(t, testSiteConfig{})
assert.NoError(err)
createSite := func(c *qt.C) (string, func()) {
dir, clean, err := createSimpleTestSite(t, testSiteConfig{})
c.Assert(err, qt.IsNil)
return dir, clean
}
defer func() {
os.RemoveAll(dir)
}()
c.Run("hugo", func(c *qt.C) {
dir, clean := createSite(c)
defer clean()
resp := Execute([]string{"-s=" + dir})
c.Assert(resp.Err, qt.IsNil)
result := resp.Result
c.Assert(len(result.Sites) == 1, qt.Equals, true)
c.Assert(len(result.Sites[0].RegularPages()) == 1, qt.Equals, true)
c.Assert(result.Sites[0].Info.Params()["myparam"], qt.Equals, "paramproduction")
})
resp := Execute([]string{"-s=" + dir})
assert.NoError(resp.Err)
result := resp.Result
assert.True(len(result.Sites) == 1)
assert.True(len(result.Sites[0].RegularPages()) == 1)
c.Run("hugo, set environment", func(c *qt.C) {
dir, clean := createSite(c)
defer clean()
resp := Execute([]string{"-s=" + dir, "-e=staging"})
c.Assert(resp.Err, qt.IsNil)
result := resp.Result
c.Assert(result.Sites[0].Info.Params()["myparam"], qt.Equals, "paramstaging")
})
c.Run("convert toJSON", func(c *qt.C) {
dir, clean := createSite(c)
output := filepath.Join(dir, "myjson")
defer clean()
resp := Execute([]string{"convert", "toJSON", "-s=" + dir, "-e=staging", "-o=" + output})
c.Assert(resp.Err, qt.IsNil)
converted := readFileFrom(c, filepath.Join(output, "content", "p1.md"))
c.Assert(converted, qt.Equals, "{\n \"title\": \"P1\",\n \"weight\": 1\n}\n\nContent\n\n", qt.Commentf(converted))
})
c.Run("config, set environment", func(c *qt.C) {
dir, clean := createSite(c)
defer clean()
out, err := captureStdout(func() error {
resp := Execute([]string{"config", "-s=" + dir, "-e=staging"})
return resp.Err
})
c.Assert(err, qt.IsNil)
c.Assert(out, qt.Contains, "params = map[myparam:paramstaging]", qt.Commentf(out))
})
c.Run("deploy, environment set", func(c *qt.C) {
dir, clean := createSite(c)
defer clean()
resp := Execute([]string{"deploy", "-s=" + dir, "-e=staging", "--target=mydeployment", "--dryRun"})
c.Assert(resp.Err, qt.Not(qt.IsNil))
c.Assert(resp.Err.Error(), qt.Contains, `no provider registered for "hugocloud"`)
})
c.Run("list", func(c *qt.C) {
dir, clean := createSite(c)
defer clean()
out, err := captureStdout(func() error {
resp := Execute([]string{"list", "all", "-s=" + dir, "-e=staging"})
return resp.Err
})
c.Assert(err, qt.IsNil)
c.Assert(out, qt.Contains, "p1.md")
})
c.Run("new theme", func(c *qt.C) {
dir, clean := createSite(c)
defer clean()
themesDir := filepath.Join(dir, "mythemes")
resp := Execute([]string{"new", "theme", "mytheme", "-s=" + dir, "-e=staging", "--themesDir=" + themesDir})
c.Assert(resp.Err, qt.IsNil)
themeTOML := readFileFrom(c, filepath.Join(themesDir, "mytheme", "theme.toml"))
c.Assert(themeTOML, qt.Contains, "name = \"Mytheme\"")
})
c.Run("new site", func(c *qt.C) {
dir, clean := createSite(c)
defer clean()
siteDir := filepath.Join(dir, "mysite")
resp := Execute([]string{"new", "site", siteDir, "-e=staging"})
c.Assert(resp.Err, qt.IsNil)
config := readFileFrom(c, filepath.Join(siteDir, "config.toml"))
c.Assert(config, qt.Contains, "baseURL = \"http://example.org/\"")
checkNewSiteInited(c, siteDir)
})
}
func checkNewSiteInited(c *qt.C, basepath string) {
paths := []string{
filepath.Join(basepath, "layouts"),
filepath.Join(basepath, "content"),
filepath.Join(basepath, "archetypes"),
filepath.Join(basepath, "static"),
filepath.Join(basepath, "data"),
filepath.Join(basepath, "config.toml"),
}
for _, path := range paths {
_, err := os.Stat(path)
c.Assert(err, qt.IsNil)
}
}
func readFileFrom(c *qt.C, filename string) string {
c.Helper()
filename = filepath.Clean(filename)
b, err := afero.ReadFile(hugofs.Os, filename)
c.Assert(err, qt.IsNil)
return string(b)
}
func TestCommandsPersistentFlags(t *testing.T) {
assert := require.New(t)
c := qt.New(t)
noOpRunE := func(cmd *cobra.Command, args []string) error {
return nil
@@ -83,10 +188,10 @@ func TestCommandsPersistentFlags(t *testing.T) {
for _, command := range commands {
if b, ok := command.(commandsBuilderGetter); ok {
v := b.getCommandsBuilder().hugoBuilderCommon
assert.Equal("myconfig.toml", v.cfgFile)
assert.Equal("myconfigdir", v.cfgDir)
assert.Equal("mysource", v.source)
assert.Equal("https://example.com/b/", v.baseURL)
c.Assert(v.cfgFile, qt.Equals, "myconfig.toml")
c.Assert(v.cfgDir, qt.Equals, "myconfigdir")
c.Assert(v.source, qt.Equals, "mysource")
c.Assert(v.baseURL, qt.Equals, "https://example.com/b/")
}
if srvCmd, ok := command.(*serverCmd); ok {
@@ -94,32 +199,32 @@ func TestCommandsPersistentFlags(t *testing.T) {
}
}
assert.NotNil(sc)
assert.True(sc.navigateToChanged)
assert.True(sc.disableLiveReload)
assert.True(sc.noHTTPCache)
assert.True(sc.renderToDisk)
assert.Equal(1366, sc.serverPort)
assert.Equal("testing", sc.environment)
c.Assert(sc, qt.Not(qt.IsNil))
c.Assert(sc.navigateToChanged, qt.Equals, true)
c.Assert(sc.disableLiveReload, qt.Equals, true)
c.Assert(sc.noHTTPCache, qt.Equals, true)
c.Assert(sc.renderToDisk, qt.Equals, true)
c.Assert(sc.serverPort, qt.Equals, 1366)
c.Assert(sc.environment, qt.Equals, "testing")
cfg := viper.New()
sc.flagsToConfig(cfg)
assert.Equal("/tmp/mydestination", cfg.GetString("publishDir"))
assert.Equal("mycontent", cfg.GetString("contentDir"))
assert.Equal("mylayouts", cfg.GetString("layoutDir"))
assert.Equal([]string{"mytheme"}, cfg.GetStringSlice("theme"))
assert.Equal("mythemes", cfg.GetString("themesDir"))
assert.Equal("https://example.com/b/", cfg.GetString("baseURL"))
c.Assert(cfg.GetString("publishDir"), qt.Equals, "/tmp/mydestination")
c.Assert(cfg.GetString("contentDir"), qt.Equals, "mycontent")
c.Assert(cfg.GetString("layoutDir"), qt.Equals, "mylayouts")
c.Assert(cfg.GetStringSlice("theme"), qt.DeepEquals, []string{"mytheme"})
c.Assert(cfg.GetString("themesDir"), qt.Equals, "mythemes")
c.Assert(cfg.GetString("baseURL"), qt.Equals, "https://example.com/b/")
assert.Equal([]string{"page", "home"}, cfg.Get("disableKinds"))
c.Assert(cfg.Get("disableKinds"), qt.DeepEquals, []string{"page", "home"})
assert.True(cfg.GetBool("gc"))
c.Assert(cfg.GetBool("gc"), qt.Equals, true)
// The flag is named path-warnings
assert.True(cfg.GetBool("logPathWarnings"))
c.Assert(cfg.GetBool("logPathWarnings"), qt.Equals, true)
// The flag is named i18n-warnings
assert.True(cfg.GetBool("logI18nWarnings"))
c.Assert(cfg.GetBool("logI18nWarnings"), qt.Equals, true)
}}}
@@ -136,7 +241,7 @@ func TestCommandsPersistentFlags(t *testing.T) {
}
rootCmd := root.getCommand()
rootCmd.SetArgs(test.args)
assert.NoError(rootCmd.Execute())
c.Assert(rootCmd.Execute(), qt.IsNil)
test.check(b.commands)
}
@@ -144,18 +249,16 @@ func TestCommandsPersistentFlags(t *testing.T) {
func TestCommandsExecute(t *testing.T) {
assert := require.New(t)
c := qt.New(t)
dir, err := createSimpleTestSite(t, testSiteConfig{})
assert.NoError(err)
dir, clean, err := createSimpleTestSite(t, testSiteConfig{})
c.Assert(err, qt.IsNil)
dirOut, err := ioutil.TempDir("", "hugo-cli-out")
assert.NoError(err)
dirOut, clean2, err := htesting.CreateTempDir(hugofs.Os, "hugo-cli-out")
c.Assert(err, qt.IsNil)
defer func() {
os.RemoveAll(dir)
os.RemoveAll(dirOut)
}()
defer clean()
defer clean2()
sourceFlag := fmt.Sprintf("-s=%s", dir)
@@ -200,17 +303,17 @@ func TestCommandsExecute(t *testing.T) {
_, err := hugoCmd.ExecuteC()
if test.expectErrToContain != "" {
assert.Error(err, fmt.Sprintf("%v", test.commands))
assert.Contains(err.Error(), test.expectErrToContain)
c.Assert(err, qt.Not(qt.IsNil))
c.Assert(err.Error(), qt.Contains, test.expectErrToContain)
} else {
assert.NoError(err, fmt.Sprintf("%v", test.commands))
c.Assert(err, qt.IsNil)
}
// Assert that we have not left any development debug artifacts in
// the code.
if b.c != nil {
_, ok := b.c.destinationFs.(types.DevMarker)
assert.False(ok)
c.Assert(ok, qt.Equals, false)
}
}
@@ -222,10 +325,10 @@ type testSiteConfig struct {
contentDir string
}
func createSimpleTestSite(t *testing.T, cfg testSiteConfig) (string, error) {
d, e := ioutil.TempDir("", "hugo-cli")
func createSimpleTestSite(t *testing.T, cfg testSiteConfig) (string, func(), error) {
d, clean, e := htesting.CreateTempDir(hugofs.Os, "hugo-cli")
if e != nil {
return "", e
return "", nil, e
}
cfgStr := `
@@ -233,6 +336,7 @@ func createSimpleTestSite(t *testing.T, cfg testSiteConfig) (string, error) {
baseURL = "https://example.org"
title = "Hugo Commands"
`
contentDir := "content"
@@ -244,8 +348,19 @@ title = "Hugo Commands"
contentDir = cfg.contentDir
}
os.MkdirAll(filepath.Join(d, "public"), 0777)
// Just the basic. These are for CLI tests, not site testing.
writeFile(t, filepath.Join(d, "config.toml"), cfgStr)
writeFile(t, filepath.Join(d, "config", "staging", "params.toml"), `myparam="paramstaging"`)
writeFile(t, filepath.Join(d, "config", "staging", "deployment.toml"), `
[[targets]]
name = "mydeployment"
URL = "hugocloud://hugotestbucket"
`)
writeFile(t, filepath.Join(d, "config", "testing", "params.toml"), `myparam="paramtesting"`)
writeFile(t, filepath.Join(d, "config", "production", "params.toml"), `myparam="paramproduction"`)
writeFile(t, filepath.Join(d, contentDir, "p1.md"), `
---
@@ -270,7 +385,7 @@ Environment: {{ hugo.Environment }}
`)
return d, nil
return d, clean, nil
}
+83 -14
View File
@@ -14,64 +14,133 @@
package commands
import (
"encoding/json"
"fmt"
"os"
"reflect"
"regexp"
"sort"
"strings"
"github.com/gohugoio/hugo/parser"
"github.com/gohugoio/hugo/parser/metadecoders"
"github.com/gohugoio/hugo/modules"
"github.com/spf13/cobra"
jww "github.com/spf13/jwalterweatherman"
"github.com/spf13/viper"
)
var _ cmder = (*configCmd)(nil)
type configCmd struct {
hugoBuilderCommon
*baseCmd
*baseBuilderCmd
}
func newConfigCmd() *configCmd {
func (b *commandsBuilder) newConfigCmd() *configCmd {
cc := &configCmd{}
cc.baseCmd = newBaseCmd(&cobra.Command{
cmd := &cobra.Command{
Use: "config",
Short: "Print the site configuration",
Long: `Print the site configuration, both default and custom settings.`,
RunE: cc.printConfig,
})
}
cc.cmd.Flags().StringVarP(&cc.source, "source", "s", "", "filesystem path to read files relative from")
printMountsCmd := &cobra.Command{
Use: "mounts",
Short: "Print the configured file mounts",
RunE: cc.printMounts,
}
cmd.AddCommand(printMountsCmd)
cc.baseBuilderCmd = b.newBuilderBasicCmd(cmd)
return cc
}
func (c *configCmd) printMounts(cmd *cobra.Command, args []string) error {
cfg, err := initializeConfig(true, false, &c.hugoBuilderCommon, c, nil)
if err != nil {
return err
}
allModules := cfg.Cfg.Get("allmodules").(modules.Modules)
for _, m := range allModules {
if err := parser.InterfaceToConfig(&modMounts{m: m}, metadecoders.JSON, os.Stdout); err != nil {
return err
}
}
return nil
}
func (c *configCmd) printConfig(cmd *cobra.Command, args []string) error {
cfg, err := initializeConfig(true, false, &c.hugoBuilderCommon, c, nil)
if err != nil {
return err
}
allSettings := cfg.Cfg.(*viper.Viper).AllSettings()
var separator string
if allSettings["metadataformat"] == "toml" {
// 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.
ignoreKeysRe := regexp.MustCompile("client|sorted|filecacheconfigs|allmodules|multilingual")
separator := ": "
if len(cfg.configFiles) > 0 && strings.HasSuffix(cfg.configFiles[0], ".toml") {
separator = " = "
} else {
separator = ": "
}
var keys []string
for k := range allSettings {
if ignoreKeysRe.MatchString(k) {
continue
}
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
kv := reflect.ValueOf(allSettings[k])
if kv.Kind() == reflect.String {
jww.FEEDBACK.Printf("%s%s\"%+v\"\n", k, separator, allSettings[k])
fmt.Printf("%s%s\"%+v\"\n", k, separator, allSettings[k])
} else {
jww.FEEDBACK.Printf("%s%s%+v\n", k, separator, allSettings[k])
fmt.Printf("%s%s%+v\n", k, separator, allSettings[k])
}
}
return nil
}
type modMounts struct {
m modules.Module
}
type modMount struct {
Source string `json:"source"`
Target string `json:"target"`
Lang string `json:"lang,omitempty"`
}
func (m *modMounts) MarshalJSON() ([]byte, error) {
var mounts []modMount
for _, mount := range m.m.Mounts() {
mounts = append(mounts, modMount{
Source: mount.Source,
Target: mount.Target,
Lang: mount.Lang,
})
}
return json.Marshal(&struct {
Path string `json:"path"`
Dir string `json:"dir"`
Mounts []modMount `json:"mounts"`
}{
Path: m.m.Path(),
Dir: m.m.Dir(),
Mounts: mounts,
})
}
+19 -58
View File
@@ -16,10 +16,11 @@ package commands
import (
"bytes"
"fmt"
"io"
"strings"
"time"
"github.com/gohugoio/hugo/parser/pageparser"
"github.com/gohugoio/hugo/resources/page"
"github.com/gohugoio/hugo/hugofs"
@@ -28,9 +29,7 @@ import (
"github.com/gohugoio/hugo/parser"
"github.com/gohugoio/hugo/parser/metadecoders"
"github.com/gohugoio/hugo/parser/pageparser"
src "github.com/gohugoio/hugo/source"
"github.com/pkg/errors"
"github.com/gohugoio/hugo/hugolib"
@@ -45,27 +44,25 @@ var (
)
type convertCmd struct {
hugoBuilderCommon
outputDir string
unsafe bool
*baseCmd
*baseBuilderCmd
}
func newConvertCmd() *convertCmd {
func (b *commandsBuilder) newConvertCmd() *convertCmd {
cc := &convertCmd{}
cc.baseCmd = newBaseCmd(&cobra.Command{
cmd := &cobra.Command{
Use: "convert",
Short: "Convert your content to different formats",
Long: `Convert your content (e.g. front matter) to different formats.
See convert's subcommands toJSON, toTOML and toYAML for more information.`,
RunE: nil,
})
}
cc.cmd.AddCommand(
cmd.AddCommand(
&cobra.Command{
Use: "toJSON",
Short: "Convert front matter to JSON",
@@ -95,10 +92,10 @@ to use YAML for the front matter.`,
},
)
cc.cmd.PersistentFlags().StringVarP(&cc.outputDir, "output", "o", "", "filesystem path to write files to")
cc.cmd.PersistentFlags().StringVarP(&cc.source, "source", "s", "", "filesystem path to read files relative from")
cc.cmd.PersistentFlags().BoolVar(&cc.unsafe, "unsafe", false, "enable less safe operations, please backup first")
cc.cmd.PersistentFlags().SetAnnotation("source", cobra.BashCompSubdirsInDir, []string{})
cmd.PersistentFlags().StringVarP(&cc.outputDir, "output", "o", "", "filesystem path to write files to")
cmd.PersistentFlags().BoolVar(&cc.unsafe, "unsafe", false, "enable less safe operations, please backup first")
cc.baseBuilderCmd = b.newBuilderBasicCmd(cmd)
return cc
}
@@ -152,15 +149,15 @@ func (cc *convertCmd) convertAndSavePage(p page.Page, site *hugolib.Site, target
site.Log.INFO.Println("Attempting to convert", p.File().Filename())
f, _ := p.File().(src.ReadableFile)
file, err := f.Open()
f := p.File()
file, err := f.FileInfo().Meta().Open()
if err != nil {
site.Log.ERROR.Println(errMsg)
file.Close()
return nil
}
pf, err := parseContentFile(file)
pf, err := pageparser.ParseFrontMatterAndContent(file)
if err != nil {
site.Log.ERROR.Println(errMsg)
file.Close()
@@ -170,23 +167,23 @@ func (cc *convertCmd) convertAndSavePage(p page.Page, site *hugolib.Site, target
file.Close()
// better handling of dates in formats that don't have support for them
if pf.frontMatterFormat == metadecoders.JSON || pf.frontMatterFormat == metadecoders.YAML || pf.frontMatterFormat == metadecoders.TOML {
for k, v := range pf.frontMatter {
if pf.FrontMatterFormat == metadecoders.JSON || pf.FrontMatterFormat == metadecoders.YAML || pf.FrontMatterFormat == metadecoders.TOML {
for k, v := range pf.FrontMatter {
switch vv := v.(type) {
case time.Time:
pf.frontMatter[k] = vv.Format(time.RFC3339)
pf.FrontMatter[k] = vv.Format(time.RFC3339)
}
}
}
var newContent bytes.Buffer
err = parser.InterfaceToFrontMatter(pf.frontMatter, targetFormat, &newContent)
err = parser.InterfaceToFrontMatter(pf.FrontMatter, targetFormat, &newContent)
if err != nil {
site.Log.ERROR.Println(errMsg)
return err
}
newContent.Write(pf.content)
newContent.Write(pf.Content)
newFilename := p.File().Filename()
@@ -213,39 +210,3 @@ type parsedFile struct {
// Everything after Front Matter
content []byte
}
func parseContentFile(r io.Reader) (parsedFile, error) {
var pf parsedFile
psr, err := pageparser.Parse(r, pageparser.Config{})
if err != nil {
return pf, err
}
iter := psr.Iterator()
walkFn := func(item pageparser.Item) bool {
if pf.frontMatterSource != nil {
// The rest is content.
pf.content = psr.Input()[item.Pos:]
// Done
return false
} else if item.IsFrontMatter() {
pf.frontMatterFormat = metadecoders.FormatFromFrontMatterType(item.Type)
pf.frontMatterSource = item.Val
}
return true
}
iter.PeekWalk(walkFn)
metadata, err := metadecoders.Default.UnmarshalToMap(pf.frontMatterSource, pf.frontMatterFormat)
if err != nil {
return pf, err
}
pf.frontMatter = metadata
return pf, nil
}
+78
View File
@@ -0,0 +1,78 @@
// Copyright 2019 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package commands
import (
"context"
"github.com/gohugoio/hugo/deploy"
"github.com/spf13/cobra"
)
var _ cmder = (*deployCmd)(nil)
// deployCmd supports deploying sites to Cloud providers.
type deployCmd struct {
*baseBuilderCmd
}
// TODO: In addition to the "deploy" command, consider adding a "--deploy"
// flag for the default command; this would build the site and then deploy it.
// It's not obvious how to do this; would all of the deploy-specific flags
// have to exist at the top level as well?
// TODO: The output files change every time "hugo" is executed, it looks
// like because of map order randomization. This means that you can
// run "hugo && hugo deploy" again and again and upload new stuff every time. Is
// this intended?
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 {
cfgInit := func(c *commandeer) error {
return nil
}
comm, err := initializeConfig(true, false, &cc.hugoBuilderCommon, cc, cfgInit)
if err != nil {
return err
}
deployer, err := deploy.New(comm.Cfg, comm.hugo().PathSpec.PublishFs)
if err != nil {
return err
}
return deployer.Deploy(context.Background())
},
}
cmd.Flags().String("target", "", "target deployment from deployments section in config file; defaults to the first one")
cmd.Flags().Bool("confirm", false, "ask for confirmation before making changes to the target")
cmd.Flags().Bool("dryRun", false, "dry run")
cmd.Flags().Bool("force", false, "force upload of all files")
cmd.Flags().Bool("invalidateCDN", true, "invalidate the CDN cache listed in the deployment target")
cmd.Flags().Int("maxDeletes", 256, "maximum # of files to delete, or -1 to disable")
cc.baseBuilderCmd = b.newBuilderBasicCmd(cmd)
return cc
}
+1 -1
View File
@@ -68,7 +68,7 @@ func (g *genChromaStyles) generate() error {
if err != nil {
return err
}
formatter := html.New(html.WithClasses())
formatter := html.New(html.WithAllClasses(true))
formatter.WriteCSS(os.Stdout, style)
return nil
}
+1 -1
View File
@@ -64,7 +64,7 @@ func (g *genDocsHelper) generate() error {
enc := json.NewEncoder(f)
enc.SetIndent("", " ")
if err := enc.Encode(docshelper.DocProviders); err != nil {
if err := enc.Encode(docshelper.GetDocProvider()); err != nil {
return err
}
+202 -223
View File
@@ -16,19 +16,18 @@
package commands
import (
"context"
"fmt"
"io/ioutil"
"os/signal"
"runtime/pprof"
"runtime/trace"
"sort"
"sync/atomic"
"github.com/gohugoio/hugo/hugofs"
"github.com/gohugoio/hugo/resources/page"
"github.com/gohugoio/hugo/common/hugo"
"github.com/pkg/errors"
"github.com/gohugoio/hugo/common/herrors"
@@ -49,7 +48,6 @@ import (
"github.com/gohugoio/hugo/config"
"github.com/gohugoio/hugo/parser/metadecoders"
flag "github.com/spf13/pflag"
"github.com/fsnotify/fsnotify"
@@ -94,7 +92,7 @@ func Execute(args []string) Response {
if c == cmd && hugoCmd.c != nil {
// Root command executed
resp.Result = hugoCmd.c.hugo
resp.Result = hugoCmd.c.hugo()
}
if err == nil {
@@ -120,9 +118,9 @@ func Execute(args []string) Response {
func initializeConfig(mustHaveConfigFile, running bool,
h *hugoBuilderCommon,
f flagsToConfigHandler,
doWithCommandeer func(c *commandeer) error) (*commandeer, error) {
cfgInit func(c *commandeer) error) (*commandeer, error) {
c, err := newCommandeer(mustHaveConfigFile, running, h, f, doWithCommandeer)
c, err := newCommandeer(mustHaveConfigFile, running, h, f, cfgInit)
if err != nil {
return nil, err
}
@@ -136,10 +134,14 @@ func (c *commandeer) createLogger(cfg config.Provider, running bool) (*loggers.L
logHandle = ioutil.Discard
logThreshold = jww.LevelWarn
logFile = cfg.GetString("logFile")
outHandle = os.Stdout
outHandle = ioutil.Discard
stdoutThreshold = jww.LevelWarn
)
if !c.h.quiet {
outHandle = os.Stdout
}
if c.h.verboseLog || c.h.logging || (c.h.logFile != "") {
var err error
if logFile != "" {
@@ -196,6 +198,7 @@ func initializeFlags(cmd *cobra.Command, cfg config.Provider) {
"forceSyncStatic",
"noTimes",
"noChmod",
"ignoreVendor",
"templateMetrics",
"templateMetricsHints",
@@ -204,17 +207,23 @@ func initializeFlags(cmd *cobra.Command, cfg config.Provider) {
"buildWatch",
"cacheDir",
"cfgFile",
"confirm",
"contentDir",
"debug",
"destination",
"disableKinds",
"dryRun",
"force",
"gc",
"i18n-warnings",
"invalidateCDN",
"layoutDir",
"logFile",
"i18n-warnings",
"maxDeletes",
"quiet",
"renderToMemory",
"source",
"target",
"theme",
"themesDir",
"verbose",
@@ -222,11 +231,6 @@ func initializeFlags(cmd *cobra.Command, cfg config.Provider) {
"duplicateTargetPaths",
}
// Will set a value even if it is the default.
flagKeysForced := []string{
"minify",
}
for _, key := range persFlagKeys {
setValueFromFlag(cmd.PersistentFlags(), key, cfg, "", false)
}
@@ -234,9 +238,7 @@ func initializeFlags(cmd *cobra.Command, cfg config.Provider) {
setValueFromFlag(cmd.Flags(), key, cfg, "", false)
}
for _, key := range flagKeysForced {
setValueFromFlag(cmd.Flags(), key, cfg, "", true)
}
setValueFromFlag(cmd.Flags(), "minify", cfg, "minifyOutput", true)
// Set some "config aliases"
setValueFromFlag(cmd.Flags(), "destination", cfg, "publishDir", false)
@@ -263,6 +265,9 @@ func setValueFromFlag(flags *flag.FlagSet, key string, cfg config.Provider, targ
case "stringSlice":
bv, _ := flags.GetStringSlice(key)
cfg.Set(configKey, bv)
case "int":
iv, _ := flags.GetInt(key)
cfg.Set(configKey, iv)
default:
panic(fmt.Sprintf("update switch with %s", f.Value.Type()))
}
@@ -282,6 +287,7 @@ func ifTerminal(s string) string {
}
func (c *commandeer) fullBuild() error {
var (
g errgroup.Group
langCount map[string]uint64
@@ -300,13 +306,9 @@ func (c *commandeer) fullBuild() error {
cnt, err := c.copyStatic()
if err != nil {
if !os.IsNotExist(err) {
return errors.Wrap(err, "Error copying static files")
}
c.logger.INFO.Println("No Static directory found")
return errors.Wrap(err, "Error copying static files")
}
langCount = cnt
langCount = cnt
return nil
}
buildSitesFunc := func() error {
@@ -333,16 +335,16 @@ func (c *commandeer) fullBuild() error {
}
}
for _, s := range c.hugo.Sites {
for _, s := range c.hugo().Sites {
s.ProcessingStats.Static = langCount[s.Language().Lang]
}
if c.h.gc {
count, err := c.hugo.GC()
count, err := c.hugo().GC()
if err != nil {
return err
}
for _, s := range c.hugo.Sites {
for _, s := range c.hugo().Sites {
// We have no way of knowing what site the garbage belonged to.
s.ProcessingStats.Cleaned = uint64(count)
}
@@ -431,8 +433,6 @@ func (c *commandeer) initProfiling() (func(), error) {
return nil, err
}
defer c.initMemProfile()
stopMutexProf, err := c.initMutexProfile()
if err != nil {
return nil, err
@@ -444,6 +444,8 @@ func (c *commandeer) initProfiling() (func(), error) {
}
return func() {
c.initMemProfile()
if stopCPUProf != nil {
stopCPUProf()
}
@@ -458,8 +460,6 @@ func (c *commandeer) initProfiling() (func(), error) {
}
func (c *commandeer) build() error {
defer c.timeTrack(time.Now(), "Total")
stopProfiling, err := c.initProfiling()
if err != nil {
return err
@@ -478,7 +478,7 @@ func (c *commandeer) build() error {
// TODO(bep) Feedback?
if !c.h.quiet {
fmt.Println()
c.hugo.PrintProcessingStats(os.Stdout)
c.hugo().PrintProcessingStats(os.Stdout)
fmt.Println()
if createCounter, ok := c.destinationFs.(hugofs.DuplicatesReporter); ok {
@@ -494,7 +494,11 @@ func (c *commandeer) build() error {
if err != nil {
return err
}
c.logger.FEEDBACK.Println("Watching for changes in", c.hugo.PathSpec.AbsPathify(c.Cfg.GetString("contentDir")))
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")
watcher, err := c.newWatcher(watchDirs...)
checkErr(c.Logger, err)
@@ -510,7 +514,7 @@ func (c *commandeer) build() error {
}
func (c *commandeer) serverBuild() error {
defer c.timeTrack(time.Now(), "Total")
defer c.timeTrack(time.Now(), "Built")
stopProfiling, err := c.initProfiling()
if err != nil {
@@ -530,7 +534,7 @@ func (c *commandeer) serverBuild() error {
// TODO(bep) Feedback?
if !c.h.quiet {
fmt.Println()
c.hugo.PrintProcessingStats(os.Stdout)
c.hugo().PrintProcessingStats(os.Stdout)
fmt.Println()
}
@@ -538,14 +542,18 @@ func (c *commandeer) serverBuild() error {
}
func (c *commandeer) copyStatic() (map[string]uint64, error) {
return c.doWithPublishDirs(c.copyStaticTo)
m, err := c.doWithPublishDirs(c.copyStaticTo)
if err == nil || os.IsNotExist(err) {
return m, nil
}
return m, err
}
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
staticFilesystems := c.hugo().BaseFs.SourceFilesystems.Static
if len(staticFilesystems) == 0 {
c.logger.INFO.Println("No static directories found to sync")
@@ -557,6 +565,7 @@ func (c *commandeer) doWithPublishDirs(f func(sourceFs *filesystems.SourceFilesy
if err != nil {
return langCount, err
}
if lang == "" {
// Not multihost
for _, l := range c.languages {
@@ -585,8 +594,18 @@ func (fs *countingStatFs) Stat(name string) (os.FileInfo, error) {
return f, err
}
func chmodFilter(dst, src os.FileInfo) bool {
// Hugo publishes data from multiple sources, potentially
// with overlapping directory structures. We cannot sync permissions
// for directories as that would mean that we might end up with write-protected
// directories inside /public.
// One example of this would be syncing from the Go Module cache,
// which have 0555 directories.
return src.IsDir()
}
func (c *commandeer) copyStaticTo(sourceFs *filesystems.SourceFilesystem) (uint64, error) {
publishDir := c.hugo.PathSpec.PublishDir
publishDir := c.hugo().PathSpec.PublishDir
// If root, remove the second '/'
if publishDir == "//" {
publishDir = helpers.FilePathSeparator
@@ -601,6 +620,7 @@ func (c *commandeer) copyStaticTo(sourceFs *filesystems.SourceFilesystem) (uint6
syncer := fsync.NewSyncer()
syncer.NoTimes = c.Cfg.GetBool("noTimes")
syncer.NoChmod = c.Cfg.GetBool("noChmod")
syncer.ChmodFilter = chmodFilter
syncer.SrcFs = fs
syncer.DestFs = c.Fs.Destination
// Now that we are using a unionFs for the static directories
@@ -630,137 +650,57 @@ func (c *commandeer) copyStaticTo(sourceFs *filesystems.SourceFilesystem) (uint6
}
func (c *commandeer) firstPathSpec() *helpers.PathSpec {
return c.hugo.Sites[0].PathSpec
return c.hugo().Sites[0].PathSpec
}
func (c *commandeer) timeTrack(start time.Time, name string) {
if c.h.quiet {
return
}
elapsed := time.Since(start)
c.logger.FEEDBACK.Printf("%s in %v ms", name, int(1000*elapsed.Seconds()))
}
// getDirList provides NewWatcher() with a list of directories to watch for changes.
func (c *commandeer) getDirList() ([]string, error) {
var a []string
var filenames []string
// To handle nested symlinked content dirs
var seen = make(map[string]bool)
var nested []string
newWalker := func(allowSymbolicDirs bool) func(path string, fi os.FileInfo, err error) error {
return func(path string, fi os.FileInfo, err error) error {
if err != nil {
if os.IsNotExist(err) {
return nil
}
c.logger.ERROR.Println("Walker: ", err)
return nil
}
// Skip .git directories.
// Related to https://github.com/gohugoio/hugo/issues/3468.
if fi.Name() == ".git" {
return nil
}
if fi.Mode()&os.ModeSymlink == os.ModeSymlink {
link, err := filepath.EvalSymlinks(path)
if err != nil {
c.logger.ERROR.Printf("Cannot read symbolic link '%s', error was: %s", path, err)
return nil
}
linkfi, err := helpers.LstatIfPossible(c.Fs.Source, link)
if err != nil {
c.logger.ERROR.Printf("Cannot stat %q: %s", link, err)
return nil
}
if !allowSymbolicDirs && !linkfi.Mode().IsRegular() {
c.logger.ERROR.Printf("Symbolic links for directories not supported, skipping %q", path)
return nil
}
if allowSymbolicDirs && linkfi.IsDir() {
// afero.Walk will not walk symbolic links, so wee need to do it.
if !seen[path] {
seen[path] = true
nested = append(nested, path)
}
return nil
}
fi = linkfi
}
if fi.IsDir() {
if fi.Name() == ".git" ||
fi.Name() == "node_modules" || fi.Name() == "bower_components" {
return filepath.SkipDir
}
a = append(a, path)
}
walkFn := func(path string, fi hugofs.FileMetaInfo, err error) error {
if err != nil {
c.logger.ERROR.Println("walker: ", err)
return nil
}
if fi.IsDir() {
if fi.Name() == ".git" ||
fi.Name() == "node_modules" || fi.Name() == "bower_components" {
return filepath.SkipDir
}
filenames = append(filenames, fi.Meta().Filename())
}
return nil
}
symLinkWalker := newWalker(true)
regularWalker := newWalker(false)
watchFiles := c.hugo().PathSpec.BaseFs.WatchDirs()
for _, fi := range watchFiles {
if !fi.IsDir() {
filenames = append(filenames, fi.Meta().Filename())
continue
}
// SymbolicWalk will log anny ERRORs
// Also note that the Dirnames fetched below will contain any relevant theme
// directories.
for _, contentDir := range c.hugo.PathSpec.BaseFs.Content.Dirnames {
_ = helpers.SymbolicWalk(c.Fs.Source, contentDir, symLinkWalker)
}
for _, staticDir := range c.hugo.PathSpec.BaseFs.Data.Dirnames {
_ = helpers.SymbolicWalk(c.Fs.Source, staticDir, regularWalker)
}
for _, staticDir := range c.hugo.PathSpec.BaseFs.I18n.Dirnames {
_ = helpers.SymbolicWalk(c.Fs.Source, staticDir, regularWalker)
}
for _, staticDir := range c.hugo.PathSpec.BaseFs.Layouts.Dirnames {
_ = helpers.SymbolicWalk(c.Fs.Source, staticDir, regularWalker)
}
for _, staticFilesystem := range c.hugo.PathSpec.BaseFs.Static {
for _, staticDir := range staticFilesystem.Dirnames {
_ = helpers.SymbolicWalk(c.Fs.Source, staticDir, regularWalker)
w := hugofs.NewWalkway(hugofs.WalkwayConfig{Logger: c.logger, Info: fi, WalkFn: walkFn})
if err := w.Walk(); err != nil {
c.logger.ERROR.Println("walker: ", err)
}
}
for _, assetDir := range c.hugo.PathSpec.BaseFs.Assets.Dirnames {
_ = helpers.SymbolicWalk(c.Fs.Source, assetDir, regularWalker)
}
filenames = helpers.UniqueStringsSorted(filenames)
if len(nested) > 0 {
for {
toWalk := nested
nested = nested[:0]
for _, d := range toWalk {
_ = helpers.SymbolicWalk(c.Fs.Source, d, symLinkWalker)
}
if len(nested) == 0 {
break
}
}
}
a = helpers.UniqueStrings(a)
sort.Strings(a)
return a, nil
return filenames, nil
}
func (c *commandeer) buildSites() (err error) {
return c.hugo.Build(hugolib.BuildCfg{})
return c.hugo().Build(hugolib.BuildCfg{})
}
func (c *commandeer) handleBuildErr(err error, msg string) {
@@ -769,7 +709,7 @@ func (c *commandeer) handleBuildErr(err error, msg string) {
c.logger.ERROR.Print(msg + ":\n\n")
c.logger.ERROR.Println(helpers.FirstUpper(err.Error()))
if !c.h.quiet && c.h.verbose {
herrors.PrintStackTrace(err)
herrors.PrintStackTraceFromErr(err)
}
}
@@ -782,47 +722,84 @@ func (c *commandeer) rebuildSites(events []fsnotify.Event) error {
// Make sure we always render the home pages
for _, l := range c.languages {
langPath := c.hugo.PathSpec.GetLangSubDir(l.Lang)
langPath := c.hugo().PathSpec.GetLangSubDir(l.Lang)
if langPath != "" {
langPath = langPath + "/"
}
home := c.hugo.PathSpec.PrependBasePath("/"+langPath, false)
home := c.hugo().PathSpec.PrependBasePath("/"+langPath, false)
visited[home] = true
}
}
return c.hugo.Build(hugolib.BuildCfg{RecentlyVisited: visited}, events...)
return c.hugo().Build(hugolib.BuildCfg{RecentlyVisited: visited, ErrRecovery: c.wasError}, events...)
}
func (c *commandeer) partialReRender(urls ...string) error {
defer func() {
c.wasError = false
}()
c.buildErr = nil
visited := make(map[string]bool)
for _, url := range urls {
visited[url] = true
}
return c.hugo.Build(hugolib.BuildCfg{RecentlyVisited: visited, PartialReRender: true})
return c.hugo().Build(hugolib.BuildCfg{RecentlyVisited: visited, PartialReRender: true, ErrRecovery: c.wasError})
}
func (c *commandeer) fullRebuild() {
c.commandeerHugoState = &commandeerHugoState{}
err := c.loadConfig(true, true)
if err != nil {
// Set the processing on pause until the state is recovered.
c.paused = true
c.handleBuildErr(err, "Failed to reload config")
} else {
c.paused = false
}
if !c.paused {
err := c.buildSites()
if err != nil {
c.logger.ERROR.Println(err)
} else if !c.h.buildWatch && !c.Cfg.GetBool("disableLiveReload") {
livereload.ForceRefresh()
func (c *commandeer) fullRebuild(changeType string) {
if changeType == configChangeGoMod {
// go.mod may be changed during the build itself, and
// we really want to prevent superfluous builds.
if !c.fullRebuildSem.TryAcquire(1) {
return
}
c.fullRebuildSem.Release(1)
}
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.
time.Sleep(2 * time.Second)
}()
defer c.timeTrack(time.Now(), "Rebuilt")
c.commandeerHugoState = newCommandeerHugoState()
err := c.loadConfig(true, true)
if err != nil {
// Set the processing on pause until the state is recovered.
c.paused = true
c.handleBuildErr(err, "Failed to reload config")
} else {
c.paused = false
}
if !c.paused {
_, err := c.copyStatic()
if err != nil {
c.logger.ERROR.Println(err)
return
}
err = c.buildSites()
if err != nil {
c.logger.ERROR.Println(err)
} else if !c.h.buildWatch && !c.Cfg.GetBool("disableLiveReload") {
livereload.ForceRefresh()
}
}
}()
}
// newWatcher creates a new watcher to watch filesystem events.
@@ -877,26 +854,57 @@ func (c *commandeer) newWatcher(dirList ...string) (*watcher.Batcher, error) {
return watcher, nil
}
func (c *commandeer) printChangeDetected(typ string) {
msg := "\nChange"
if typ != "" {
msg += " of " + typ
}
msg += " detected, rebuilding site."
c.logger.FEEDBACK.Println(msg)
const layout = "2006-01-02 15:04:05.000 -0700"
c.logger.FEEDBACK.Println(time.Now().Format(layout))
}
const (
configChangeConfig = "config file"
configChangeGoMod = "go.mod file"
)
func (c *commandeer) handleEvents(watcher *watcher.Batcher,
staticSyncer *staticSyncer,
evs []fsnotify.Event,
configSet map[string]bool) {
defer func() {
c.wasError = false
}()
var isHandled bool
for _, ev := range evs {
isConfig := configSet[ev.Name]
configChangeType := configChangeConfig
if isConfig {
if strings.Contains(ev.Name, "go.mod") {
configChangeType = configChangeGoMod
}
}
if !isConfig {
// It may be one of the /config folders
dirname := filepath.Dir(ev.Name)
if dirname != "." && configSet[dirname] {
isConfig = true
}
}
if isConfig {
isHandled = true
if ev.Op&fsnotify.Chmod == fsnotify.Chmod {
continue
}
if ev.Op&fsnotify.Remove == fsnotify.Remove || ev.Op&fsnotify.Rename == fsnotify.Rename {
for _, configFile := range c.configFiles {
counter := 0
@@ -908,13 +916,20 @@ func (c *commandeer) handleEvents(watcher *watcher.Batcher,
time.Sleep(100 * time.Millisecond)
}
}
}
// Config file(s) changed. Need full rebuild.
c.fullRebuild()
break
c.fullRebuild(configChangeType)
return
}
}
if isHandled {
return
}
if c.paused {
// Wait for the server to get into a consistent state before
// we continue with processing.
@@ -924,7 +939,9 @@ func (c *commandeer) handleEvents(watcher *watcher.Batcher,
if len(evs) > 50 {
// This is probably a mass edit of the content dir.
// Schedule a full rebuild for when it slows down.
c.debounce(c.fullRebuild)
c.debounce(func() {
c.fullRebuild("")
})
return
}
@@ -937,7 +954,7 @@ func (c *commandeer) handleEvents(watcher *watcher.Batcher,
filtered := []fsnotify.Event{}
for _, ev := range evs {
// Check the most specific first, i.e. files.
contentMapped := c.hugo.ContentChanges.GetSymbolicLinkMappings(ev.Name)
contentMapped := c.hugo().ContentChanges.GetSymbolicLinkMappings(ev.Name)
if len(contentMapped) > 0 {
for _, mapped := range contentMapped {
filtered = append(filtered, fsnotify.Event{Name: mapped, Op: ev.Op})
@@ -949,7 +966,7 @@ func (c *commandeer) handleEvents(watcher *watcher.Batcher,
dir, name := filepath.Split(ev.Name)
contentMapped = c.hugo.ContentChanges.GetSymbolicLinkMappings(dir)
contentMapped = c.hugo().ContentChanges.GetSymbolicLinkMappings(dir)
if len(contentMapped) == 0 {
filtered = append(filtered, ev)
@@ -983,7 +1000,7 @@ func (c *commandeer) handleEvents(watcher *watcher.Batcher,
if istemp {
continue
}
if c.hugo.Deps.SourceSpec.IgnoreFile(ev.Name) {
if c.hugo().Deps.SourceSpec.IgnoreFile(ev.Name) {
continue
}
// Sometimes during rm -rf operations a '"": REMOVE' is triggered. Just ignore these
@@ -1006,7 +1023,7 @@ func (c *commandeer) handleEvents(watcher *watcher.Batcher,
continue
}
walkAdder := func(path string, f os.FileInfo, err error) error {
walkAdder := func(path string, f hugofs.FileMetaInfo, err error) error {
if f.IsDir() {
c.logger.FEEDBACK.Println("adding created directory to watchlist", path)
if err := watcher.Add(path); err != nil {
@@ -1037,9 +1054,7 @@ func (c *commandeer) handleEvents(watcher *watcher.Batcher,
}
if len(staticEvents) > 0 {
c.logger.FEEDBACK.Println("\nStatic file changes detected")
const layout = "2006-01-02 15:04:05.000 -0700"
c.logger.FEEDBACK.Println(time.Now().Format(layout))
c.printChangeDetected("Static files")
if c.Cfg.GetBool("forceSyncStatic") {
c.logger.FEEDBACK.Printf("Syncing all static files\n")
@@ -1059,10 +1074,11 @@ func (c *commandeer) handleEvents(watcher *watcher.Batcher,
// Will block forever trying to write to a channel that nobody is reading if livereload isn't initialized
// force refresh when more than one file
if len(staticEvents) == 1 {
if !c.wasError && len(staticEvents) == 1 {
ev := staticEvents[0]
path := c.hugo.BaseFs.SourceFilesystems.MakeStaticPathRelative(ev.Name)
path := c.hugo().BaseFs.SourceFilesystems.MakeStaticPathRelative(ev.Name)
path = c.firstPathSpec().RelURL(helpers.ToSlashTrimLeading(path), false)
livereload.RefreshPath(path)
} else {
livereload.ForceRefresh()
@@ -1078,10 +1094,7 @@ func (c *commandeer) handleEvents(watcher *watcher.Batcher,
doLiveReload := !c.h.buildWatch && !c.Cfg.GetBool("disableLiveReload")
onePageName := pickOneWriteOrCreatePath(partitionedEvents.ContentEvents)
c.logger.FEEDBACK.Println("\nChange detected, rebuilding site")
const layout = "2006-01-02 15:04:05.000 -0700"
c.logger.FEEDBACK.Println(time.Now().Format(layout))
c.printChangeDetected("")
c.changeDetector.PrepareNew()
if err := c.rebuildSites(dynamicEvents); err != nil {
c.handleBuildErr(err, "Rebuild failed")
@@ -1089,6 +1102,10 @@ func (c *commandeer) handleEvents(watcher *watcher.Batcher,
if doLiveReload {
if len(partitionedEvents.ContentEvents) == 0 && len(partitionedEvents.AssetEvents) > 0 {
if c.wasError {
livereload.ForceRefresh()
return
}
changed := c.changeDetector.changed()
if c.changeDetector != nil && len(changed) == 0 {
// Nothing has changed.
@@ -1110,7 +1127,7 @@ func (c *commandeer) handleEvents(watcher *watcher.Batcher,
if navigate {
if onePageName != "" {
p = c.hugo.GetContentPage(onePageName)
p = c.hugo().GetContentPage(onePageName)
}
}
@@ -1158,41 +1175,3 @@ func pickOneWriteOrCreatePath(events []fsnotify.Event) string {
return name
}
// isThemeVsHugoVersionMismatch returns whether the current Hugo version is
// less than any of the themes' min_version.
func (c *commandeer) isThemeVsHugoVersionMismatch(fs afero.Fs) (dir string, mismatch bool, requiredMinVersion string) {
if !c.hugo.PathSpec.ThemeSet() {
return
}
for _, absThemeDir := range c.hugo.BaseFs.AbsThemeDirs {
path := filepath.Join(absThemeDir, "theme.toml")
exists, err := helpers.Exists(path, fs)
if err != nil || !exists {
continue
}
b, err := afero.ReadFile(fs, path)
if err != nil {
continue
}
tomlMeta, err := metadecoders.Default.UnmarshalToMap(b, metadecoders.TOML)
if err != nil {
continue
}
if minVersion, ok := tomlMeta["min_version"]; ok {
if hugo.CompareVersion(minVersion) > 0 {
return absThemeDir, true, fmt.Sprint(minVersion)
}
}
}
return
}
+6 -10
View File
@@ -14,15 +14,14 @@
package commands
import (
"os"
"testing"
"github.com/stretchr/testify/require"
qt "github.com/frankban/quicktest"
)
// Issue #5662
func TestHugoWithContentDirOverride(t *testing.T) {
assert := require.New(t)
c := qt.New(t)
hugoCmd := newCommandsBuilder().addAll().build()
cmd := hugoCmd.getCommand()
@@ -37,16 +36,13 @@ title = "Hugo Commands"
contentDir = "thisdoesnotexist"
`
dir, err := createSimpleTestSite(t, testSiteConfig{configTOML: cfgStr, contentDir: contentDir})
assert.NoError(err)
defer func() {
os.RemoveAll(dir)
}()
dir, clean, err := createSimpleTestSite(t, testSiteConfig{configTOML: cfgStr, contentDir: contentDir})
c.Assert(err, qt.IsNil)
defer clean()
cmd.SetArgs([]string{"-s=" + dir, "-c=" + contentDir})
_, err = cmd.ExecuteC()
assert.NoError(err)
c.Assert(err, qt.IsNil)
}
+39 -79
View File
@@ -17,7 +17,6 @@ import (
"bytes"
"errors"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
@@ -27,14 +26,18 @@ import (
"time"
"unicode"
"github.com/gohugoio/hugo/parser/pageparser"
"github.com/gohugoio/hugo/common/hugio"
"github.com/gohugoio/hugo/parser/metadecoders"
"github.com/gohugoio/hugo/common/maps"
"github.com/gohugoio/hugo/helpers"
"github.com/gohugoio/hugo/hugofs"
"github.com/gohugoio/hugo/hugolib"
"github.com/gohugoio/hugo/parser"
"github.com/spf13/afero"
"github.com/spf13/cast"
"github.com/spf13/cobra"
jww "github.com/spf13/jwalterweatherman"
)
@@ -104,7 +107,7 @@ func (i *importCmd) importFromJekyll(cmd *cobra.Command, args []string) error {
return errors.New("abort: jekyll root contains neither posts nor drafts")
}
site, err := i.createSiteFromJekyll(jekyllRoot, targetDir, jekyllPostDirs, forceImport)
err = i.createSiteFromJekyll(jekyllRoot, targetDir, jekyllPostDirs, forceImport)
if err != nil {
return newUserError(err)
@@ -113,7 +116,7 @@ func (i *importCmd) importFromJekyll(cmd *cobra.Command, args []string) error {
jww.FEEDBACK.Println("Importing...")
fileCount := 0
callback := func(path string, fi os.FileInfo, err error) error {
callback := func(path string, fi hugofs.FileMetaInfo, err error) error {
if err != nil {
return err
}
@@ -141,7 +144,7 @@ func (i *importCmd) importFromJekyll(cmd *cobra.Command, args []string) error {
}
fileCount++
return convertJekyllPost(site, path, relPath, targetDir, draft)
return convertJekyllPost(path, relPath, targetDir, draft)
}
for jekyllPostDir, hasAnyPostInDir := range jekyllPostDirs {
@@ -199,22 +202,22 @@ func (i *importCmd) retrieveJekyllPostDir(fs afero.Fs, dir string) (bool, bool)
return false, true
}
func (i *importCmd) createSiteFromJekyll(jekyllRoot, targetDir string, jekyllPostDirs map[string]bool, force bool) (*hugolib.Site, error) {
func (i *importCmd) createSiteFromJekyll(jekyllRoot, targetDir string, jekyllPostDirs map[string]bool, force bool) error {
s, err := hugolib.NewSiteDefaultLang()
if err != nil {
return nil, err
return err
}
fs := s.Fs.Source
if exists, _ := helpers.Exists(targetDir, fs); exists {
if isDir, _ := helpers.IsDir(targetDir, fs); !isDir {
return nil, errors.New("target path \"" + targetDir + "\" exists but is not a directory")
return errors.New("target path \"" + targetDir + "\" exists but is not a directory")
}
isEmpty, _ := helpers.IsEmpty(targetDir, fs)
if !isEmpty && !force {
return nil, errors.New("target path \"" + targetDir + "\" exists and is not empty")
return errors.New("target path \"" + targetDir + "\" exists and is not empty")
}
}
@@ -231,7 +234,7 @@ func (i *importCmd) createSiteFromJekyll(jekyllRoot, targetDir string, jekyllPos
i.copyJekyllFilesAndFolders(jekyllRoot, filepath.Join(targetDir, "static"), jekyllPostDirs)
return s, nil
return nil
}
func (i *importCmd) loadJekyllConfig(fs afero.Fs, jekyllRoot string) map[string]interface{} {
@@ -302,66 +305,10 @@ func (i *importCmd) createConfigFromJekyll(fs afero.Fs, inpath string, kind meta
return helpers.WriteToDisk(filepath.Join(inpath, "config."+string(kind)), &buf, fs)
}
func copyFile(source string, dest string) error {
sf, err := os.Open(source)
if err != nil {
return err
}
defer sf.Close()
df, err := os.Create(dest)
if err != nil {
return err
}
defer df.Close()
_, err = io.Copy(df, sf)
if err == nil {
si, err := os.Stat(source)
if err != nil {
err = os.Chmod(dest, si.Mode())
if err != nil {
return err
}
}
}
return nil
}
func copyDir(source string, dest string) error {
fi, err := os.Stat(source)
if err != nil {
return err
}
if !fi.IsDir() {
return errors.New(source + " is not a directory")
}
err = os.MkdirAll(dest, fi.Mode())
if err != nil {
return err
}
entries, _ := ioutil.ReadDir(source)
for _, entry := range entries {
sfp := filepath.Join(source, entry.Name())
dfp := filepath.Join(dest, entry.Name())
if entry.IsDir() {
err = copyDir(sfp, dfp)
if err != nil {
jww.ERROR.Println(err)
}
} else {
err = copyFile(sfp, dfp)
if err != nil {
jww.ERROR.Println(err)
}
}
}
return nil
}
func (i *importCmd) copyJekyllFilesAndFolders(jekyllRoot, dest string, jekyllPostDirs map[string]bool) (err error) {
fi, err := os.Stat(jekyllRoot)
fs := hugofs.Os
fi, err := fs.Stat(jekyllRoot)
if err != nil {
return err
}
@@ -383,7 +330,7 @@ func (i *importCmd) copyJekyllFilesAndFolders(jekyllRoot, dest string, jekyllPos
if entry.IsDir() {
if entry.Name()[0] != '_' && entry.Name()[0] != '.' {
if _, ok := jekyllPostDirs[entry.Name()]; !ok {
err = copyDir(sfp, dfp)
err = hugio.CopyDir(fs, sfp, dfp, nil)
if err != nil {
jww.ERROR.Println(err)
}
@@ -402,7 +349,7 @@ func (i *importCmd) copyJekyllFilesAndFolders(jekyllRoot, dest string, jekyllPos
}
if !isExcept && entry.Name()[0] != '.' && entry.Name()[0] != '_' {
err = copyFile(sfp, dfp)
err = hugio.CopyFile(fs, sfp, dfp)
if err != nil {
jww.ERROR.Println(err)
}
@@ -430,7 +377,7 @@ func parseJekyllFilename(filename string) (time.Time, string, error) {
return postDate, postName, nil
}
func convertJekyllPost(s *hugolib.Site, path, relPath, targetDir string, draft bool) error {
func convertJekyllPost(path, relPath, targetDir string, draft bool) error {
jww.TRACE.Println("Converting", path)
filename := filepath.Base(path)
@@ -452,19 +399,23 @@ func convertJekyllPost(s *hugolib.Site, path, relPath, targetDir string, draft b
return err
}
pf, err := parseContentFile(bytes.NewReader(contentBytes))
pf, err := pageparser.ParseFrontMatterAndContent(bytes.NewReader(contentBytes))
if err != nil {
jww.ERROR.Println("Parse file error:", path)
return err
}
newmetadata, err := convertJekyllMetaData(pf.frontMatter, postName, postDate, draft)
newmetadata, err := convertJekyllMetaData(pf.FrontMatter, postName, postDate, draft)
if err != nil {
jww.ERROR.Println("Convert metadata error:", path)
return err
}
content := convertJekyllContent(newmetadata, string(pf.content))
content, err := convertJekyllContent(newmetadata, string(pf.Content))
if err != nil {
jww.ERROR.Println("Converting Jekyll error:", path)
return err
}
fs := hugofs.Os
if err := helpers.WriteToDisk(targetFile, strings.NewReader(content), fs); err != nil {
@@ -475,7 +426,7 @@ func convertJekyllPost(s *hugolib.Site, path, relPath, targetDir string, draft b
}
func convertJekyllMetaData(m interface{}, postName string, postDate time.Time, draft bool) (interface{}, error) {
metadata, err := cast.ToStringMapE(m)
metadata, err := maps.ToStringMapE(m)
if err != nil {
return nil, err
}
@@ -526,8 +477,8 @@ func convertJekyllMetaData(m interface{}, postName string, postDate time.Time, d
return metadata, nil
}
func convertJekyllContent(m interface{}, content string) string {
metadata, _ := cast.ToStringMapE(m)
func convertJekyllContent(m interface{}, content string) (string, error) {
metadata, _ := maps.ToStringMapE(m)
lines := strings.Split(content, "\n")
var resultLines []string
@@ -570,7 +521,16 @@ func convertJekyllContent(m interface{}, content string) string {
content = replace.re.ReplaceAllStringFunc(content, replace.replace)
}
return content
var buf bytes.Buffer
if len(metadata) != 0 {
err := parser.InterfaceToFrontMatter(m, metadecoders.YAML, &buf)
if err != nil {
return "", err
}
}
buf.WriteString(content)
return buf.String(), nil
}
func replaceHighlightTag(match string) string {
+21 -13
View File
@@ -15,12 +15,14 @@ package commands
import (
"encoding/json"
"github.com/stretchr/testify/assert"
"testing"
"time"
qt "github.com/frankban/quicktest"
)
func TestParseJekyllFilename(t *testing.T) {
c := qt.New(t)
filenameArray := []string{
"2015-01-02-test.md",
"2012-03-15-中文.markup",
@@ -36,13 +38,14 @@ func TestParseJekyllFilename(t *testing.T) {
for i, filename := range filenameArray {
postDate, postName, err := parseJekyllFilename(filename)
assert.Equal(t, err, nil)
assert.Equal(t, expectResult[i].postDate.Format("2006-01-02"), postDate.Format("2006-01-02"))
assert.Equal(t, expectResult[i].postName, postName)
c.Assert(err, qt.IsNil)
c.Assert(expectResult[i].postDate.Format("2006-01-02"), qt.Equals, postDate.Format("2006-01-02"))
c.Assert(expectResult[i].postName, qt.Equals, postName)
}
}
func TestConvertJekyllMetadata(t *testing.T) {
c := qt.New(t)
testDataList := []struct {
metadata interface{}
postName string
@@ -73,25 +76,27 @@ func TestConvertJekyllMetadata(t *testing.T) {
for _, data := range testDataList {
result, err := convertJekyllMetaData(data.metadata, data.postName, data.postDate, data.draft)
assert.Equal(t, nil, err)
c.Assert(err, qt.IsNil)
jsonResult, err := json.Marshal(result)
assert.Equal(t, nil, err)
assert.Equal(t, data.expect, string(jsonResult))
c.Assert(err, qt.IsNil)
c.Assert(string(jsonResult), qt.Equals, data.expect)
}
}
func TestConvertJekyllContent(t *testing.T) {
c := qt.New(t)
testDataList := []struct {
metadata interface{}
content string
expect string
}{
{map[interface{}]interface{}{},
`Test content\n<!-- more -->\npart2 content`, `Test content\n<!--more-->\npart2 content`},
"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`},
"Test content\n<!-- More -->\npart2 content", "Test content\n<!--more-->\npart2 content"},
{map[interface{}]interface{}{"excerpt_separator": "<!--sep-->"},
`Test content\n<!--sep-->\npart2 content`, `Test content\n<!--more-->\npart2 content`},
"Test content\n<!--sep-->\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{}{},
@@ -120,10 +125,13 @@ func TestConvertJekyllContent(t *testing.T) {
{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"},
"somecontent",
"---\nDate: \"2015-10-01 12:13:11\"\ncategory: book\nlayout: post\n---\nsomecontent"},
}
for _, data := range testDataList {
result := convertJekyllContent(data.metadata, data.content)
assert.Equal(t, data.expect, result)
result, err := convertJekyllContent(data.metadata, data.content)
c.Assert(result, qt.Equals, data.expect)
c.Assert(err, qt.IsNil)
}
}
+100 -65
View File
@@ -16,7 +16,8 @@ package commands
import (
"encoding/csv"
"os"
"path/filepath"
"strconv"
"strings"
"time"
"github.com/gohugoio/hugo/hugolib"
@@ -28,81 +29,77 @@ import (
var _ cmder = (*listCmd)(nil)
type listCmd struct {
hugoBuilderCommon
*baseCmd
*baseBuilderCmd
}
func newListCmd() *listCmd {
func (lc *listCmd) buildSites(config map[string]interface{}) (*hugolib.HugoSites, error) {
cfgInit := func(c *commandeer) error {
for key, value := range config {
c.Set(key, value)
}
return nil
}
c, err := initializeConfig(true, false, &lc.hugoBuilderCommon, lc, cfgInit)
if err != nil {
return nil, err
}
sites, err := hugolib.NewHugoSites(*c.DepsCfg)
if err != nil {
return nil, newSystemError("Error creating sites", err)
}
if err := sites.Build(hugolib.BuildCfg{SkipRender: true}); err != nil {
return nil, newSystemError("Error Processing Source Content", err)
}
return sites, nil
}
func (b *commandsBuilder) newListCmd() *listCmd {
cc := &listCmd{}
cc.baseCmd = newBaseCmd(&cobra.Command{
cmd := &cobra.Command{
Use: "list",
Short: "Listing out various types of content",
Long: `Listing out various types of content.
List requires a subcommand, e.g. ` + "`hugo list drafts`.",
RunE: nil,
})
}
cc.cmd.AddCommand(
cmd.AddCommand(
&cobra.Command{
Use: "drafts",
Short: "List all drafts",
Long: `List all of the drafts in your content directory.`,
RunE: func(cmd *cobra.Command, args []string) error {
cfgInit := func(c *commandeer) error {
c.Set("buildDrafts", true)
return nil
}
c, err := initializeConfig(true, false, &cc.hugoBuilderCommon, cc, cfgInit)
if err != nil {
return err
}
sites, err := hugolib.NewHugoSites(*c.DepsCfg)
sites, err := cc.buildSites(map[string]interface{}{"buildDrafts": true})
if err != nil {
return newSystemError("Error creating sites", err)
}
if err := sites.Build(hugolib.BuildCfg{SkipRender: true}); err != nil {
return newSystemError("Error Processing Source Content", err)
return newSystemError("Error building sites", err)
}
for _, p := range sites.Pages() {
if p.Draft() {
jww.FEEDBACK.Println(filepath.Join(p.File().Dir(), p.File().LogicalName()))
jww.FEEDBACK.Println(strings.TrimPrefix(p.File().Filename(), sites.WorkingDir+string(os.PathSeparator)))
}
}
return nil
},
},
&cobra.Command{
Use: "future",
Short: "List all posts dated in the future",
Long: `List all of the posts in your content directory which will be
posted in the future.`,
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 {
cfgInit := func(c *commandeer) error {
c.Set("buildFuture", true)
return nil
}
c, err := initializeConfig(true, false, &cc.hugoBuilderCommon, cc, cfgInit)
if err != nil {
return err
}
sites, err := hugolib.NewHugoSites(*c.DepsCfg)
sites, err := cc.buildSites(map[string]interface{}{"buildFuture": true})
if err != nil {
return newSystemError("Error creating sites", err)
}
if err := sites.Build(hugolib.BuildCfg{SkipRender: true}); err != nil {
return newSystemError("Error Processing Source Content", err)
return newSystemError("Error building sites", err)
}
writer := csv.NewWriter(os.Stdout)
@@ -110,7 +107,10 @@ posted in the future.`,
for _, p := range sites.Pages() {
if resource.IsFuture(p) {
err := writer.Write([]string{filepath.Join(p.File().Dir(), p.File().LogicalName()), p.PublishDate().Format(time.RFC3339)})
err := writer.Write([]string{
strings.TrimPrefix(p.File().Filename(), sites.WorkingDir+string(os.PathSeparator)),
p.PublishDate().Format(time.RFC3339),
})
if err != nil {
return newSystemError("Error writing future posts to stdout", err)
}
@@ -118,32 +118,17 @@ posted in the future.`,
}
return nil
},
},
&cobra.Command{
Use: "expired",
Short: "List all posts already expired",
Long: `List all of the posts in your content directory which has already
expired.`,
Long: `List all of the posts in your content directory which has already expired.`,
RunE: func(cmd *cobra.Command, args []string) error {
cfgInit := func(c *commandeer) error {
c.Set("buildExpired", true)
return nil
}
c, err := initializeConfig(true, false, &cc.hugoBuilderCommon, cc, cfgInit)
if err != nil {
return err
}
sites, err := hugolib.NewHugoSites(*c.DepsCfg)
sites, err := cc.buildSites(map[string]interface{}{"buildExpired": true})
if err != nil {
return newSystemError("Error creating sites", err)
}
if err := sites.Build(hugolib.BuildCfg{SkipRender: true}); err != nil {
return newSystemError("Error Processing Source Content", err)
return newSystemError("Error building sites", err)
}
writer := csv.NewWriter(os.Stdout)
@@ -151,22 +136,72 @@ expired.`,
for _, p := range sites.Pages() {
if resource.IsExpired(p) {
err := writer.Write([]string{filepath.Join(p.File().Dir(), p.File().LogicalName()), p.ExpiryDate().Format(time.RFC3339)})
err := writer.Write([]string{
strings.TrimPrefix(p.File().Filename(), sites.WorkingDir+string(os.PathSeparator)),
p.ExpiryDate().Format(time.RFC3339),
})
if err != nil {
return newSystemError("Error writing expired posts to stdout", err)
}
}
}
return nil
},
},
&cobra.Command{
Use: "all",
Short: "List all posts",
Long: `List all of the posts in your content directory, include drafts, future and expired pages.`,
RunE: func(cmd *cobra.Command, args []string) error {
sites, err := cc.buildSites(map[string]interface{}{
"buildExpired": true,
"buildDrafts": true,
"buildFuture": true,
})
if err != nil {
return newSystemError("Error building sites", err)
}
writer := csv.NewWriter(os.Stdout)
defer writer.Flush()
writer.Write([]string{
"path",
"slug",
"title",
"date",
"expiryDate",
"publishDate",
"draft",
"permalink",
})
for _, p := range sites.Pages() {
if !p.IsPage() {
continue
}
err := writer.Write([]string{
strings.TrimPrefix(p.File().Filename(), sites.WorkingDir+string(os.PathSeparator)),
p.Slug(),
p.Title(),
p.Date().Format(time.RFC3339),
p.ExpiryDate().Format(time.RFC3339),
p.PublishDate().Format(time.RFC3339),
strconv.FormatBool(p.Draft()),
p.Permalink(),
})
if err != nil {
return newSystemError("Error writing posts to stdout", err)
}
}
return nil
},
},
)
cc.cmd.PersistentFlags().StringVarP(&cc.source, "source", "s", "", "filesystem path to read files relative from")
cc.cmd.PersistentFlags().SetAnnotation("source", cobra.BashCompSubdirsInDir, []string{})
cc.baseBuilderCmd = b.newBuilderBasicCmd(cmd)
return cc
}
+71
View File
@@ -0,0 +1,71 @@
package commands
import (
"bytes"
"encoding/csv"
"io"
"os"
"path/filepath"
"strings"
"testing"
qt "github.com/frankban/quicktest"
)
func captureStdout(f func() error) (string, error) {
old := os.Stdout
r, w, _ := os.Pipe()
os.Stdout = w
err := f()
w.Close()
os.Stdout = old
var buf bytes.Buffer
io.Copy(&buf, r)
return buf.String(), err
}
func TestListAll(t *testing.T) {
c := qt.New(t)
dir, clean, err := createSimpleTestSite(t, testSiteConfig{})
defer clean()
c.Assert(err, qt.IsNil)
hugoCmd := newCommandsBuilder().addAll().build()
cmd := hugoCmd.getCommand()
defer func() {
os.RemoveAll(dir)
}()
cmd.SetArgs([]string{"-s=" + dir, "list", "all"})
out, err := captureStdout(func() error {
_, err := cmd.ExecuteC()
return err
})
c.Assert(err, qt.IsNil)
r := csv.NewReader(strings.NewReader(out))
header, err := r.Read()
c.Assert(err, qt.IsNil)
c.Assert(header, qt.DeepEquals, []string{
"path", "slug", "title",
"date", "expiryDate", "publishDate",
"draft", "permalink",
})
record, err := r.Read()
c.Assert(err, qt.IsNil)
c.Assert(record, qt.DeepEquals, []string{
filepath.Join("content", "p1.md"), "", "P1",
"0001-01-01T00:00:00Z", "0001-01-01T00:00:00Z", "0001-01-01T00:00:00Z",
"false", "https://example.org/p1/",
})
}
+281
View File
@@ -0,0 +1,281 @@
// Copyright 2019 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package commands
import (
"errors"
"fmt"
"os"
"path/filepath"
"regexp"
"github.com/gohugoio/hugo/modules"
"github.com/spf13/cobra"
)
var _ cmder = (*modCmd)(nil)
type modCmd struct {
*baseBuilderCmd
}
func (c *modCmd) newVerifyCmd() *cobra.Command {
var clean bool
verifyCmd := &cobra.Command{
Use: "verify",
Short: "Verify dependencies.",
Long: `Verify checks that the dependencies of the current module, which are stored in a local downloaded source cache, have not been modified since being downloaded.
`,
RunE: func(cmd *cobra.Command, args []string) error {
return c.withModsClient(true, func(c *modules.Client) error {
return c.Verify(clean)
})
},
}
verifyCmd.Flags().BoolVarP(&clean, "clean", "", false, "delete module cache for dependencies that fail verification")
return verifyCmd
}
var moduleNotFoundRe = regexp.MustCompile("module.*not found")
func (c *modCmd) newCleanCmd() *cobra.Command {
var pattern string
var all bool
cmd := &cobra.Command{
Use: "clean",
Short: "Delete the Hugo Module cache for the current project.",
Long: `Delete the Hugo Module cache for the current project.
Note that after you run this command, all of your dependencies will be re-downloaded next time you run "hugo".
Also note that if you configure a positive maxAge for the "modules" file cache, it will also be cleaned as part of "hugo --gc".
`,
RunE: func(cmd *cobra.Command, args []string) error {
if all {
com, err := c.initConfig(false)
if err != nil && !moduleNotFoundRe.MatchString(err.Error()) {
return err
}
_, err = com.hugo().FileCaches.ModulesCache().Prune(true)
return err
}
return c.withModsClient(true, func(c *modules.Client) error {
return c.Clean(pattern)
})
},
}
cmd.Flags().StringVarP(&pattern, "pattern", "", "", `pattern matching module paths to clean (all if not set), e.g. "**hugo*"`)
cmd.Flags().BoolVarP(&all, "all", "", false, "clean entire module cache")
return cmd
}
func (b *commandsBuilder) newModCmd() *modCmd {
c := &modCmd{}
const commonUsage = `
Note that Hugo will always start out by resolving the components defined in the site
configuration, provided by a _vendor directory (if no --ignoreVendor flag provided),
Go Modules, or a folder inside the themes directory, in that order.
See https://gohugo.io/hugo-modules/ for more information.
`
cmd := &cobra.Command{
Use: "mod",
Short: "Various Hugo Modules helpers.",
Long: `Various helpers to help manage the modules in your project's dependency graph.
Most operations here requires a Go version installed on your system (>= Go 1.12) and the relevant VCS client (typically Git).
This is not needed if you only operate on modules inside /themes or if you have vendored them via "hugo mod vendor".
` + commonUsage,
RunE: nil,
}
cmd.AddCommand(
&cobra.Command{
Use: "get",
DisableFlagParsing: true,
Short: "Resolves dependencies in your current Hugo Project.",
Long: `
Resolves dependencies in your current Hugo Project.
Some examples:
Install the latest version possible for a given module:
hugo mod get github.com/gohugoio/testshortcodes
Install a specific version:
hugo mod get github.com/gohugoio/testshortcodes@v0.3.0
Install the latest versions of all module dependencies:
hugo mod get -u
hugo mod get -u ./... (recursive)
Run "go help get" for more information. All flags available for "go get" is also relevant here.
` + commonUsage,
RunE: func(cmd *cobra.Command, args []string) error {
// We currently just pass on the flags we get to Go and
// need to do the flag handling manually.
if len(args) == 1 && args[0] == "-h" {
return cmd.Help()
}
var lastArg string
if len(args) != 0 {
lastArg = args[len(args)-1]
}
if lastArg == "./..." {
args = args[:len(args)-1]
// Do a recursive update.
dirname, err := os.Getwd()
if err != nil {
return err
}
// Sanity check. We do recursive walking and want to avoid
// accidents.
if len(dirname) < 5 {
return errors.New("must not be run from the file system root")
}
filepath.Walk(dirname, func(path string, info os.FileInfo, err error) error {
if info.IsDir() {
return nil
}
if info.Name() == "go.mod" {
// Found a module.
dir := filepath.Dir(path)
fmt.Println("Update module in", dir)
c.source = dir
err := c.withModsClient(false, func(c *modules.Client) error {
if len(args) == 1 && args[0] == "-h" {
return cmd.Help()
}
return c.Get(args...)
})
if err != nil {
return err
}
}
return nil
})
return nil
}
return c.withModsClient(false, func(c *modules.Client) error {
return c.Get(args...)
})
},
},
&cobra.Command{
Use: "graph",
Short: "Print a module dependency graph.",
Long: `Print a module dependency graph with information about module status (disabled, vendored).
Note that for vendored modules, that is the version listed and not the one from go.mod.
`,
RunE: func(cmd *cobra.Command, args []string) error {
return c.withModsClient(true, func(c *modules.Client) error {
return c.Graph(os.Stdout)
})
},
},
&cobra.Command{
Use: "init",
Short: "Initialize this project as a Hugo Module.",
Long: `Initialize this project as a Hugo Module.
It will try to guess the module path, but you may help by passing it as an argument, e.g:
hugo mod init github.com/gohugoio/testshortcodes
Note that Hugo Modules supports multi-module projects, so you can initialize a Hugo Module
inside a subfolder on GitHub, as one example.
`,
RunE: func(cmd *cobra.Command, args []string) error {
var path string
if len(args) >= 1 {
path = args[0]
}
return c.withModsClient(false, func(c *modules.Client) error {
return c.Init(path)
})
},
},
&cobra.Command{
Use: "vendor",
Short: "Vendor all module dependencies into the _vendor directory.",
Long: `Vendor all module dependencies into the _vendor directory.
If a module is vendored, that is where Hugo will look for it's dependencies.
`,
RunE: func(cmd *cobra.Command, args []string) error {
return c.withModsClient(true, func(c *modules.Client) error {
return c.Vendor()
})
},
},
c.newVerifyCmd(),
&cobra.Command{
Use: "tidy",
Short: "Remove unused entries in go.mod and go.sum.",
RunE: func(cmd *cobra.Command, args []string) error {
return c.withModsClient(true, func(c *modules.Client) error {
return c.Tidy()
})
},
},
c.newCleanCmd(),
)
c.baseBuilderCmd = b.newBuilderCmd(cmd)
return c
}
func (c *modCmd) withModsClient(failOnMissingConfig bool, f func(*modules.Client) error) error {
com, err := c.initConfig(failOnMissingConfig)
if err != nil {
return err
}
return f(com.hugo().ModulesClient)
}
func (c *modCmd) initConfig(failOnNoConfig bool) (*commandeer, error) {
com, err := initializeConfig(failOnNoConfig, false, &c.hugoBuilderCommon, c, nil)
if err != nil {
return nil, err
}
return com, nil
}
+6 -8
View File
@@ -53,12 +53,10 @@ Ensure you run this within the root directory of your site.`,
cc := &newCmd{baseBuilderCmd: b.newBuilderCmd(cmd)}
cmd.Flags().StringVarP(&cc.contentType, "kind", "k", "", "content type to create")
cmd.PersistentFlags().StringVarP(&cc.source, "source", "s", "", "filesystem path to read files relative from")
cmd.PersistentFlags().SetAnnotation("source", cobra.BashCompSubdirsInDir, []string{})
cmd.Flags().StringVar(&cc.contentEditor, "editor", "", "edit new content with this editor, if provided")
cmd.AddCommand(newNewSiteCmd().getCommand())
cmd.AddCommand(newNewThemeCmd().getCommand())
cmd.AddCommand(b.newNewSiteCmd().getCommand())
cmd.AddCommand(b.newNewThemeCmd().getCommand())
cmd.RunE = cc.newContent
@@ -87,13 +85,13 @@ func (n *newCmd) newContent(cmd *cobra.Command, args []string) error {
var kind string
createPath, kind = newContentPathSection(c.hugo, createPath)
createPath, kind = newContentPathSection(c.hugo(), createPath)
if n.contentType != "" {
kind = n.contentType
}
return create.NewContent(c.hugo, kind, createPath)
return create.NewContent(c.hugo(), kind, createPath)
}
func mkdir(x ...string) {
@@ -120,8 +118,8 @@ func newContentPathSection(h *hugolib.HugoSites, path string) (string, string) {
createpath := filepath.FromSlash(path)
if h != nil {
for _, s := range h.Sites {
createpath = strings.TrimPrefix(createpath, s.PathSpec.ContentDir)
for _, dir := range h.BaseFs.Content.Dirs {
createpath = strings.TrimPrefix(createpath, dir.Meta().Filename())
}
}
+4 -103
View File
@@ -17,112 +17,13 @@ import (
"path/filepath"
"testing"
"github.com/gohugoio/hugo/hugofs"
"github.com/spf13/viper"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
qt "github.com/frankban/quicktest"
)
// Issue #1133
func TestNewContentPathSectionWithForwardSlashes(t *testing.T) {
c := qt.New(t)
p, s := newContentPathSection(nil, "/post/new.md")
assert.Equal(t, filepath.FromSlash("/post/new.md"), p)
assert.Equal(t, "post", s)
}
func checkNewSiteInited(fs *hugofs.Fs, basepath string, t *testing.T) {
paths := []string{
filepath.Join(basepath, "layouts"),
filepath.Join(basepath, "content"),
filepath.Join(basepath, "archetypes"),
filepath.Join(basepath, "static"),
filepath.Join(basepath, "data"),
filepath.Join(basepath, "config.toml"),
}
for _, path := range paths {
_, err := fs.Source.Stat(path)
require.NoError(t, err)
}
}
func TestDoNewSite(t *testing.T) {
n := newNewSiteCmd()
basepath := filepath.Join("base", "blog")
_, fs := newTestCfg()
require.NoError(t, n.doNewSite(fs, basepath, false))
checkNewSiteInited(fs, basepath, t)
}
func TestDoNewSite_noerror_base_exists_but_empty(t *testing.T) {
basepath := filepath.Join("base", "blog")
_, fs := newTestCfg()
n := newNewSiteCmd()
require.NoError(t, fs.Source.MkdirAll(basepath, 0777))
require.NoError(t, n.doNewSite(fs, basepath, false))
}
func TestDoNewSite_error_base_exists(t *testing.T) {
basepath := filepath.Join("base", "blog")
_, fs := newTestCfg()
n := newNewSiteCmd()
require.NoError(t, fs.Source.MkdirAll(basepath, 0777))
_, err := fs.Source.Create(filepath.Join(basepath, "foo"))
require.NoError(t, err)
// Since the directory already exists and isn't empty, expect an error
require.Error(t, n.doNewSite(fs, basepath, false))
}
func TestDoNewSite_force_empty_dir(t *testing.T) {
basepath := filepath.Join("base", "blog")
_, fs := newTestCfg()
n := newNewSiteCmd()
require.NoError(t, fs.Source.MkdirAll(basepath, 0777))
require.NoError(t, n.doNewSite(fs, basepath, true))
checkNewSiteInited(fs, basepath, t)
}
func TestDoNewSite_error_force_dir_inside_exists(t *testing.T) {
basepath := filepath.Join("base", "blog")
_, fs := newTestCfg()
n := newNewSiteCmd()
contentPath := filepath.Join(basepath, "content")
require.NoError(t, fs.Source.MkdirAll(contentPath, 0777))
require.Error(t, n.doNewSite(fs, basepath, true))
}
func TestDoNewSite_error_force_config_inside_exists(t *testing.T) {
basepath := filepath.Join("base", "blog")
_, fs := newTestCfg()
n := newNewSiteCmd()
configPath := filepath.Join(basepath, "config.toml")
require.NoError(t, fs.Source.MkdirAll(basepath, 0777))
_, err := fs.Source.Create(configPath)
require.NoError(t, err)
require.Error(t, n.doNewSite(fs, basepath, true))
}
func newTestCfg() (*viper.Viper, *hugofs.Fs) {
v := viper.New()
fs := hugofs.NewMem(v)
v.SetFs(fs.Source)
return v, fs
c.Assert(p, qt.Equals, filepath.FromSlash("/post/new.md"))
c.Assert(s, qt.Equals, "post")
}
+9 -9
View File
@@ -37,11 +37,11 @@ var _ cmder = (*newSiteCmd)(nil)
type newSiteCmd struct {
configFormat string
*baseCmd
*baseBuilderCmd
}
func newNewSiteCmd() *newSiteCmd {
ccmd := &newSiteCmd{}
func (b *commandsBuilder) newNewSiteCmd() *newSiteCmd {
cc := &newSiteCmd{}
cmd := &cobra.Command{
Use: "site [path]",
@@ -49,15 +49,15 @@ func newNewSiteCmd() *newSiteCmd {
Long: `Create a new site in the provided directory.
The new site will have the correct structure, but no content or theme yet.
Use ` + "`hugo new [contentPath]`" + ` to create new content.`,
RunE: ccmd.newSite,
RunE: cc.newSite,
}
cmd.Flags().StringVarP(&ccmd.configFormat, "format", "f", "toml", "config & frontmatter format")
cmd.Flags().StringVarP(&cc.configFormat, "format", "f", "toml", "config & frontmatter format")
cmd.Flags().Bool("force", false, "init inside non-empty directory")
ccmd.baseCmd = newBaseCmd(cmd)
cc.baseBuilderCmd = b.newBuilderBasicCmd(cmd)
return ccmd
return cc
}
@@ -81,7 +81,7 @@ func (n *newSiteCmd) doNewSite(fs *hugofs.Fs, basepath string, force bool) error
switch {
case !isEmpty && !force:
return errors.New(basepath + " already exists and is not empty")
return errors.New(basepath + " already exists and is not empty. See --force.")
case !isEmpty && force:
all := append(dirs, filepath.Join(basepath, "config."+n.configFormat))
@@ -149,7 +149,7 @@ func nextStepsText() string {
nextStepsText.WriteString(`Just a few more steps and you're ready to go:
1. Download a theme into the same-named folder.
Choose a theme from https://themes.gohugo.io/, or
Choose a theme from https://themes.gohugo.io/ or
create your own with the "hugo new theme <THEMENAME>" command.
2. Perhaps you want to add some content. You can add single files
with "hugo new `)
+8 -9
View File
@@ -29,12 +29,11 @@ import (
var _ cmder = (*newThemeCmd)(nil)
type newThemeCmd struct {
*baseCmd
hugoBuilderCommon
*baseBuilderCmd
}
func newNewThemeCmd() *newThemeCmd {
ccmd := &newThemeCmd{baseCmd: newBaseCmd(nil)}
func (b *commandsBuilder) newNewThemeCmd() *newThemeCmd {
cc := &newThemeCmd{}
cmd := &cobra.Command{
Use: "theme [name]",
@@ -43,12 +42,12 @@ func newNewThemeCmd() *newThemeCmd {
New theme is a skeleton. Please add content to the touched files. Add your
name to the copyright line in the license and adjust the theme.toml file
as you see fit.`,
RunE: ccmd.newTheme,
RunE: cc.newTheme,
}
ccmd.cmd = cmd
cc.baseBuilderCmd = b.newBuilderBasicCmd(cmd)
return ccmd
return cc
}
// newTheme creates a new Hugo theme template
@@ -63,7 +62,7 @@ func (n *newThemeCmd) newTheme(cmd *cobra.Command, args []string) error {
return newUserError("theme name needs to be provided")
}
createpath := c.hugo.PathSpec.AbsPathify(filepath.Join(c.Cfg.GetString("themesDir"), args[0]))
createpath := c.hugo().PathSpec.AbsPathify(filepath.Join(c.Cfg.GetString("themesDir"), args[0]))
jww.FEEDBACK.Println("Creating theme at", createpath)
cfg := c.DepsCfg
@@ -157,7 +156,7 @@ description = ""
homepage = "http://example.com/"
tags = []
features = []
min_version = "0.41"
min_version = "0.41.0"
[author]
name = ""
+41 -26
View File
@@ -16,6 +16,7 @@ package commands
import (
"bytes"
"fmt"
"io"
"net"
"net/http"
"net/url"
@@ -33,7 +34,6 @@ import (
"github.com/pkg/errors"
"github.com/gohugoio/hugo/livereload"
"github.com/gohugoio/hugo/tpl"
"github.com/gohugoio/hugo/config"
"github.com/gohugoio/hugo/helpers"
@@ -244,7 +244,7 @@ func (sc *serverCmd) server(cmd *cobra.Command, args []string) error {
return err
}
for _, s := range c.hugo.Sites {
for _, s := range c.hugo().Sites {
s.RegisterMediaTypes()
}
@@ -256,15 +256,11 @@ func (sc *serverCmd) server(cmd *cobra.Command, args []string) error {
return err
}
baseWatchDir := c.Cfg.GetString("workingDir")
relWatchDirs := make([]string, len(watchDirs))
for i, dir := range watchDirs {
relWatchDirs[i], _ = helpers.GetRelativePath(dir, baseWatchDir)
watchGroups := helpers.ExtractAndGroupRootPaths(watchDirs)
for _, group := range watchGroups {
jww.FEEDBACK.Printf("Watching for changes in %s\n", group)
}
rootWatchDirs := strings.Join(helpers.UniqueStrings(helpers.ExtractRootPaths(relWatchDirs)), ",")
jww.FEEDBACK.Printf("Watching for changes in %s%s{%s}\n", baseWatchDir, helpers.FilePathSeparator, rootWatchDirs)
watcher, err := c.newWatcher(watchDirs...)
if err != nil {
@@ -279,10 +275,19 @@ func (sc *serverCmd) server(cmd *cobra.Command, args []string) error {
}
func getRootWatchDirsStr(baseDir string, watchDirs []string) string {
relWatchDirs := make([]string, len(watchDirs))
for i, dir := range watchDirs {
relWatchDirs[i], _ = helpers.GetRelativePath(dir, baseDir)
}
return strings.Join(helpers.UniqueStringsSorted(helpers.ExtractRootPaths(relWatchDirs)), ",")
}
type fileServer struct {
baseURLs []string
roots []string
errorTemplate tpl.Template
errorTemplate func(err interface{}) (io.Reader, error)
c *commandeer
s *serverCmd
}
@@ -298,9 +303,9 @@ func (f *fileServer) createEndpoint(i int) (*http.ServeMux, string, string, erro
publishDir = filepath.Join(publishDir, root)
}
absPublishDir := f.c.hugo.PathSpec.AbsPathify(publishDir)
absPublishDir := f.c.hugo().PathSpec.AbsPathify(publishDir)
jww.FEEDBACK.Printf("Environment: %q", f.c.hugo.Deps.Site.Hugo().Environment)
jww.FEEDBACK.Printf("Environment: %q", f.c.hugo().Deps.Site.Hugo().Environment)
if i == 0 {
if f.s.renderToDisk {
@@ -329,17 +334,18 @@ func (f *fileServer) createEndpoint(i int) (*http.ServeMux, string, string, erro
// First check the error state
err := f.c.getErrorWithContext()
if err != nil {
f.c.wasError = true
w.WriteHeader(500)
var b bytes.Buffer
err := f.errorTemplate.Execute(&b, err)
r, err := f.errorTemplate(err)
if err != nil {
f.c.logger.ERROR.Println(err)
}
port = 1313
if !f.c.paused {
port = f.c.Cfg.GetInt("liveReloadPort")
}
fmt.Fprint(w, injectLiveReloadScript(&b, port))
fmt.Fprint(w, injectLiveReloadScript(r, port))
return
}
@@ -350,8 +356,13 @@ func (f *fileServer) createEndpoint(i int) (*http.ServeMux, string, string, erro
w.Header().Set("Pragma", "no-cache")
}
for _, header := range f.c.serverConfig.Match(r.RequestURI) {
w.Header().Set(header.Key, header.Value)
}
if f.c.fastRenderMode && f.c.buildErr == nil {
p := r.RequestURI
p := strings.TrimSuffix(r.RequestURI, "?"+r.URL.RawQuery)
if strings.HasSuffix(p, "/") || strings.HasSuffix(p, "html") || strings.HasSuffix(p, "htm") {
if !f.c.visitedURLs.Contains(p) {
// If not already on stack, re-render that single page.
@@ -393,7 +404,7 @@ func removeErrorPrefixFromLog(content string) string {
}
func (c *commandeer) serve(s *serverCmd) error {
isMultiHost := c.hugo.IsMultihost()
isMultiHost := c.hugo().IsMultihost()
var (
baseURLs []string
@@ -401,27 +412,31 @@ func (c *commandeer) serve(s *serverCmd) error {
)
if isMultiHost {
for _, s := range c.hugo.Sites {
for _, s := range c.hugo().Sites {
baseURLs = append(baseURLs, s.BaseURL.String())
roots = append(roots, s.Language().Lang)
}
} else {
s := c.hugo.Sites[0]
s := c.hugo().Sites[0]
baseURLs = []string{s.BaseURL.String()}
roots = []string{""}
}
templ, err := c.hugo.TextTmpl.Parse("__default_server_error", buildErrorTemplate)
templ, err := c.hugo().TextTmpl().Parse("__default_server_error", buildErrorTemplate)
if err != nil {
return err
}
srv := &fileServer{
baseURLs: baseURLs,
roots: roots,
c: c,
s: s,
errorTemplate: templ,
baseURLs: baseURLs,
roots: roots,
c: c,
s: s,
errorTemplate: func(ctx interface{}) (io.Reader, error) {
b := &bytes.Buffer{}
err := c.hugo().Tmpl().Execute(templ, b, ctx)
return b, err
},
}
doLiveReload := !c.Cfg.GetBool("disableLiveReload")
+5 -9
View File
@@ -30,8 +30,7 @@ var buildErrorTemplate = `<!doctype html>
body {
font-family: "Muli",avenir, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
font-size: 16px;
background-color: black;
color: rgba(255, 255, 255, 0.9);
background-color: #2f1e2e;
}
main {
margin: auto;
@@ -43,7 +42,7 @@ var buildErrorTemplate = `<!doctype html>
padding: 1rem 0;
}
.stack {
margin-top: 6rem;
margin-top: 4rem;
}
pre {
white-space: pre-wrap;
@@ -54,10 +53,7 @@ var buildErrorTemplate = `<!doctype html>
}
.highlight {
overflow-x: auto;
padding: 0.75rem;
margin-bottom: 1rem;
background-color: #272822;
border: 1px solid black;
}
a {
color: #0594cb;
@@ -70,14 +66,14 @@ var buildErrorTemplate = `<!doctype html>
</head>
<body>
<main>
{{ highlight .Error "apl" "noclasses=true,style=monokai" }}
{{ highlight .Error "apl" "linenos=false,noclasses=true,style=paraiso-dark" }}
{{ with .File }}
{{ $params := printf "noclasses=true,style=monokai,linenos=table,hl_lines=%d,linenostart=%d" (add .LinesPos 1) (sub .Position.LineNumber .LinesPos) }}
{{ $params := printf "noclasses=true,style=paraiso-dark,linenos=table,hl_lines=%d,linenostart=%d" (add .LinesPos 1) (sub .Position.LineNumber .LinesPos) }}
{{ $lexer := .ChromaLexer | default "go-html-template" }}
{{ highlight (delimit .Lines "\n") $lexer $params }}
{{ end }}
{{ with .StackTrace }}
{{ highlight . "apl" "noclasses=true,style=monokai" }}
{{ highlight . "apl" "noclasses=true,style=paraiso-dark" }}
{{ end }}
<p class="version">{{ .Version }}</p>
<a href="">Reload Page</a>
+11 -10
View File
@@ -24,8 +24,8 @@ import (
"github.com/gohugoio/hugo/helpers"
qt "github.com/frankban/quicktest"
"github.com/spf13/viper"
"github.com/stretchr/testify/require"
)
func TestServer(t *testing.T) {
@@ -33,9 +33,10 @@ func TestServer(t *testing.T) {
// TODO(bep) not sure why server tests have started to fail on the Windows CI server.
t.Skip("Skip server test on appveyor")
}
assert := require.New(t)
dir, err := createSimpleTestSite(t, testSiteConfig{})
assert.NoError(err)
c := qt.New(t)
dir, clean, err := createSimpleTestSite(t, testSiteConfig{})
defer clean()
c.Assert(err, qt.IsNil)
// Let us hope that this port is available on all systems ...
port := 1331
@@ -54,7 +55,7 @@ func TestServer(t *testing.T) {
go func() {
_, err = cmd.ExecuteC()
assert.NoError(err)
c.Assert(err, qt.IsNil)
}()
// There is no way to know exactly when the server is ready for connections.
@@ -63,12 +64,12 @@ func TestServer(t *testing.T) {
time.Sleep(2 * time.Second)
resp, err := http.Get("http://localhost:1331/")
assert.NoError(err)
c.Assert(err, qt.IsNil)
defer resp.Body.Close()
homeContent := helpers.ReaderToString(resp.Body)
assert.Contains(homeContent, "List: Hugo Commands")
assert.Contains(homeContent, "Environment: development")
c.Assert(homeContent, qt.Contains, "List: Hugo Commands")
c.Assert(homeContent, qt.Contains, "Environment: development")
// Stop the server.
stop <- true
@@ -118,14 +119,14 @@ func TestFixURL(t *testing.T) {
}
func TestRemoveErrorPrefixFromLog(t *testing.T) {
assert := require.New(t)
c := qt.New(t)
content := `ERROR 2018/10/07 13:11:12 Error while rendering "home": template: _default/baseof.html:4:3: executing "main" at <partial "logo" .>: error calling partial: template: partials/logo.html:5:84: executing "partials/logo.html" at <$resized.AHeight>: can't evaluate field AHeight in type *resource.Image
ERROR 2018/10/07 13:11:12 Rebuild failed: logged 1 error(s)
`
withoutError := removeErrorPrefixFromLog(content)
assert.False(strings.Contains(withoutError, "ERROR"), withoutError)
c.Assert(strings.Contains(withoutError, "ERROR"), qt.Equals, false)
}
+4 -2
View File
@@ -33,14 +33,14 @@ func newStaticSyncer(c *commandeer) (*staticSyncer, error) {
}
func (s *staticSyncer) isStatic(filename string) bool {
return s.c.hugo.BaseFs.SourceFilesystems.IsStatic(filename)
return s.c.hugo().BaseFs.SourceFilesystems.IsStatic(filename)
}
func (s *staticSyncer) syncsStaticEvents(staticEvents []fsnotify.Event) error {
c := s.c
syncFn := func(sourceFs *filesystems.SourceFilesystem) (uint64, error) {
publishDir := c.hugo.PathSpec.PublishDir
publishDir := c.hugo().PathSpec.PublishDir
// If root, remove the second '/'
if publishDir == "//" {
publishDir = helpers.FilePathSeparator
@@ -53,6 +53,7 @@ func (s *staticSyncer) syncsStaticEvents(staticEvents []fsnotify.Event) error {
syncer := fsync.NewSyncer()
syncer.NoTimes = c.Cfg.GetBool("noTimes")
syncer.NoChmod = c.Cfg.GetBool("noChmod")
syncer.ChmodFilter = chmodFilter
syncer.SrcFs = sourceFs.Fs
syncer.DestFs = c.Fs.Destination
@@ -79,6 +80,7 @@ func (s *staticSyncer) syncsStaticEvents(staticEvents []fsnotify.Event) error {
fromPath := ev.Name
relPath := sourceFs.MakePathRelative(fromPath)
if relPath == "" {
// Not member of this virtual host.
continue
+1
View File
@@ -65,6 +65,7 @@ func Append(to interface{}, from ...interface{}) (interface{}, error) {
fv := reflect.ValueOf(f)
if !fv.Type().AssignableTo(tot) {
// Fall back to a []interface{} slice.
tov, _ := indirect(reflect.ValueOf(to))
return appendToInterfaceSlice(tov, from...)
}
tov = reflect.Append(tov, fv)
+9 -12
View File
@@ -14,17 +14,17 @@
package collections
import (
"fmt"
"reflect"
"html/template"
"testing"
"github.com/stretchr/testify/require"
qt "github.com/frankban/quicktest"
)
func TestAppend(t *testing.T) {
t.Parallel()
c := qt.New(t)
for i, test := range []struct {
for _, test := range []struct {
start interface{}
addend []interface{}
expected interface{}
@@ -32,6 +32,7 @@ func TestAppend(t *testing.T) {
{[]string{"a", "b"}, []interface{}{"c"}, []string{"a", "b", "c"}},
{[]string{"a", "b"}, []interface{}{"c", "d", "e"}, []string{"a", "b", "c", "d", "e"}},
{[]string{"a", "b"}, []interface{}{[]string{"c", "d", "e"}}, []string{"a", "b", "c", "d", "e"}},
{[]string{"a"}, []interface{}{"b", template.HTML("c")}, []interface{}{"a", "b", template.HTML("c")}},
{nil, []interface{}{"a", "b"}, []string{"a", "b"}},
{nil, []interface{}{nil}, []interface{}{nil}},
{[]interface{}{}, []interface{}{[]string{"c", "d", "e"}}, []string{"c", "d", "e"}},
@@ -59,20 +60,16 @@ func TestAppend(t *testing.T) {
false},
} {
errMsg := fmt.Sprintf("[%d]", i)
result, err := Append(test.start, test.addend...)
if b, ok := test.expected.(bool); ok && !b {
require.Error(t, err, errMsg)
c.Assert(err, qt.Not(qt.IsNil))
continue
}
require.NoError(t, err, errMsg)
if !reflect.DeepEqual(test.expected, result) {
t.Fatalf("%s got\n%T: %v\nexpected\n%T: %v", errMsg, result, result, test.expected, test.expected)
}
c.Assert(err, qt.IsNil)
c.Assert(result, qt.DeepEquals, test.expected)
}
}
+9 -10
View File
@@ -15,10 +15,9 @@ package collections
import (
"errors"
"fmt"
"testing"
"github.com/alecthomas/assert"
qt "github.com/frankban/quicktest"
)
var _ Slicer = (*tstSlicer)(nil)
@@ -34,15 +33,15 @@ type testSlicerInterface interface {
type testSlicerInterfaces []testSlicerInterface
type tstSlicerIn1 struct {
name string
TheName string
}
type tstSlicerIn2 struct {
name string
TheName string
}
type tstSlicer struct {
name string
TheName string
}
func (p *tstSlicerIn1) Slice(in interface{}) (interface{}, error) {
@@ -75,11 +74,11 @@ func (p *tstSlicerIn2) Slice(in interface{}) (interface{}, error) {
}
func (p *tstSlicerIn1) Name() string {
return p.name
return p.TheName
}
func (p *tstSlicerIn2) Name() string {
return p.name
return p.TheName
}
func (p *tstSlicer) Slice(in interface{}) (interface{}, error) {
@@ -100,6 +99,7 @@ type tstSlicers []*tstSlicer
func TestSlice(t *testing.T) {
t.Parallel()
c := qt.New(t)
for i, test := range []struct {
args []interface{}
@@ -114,12 +114,11 @@ func TestSlice(t *testing.T) {
{[]interface{}{&tstSlicerIn1{"a"}, &tstSlicerIn2{"b"}}, testSlicerInterfaces{&tstSlicerIn1{"a"}, &tstSlicerIn2{"b"}}},
{[]interface{}{&tstSlicerIn1{"a"}, &tstSlicer{"b"}}, []interface{}{&tstSlicerIn1{"a"}, &tstSlicer{"b"}}},
} {
errMsg := fmt.Sprintf("[%d] %v", i, test.args)
errMsg := qt.Commentf("[%d] %v", i, test.args)
result := Slice(test.args...)
assert.Equal(t, test.expected, result, errMsg)
c.Assert(test.expected, qt.DeepEquals, result, errMsg)
}
assert.Len(t, Slice(), 0)
}
+2 -2
View File
@@ -11,7 +11,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// Package errors contains common Hugo errors and error related utilities.
// Package herrors contains common Hugo errors and error related utilities.
package herrors
import (
@@ -206,7 +206,7 @@ func locateError(r io.Reader, le FileError, matches LineMatcherFn) ErrorContext
lines := strings.Split(string(b), "\n")
if le != nil && lepos.ColumnNumber >= 0 {
if lepos.ColumnNumber >= 0 {
pos.ColumnNumber = lepos.ColumnNumber
}
+28 -28
View File
@@ -11,18 +11,18 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// Package errors contains common Hugo errors and error related utilities.
// Package herrors contains common Hugo errors and error related utilities.
package herrors
import (
"strings"
"testing"
"github.com/stretchr/testify/require"
qt "github.com/frankban/quicktest"
)
func TestErrorLocator(t *testing.T) {
assert := require.New(t)
c := qt.New(t)
lineMatcher := func(m LineMatcher) bool {
return strings.Contains(m.Line, "THEONE")
@@ -39,45 +39,45 @@ LINE 8
`
location := locateErrorInString(lines, lineMatcher)
assert.Equal([]string{"LINE 3", "LINE 4", "This is THEONE", "LINE 6", "LINE 7"}, location.Lines)
c.Assert(location.Lines, qt.DeepEquals, []string{"LINE 3", "LINE 4", "This is THEONE", "LINE 6", "LINE 7"})
pos := location.Position()
assert.Equal(5, pos.LineNumber)
assert.Equal(2, location.LinesPos)
c.Assert(pos.LineNumber, qt.Equals, 5)
c.Assert(location.LinesPos, qt.Equals, 2)
assert.Equal([]string{"This is THEONE"}, locateErrorInString(`This is THEONE`, lineMatcher).Lines)
c.Assert(locateErrorInString(`This is THEONE`, lineMatcher).Lines, qt.DeepEquals, []string{"This is THEONE"})
location = locateErrorInString(`L1
This is THEONE
L2
`, lineMatcher)
assert.Equal(2, location.Position().LineNumber)
assert.Equal(1, location.LinesPos)
assert.Equal([]string{"L1", "This is THEONE", "L2", ""}, location.Lines)
c.Assert(location.Position().LineNumber, qt.Equals, 2)
c.Assert(location.LinesPos, qt.Equals, 1)
c.Assert(location.Lines, qt.DeepEquals, []string{"L1", "This is THEONE", "L2", ""})
location = locateErrorInString(`This is THEONE
L2
`, lineMatcher)
assert.Equal(0, location.LinesPos)
assert.Equal([]string{"This is THEONE", "L2", ""}, location.Lines)
c.Assert(location.LinesPos, qt.Equals, 0)
c.Assert(location.Lines, qt.DeepEquals, []string{"This is THEONE", "L2", ""})
location = locateErrorInString(`L1
This THEONE
`, lineMatcher)
assert.Equal([]string{"L1", "This THEONE", ""}, location.Lines)
assert.Equal(1, location.LinesPos)
c.Assert(location.Lines, qt.DeepEquals, []string{"L1", "This THEONE", ""})
c.Assert(location.LinesPos, qt.Equals, 1)
location = locateErrorInString(`L1
L2
This THEONE
`, lineMatcher)
assert.Equal([]string{"L1", "L2", "This THEONE", ""}, location.Lines)
assert.Equal(2, location.LinesPos)
c.Assert(location.Lines, qt.DeepEquals, []string{"L1", "L2", "This THEONE", ""})
c.Assert(location.LinesPos, qt.Equals, 2)
location = locateErrorInString("NO MATCH", lineMatcher)
assert.Equal(-1, location.Position().LineNumber)
assert.Equal(-1, location.LinesPos)
assert.Equal(0, len(location.Lines))
c.Assert(location.Position().LineNumber, qt.Equals, -1)
c.Assert(location.LinesPos, qt.Equals, -1)
c.Assert(len(location.Lines), qt.Equals, 0)
lineMatcher = func(m LineMatcher) bool {
return m.LineNumber == 6
@@ -94,9 +94,9 @@ H
I
J`, lineMatcher)
assert.Equal([]string{"D", "E", "F", "G", "H"}, location.Lines)
assert.Equal(6, location.Position().LineNumber)
assert.Equal(2, location.LinesPos)
c.Assert(location.Lines, qt.DeepEquals, []string{"D", "E", "F", "G", "H"})
c.Assert(location.Position().LineNumber, qt.Equals, 6)
c.Assert(location.LinesPos, qt.Equals, 2)
// Test match EOF
lineMatcher = func(m LineMatcher) bool {
@@ -108,9 +108,9 @@ B
C
`, lineMatcher)
assert.Equal([]string{"B", "C", ""}, location.Lines)
assert.Equal(4, location.Position().LineNumber)
assert.Equal(2, location.LinesPos)
c.Assert(location.Lines, qt.DeepEquals, []string{"B", "C", ""})
c.Assert(location.Position().LineNumber, qt.Equals, 4)
c.Assert(location.LinesPos, qt.Equals, 2)
offsetMatcher := func(m LineMatcher) bool {
return m.Offset == 1
@@ -122,8 +122,8 @@ C
D
E`, offsetMatcher)
assert.Equal([]string{"A", "B", "C", "D"}, location.Lines)
assert.Equal(2, location.Position().LineNumber)
assert.Equal(1, location.LinesPos)
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)
}
+42 -5
View File
@@ -15,10 +15,14 @@
package herrors
import (
"bytes"
"errors"
"fmt"
"io"
"os"
"runtime"
"runtime/debug"
"strconv"
_errors "github.com/pkg/errors"
)
@@ -32,13 +36,13 @@ type stackTracer interface {
StackTrace() _errors.StackTrace
}
// PrintStackTrace prints the error's stack trace to stdoud.
func PrintStackTrace(err error) {
FprintStackTrace(os.Stdout, err)
// PrintStackTraceFromErr prints the error's stack trace to stdoud.
func PrintStackTraceFromErr(err error) {
FprintStackTraceFromErr(os.Stdout, err)
}
// FprintStackTrace prints the error's stack trace to w.
func FprintStackTrace(w io.Writer, err error) {
// FprintStackTraceFromErr prints the error's stack trace to w.
func FprintStackTraceFromErr(w io.Writer, err error) {
if err, ok := err.(stackTracer); ok {
for _, f := range err.StackTrace() {
fmt.Fprintf(w, "%+s:%d\n", f, f)
@@ -46,6 +50,39 @@ func FprintStackTrace(w io.Writer, err error) {
}
}
// PrintStackTrace prints the current stacktrace to w.
func PrintStackTrace(w io.Writer) {
buf := make([]byte, 1<<16)
runtime.Stack(buf, true)
fmt.Fprintf(w, "%s", buf)
}
// ErrorSender is a, typically, non-blocking error handler.
type ErrorSender interface {
SendError(err error)
}
// Recover is a helper function that can be used to capture panics.
// Put this at the top of a method/function that crashes in a template:
// defer herrors.Recover()
func Recover(args ...interface{}) {
if r := recover(); r != nil {
fmt.Println("ERR:", r)
args = append(args, "stacktrace from panic: \n"+string(debug.Stack()), "\n")
fmt.Println(args...)
}
}
// Get the current goroutine id. Used only for debugging.
func GetGID() uint64 {
b := make([]byte, 64)
b = b[:runtime.Stack(b, false)]
b = bytes.TrimPrefix(b, []byte("goroutine "))
b = b[:bytes.IndexByte(b, ' ')]
n, _ := strconv.ParseUint(string(b), 10, 64)
return n
}
// ErrFeatureNotAvailable denotes that a feature is unavailable.
//
// We will, at least to begin with, make some Hugo features (SCSS with libsass) optional,
+1 -1
View File
@@ -9,7 +9,7 @@
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitatio ns under the License.
// limitations under the License.
package herrors
+8 -9
View File
@@ -14,18 +14,17 @@
package herrors
import (
"fmt"
"testing"
"github.com/pkg/errors"
"github.com/stretchr/testify/require"
qt "github.com/frankban/quicktest"
)
func TestToLineNumberError(t *testing.T) {
t.Parallel()
assert := require.New(t)
c := qt.New(t)
for i, test := range []struct {
in error
@@ -43,15 +42,15 @@ func TestToLineNumberError(t *testing.T) {
got := ToFileError("template", test.in)
errMsg := fmt.Sprintf("[%d][%T]", i, got)
errMsg := qt.Commentf("[%d][%T]", i, got)
le, ok := got.(FileError)
assert.True(ok)
c.Assert(ok, qt.Equals, true)
assert.True(ok, errMsg)
c.Assert(ok, qt.Equals, true, errMsg)
pos := le.Position()
assert.Equal(test.lineNumber, pos.LineNumber, errMsg)
assert.Equal(test.columnNumber, pos.ColumnNumber, errMsg)
assert.Error(errors.Cause(got))
c.Assert(pos.LineNumber, qt.Equals, test.lineNumber, errMsg)
c.Assert(pos.ColumnNumber, qt.Equals, test.columnNumber, errMsg)
c.Assert(errors.Cause(got), qt.Not(qt.IsNil))
}
}
+1 -1
View File
@@ -9,7 +9,7 @@
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitatio ns under the License.
// limitations under the License.
package herrors
+6 -6
View File
@@ -18,16 +18,16 @@ import (
"testing"
"time"
"github.com/stretchr/testify/require"
qt "github.com/frankban/quicktest"
)
func TestIsTruthful(t *testing.T) {
assert := require.New(t)
c := qt.New(t)
assert.True(IsTruthful(true))
assert.False(IsTruthful(false))
assert.True(IsTruthful(time.Now()))
assert.False(IsTruthful(time.Time{}))
c.Assert(IsTruthful(true), qt.Equals, true)
c.Assert(IsTruthful(false), qt.Equals, false)
c.Assert(IsTruthful(time.Now()), qt.Equals, true)
c.Assert(IsTruthful(time.Time{}), qt.Equals, false)
}
func BenchmarkIsTruthFul(b *testing.B) {
+90
View File
@@ -0,0 +1,90 @@
// Copyright 2019 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package hugio
import (
"io"
"io/ioutil"
"os"
"path/filepath"
"github.com/pkg/errors"
"github.com/spf13/afero"
)
// CopyFile copies a file.
func CopyFile(fs afero.Fs, from, to string) error {
sf, err := os.Open(from)
if err != nil {
return err
}
defer sf.Close()
df, err := os.Create(to)
if err != nil {
return err
}
defer df.Close()
_, err = io.Copy(df, sf)
if err == nil {
si, err := os.Stat(from)
if err != nil {
err = os.Chmod(to, si.Mode())
if err != nil {
return err
}
}
}
return nil
}
// CopyDir copies a directory.
func CopyDir(fs afero.Fs, from, to string, shouldCopy func(filename string) bool) error {
fi, err := os.Stat(from)
if err != nil {
return err
}
if !fi.IsDir() {
return errors.Errorf("%q is not a directory", from)
}
err = fs.MkdirAll(to, 0777) // before umask
if err != nil {
return err
}
entries, _ := ioutil.ReadDir(from)
for _, entry := range entries {
fromFilename := filepath.Join(from, entry.Name())
toFilename := filepath.Join(to, entry.Name())
if entry.IsDir() {
if shouldCopy != nil && !shouldCopy(fromFilename) {
continue
}
if err := CopyDir(fs, fromFilename, toFilename, shouldCopy); err != nil {
return err
}
} else {
if err := CopyFile(fs, fromFilename, toFilename); err != nil {
return err
}
}
}
return nil
}
+13
View File
@@ -16,6 +16,9 @@ package hugo
import (
"fmt"
"html/template"
"os"
"github.com/gohugoio/hugo/config"
)
const (
@@ -54,6 +57,10 @@ func (i Info) Generator() template.HTML {
return template.HTML(fmt.Sprintf(`<meta name="generator" content="Hugo %s" />`, CurrentVersion.String()))
}
func (i Info) IsProduction() bool {
return i.Environment == EnvironmentProduction
}
// NewInfo creates a new Hugo Info object.
func NewInfo(environment string) Info {
if environment == "" {
@@ -65,3 +72,9 @@ func NewInfo(environment string) Info {
Environment: environment,
}
}
func GetExecEnviron(cfg config.Provider) []string {
env := os.Environ()
config.SetEnvVars(&env, "HUGO_ENVIRONMENT", cfg.GetString("environment"))
return env
}
+12 -8
View File
@@ -17,19 +17,23 @@ import (
"fmt"
"testing"
"github.com/stretchr/testify/require"
qt "github.com/frankban/quicktest"
)
func TestHugoInfo(t *testing.T) {
assert := require.New(t)
c := qt.New(t)
hugoInfo := NewInfo("")
assert.Equal(CurrentVersion.Version(), hugoInfo.Version())
assert.IsType(VersionString(""), hugoInfo.Version())
assert.Equal(commitHash, hugoInfo.CommitHash)
assert.Equal(buildDate, hugoInfo.BuildDate)
assert.Equal("production", hugoInfo.Environment)
assert.Contains(hugoInfo.Generator(), fmt.Sprintf("Hugo %s", hugoInfo.Version()))
c.Assert(hugoInfo.Version(), qt.Equals, CurrentVersion.Version())
c.Assert(fmt.Sprintf("%T", VersionString("")), qt.Equals, fmt.Sprintf("%T", hugoInfo.Version()))
c.Assert(hugoInfo.CommitHash, qt.Equals, commitHash)
c.Assert(hugoInfo.BuildDate, qt.Equals, buildDate)
c.Assert(hugoInfo.Environment, qt.Equals, "production")
c.Assert(string(hugoInfo.Generator()), qt.Contains, fmt.Sprintf("Hugo %s", hugoInfo.Version()))
c.Assert(hugoInfo.IsProduction(), qt.Equals, true)
devHugoInfo := NewInfo("development")
c.Assert(devHugoInfo.IsProduction(), qt.Equals, false)
}
+1 -1
View File
@@ -15,4 +15,4 @@
package hugo
var isExtended = true
var IsExtended = true
+1 -1
View File
@@ -15,4 +15,4 @@
package hugo
var isExtended = false
var IsExtended = false
+23 -1
View File
@@ -15,6 +15,7 @@ package hugo
import (
"fmt"
"io"
"runtime"
"strings"
@@ -133,7 +134,7 @@ func BuildVersionString() string {
if commitHash != "" {
version += "-" + strings.ToUpper(commitHash)
}
if isExtended {
if IsExtended {
version += "/extended"
}
@@ -235,3 +236,24 @@ func compareFloatVersions(version float32, v float32) int {
}
return 1
}
func GoMinorVersion() int {
return goMinorVersion(runtime.Version())
}
func goMinorVersion(version string) int {
if strings.HasPrefix(version, "devel") {
return 9999 // magic
}
var major, minor int
var trailing string
n, err := fmt.Sscanf(version, "go%d.%d%s", &major, &minor, &trailing)
if n == 2 && err == io.EOF {
// Means there were no trailing characters (i.e., not an alpha/beta)
err = nil
}
if err != nil {
return 0
}
return minor
}
+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.55,
PatchLevel: 3,
Number: 0.71,
PatchLevel: 1,
Suffix: "",
}
+50 -40
View File
@@ -16,64 +16,74 @@ package hugo
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
qt "github.com/frankban/quicktest"
)
func TestHugoVersion(t *testing.T) {
assert.Equal(t, "0.15-DEV", version(0.15, 0, "-DEV"))
assert.Equal(t, "0.15.2-DEV", version(0.15, 2, "-DEV"))
c := qt.New(t)
c.Assert(version(0.15, 0, "-DEV"), qt.Equals, "0.15-DEV")
c.Assert(version(0.15, 2, "-DEV"), qt.Equals, "0.15.2-DEV")
v := Version{Number: 0.21, PatchLevel: 0, Suffix: "-DEV"}
require.Equal(t, v.ReleaseVersion().String(), "0.21")
require.Equal(t, "0.21-DEV", v.String())
require.Equal(t, "0.22", v.Next().String())
c.Assert(v.ReleaseVersion().String(), qt.Equals, "0.21")
c.Assert(v.String(), qt.Equals, "0.21-DEV")
c.Assert(v.Next().String(), qt.Equals, "0.22")
nextVersionString := v.Next().Version()
require.Equal(t, "0.22", nextVersionString.String())
require.True(t, nextVersionString.Eq("0.22"))
require.False(t, nextVersionString.Eq("0.21"))
require.True(t, nextVersionString.Eq(nextVersionString))
require.Equal(t, "0.20.3", v.NextPatchLevel(3).String())
c.Assert(nextVersionString.String(), qt.Equals, "0.22")
c.Assert(nextVersionString.Eq("0.22"), qt.Equals, true)
c.Assert(nextVersionString.Eq("0.21"), qt.Equals, false)
c.Assert(nextVersionString.Eq(nextVersionString), qt.Equals, true)
c.Assert(v.NextPatchLevel(3).String(), qt.Equals, "0.20.3")
// We started to use full semver versions even for main
// releases in v0.54.0
v = Version{Number: 0.53, PatchLevel: 0}
require.Equal(t, "0.53", v.String())
require.Equal(t, "0.54.0", v.Next().String())
require.Equal(t, "0.55.0", v.Next().Next().String())
c.Assert(v.String(), qt.Equals, "0.53")
c.Assert(v.Next().String(), qt.Equals, "0.54.0")
c.Assert(v.Next().Next().String(), qt.Equals, "0.55.0")
v = Version{Number: 0.54, PatchLevel: 0, Suffix: "-DEV"}
require.Equal(t, "0.54.0-DEV", v.String())
c.Assert(v.String(), qt.Equals, "0.54.0-DEV")
}
func TestCompareVersions(t *testing.T) {
require.Equal(t, 0, compareVersions(0.20, 0, 0.20))
require.Equal(t, 0, compareVersions(0.20, 0, float32(0.20)))
require.Equal(t, 0, compareVersions(0.20, 0, float64(0.20)))
require.Equal(t, 1, compareVersions(0.19, 1, 0.20))
require.Equal(t, 1, compareVersions(0.19, 3, "0.20.2"))
require.Equal(t, -1, compareVersions(0.19, 1, 0.01))
require.Equal(t, 1, compareVersions(0, 1, 3))
require.Equal(t, 1, compareVersions(0, 1, int32(3)))
require.Equal(t, 1, compareVersions(0, 1, int64(3)))
require.Equal(t, 0, compareVersions(0.20, 0, "0.20"))
require.Equal(t, 0, compareVersions(0.20, 1, "0.20.1"))
require.Equal(t, -1, compareVersions(0.20, 1, "0.20"))
require.Equal(t, 1, compareVersions(0.20, 0, "0.20.1"))
require.Equal(t, 1, compareVersions(0.20, 1, "0.20.2"))
require.Equal(t, 1, compareVersions(0.21, 1, "0.22.1"))
require.Equal(t, -1, compareVersions(0.22, 0, "0.22-DEV"))
require.Equal(t, 1, compareVersions(0.22, 0, "0.22.1-DEV"))
require.Equal(t, 1, compareVersionsWithSuffix(0.22, 0, "-DEV", "0.22"))
require.Equal(t, -1, compareVersionsWithSuffix(0.22, 1, "-DEV", "0.22"))
require.Equal(t, 0, compareVersionsWithSuffix(0.22, 1, "-DEV", "0.22.1-DEV"))
c := qt.New(t)
c.Assert(compareVersions(0.20, 0, 0.20), qt.Equals, 0)
c.Assert(compareVersions(0.20, 0, float32(0.20)), qt.Equals, 0)
c.Assert(compareVersions(0.20, 0, float64(0.20)), qt.Equals, 0)
c.Assert(compareVersions(0.19, 1, 0.20), qt.Equals, 1)
c.Assert(compareVersions(0.19, 3, "0.20.2"), qt.Equals, 1)
c.Assert(compareVersions(0.19, 1, 0.01), qt.Equals, -1)
c.Assert(compareVersions(0, 1, 3), qt.Equals, 1)
c.Assert(compareVersions(0, 1, int32(3)), qt.Equals, 1)
c.Assert(compareVersions(0, 1, int64(3)), qt.Equals, 1)
c.Assert(compareVersions(0.20, 0, "0.20"), qt.Equals, 0)
c.Assert(compareVersions(0.20, 1, "0.20.1"), qt.Equals, 0)
c.Assert(compareVersions(0.20, 1, "0.20"), qt.Equals, -1)
c.Assert(compareVersions(0.20, 0, "0.20.1"), qt.Equals, 1)
c.Assert(compareVersions(0.20, 1, "0.20.2"), qt.Equals, 1)
c.Assert(compareVersions(0.21, 1, "0.22.1"), qt.Equals, 1)
c.Assert(compareVersions(0.22, 0, "0.22-DEV"), qt.Equals, -1)
c.Assert(compareVersions(0.22, 0, "0.22.1-DEV"), qt.Equals, 1)
c.Assert(compareVersionsWithSuffix(0.22, 0, "-DEV", "0.22"), qt.Equals, 1)
c.Assert(compareVersionsWithSuffix(0.22, 1, "-DEV", "0.22"), qt.Equals, -1)
c.Assert(compareVersionsWithSuffix(0.22, 1, "-DEV", "0.22.1-DEV"), qt.Equals, 0)
}
func TestParseHugoVersion(t *testing.T) {
require.Equal(t, "0.25", MustParseVersion("0.25").String())
require.Equal(t, "0.25.2", MustParseVersion("0.25.2").String())
require.Equal(t, "0.25-test", MustParseVersion("0.25-test").String())
require.Equal(t, "0.25-DEV", MustParseVersion("0.25-DEV").String())
c := qt.New(t)
c.Assert(MustParseVersion("0.25").String(), qt.Equals, "0.25")
c.Assert(MustParseVersion("0.25.2").String(), qt.Equals, "0.25.2")
c.Assert(MustParseVersion("0.25-test").String(), qt.Equals, "0.25-test")
c.Assert(MustParseVersion("0.25-DEV").String(), qt.Equals, "0.25-DEV")
}
func TestGoMinorVersion(t *testing.T) {
c := qt.New(t)
c.Assert(goMinorVersion("go1.12.5"), qt.Equals, 12)
c.Assert(goMinorVersion("go1.14rc1"), qt.Equals, 14)
c.Assert(GoMinorVersion() >= 11, qt.Equals, true)
}
+50 -2
View File
@@ -15,11 +15,14 @@ package loggers
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"log"
"os"
"regexp"
"runtime"
"time"
"github.com/gohugoio/hugo/common/terminal"
@@ -39,12 +42,35 @@ func init() {
// Logger wraps a *loggers.Logger and some other related logging state.
type Logger struct {
*jww.Notepad
// The writer that represents stdout.
// Will be ioutil.Discard when in quiet mode.
Out io.Writer
ErrorCounter *jww.Counter
WarnCounter *jww.Counter
// This is only set in server mode.
errors *bytes.Buffer
}
// PrintTimerIfDelayed prints a time statement to the FEEDBACK logger
// if considerable time is spent.
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)
}
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)
}
func (l *Logger) Errors() string {
if l.errors == nil {
return ""
@@ -141,11 +167,32 @@ func getLogWriters(outHandle, logHandle io.Writer) (io.Writer, io.Writer) {
}
type fatalLogWriter int
func (s fatalLogWriter) Write(p []byte) (n int, err error) {
trace := make([]byte, 1500)
runtime.Stack(trace, true)
fmt.Printf("\n===========\n\n%s\n", trace)
os.Exit(-1)
return 0, nil
}
var fatalLogListener = func(t jww.Threshold) io.Writer {
if t != jww.LevelError {
// Only interested in ERROR
return nil
}
return new(fatalLogWriter)
}
func newLogger(stdoutThreshold, logThreshold jww.Threshold, outHandle, logHandle io.Writer, saveErrors bool) *Logger {
errorCounter := &jww.Counter{}
warnCounter := &jww.Counter{}
outHandle, logHandle = getLogWriters(outHandle, logHandle)
listeners := []jww.LogListener{jww.LogCounter(errorCounter, jww.LevelError)}
listeners := []jww.LogListener{jww.LogCounter(errorCounter, jww.LevelError), jww.LogCounter(warnCounter, jww.LevelWarn)}
var errorBuff *bytes.Buffer
if saveErrors {
errorBuff = new(bytes.Buffer)
@@ -154,7 +201,6 @@ func newLogger(stdoutThreshold, logThreshold jww.Threshold, outHandle, logHandle
// Only interested in ERROR
return nil
}
return errorBuff
}
@@ -163,7 +209,9 @@ func newLogger(stdoutThreshold, logThreshold jww.Threshold, outHandle, logHandle
return &Logger{
Notepad: jww.NewNotepad(stdoutThreshold, logThreshold, outHandle, logHandle, "", log.Ldate|log.Ltime, listeners...),
Out: outHandle,
ErrorCounter: errorCounter,
WarnCounter: warnCounter,
errors: errorBuff,
}
}
+3 -3
View File
@@ -16,17 +16,17 @@ package loggers
import (
"testing"
"github.com/stretchr/testify/require"
qt "github.com/frankban/quicktest"
)
func TestLogger(t *testing.T) {
assert := require.New(t)
c := qt.New(t)
l := NewWarningLogger()
l.ERROR.Println("One error")
l.ERROR.Println("Two error")
l.WARN.Println("A warning")
assert.Equal(uint64(2), l.ErrorCounter.Count())
c.Assert(l.ErrorCounter.Count(), qt.Equals, uint64(2))
}
+26 -7
View File
@@ -25,26 +25,45 @@ import (
// recursively.
// Notes:
// * This will modify the map given.
// * Any nested map[interface{}]interface{} will be converted to map[string]interface{}.
func ToLower(m map[string]interface{}) {
// * 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{}:
v = cast.ToStringMap(v)
ToLower(v.(map[string]interface{}))
var p Params = cast.ToStringMap(v)
v = p
ToLower(p)
retyped = true
case map[string]interface{}:
ToLower(v.(map[string]interface{}))
var p Params = v.(map[string]interface{})
v = p
ToLower(p)
retyped = true
}
lKey := strings.ToLower(k)
if k != lKey {
if retyped || k != lKey {
delete(m, k)
m[lKey] = v
}
}
}
func ToStringMapE(in interface{}) (map[string]interface{}, error) {
switch in.(type) {
case Params:
return in.(Params), nil
default:
return cast.ToStringMapE(in)
}
}
func ToStringMap(in interface{}) map[string]interface{} {
m, _ := ToStringMapE(in)
return m
}
type keyRename struct {
pattern glob.Glob
newKey string
+31
View File
@@ -0,0 +1,31 @@
// Copyright 2019 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package maps
import (
"github.com/spf13/cast"
)
// GetString tries to get a value with key from map m and convert it to a string.
// It will return an empty string if not found or if it cannot be convertd to a string.
func GetString(m map[string]interface{}, key string) string {
if m == nil {
return ""
}
v, found := m[key]
if !found {
return ""
}
return cast.ToString(v)
}
+16 -14
View File
@@ -14,14 +14,14 @@
package maps
import (
"fmt"
"reflect"
"testing"
"github.com/stretchr/testify/require"
qt "github.com/frankban/quicktest"
)
func TestToLower(t *testing.T) {
tests := []struct {
input map[string]interface{}
expected map[string]interface{}
@@ -30,7 +30,7 @@ func TestToLower(t *testing.T) {
map[string]interface{}{
"abC": 32,
},
map[string]interface{}{
Params{
"abc": 32,
},
},
@@ -48,16 +48,16 @@ func TestToLower(t *testing.T) {
"J": 25,
},
},
map[string]interface{}{
Params{
"abc": 32,
"def": map[string]interface{}{
"def": Params{
"23": "A value",
"24": map[string]interface{}{
"24": Params{
"abcde": "A value",
"efghi": "Another value",
},
},
"ghi": map[string]interface{}{
"ghi": Params{
"j": 25,
},
},
@@ -65,16 +65,18 @@ func TestToLower(t *testing.T) {
}
for i, test := range tests {
// ToLower modifies input.
ToLower(test.input)
if !reflect.DeepEqual(test.expected, test.input) {
t.Errorf("[%d] Expected\n%#v, got\n%#v\n", i, test.expected, test.input)
}
t.Run(fmt.Sprint(i), func(t *testing.T) {
// ToLower modifies input.
ToLower(test.input)
if !reflect.DeepEqual(test.expected, test.input) {
t.Errorf("[%d] Expected\n%#v, got\n%#v\n", i, test.expected, test.input)
}
})
}
}
func TestRenameKeys(t *testing.T) {
assert := require.New(t)
c := qt.New(t)
m := map[string]interface{}{
"a": 32,
@@ -112,7 +114,7 @@ func TestRenameKeys(t *testing.T) {
"{ren1,sub/*/ren1}", "new1",
"{Ren2,sub/ren2}", "new2",
)
assert.NoError(err)
c.Assert(err, qt.IsNil)
renamer.Rename(m)
+107
View File
@@ -0,0 +1,107 @@
// Copyright 2019 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package maps
import (
"strings"
"github.com/spf13/cast"
)
// Params is a map where all keys are lower case.
type Params map[string]interface{}
// Get does a lower case and nested search in this map.
// It will return nil if none found.
func (p Params) Get(indices ...string) interface{} {
v, _, _ := getNested(p, indices)
return v
}
func getNested(m map[string]interface{}, indices []string) (interface{}, string, map[string]interface{}) {
if len(indices) == 0 {
return nil, "", nil
}
first := indices[0]
v, found := m[strings.ToLower(cast.ToString(first))]
if !found {
return nil, "", nil
}
if len(indices) == 1 {
return v, first, m
}
switch m2 := v.(type) {
case Params:
return getNested(m2, indices[1:])
case map[string]interface{}:
return getNested(m2, indices[1:])
default:
return nil, "", nil
}
}
// GetNestedParam gets the first match of the keyStr in the candidates given.
// It will first try the exact match and then try to find it as a nested map value,
// using the given separator, e.g. "mymap.name".
// It assumes that all the maps given have lower cased keys.
func GetNestedParam(keyStr, separator string, candidates ...Params) (interface{}, error) {
keyStr = strings.ToLower(keyStr)
// Try exact match first
for _, m := range candidates {
if v, ok := m[keyStr]; ok {
return v, nil
}
}
keySegments := strings.Split(keyStr, separator)
for _, m := range candidates {
if v := m.Get(keySegments...); v != nil {
return v, nil
}
}
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)
if len(keySegments) == 0 {
return nil, "", nil, nil
}
first := lookupFn(keySegments[0])
if first == nil {
return nil, "", nil, nil
}
if len(keySegments) == 1 {
return first, keySegments[0], nil, nil
}
switch m := first.(type) {
case map[string]interface{}:
v, key, owner := getNested(m, keySegments[1:])
return v, key, owner, nil
case Params:
v, key, owner := getNested(m, keySegments[1:])
return v, key, owner, nil
}
return nil, "", nil, nil
}
+51
View File
@@ -0,0 +1,51 @@
// Copyright 2019 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package maps
import (
"testing"
qt "github.com/frankban/quicktest"
)
func TestGetNestedParam(t *testing.T) {
m := map[string]interface{}{
"string": "value",
"first": 1,
"with_underscore": 2,
"nested": map[string]interface{}{
"color": "blue",
"nestednested": map[string]interface{}{
"color": "green",
},
},
}
c := qt.New(t)
must := func(keyStr, separator string, candidates ...Params) interface{} {
v, err := GetNestedParam(keyStr, separator, candidates...)
c.Assert(err, qt.IsNil)
return v
}
c.Assert(must("first", "_", m), qt.Equals, 1)
c.Assert(must("First", "_", m), qt.Equals, 1)
c.Assert(must("with_underscore", "_", m), qt.Equals, 2)
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)
}
+22 -22
View File
@@ -18,31 +18,31 @@ import (
"sync"
"testing"
"github.com/stretchr/testify/require"
qt "github.com/frankban/quicktest"
)
func TestScratchAdd(t *testing.T) {
t.Parallel()
assert := require.New(t)
c := qt.New(t)
scratch := NewScratch()
scratch.Add("int1", 10)
scratch.Add("int1", 20)
scratch.Add("int2", 20)
assert.Equal(int64(30), scratch.Get("int1"))
assert.Equal(20, scratch.Get("int2"))
c.Assert(scratch.Get("int1"), qt.Equals, int64(30))
c.Assert(scratch.Get("int2"), qt.Equals, 20)
scratch.Add("float1", float64(10.5))
scratch.Add("float1", float64(20.1))
assert.Equal(float64(30.6), scratch.Get("float1"))
c.Assert(scratch.Get("float1"), qt.Equals, float64(30.6))
scratch.Add("string1", "Hello ")
scratch.Add("string1", "big ")
scratch.Add("string1", "World!")
assert.Equal("Hello big World!", scratch.Get("string1"))
c.Assert(scratch.Get("string1"), qt.Equals, "Hello big World!")
scratch.Add("scratch", scratch)
_, err := scratch.Add("scratch", scratch)
@@ -55,14 +55,14 @@ func TestScratchAdd(t *testing.T) {
func TestScratchAddSlice(t *testing.T) {
t.Parallel()
assert := require.New(t)
c := qt.New(t)
scratch := NewScratch()
_, err := scratch.Add("intSlice", []int{1, 2})
assert.NoError(err)
c.Assert(err, qt.IsNil)
_, err = scratch.Add("intSlice", 3)
assert.NoError(err)
c.Assert(err, qt.IsNil)
sl := scratch.Get("intSlice")
expected := []int{1, 2, 3}
@@ -72,7 +72,7 @@ func TestScratchAddSlice(t *testing.T) {
}
_, err = scratch.Add("intSlice", []int{4, 5})
assert.NoError(err)
c.Assert(err, qt.IsNil)
sl = scratch.Get("intSlice")
expected = []int{1, 2, 3, 4, 5}
@@ -85,49 +85,49 @@ func TestScratchAddSlice(t *testing.T) {
// https://github.com/gohugoio/hugo/issues/5275
func TestScratchAddTypedSliceToInterfaceSlice(t *testing.T) {
t.Parallel()
assert := require.New(t)
c := qt.New(t)
scratch := NewScratch()
scratch.Set("slice", []interface{}{})
_, err := scratch.Add("slice", []int{1, 2})
assert.NoError(err)
assert.Equal([]int{1, 2}, scratch.Get("slice"))
c.Assert(err, qt.IsNil)
c.Assert(scratch.Get("slice"), qt.DeepEquals, []int{1, 2})
}
// https://github.com/gohugoio/hugo/issues/5361
func TestScratchAddDifferentTypedSliceToInterfaceSlice(t *testing.T) {
t.Parallel()
assert := require.New(t)
c := qt.New(t)
scratch := NewScratch()
scratch.Set("slice", []string{"foo"})
_, err := scratch.Add("slice", []int{1, 2})
assert.NoError(err)
assert.Equal([]interface{}{"foo", 1, 2}, scratch.Get("slice"))
c.Assert(err, qt.IsNil)
c.Assert(scratch.Get("slice"), qt.DeepEquals, []interface{}{"foo", 1, 2})
}
func TestScratchSet(t *testing.T) {
t.Parallel()
assert := require.New(t)
c := qt.New(t)
scratch := NewScratch()
scratch.Set("key", "val")
assert.Equal("val", scratch.Get("key"))
c.Assert(scratch.Get("key"), qt.Equals, "val")
}
func TestScratchDelete(t *testing.T) {
t.Parallel()
assert := require.New(t)
c := qt.New(t)
scratch := NewScratch()
scratch.Set("key", "val")
scratch.Delete("key")
scratch.Add("key", "Lucy Parsons")
assert.Equal("Lucy Parsons", scratch.Get("key"))
c.Assert(scratch.Get("key"), qt.Equals, "Lucy Parsons")
}
// Issue #2005
@@ -177,7 +177,7 @@ func TestScratchGet(t *testing.T) {
func TestScratchSetInMap(t *testing.T) {
t.Parallel()
assert := require.New(t)
c := qt.New(t)
scratch := NewScratch()
scratch.SetInMap("key", "lux", "Lux")
@@ -185,7 +185,7 @@ func TestScratchSetInMap(t *testing.T) {
scratch.SetInMap("key", "zyx", "Zyx")
scratch.SetInMap("key", "abc", "Abc (updated)")
scratch.SetInMap("key", "def", "Def")
assert.Equal([]interface{}{0: "Abc (updated)", 1: "Def", 2: "Lux", 3: "Zyx"}, scratch.GetSortedMapValues("key"))
c.Assert(scratch.GetSortedMapValues("key"), qt.DeepEquals, []interface{}{0: "Abc (updated)", 1: "Def", 2: "Lux", 3: "Zyx"})
}
func TestScratchGetSortedMapValues(t *testing.T) {
+6 -9
View File
@@ -14,17 +14,16 @@
package math
import (
"fmt"
"testing"
"github.com/alecthomas/assert"
"github.com/stretchr/testify/require"
qt "github.com/frankban/quicktest"
)
func TestDoArithmetic(t *testing.T) {
t.Parallel()
c := qt.New(t)
for i, test := range []struct {
for _, test := range []struct {
a interface{}
b interface{}
op rune
@@ -94,16 +93,14 @@ func TestDoArithmetic(t *testing.T) {
{"foo", "bar", '-', false},
{3, 2, '%', false},
} {
errMsg := fmt.Sprintf("[%d] %v", i, test)
result, err := DoArithmetic(test.a, test.b, test.op)
if b, ok := test.expect.(bool); ok && !b {
require.Error(t, err, errMsg)
c.Assert(err, qt.Not(qt.IsNil))
continue
}
require.NoError(t, err, errMsg)
assert.Equal(t, test.expect, result, errMsg)
c.Assert(err, qt.IsNil)
c.Assert(test.expect, qt.Equals, result)
}
}
+73
View File
@@ -0,0 +1,73 @@
// Copyright 2019 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package para implements parallel execution helpers.
package para
import (
"context"
"golang.org/x/sync/errgroup"
)
// Workers configures a task executor with the most number of tasks to be executed in parallel.
type Workers struct {
sem chan struct{}
}
// Runner wraps the lifecycle methods of a new task set.
//
// Run wil block until a worker is available or the context is cancelled,
// and then run the given func in a new goroutine.
// Wait will wait for all the running goroutines to finish.
type Runner interface {
Run(func() error)
Wait() error
}
type errGroupRunner struct {
*errgroup.Group
w *Workers
ctx context.Context
}
func (g *errGroupRunner) Run(fn func() error) {
select {
case g.w.sem <- struct{}{}:
case <-g.ctx.Done():
return
}
g.Go(func() error {
err := fn()
<-g.w.sem
return err
})
}
// New creates a new Workers with the given number of workers.
func New(numWorkers int) *Workers {
return &Workers{
sem: make(chan struct{}, numWorkers),
}
}
// Start starts a new Runner.
func (w *Workers) Start(ctx context.Context) (Runner, context.Context) {
g, ctx := errgroup.WithContext(ctx)
return &errGroupRunner{
Group: g,
ctx: ctx,
w: w,
}, ctx
}
+90
View File
@@ -0,0 +1,90 @@
// Copyright 2019 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package para
import (
"context"
"runtime"
"sort"
"sync"
"sync/atomic"
"testing"
"time"
qt "github.com/frankban/quicktest"
)
func TestPara(t *testing.T) {
if runtime.NumCPU() < 4 {
t.Skipf("skip para test, CPU count is %d", runtime.NumCPU())
}
c := qt.New(t)
c.Run("Order", func(c *qt.C) {
n := 500
ints := make([]int, n)
for i := 0; i < n; i++ {
ints[i] = i
}
p := New(4)
r, _ := p.Start(context.Background())
var result []int
var mu sync.Mutex
for i := 0; i < n; i++ {
i := i
r.Run(func() error {
mu.Lock()
defer mu.Unlock()
result = append(result, i)
return nil
})
}
c.Assert(r.Wait(), qt.IsNil)
c.Assert(result, qt.HasLen, len(ints))
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) {
const n = 100
p := New(5)
r, _ := p.Start(context.Background())
start := time.Now()
var counter int64
for i := 0; i < n; i++ {
r.Run(func() error {
atomic.AddInt64(&counter, 1)
time.Sleep(1 * time.Millisecond)
return nil
})
}
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)
})
}
+7 -7
View File
@@ -16,18 +16,18 @@ package text
import (
"testing"
"github.com/stretchr/testify/require"
qt "github.com/frankban/quicktest"
)
func TestPositionStringFormatter(t *testing.T) {
assert := require.New(t)
c := qt.New(t)
pos := Position{Filename: "/my/file.txt", LineNumber: 12, ColumnNumber: 13, Offset: 14}
assert.Equal("/my/file.txt|13|12", createPositionStringFormatter(":file|:col|:line")(pos))
assert.Equal("13|/my/file.txt|12", createPositionStringFormatter(":col|:file|:line")(pos))
assert.Equal("好:13", createPositionStringFormatter("好::col")(pos))
assert.Equal("\"/my/file.txt:12:13\"", createPositionStringFormatter("")(pos))
assert.Equal("\"/my/file.txt:12:13\"", pos.String())
c.Assert(createPositionStringFormatter(":file|:col|:line")(pos), qt.Equals, "/my/file.txt|13|12")
c.Assert(createPositionStringFormatter(":col|:file|:line")(pos), qt.Equals, "13|/my/file.txt|12")
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\"")
}
+47
View File
@@ -0,0 +1,47 @@
// Copyright 2019 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package text
import (
"sync"
"unicode"
"golang.org/x/text/runes"
"golang.org/x/text/transform"
"golang.org/x/text/unicode/norm"
)
var accentTransformerPool = &sync.Pool{
New: func() interface{} {
return transform.Chain(norm.NFD, runes.Remove(runes.In(unicode.Mn)), norm.NFC)
},
}
// RemoveAccents removes all accents from b.
func RemoveAccents(b []byte) []byte {
t := accentTransformerPool.Get().(transform.Transformer)
b, _, _ = transform.Bytes(t, b)
t.Reset()
accentTransformerPool.Put(t)
return b
}
// RemoveAccentsString removes all accents from s.
func RemoveAccentsString(s string) string {
t := accentTransformerPool.Get().(transform.Transformer)
s, _, _ = transform.String(t, s)
t.Reset()
accentTransformerPool.Put(t)
return s
}
+29
View File
@@ -0,0 +1,29 @@
// Copyright 2019 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package text
import (
"testing"
qt "github.com/frankban/quicktest"
)
func TestRemoveAccents(t *testing.T) {
c := qt.New(t)
c.Assert(string(RemoveAccents([]byte("Resumé"))), qt.Equals, "Resume")
c.Assert(string(RemoveAccents([]byte("Hugo Rocks!"))), qt.Equals, "Hugo Rocks!")
c.Assert(string(RemoveAccentsString("Resumé")), qt.Equals, "Resume")
}
+68
View File
@@ -0,0 +1,68 @@
// Copyright 2019 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package types
import (
"html/template"
"github.com/spf13/cast"
)
// ToStringSlicePreserveString converts v to a string slice.
// If v is a string, it will be wrapped in a string slice.
func ToStringSlicePreserveString(v interface{}) []string {
if v == nil {
return nil
}
if sds, ok := v.(string); ok {
return []string{sds}
}
return cast.ToStringSlice(v)
}
// TypeToString converts v to a string if it's a valid string type.
// Note that this will not try to convert numeric values etc.,
// use ToString for that.
func TypeToString(v interface{}) (string, bool) {
switch s := v.(type) {
case string:
return s, true
case template.HTML:
return string(s), true
case template.CSS:
return string(s), true
case template.HTMLAttr:
return string(s), true
case template.JS:
return string(s), true
case template.JSStr:
return string(s), true
case template.URL:
return string(s), true
case template.Srcset:
return string(s), true
}
return "", false
}
// ToString converts v to a string.
func ToString(v interface{}) string {
if s, ok := TypeToString(v); ok {
return s
}
return cast.ToString(v)
}
+29
View File
@@ -0,0 +1,29 @@
// Copyright 2019 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package types
import (
"testing"
qt "github.com/frankban/quicktest"
)
func TestToStringSlicePreserveString(t *testing.T) {
c := qt.New(t)
c.Assert(ToStringSlicePreserveString("Hugo"), qt.DeepEquals, []string{"Hugo"})
c.Assert(ToStringSlicePreserveString([]interface{}{"A", "B"}), qt.DeepEquals, []string{"A", "B"})
c.Assert(ToStringSlicePreserveString(nil), qt.IsNil)
}
+12 -12
View File
@@ -17,36 +17,36 @@ import (
"sync"
"testing"
"github.com/stretchr/testify/require"
qt "github.com/frankban/quicktest"
)
func TestEvictingStringQueue(t *testing.T) {
assert := require.New(t)
c := qt.New(t)
queue := NewEvictingStringQueue(3)
assert.Equal("", queue.Peek())
c.Assert(queue.Peek(), qt.Equals, "")
queue.Add("a")
queue.Add("b")
queue.Add("a")
assert.Equal("b", queue.Peek())
c.Assert(queue.Peek(), qt.Equals, "b")
queue.Add("b")
assert.Equal("b", queue.Peek())
c.Assert(queue.Peek(), qt.Equals, "b")
queue.Add("a")
queue.Add("b")
assert.True(queue.Contains("a"))
assert.False(queue.Contains("foo"))
c.Assert(queue.Contains("a"), qt.Equals, true)
c.Assert(queue.Contains("foo"), qt.Equals, false)
assert.Equal([]string{"b", "a"}, queue.PeekAll())
assert.Equal("b", queue.Peek())
c.Assert(queue.PeekAll(), qt.DeepEquals, []string{"b", "a"})
c.Assert(queue.Peek(), qt.Equals, "b")
queue.Add("c")
queue.Add("d")
// Overflowed, a should now be removed.
assert.Equal([]string{"d", "c", "b"}, queue.PeekAll())
assert.Len(queue.PeekAllSet(), 3)
assert.True(queue.PeekAllSet()["c"])
c.Assert(queue.PeekAll(), qt.DeepEquals, []string{"d", "c", "b"})
c.Assert(len(queue.PeekAllSet()), qt.Equals, 3)
c.Assert(queue.PeekAllSet()["c"], qt.Equals, true)
}
func TestEvictingStringQueueConcurrent(t *testing.T) {
+6
View File
@@ -21,6 +21,12 @@ import (
"github.com/spf13/cast"
)
// RLocker represents the read locks in sync.RWMutex.
type RLocker interface {
RLock()
RUnlock()
}
// KeyValueStr is a string tuple.
type KeyValueStr struct {
Key string
+4 -4
View File
@@ -16,14 +16,14 @@ package types
import (
"testing"
"github.com/stretchr/testify/require"
qt "github.com/frankban/quicktest"
)
func TestKeyValues(t *testing.T) {
assert := require.New(t)
c := qt.New(t)
kv := NewKeyValuesStrings("key", "a1", "a2")
assert.Equal("key", kv.KeyString())
assert.Equal([]interface{}{"a1", "a2"}, kv.Values)
c.Assert(kv.KeyString(), qt.Equals, "key")
c.Assert(kv.Values, qt.DeepEquals, []interface{}{"a1", "a2"})
}
+2 -2
View File
@@ -1,4 +1,4 @@
// Copyright 2017-present The Hugo Authors. All rights reserved.
// Copyright 2019 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -20,7 +20,7 @@ type Eqer interface {
Eq(other interface{}) bool
}
// ProbablyEq is an equal check that may return false positives, but never
// ProbablyEqer is an equal check that may return false positives, but never
// a false negative.
type ProbablyEqer interface {
ProbablyEq(other interface{}) bool
+113
View File
@@ -0,0 +1,113 @@
// Copyright 2019 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package compare
import (
"strings"
"unicode"
"unicode/utf8"
)
// Strings returns an integer comparing two strings lexicographically.
func Strings(s, t string) int {
c := compareFold(s, t)
if c == 0 {
// "B" and "b" would be the same so we need a tiebreaker.
return strings.Compare(s, t)
}
return c
}
// This function is derived from strings.EqualFold in Go's stdlib.
// https://github.com/golang/go/blob/ad4a58e31501bce5de2aad90a620eaecdc1eecb8/src/strings/strings.go#L893
func compareFold(s, t string) int {
for s != "" && t != "" {
var sr, tr rune
if s[0] < utf8.RuneSelf {
sr, s = rune(s[0]), s[1:]
} else {
r, size := utf8.DecodeRuneInString(s)
sr, s = r, s[size:]
}
if t[0] < utf8.RuneSelf {
tr, t = rune(t[0]), t[1:]
} else {
r, size := utf8.DecodeRuneInString(t)
tr, t = r, t[size:]
}
if tr == sr {
continue
}
c := 1
if tr < sr {
tr, sr = sr, tr
c = -c
}
// ASCII only.
if tr < utf8.RuneSelf {
if sr >= 'A' && sr <= 'Z' {
if tr <= 'Z' {
// Same case.
return -c
}
diff := tr - (sr + 'a' - 'A')
if diff == 0 {
continue
}
if diff < 0 {
return c
}
if diff > 0 {
return -c
}
}
}
// Unicode.
r := unicode.SimpleFold(sr)
for r != sr && r < tr {
r = unicode.SimpleFold(r)
}
if r == tr {
continue
}
return -c
}
if s == "" && t == "" {
return 0
}
if s == "" {
return -1
}
return 1
}
// LessStrings returns whether s is less than t lexicographically.
func LessStrings(s, t string) bool {
return Strings(s, t) < 0
}
+65
View File
@@ -0,0 +1,65 @@
// Copyright 2019 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package compare
import (
"sort"
"strings"
"testing"
qt "github.com/frankban/quicktest"
)
func TestCompare(t *testing.T) {
c := qt.New(t)
for _, test := range []struct {
a string
b string
}{
{"a", "a"},
{"A", "a"},
{"Ab", "Ac"},
{"az", "Za"},
{"C", "D"},
{"B", "a"},
{"C", ""},
{"", ""},
{"αβδC", "ΑΒΔD"},
{"αβδC", "ΑΒΔ"},
{"αβδ", "ΑΒΔD"},
{"αβδ", "ΑΒΔ"},
{"β", "δ"},
{"好", strings.ToLower("好")},
} {
expect := strings.Compare(strings.ToLower(test.a), strings.ToLower(test.b))
got := compareFold(test.a, test.b)
c.Assert(got, qt.Equals, expect)
}
}
func TestLexicographicSort(t *testing.T) {
c := qt.New(t)
s := []string{"b", "Bz", "ba", "A", "Ba", "ba"}
sort.Slice(s, func(i, j int) bool {
return LessStrings(s[i], s[j])
})
c.Assert(s, qt.DeepEquals, []string{"A", "b", "Ba", "ba", "ba", "Bz"})
}
+154
View File
@@ -0,0 +1,154 @@
// Copyright 2019 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package config
import (
"sort"
"strings"
"sync"
"github.com/gohugoio/hugo/common/types"
"github.com/gobwas/glob"
"github.com/gohugoio/hugo/common/herrors"
"github.com/mitchellh/mapstructure"
"github.com/spf13/cast"
jww "github.com/spf13/jwalterweatherman"
)
var DefaultBuild = Build{
UseResourceCacheWhen: "fallback",
WriteStats: false,
}
// Build holds some build related condfiguration.
type Build struct {
UseResourceCacheWhen string // never, fallback, always. Default is fallback
// When enabled, will collect and write a hugo_stats.json with some build
// related aggregated data (e.g. CSS class names).
WriteStats bool
}
func (b Build) UseResourceCache(err error) bool {
if b.UseResourceCacheWhen == "never" {
return false
}
if b.UseResourceCacheWhen == "fallback" {
return err == herrors.ErrFeatureNotAvailable
}
return true
}
func DecodeBuild(cfg Provider) Build {
m := cfg.GetStringMap("build")
b := DefaultBuild
if m == nil {
return b
}
err := mapstructure.WeakDecode(m, &b)
if err != nil {
return DefaultBuild
}
b.UseResourceCacheWhen = strings.ToLower(b.UseResourceCacheWhen)
when := b.UseResourceCacheWhen
if when != "never" && when != "always" && when != "fallback" {
b.UseResourceCacheWhen = "fallback"
}
return b
}
// Sitemap configures the sitemap to be generated.
type Sitemap struct {
ChangeFreq string
Priority float64
Filename string
}
func DecodeSitemap(prototype Sitemap, input map[string]interface{}) Sitemap {
for key, value := range input {
switch key {
case "changefreq":
prototype.ChangeFreq = cast.ToString(value)
case "priority":
prototype.Priority = cast.ToFloat64(value)
case "filename":
prototype.Filename = cast.ToString(value)
default:
jww.WARN.Printf("Unknown Sitemap field: %s\n", key)
}
}
return prototype
}
// Config for the dev server.
type Server struct {
Headers []Headers
compiledInit sync.Once
compiled []glob.Glob
}
func (s *Server) Match(pattern string) []types.KeyValueStr {
s.compiledInit.Do(func() {
for _, h := range s.Headers {
s.compiled = append(s.compiled, glob.MustCompile(h.For))
}
})
if s.compiled == nil {
return nil
}
var matches []types.KeyValueStr
for i, g := range s.compiled {
if g.Match(pattern) {
h := s.Headers[i]
for k, v := range h.Values {
matches = append(matches, types.KeyValueStr{Key: k, Value: cast.ToString(v)})
}
}
}
sort.Slice(matches, func(i, j int) bool {
return matches[i].Key < matches[j].Key
})
return matches
}
type Headers struct {
For string
Values map[string]interface{}
}
func DecodeServer(cfg Provider) *Server {
m := cfg.GetStringMap("server")
s := &Server{}
if m == nil {
return s
}
_ = mapstructure.WeakDecode(m, s)
return s
}
+84
View File
@@ -0,0 +1,84 @@
// Copyright 2020 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package config
import (
"errors"
"testing"
"github.com/gohugoio/hugo/common/herrors"
"github.com/gohugoio/hugo/common/types"
qt "github.com/frankban/quicktest"
"github.com/spf13/viper"
)
func TestBuild(t *testing.T) {
c := qt.New(t)
v := viper.New()
v.Set("build", map[string]interface{}{
"useResourceCacheWhen": "always",
})
b := DecodeBuild(v)
c.Assert(b.UseResourceCacheWhen, qt.Equals, "always")
v.Set("build", map[string]interface{}{
"useResourceCacheWhen": "foo",
})
b = DecodeBuild(v)
c.Assert(b.UseResourceCacheWhen, qt.Equals, "fallback")
c.Assert(b.UseResourceCache(herrors.ErrFeatureNotAvailable), qt.Equals, true)
c.Assert(b.UseResourceCache(errors.New("err")), qt.Equals, false)
b.UseResourceCacheWhen = "always"
c.Assert(b.UseResourceCache(herrors.ErrFeatureNotAvailable), qt.Equals, true)
c.Assert(b.UseResourceCache(errors.New("err")), qt.Equals, true)
c.Assert(b.UseResourceCache(nil), qt.Equals, true)
b.UseResourceCacheWhen = "never"
c.Assert(b.UseResourceCache(herrors.ErrFeatureNotAvailable), qt.Equals, false)
c.Assert(b.UseResourceCache(errors.New("err")), qt.Equals, false)
c.Assert(b.UseResourceCache(nil), qt.Equals, false)
}
func TestServer(t *testing.T) {
c := qt.New(t)
cfg, err := FromConfigString(`[[server.headers]]
for = "/*.jpg"
[server.headers.values]
X-Frame-Options = "DENY"
X-XSS-Protection = "1; mode=block"
X-Content-Type-Options = "nosniff"
`, "toml")
c.Assert(err, qt.IsNil)
s := DecodeServer(cfg)
c.Assert(s.Match("/foo.jpg"), qt.DeepEquals, []types.KeyValueStr{
{Key: "X-Content-Type-Options", Value: "nosniff"},
{Key: "X-Frame-Options", Value: "DENY"},
{Key: "X-XSS-Protection", Value: "1; mode=block"}})
}
-2
View File
@@ -120,8 +120,6 @@ func RenameKeys(m map[string]interface{}) {
func newViper() *viper.Viper {
v := viper.New()
v.AutomaticEnv()
v.SetEnvPrefix("hugo")
return v
}
+6 -6
View File
@@ -17,18 +17,18 @@ import (
"strings"
"testing"
"github.com/stretchr/testify/require"
qt "github.com/frankban/quicktest"
)
func TestIsValidConfigFileName(t *testing.T) {
assert := require.New(t)
c := qt.New(t)
for _, ext := range ValidConfigFileExtensions {
filename := "config." + ext
assert.True(IsValidConfigFilename(filename), ext)
assert.True(IsValidConfigFilename(strings.ToUpper(filename)))
c.Assert(IsValidConfigFilename(filename), qt.Equals, true)
c.Assert(IsValidConfigFilename(strings.ToUpper(filename)), qt.Equals, true)
}
assert.False(IsValidConfigFilename(""))
assert.False(IsValidConfigFilename("config.toml.swp"))
c.Assert(IsValidConfigFilename(""), qt.Equals, false)
c.Assert(IsValidConfigFilename("config.toml.swp"), qt.Equals, false)
}
+2 -5
View File
@@ -14,7 +14,7 @@
package config
import (
"github.com/spf13/cast"
"github.com/gohugoio/hugo/common/types"
)
// Provider provides the configuration settings for Hugo.
@@ -35,10 +35,7 @@ type Provider interface {
// we do not attempt to split it into fields.
func GetStringSlicePreserveString(cfg Provider, key string) []string {
sd := cfg.Get(key)
if sds, ok := sd.(string); ok {
return []string{sds}
}
return cast.ToStringSlice(sd)
return types.ToStringSlicePreserveString(sd)
}
// SetBaseTestDefaults provides some common config defaults used in tests.
+5 -5
View File
@@ -16,12 +16,12 @@ package config
import (
"testing"
qt "github.com/frankban/quicktest"
"github.com/spf13/viper"
"github.com/stretchr/testify/require"
)
func TestGetStringSlicePreserveString(t *testing.T) {
assert := require.New(t)
c := qt.New(t)
cfg := viper.New()
s := "This is a string"
@@ -30,7 +30,7 @@ func TestGetStringSlicePreserveString(t *testing.T) {
cfg.Set("s1", s)
cfg.Set("s2", sSlice)
assert.Equal([]string{s}, GetStringSlicePreserveString(cfg, "s1"))
assert.Equal(sSlice, GetStringSlicePreserveString(cfg, "s2"))
assert.Nil(GetStringSlicePreserveString(cfg, "s3"))
c.Assert(GetStringSlicePreserveString(cfg, "s1"), qt.DeepEquals, []string{s})
c.Assert(GetStringSlicePreserveString(cfg, "s2"), qt.DeepEquals, sSlice)
c.Assert(GetStringSlicePreserveString(cfg, "s3"), qt.IsNil)
}
+24
View File
@@ -17,6 +17,7 @@ import (
"os"
"runtime"
"strconv"
"strings"
)
// GetNumWorkerMultiplier returns the base value used to calculate the number
@@ -31,3 +32,26 @@ func GetNumWorkerMultiplier() int {
}
return runtime.NumCPU()
}
// SetEnvVars sets vars on the form key=value in the oldVars slice.
func SetEnvVars(oldVars *[]string, keyValues ...string) {
for i := 0; i < len(keyValues); i += 2 {
setEnvVar(oldVars, keyValues[i], keyValues[i+1])
}
}
func SplitEnvVar(v string) (string, string) {
parts := strings.Split(v, "=")
return parts[0], parts[1]
}
func setEnvVar(vars *[]string, key, value string) {
for i := range *vars {
if strings.HasPrefix((*vars)[i], key+"=") {
(*vars)[i] = key + "=" + value
return
}
}
// New var.
*vars = append(*vars, key+"="+value)
}
+32
View File
@@ -0,0 +1,32 @@
// Copyright 2019 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package config
import (
"testing"
qt "github.com/frankban/quicktest"
)
func TestSetEnvVars(t *testing.T) {
t.Parallel()
c := qt.New(t)
vars := []string{"FOO=bar", "HUGO=cool", "BAR=foo"}
SetEnvVars(&vars, "HUGO", "rocking!", "NEW", "bar")
c.Assert(vars, qt.DeepEquals, []string{"FOO=bar", "HUGO=rocking!", "BAR=foo", "NEW=bar"})
key, val := SplitEnvVar("HUGO=rocks")
c.Assert(key, qt.Equals, "HUGO")
c.Assert(val, qt.Equals, "rocks")
}
+25 -28
View File
@@ -16,13 +16,13 @@ package privacy
import (
"testing"
qt "github.com/frankban/quicktest"
"github.com/gohugoio/hugo/config"
"github.com/spf13/viper"
"github.com/stretchr/testify/require"
)
func TestDecodeConfigFromTOML(t *testing.T) {
assert := require.New(t)
c := qt.New(t)
tomlConfig := `
@@ -52,30 +52,27 @@ privacyEnhanced = true
simple = true
`
cfg, err := config.FromConfigString(tomlConfig, "toml")
assert.NoError(err)
c.Assert(err, qt.IsNil)
pc, err := DecodeConfig(cfg)
assert.NoError(err)
assert.NotNil(pc)
c.Assert(err, qt.IsNil)
c.Assert(pc, qt.Not(qt.IsNil))
got := []bool{
pc.Disqus.Disable, pc.GoogleAnalytics.Disable,
pc.GoogleAnalytics.RespectDoNotTrack, pc.GoogleAnalytics.AnonymizeIP,
pc.GoogleAnalytics.UseSessionStorage, pc.Instagram.Disable,
pc.Instagram.Simple, pc.Twitter.Disable, pc.Twitter.EnableDNT,
pc.Twitter.Simple, pc.Vimeo.Disable, pc.Vimeo.Simple,
pc.YouTube.PrivacyEnhanced, pc.YouTube.Disable,
}
c.Assert(got, qt.All(qt.Equals), true)
assert.True(pc.Disqus.Disable)
assert.True(pc.GoogleAnalytics.Disable)
assert.True(pc.GoogleAnalytics.RespectDoNotTrack)
assert.True(pc.GoogleAnalytics.AnonymizeIP)
assert.True(pc.GoogleAnalytics.UseSessionStorage)
assert.True(pc.Instagram.Disable)
assert.True(pc.Instagram.Simple)
assert.True(pc.Twitter.Disable)
assert.True(pc.Twitter.EnableDNT)
assert.True(pc.Twitter.Simple)
assert.True(pc.Vimeo.Disable)
assert.True(pc.Vimeo.Simple)
assert.True(pc.YouTube.PrivacyEnhanced)
assert.True(pc.YouTube.Disable)
}
func TestDecodeConfigFromTOMLCaseInsensitive(t *testing.T) {
assert := require.New(t)
c := qt.New(t)
tomlConfig := `
@@ -86,19 +83,19 @@ someOtherValue = "foo"
PrivacyENhanced = true
`
cfg, err := config.FromConfigString(tomlConfig, "toml")
assert.NoError(err)
c.Assert(err, qt.IsNil)
pc, err := DecodeConfig(cfg)
assert.NoError(err)
assert.NotNil(pc)
assert.True(pc.YouTube.PrivacyEnhanced)
c.Assert(err, qt.IsNil)
c.Assert(pc, qt.Not(qt.IsNil))
c.Assert(pc.YouTube.PrivacyEnhanced, qt.Equals, true)
}
func TestDecodeConfigDefault(t *testing.T) {
assert := require.New(t)
c := qt.New(t)
pc, err := DecodeConfig(viper.New())
assert.NoError(err)
assert.NotNil(pc)
assert.False(pc.YouTube.PrivacyEnhanced)
c.Assert(err, qt.IsNil)
c.Assert(pc, qt.Not(qt.IsNil))
c.Assert(pc.YouTube.PrivacyEnhanced, qt.Equals, false)
}
+13 -13
View File
@@ -16,13 +16,13 @@ package services
import (
"testing"
qt "github.com/frankban/quicktest"
"github.com/gohugoio/hugo/config"
"github.com/spf13/viper"
"github.com/stretchr/testify/require"
)
func TestDecodeConfigFromTOML(t *testing.T) {
assert := require.New(t)
c := qt.New(t)
tomlConfig := `
@@ -39,31 +39,31 @@ disableInlineCSS = true
disableInlineCSS = true
`
cfg, err := config.FromConfigString(tomlConfig, "toml")
assert.NoError(err)
c.Assert(err, qt.IsNil)
config, err := DecodeConfig(cfg)
assert.NoError(err)
assert.NotNil(config)
c.Assert(err, qt.IsNil)
c.Assert(config, qt.Not(qt.IsNil))
assert.Equal("DS", config.Disqus.Shortname)
assert.Equal("ga_id", config.GoogleAnalytics.ID)
c.Assert(config.Disqus.Shortname, qt.Equals, "DS")
c.Assert(config.GoogleAnalytics.ID, qt.Equals, "ga_id")
assert.True(config.Instagram.DisableInlineCSS)
c.Assert(config.Instagram.DisableInlineCSS, qt.Equals, true)
}
// Support old root-level GA settings etc.
func TestUseSettingsFromRootIfSet(t *testing.T) {
assert := require.New(t)
c := qt.New(t)
cfg := viper.New()
cfg.Set("disqusShortname", "root_short")
cfg.Set("googleAnalytics", "ga_root")
config, err := DecodeConfig(cfg)
assert.NoError(err)
assert.NotNil(config)
c.Assert(err, qt.IsNil)
c.Assert(config, qt.Not(qt.IsNil))
assert.Equal("root_short", config.Disqus.Shortname)
assert.Equal("ga_root", config.GoogleAnalytics.ID)
c.Assert(config.Disqus.Shortname, qt.Equals, "root_short")
c.Assert(config.GoogleAnalytics.ID, qt.Equals, "ga_root")
}
+59 -23
View File
@@ -25,6 +25,8 @@ import (
"path/filepath"
"strings"
"github.com/gohugoio/hugo/hugofs/files"
"github.com/gohugoio/hugo/hugofs"
"github.com/gohugoio/hugo/helpers"
@@ -50,7 +52,10 @@ func NewContent(
if isDir {
langFs := hugofs.NewLanguageFs(s.Language().Lang, sites.LanguageSet(), archetypeFs)
langFs, err := hugofs.NewLanguageFs(sites.LanguageSet(), archetypeFs)
if err != nil {
return err
}
cm, err := mapArcheTypeDir(ps, langFs, archetypeFilename)
if err != nil {
@@ -64,7 +69,7 @@ func NewContent(
}
name := filepath.Base(targetPath)
return newContentFromDir(archetypeFilename, sites, archetypeFs, sourceFs, cm, name, contentPath)
return newContentFromDir(archetypeFilename, sites, sourceFs, cm, name, contentPath)
}
// Building the sites can be expensive, so only do it if really needed.
@@ -111,9 +116,9 @@ func NewContent(
return nil
}
func targetSite(sites *hugolib.HugoSites, fi *hugofs.LanguageFileInfo) *hugolib.Site {
func targetSite(sites *hugolib.HugoSites, fi hugofs.FileMetaInfo) *hugolib.Site {
for _, s := range sites.Sites {
if fi.Lang() == s.Language().Lang {
if fi.Meta().Lang() == s.Language().Lang {
return s
}
}
@@ -123,13 +128,14 @@ func targetSite(sites *hugolib.HugoSites, fi *hugofs.LanguageFileInfo) *hugolib.
func newContentFromDir(
archetypeDir string,
sites *hugolib.HugoSites,
sourceFs, targetFs afero.Fs,
targetFs afero.Fs,
cm archetypeMap, name, targetPath string) error {
for _, f := range cm.otherFiles {
filename := f.Filename()
meta := f.Meta()
filename := meta.Path()
// Just copy the file to destination.
in, err := sourceFs.Open(filename)
in, err := meta.Open()
if err != nil {
return errors.Wrap(err, "failed to open non-content file")
}
@@ -156,7 +162,7 @@ func newContentFromDir(
}
for _, f := range cm.contentFiles {
filename := f.Filename()
filename := f.Meta().Path()
s := targetSite(sites, f)
targetFilename := filepath.Join(targetPath, strings.TrimPrefix(filename, archetypeDir))
@@ -177,9 +183,9 @@ func newContentFromDir(
type archetypeMap struct {
// These needs to be parsed and executed as Go templates.
contentFiles []*hugofs.LanguageFileInfo
contentFiles []hugofs.FileMetaInfo
// These are just copied to destination.
otherFiles []*hugofs.LanguageFileInfo
otherFiles []hugofs.FileMetaInfo
// If the templates needs a fully built site. This can potentially be
// expensive, so only do when needed.
siteUsed bool
@@ -192,7 +198,7 @@ func mapArcheTypeDir(
var m archetypeMap
walkFn := func(filename string, fi os.FileInfo, err error) error {
walkFn := func(path string, fi hugofs.FileMetaInfo, err error) error {
if err != nil {
return err
@@ -202,12 +208,12 @@ func mapArcheTypeDir(
return nil
}
fil := fi.(*hugofs.LanguageFileInfo)
fil := fi.(hugofs.FileMetaInfo)
if hugolib.IsContentFile(filename) {
if files.IsContentFile(path) {
m.contentFiles = append(m.contentFiles, fil)
if !m.siteUsed {
m.siteUsed, err = usesSiteVar(fs, filename)
m.siteUsed, err = usesSiteVar(fs, path)
if err != nil {
return err
}
@@ -220,7 +226,15 @@ func mapArcheTypeDir(
return nil
}
if err := helpers.SymbolicWalk(fs, archetypeDir, walkFn); err != nil {
walkCfg := hugofs.WalkwayConfig{
WalkFn: walkFn,
Fs: fs,
Root: archetypeDir,
}
w := hugofs.NewWalkway(walkCfg)
if err := w.Walk(); err != nil {
return m, errors.Wrapf(err, "failed to walk archetype dir %q", archetypeDir)
}
@@ -254,20 +268,32 @@ func resolveContentPath(sites *hugolib.HugoSites, fs afero.Fs, targetPath string
}
}
for _, ss := range sites.Sites {
contentDir := ss.PathSpec.ContentDir
var dirLang string
for _, dir := range sites.BaseFs.Content.Dirs {
meta := dir.Meta()
contentDir := meta.Filename()
if !strings.HasSuffix(contentDir, helpers.FilePathSeparator) {
contentDir += helpers.FilePathSeparator
}
if strings.HasPrefix(targetPath, contentDir) {
siteContentDir = ss.PathSpec.ContentDir
if s == nil {
s = ss
}
siteContentDir = contentDir
dirLang = meta.Lang()
break
}
}
if s == nil && dirLang != "" {
for _, ss := range sites.Sites {
if ss.Lang() == dirLang {
s = ss
break
}
}
}
if s == nil {
s = first
}
@@ -280,12 +306,22 @@ func resolveContentPath(sites *hugolib.HugoSites, fs afero.Fs, targetPath string
}
}
if siteContentDir == "" {
}
if siteContentDir != "" {
pp := filepath.Join(siteContentDir, strings.TrimPrefix(targetPath, siteContentDir))
return s.PathSpec.AbsPathify(pp), s
} else {
return s.PathSpec.AbsPathify(filepath.Join(first.PathSpec.ContentDir, targetPath)), s
var contentDir string
for _, dir := range sites.BaseFs.Content.Dirs {
contentDir = dir.Meta().Filename()
if dir.Meta().Lang() == s.Lang() {
break
}
}
return s.PathSpec.AbsPathify(filepath.Join(contentDir, targetPath)), s
}
}
+9 -6
View File
@@ -90,7 +90,10 @@ func executeArcheTypeAsTemplate(s *hugolib.Site, name, kind, targetPath, archety
err error
)
f := s.SourceSpec.NewFileInfo("", targetPath, false, nil)
f, err := s.SourceSpec.NewFileInfoFrom(targetPath, targetPath)
if err != nil {
return nil, err
}
if name == "" {
name = f.TranslationBaseName()
@@ -107,7 +110,7 @@ func executeArcheTypeAsTemplate(s *hugolib.Site, name, kind, targetPath, archety
Date: time.Now().Format(time.RFC3339),
Name: name,
File: f,
Site: &s.Info,
Site: s.Info,
}
if archetypeFilename == "" {
@@ -126,16 +129,16 @@ func executeArcheTypeAsTemplate(s *hugolib.Site, name, kind, targetPath, archety
archetypeTemplate = []byte(archetypeShortcodeReplacementsPre.Replace(string(archetypeTemplate)))
// Reuse the Hugo template setup to get the template funcs properly set up.
templateHandler := s.Deps.Tmpl.(tpl.TemplateHandler)
templateName := "_text/" + helpers.Filename(archetypeFilename)
if err := templateHandler.AddTemplate(templateName, string(archetypeTemplate)); err != nil {
templateHandler := s.Deps.Tmpl().(tpl.TemplateManager)
templateName := helpers.Filename(archetypeFilename)
if err := templateHandler.AddTemplate("_text/"+templateName, string(archetypeTemplate)); err != nil {
return nil, errors.Wrapf(err, "Failed to parse archetype file %q:", archetypeFilename)
}
templ, _ := templateHandler.Lookup(templateName)
var buff bytes.Buffer
if err := templ.Execute(&buff, data); err != nil {
if err := templateHandler.Execute(templ, &buff, data); err != nil {
return nil, errors.Wrapf(err, "Failed to process archetype file %q:", archetypeFilename)
}
+71 -58
View File
@@ -27,15 +27,14 @@ import (
"github.com/gohugoio/hugo/hugofs"
qt "github.com/frankban/quicktest"
"github.com/gohugoio/hugo/create"
"github.com/gohugoio/hugo/helpers"
"github.com/spf13/afero"
"github.com/spf13/viper"
"github.com/stretchr/testify/require"
)
func TestNewContent(t *testing.T) {
assert := require.New(t)
cases := []struct {
kind string
@@ -50,12 +49,12 @@ func TestNewContent(t *testing.T) {
{"product", "product/sample-4.md", []string{`title = "SAMPLE-4"`}}, // empty archetype front matter
{"lang", "post/lang-1.md", []string{`Site Lang: en|Name: Lang 1|i18n: Hugo Rocks!`}},
{"lang", "post/lang-2.en.md", []string{`Site Lang: en|Name: Lang 2|i18n: Hugo Rocks!`}},
{"lang", "post/lang-3.nn.md", []string{`Site Lang: nn|Name: Lang 3|i18n: Hugo Rokkar!`}},
{"lang", "content/post/lang-3.nn.md", []string{`Site Lang: nn|Name: Lang 3|i18n: Hugo Rokkar!`}},
{"lang", "content_nn/post/lang-4.md", []string{`Site Lang: nn|Name: Lang 4|i18n: Hugo Rokkar!`}},
{"lang", "content_nn/post/lang-5.en.md", []string{`Site Lang: en|Name: Lang 5|i18n: Hugo Rocks!`}},
{"lang", "post/my-bundle/index.md", []string{`Site Lang: en|Name: My Bundle|i18n: Hugo Rocks!`}},
{"lang", "post/my-bundle/index.en.md", []string{`Site Lang: en|Name: My Bundle|i18n: Hugo Rocks!`}},
{"lang", "post/my-bundle/index.nn.md", []string{`Site Lang: nn|Name: My Bundle|i18n: Hugo Rokkar!`}},
{"lang", "content/post/my-bundle/index.nn.md", []string{`Site Lang: nn|Name: My Bundle|i18n: Hugo Rokkar!`}},
{"shortcodes", "shortcodes/go.md", []string{
`title = "GO"`,
"{{< myshortcode >}}",
@@ -63,38 +62,44 @@ func TestNewContent(t *testing.T) {
"{{</* comment */>}}\n{{%/* comment */%}}"}}, // shortcodes
}
for i, c := range cases {
cfg, fs := newTestCfg(assert)
assert.NoError(initFs(fs))
h, err := hugolib.NewHugoSites(deps.DepsCfg{Cfg: cfg, Fs: fs})
assert.NoError(err)
for i, cas := range cases {
cas := cas
t.Run(fmt.Sprintf("%s-%d", cas.kind, i), func(t *testing.T) {
t.Parallel()
c := qt.New(t)
mm := afero.NewMemMapFs()
c.Assert(initFs(mm), qt.IsNil)
cfg, fs := newTestCfg(c, mm)
h, err := hugolib.NewHugoSites(deps.DepsCfg{Cfg: cfg, Fs: fs})
c.Assert(err, qt.IsNil)
assert.NoError(create.NewContent(h, c.kind, c.path))
c.Assert(create.NewContent(h, cas.kind, cas.path), qt.IsNil)
fname := filepath.FromSlash(c.path)
if !strings.HasPrefix(fname, "content") {
fname = filepath.Join("content", fname)
}
content := readFileFromFs(t, fs.Source, fname)
for _, v := range c.expected {
found := strings.Contains(content, v)
if !found {
t.Fatalf("[%d] %q missing from output:\n%q", i, v, content)
fname := filepath.FromSlash(cas.path)
if !strings.HasPrefix(fname, "content") {
fname = filepath.Join("content", fname)
}
}
content := readFileFromFs(t, fs.Source, fname)
for _, v := range cas.expected {
found := strings.Contains(content, v)
if !found {
t.Fatalf("[%d] %q missing from output:\n%q", i, v, content)
}
}
})
}
}
func TestNewContentFromDir(t *testing.T) {
assert := require.New(t)
cfg, fs := newTestCfg(assert)
assert.NoError(initFs(fs))
mm := afero.NewMemMapFs()
c := qt.New(t)
archetypeDir := filepath.Join("archetypes", "my-bundle")
assert.NoError(fs.Source.Mkdir(archetypeDir, 0755))
c.Assert(mm.MkdirAll(archetypeDir, 0755), qt.IsNil)
archetypeThemeDir := filepath.Join("themes", "mytheme", "archetypes", "my-theme-bundle")
assert.NoError(fs.Source.Mkdir(archetypeThemeDir, 0755))
c.Assert(mm.MkdirAll(archetypeThemeDir, 0755), qt.IsNil)
contentFile := `
File: %s
@@ -103,39 +108,42 @@ Name: {{ replace .Name "-" " " | title }}
i18n: {{ T "hugo" }}
`
assert.NoError(afero.WriteFile(fs.Source, filepath.Join(archetypeDir, "index.md"), []byte(fmt.Sprintf(contentFile, "index.md")), 0755))
assert.NoError(afero.WriteFile(fs.Source, filepath.Join(archetypeDir, "index.nn.md"), []byte(fmt.Sprintf(contentFile, "index.nn.md")), 0755))
c.Assert(afero.WriteFile(mm, filepath.Join(archetypeDir, "index.md"), []byte(fmt.Sprintf(contentFile, "index.md")), 0755), qt.IsNil)
c.Assert(afero.WriteFile(mm, filepath.Join(archetypeDir, "index.nn.md"), []byte(fmt.Sprintf(contentFile, "index.nn.md")), 0755), qt.IsNil)
assert.NoError(afero.WriteFile(fs.Source, filepath.Join(archetypeDir, "pages", "bio.md"), []byte(fmt.Sprintf(contentFile, "bio.md")), 0755))
assert.NoError(afero.WriteFile(fs.Source, filepath.Join(archetypeDir, "resources", "hugo1.json"), []byte(`hugo1: {{ printf "no template handling in here" }}`), 0755))
assert.NoError(afero.WriteFile(fs.Source, filepath.Join(archetypeDir, "resources", "hugo2.xml"), []byte(`hugo2: {{ printf "no template handling in here" }}`), 0755))
c.Assert(afero.WriteFile(mm, filepath.Join(archetypeDir, "pages", "bio.md"), []byte(fmt.Sprintf(contentFile, "bio.md")), 0755), qt.IsNil)
c.Assert(afero.WriteFile(mm, filepath.Join(archetypeDir, "resources", "hugo1.json"), []byte(`hugo1: {{ printf "no template handling in here" }}`), 0755), qt.IsNil)
c.Assert(afero.WriteFile(mm, filepath.Join(archetypeDir, "resources", "hugo2.xml"), []byte(`hugo2: {{ printf "no template handling in here" }}`), 0755), qt.IsNil)
assert.NoError(afero.WriteFile(fs.Source, filepath.Join(archetypeThemeDir, "index.md"), []byte(fmt.Sprintf(contentFile, "index.md")), 0755))
assert.NoError(afero.WriteFile(fs.Source, filepath.Join(archetypeThemeDir, "resources", "hugo1.json"), []byte(`hugo1: {{ printf "no template handling in here" }}`), 0755))
c.Assert(afero.WriteFile(mm, filepath.Join(archetypeThemeDir, "index.md"), []byte(fmt.Sprintf(contentFile, "index.md")), 0755), qt.IsNil)
c.Assert(afero.WriteFile(mm, filepath.Join(archetypeThemeDir, "resources", "hugo1.json"), []byte(`hugo1: {{ printf "no template handling in here" }}`), 0755), qt.IsNil)
c.Assert(initFs(mm), qt.IsNil)
cfg, fs := newTestCfg(c, mm)
h, err := hugolib.NewHugoSites(deps.DepsCfg{Cfg: cfg, Fs: fs})
assert.NoError(err)
assert.Equal(2, len(h.Sites))
c.Assert(err, qt.IsNil)
c.Assert(len(h.Sites), qt.Equals, 2)
assert.NoError(create.NewContent(h, "my-bundle", "post/my-post"))
c.Assert(create.NewContent(h, "my-bundle", "post/my-post"), qt.IsNil)
assertContains(assert, readFileFromFs(t, fs.Source, filepath.Join("content", "post/my-post/resources/hugo1.json")), `hugo1: {{ printf "no template handling in here" }}`)
assertContains(assert, readFileFromFs(t, fs.Source, filepath.Join("content", "post/my-post/resources/hugo2.xml")), `hugo2: {{ printf "no template handling in here" }}`)
cContains(c, readFileFromFs(t, fs.Source, filepath.Join("content", "post/my-post/resources/hugo1.json")), `hugo1: {{ printf "no template handling in here" }}`)
cContains(c, readFileFromFs(t, fs.Source, filepath.Join("content", "post/my-post/resources/hugo2.xml")), `hugo2: {{ printf "no template handling in here" }}`)
// Content files should get the correct site context.
// TODO(bep) archetype check i18n
assertContains(assert, readFileFromFs(t, fs.Source, filepath.Join("content", "post/my-post/index.md")), `File: index.md`, `Site Lang: en`, `Name: My Post`, `i18n: Hugo Rocks!`)
assertContains(assert, readFileFromFs(t, fs.Source, filepath.Join("content", "post/my-post/index.nn.md")), `File: index.nn.md`, `Site Lang: nn`, `Name: My Post`, `i18n: Hugo Rokkar!`)
cContains(c, readFileFromFs(t, fs.Source, filepath.Join("content", "post/my-post/index.md")), `File: index.md`, `Site Lang: en`, `Name: My Post`, `i18n: Hugo Rocks!`)
cContains(c, readFileFromFs(t, fs.Source, filepath.Join("content", "post/my-post/index.nn.md")), `File: index.nn.md`, `Site Lang: nn`, `Name: My Post`, `i18n: Hugo Rokkar!`)
assertContains(assert, readFileFromFs(t, fs.Source, filepath.Join("content", "post/my-post/pages/bio.md")), `File: bio.md`, `Site Lang: en`, `Name: My Post`)
cContains(c, readFileFromFs(t, fs.Source, filepath.Join("content", "post/my-post/pages/bio.md")), `File: bio.md`, `Site Lang: en`, `Name: My Post`)
assert.NoError(create.NewContent(h, "my-theme-bundle", "post/my-theme-post"))
assertContains(assert, readFileFromFs(t, fs.Source, filepath.Join("content", "post/my-theme-post/index.md")), `File: index.md`, `Site Lang: en`, `Name: My Theme Post`, `i18n: Hugo Rocks!`)
assertContains(assert, readFileFromFs(t, fs.Source, filepath.Join("content", "post/my-theme-post/resources/hugo1.json")), `hugo1: {{ printf "no template handling in here" }}`)
c.Assert(create.NewContent(h, "my-theme-bundle", "post/my-theme-post"), qt.IsNil)
cContains(c, readFileFromFs(t, fs.Source, filepath.Join("content", "post/my-theme-post/index.md")), `File: index.md`, `Site Lang: en`, `Name: My Theme Post`, `i18n: Hugo Rocks!`)
cContains(c, readFileFromFs(t, fs.Source, filepath.Join("content", "post/my-theme-post/resources/hugo1.json")), `hugo1: {{ printf "no template handling in here" }}`)
}
func initFs(fs *hugofs.Fs) error {
func initFs(fs afero.Fs) error {
perm := os.FileMode(0755)
var err error
@@ -146,8 +154,8 @@ func initFs(fs *hugofs.Fs) error {
filepath.Join("themes", "sample", "archetypes"),
}
for _, dir := range dirs {
err = fs.Source.Mkdir(dir, perm)
if err != nil {
err = fs.Mkdir(dir, perm)
if err != nil && !os.IsExist(err) {
return err
}
}
@@ -198,7 +206,7 @@ Some text.
`,
},
} {
f, err := fs.Source.Create(v.path)
f, err := fs.Create(v.path)
if err != nil {
return err
}
@@ -213,14 +221,15 @@ Some text.
return nil
}
func assertContains(assert *require.Assertions, v interface{}, matches ...string) {
func cContains(c *qt.C, v interface{}, matches ...string) {
for _, m := range matches {
assert.Contains(v, m)
c.Assert(v, qt.Contains, m)
}
}
// TODO(bep) extract common testing package with this and some others
func readFileFromFs(t *testing.T, fs afero.Fs, filename string) string {
t.Helper()
filename = filepath.FromSlash(filename)
b, err := afero.ReadFile(fs, filename)
if err != nil {
@@ -238,12 +247,11 @@ func readFileFromFs(t *testing.T, fs afero.Fs, filename string) string {
return string(b)
}
func newTestCfg(assert *require.Assertions) (*viper.Viper, *hugofs.Fs) {
func newTestCfg(c *qt.C, mm afero.Fs) (*viper.Viper, *hugofs.Fs) {
cfg := `
theme = "mytheme"
[languages]
[languages.en]
weight = 1
@@ -254,18 +262,23 @@ languageName = "Nynorsk"
contentDir = "content_nn"
`
if mm == nil {
mm = afero.NewMemMapFs()
}
mm := afero.NewMemMapFs()
mm.MkdirAll(filepath.FromSlash("content_nn"), 0777)
assert.NoError(afero.WriteFile(mm, filepath.Join("i18n", "en.toml"), []byte(`[hugo]
other = "Hugo Rocks!"`), 0755))
assert.NoError(afero.WriteFile(mm, filepath.Join("i18n", "nn.toml"), []byte(`[hugo]
other = "Hugo Rokkar!"`), 0755))
mm.MkdirAll(filepath.FromSlash("themes/mytheme"), 0777)
assert.NoError(afero.WriteFile(mm, "config.toml", []byte(cfg), 0755))
c.Assert(afero.WriteFile(mm, filepath.Join("i18n", "en.toml"), []byte(`[hugo]
other = "Hugo Rocks!"`), 0755), qt.IsNil)
c.Assert(afero.WriteFile(mm, filepath.Join("i18n", "nn.toml"), []byte(`[hugo]
other = "Hugo Rokkar!"`), 0755), qt.IsNil)
c.Assert(afero.WriteFile(mm, "config.toml", []byte(cfg), 0755), qt.IsNil)
v, _, err := hugolib.LoadConfig(hugolib.ConfigSourceDescriptor{Fs: mm, Filename: "config.toml"})
assert.NoError(err)
c.Assert(err, qt.IsNil)
return v, hugofs.NewFrom(mm, v)
+51
View File
@@ -0,0 +1,51 @@
// Copyright 2019 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package deploy
import (
"context"
"time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/cloudfront"
)
// InvalidateCloudFront invalidates the CloudFront cache for distributionID.
// It uses the default AWS credentials from the environment.
func InvalidateCloudFront(ctx context.Context, distributionID string) error {
// SharedConfigEnable enables loading "shared config (~/.aws/config) and
// shared credentials (~/.aws/credentials) files".
// See https://docs.aws.amazon.com/sdk-for-go/api/aws/session/ for more
// details.
// This is the same codepath used by Go CDK when creating an s3 URL.
// TODO: Update this to a Go CDK helper once available
// (https://github.com/google/go-cloud/issues/2003).
sess, err := session.NewSessionWithOptions(session.Options{SharedConfigState: session.SharedConfigEnable})
if err != nil {
return err
}
req := &cloudfront.CreateInvalidationInput{
DistributionId: aws.String(distributionID),
InvalidationBatch: &cloudfront.InvalidationBatch{
CallerReference: aws.String(time.Now().Format("20060102150405")),
Paths: &cloudfront.Paths{
Items: []*string{aws.String("/*")},
Quantity: aws.Int64(1),
},
},
}
_, err = cloudfront.New(sess).CreateInvalidationWithContext(ctx, req)
return err
}
+696
View File
@@ -0,0 +1,696 @@
// Copyright 2019 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package deploy
import (
"bytes"
"compress/gzip"
"context"
"crypto/md5"
"fmt"
"io"
"io/ioutil"
"mime"
"os"
"path/filepath"
"regexp"
"runtime"
"sort"
"strings"
"sync"
"github.com/dustin/go-humanize"
"github.com/gobwas/glob"
"github.com/gohugoio/hugo/config"
"github.com/pkg/errors"
"github.com/spf13/afero"
jww "github.com/spf13/jwalterweatherman"
"golang.org/x/text/unicode/norm"
"gocloud.dev/blob"
_ "gocloud.dev/blob/fileblob" // import
_ "gocloud.dev/blob/gcsblob" // import
_ "gocloud.dev/blob/s3blob" // import
)
// Deployer supports deploying the site to target cloud providers.
type Deployer struct {
localFs afero.Fs
bucket *blob.Bucket
target *target // the target to deploy to
matchers []*matcher // matchers to apply to uploaded files
ordering []*regexp.Regexp // orders uploads
quiet bool // true reduces STDOUT
confirm bool // true enables confirmation before making changes
dryRun bool // true skips conformations and prints changes instead of applying them
force bool // true forces upload of all files
invalidateCDN bool // true enables invalidate CDN cache (if possible)
maxDeletes int // caps the # of files to delete; -1 to disable
// For tests...
summary deploySummary // summary of latest Deploy results
}
type deploySummary struct {
NumLocal, NumRemote, NumUploads, NumDeletes int
}
// New constructs a new *Deployer.
func New(cfg config.Provider, localFs afero.Fs) (*Deployer, error) {
targetName := cfg.GetString("target")
// Load the [deployment] section of the config.
dcfg, err := decodeConfig(cfg)
if err != nil {
return nil, err
}
if len(dcfg.Targets) == 0 {
return nil, errors.New("no deployment targets found")
}
// Find the target to deploy to.
var tgt *target
if targetName == "" {
// Default to the first target.
tgt = dcfg.Targets[0]
} else {
for _, t := range dcfg.Targets {
if t.Name == targetName {
tgt = t
}
}
if tgt == nil {
return nil, fmt.Errorf("deployment target %q not found", targetName)
}
}
return &Deployer{
localFs: localFs,
target: tgt,
matchers: dcfg.Matchers,
ordering: dcfg.ordering,
quiet: cfg.GetBool("quiet"),
confirm: cfg.GetBool("confirm"),
dryRun: cfg.GetBool("dryRun"),
force: cfg.GetBool("force"),
invalidateCDN: cfg.GetBool("invalidateCDN"),
maxDeletes: cfg.GetInt("maxDeletes"),
}, nil
}
func (d *Deployer) openBucket(ctx context.Context) (*blob.Bucket, error) {
if d.bucket != nil {
return d.bucket, nil
}
jww.FEEDBACK.Printf("Deploying to target %q (%s)\n", d.target.Name, d.target.URL)
return blob.OpenBucket(ctx, d.target.URL)
}
// Deploy deploys the site to a target.
func (d *Deployer) Deploy(ctx context.Context) error {
bucket, err := d.openBucket(ctx)
if err != nil {
return err
}
// Load local files from the source directory.
var include, exclude glob.Glob
if d.target != nil {
include, exclude = d.target.includeGlob, d.target.excludeGlob
}
local, err := walkLocal(d.localFs, d.matchers, include, exclude)
if err != nil {
return err
}
jww.INFO.Printf("Found %d local files.\n", len(local))
d.summary.NumLocal = len(local)
// Load remote files from the target.
remote, err := walkRemote(ctx, bucket, include, exclude)
if err != nil {
return err
}
jww.INFO.Printf("Found %d remote files.\n", len(remote))
d.summary.NumRemote = len(remote)
// Diff local vs remote to see what changes need to be applied.
uploads, deletes := findDiffs(local, remote, d.force)
d.summary.NumUploads = len(uploads)
d.summary.NumDeletes = len(deletes)
if len(uploads)+len(deletes) == 0 {
if !d.quiet {
jww.FEEDBACK.Println("No changes required.")
}
return nil
}
if !d.quiet {
jww.FEEDBACK.Println(summarizeChanges(uploads, deletes))
}
// Ask for confirmation before proceeding.
if d.confirm && !d.dryRun {
fmt.Printf("Continue? (Y/n) ")
var confirm string
if _, err := fmt.Scanln(&confirm); err != nil {
return err
}
if confirm != "" && confirm[0] != 'y' && confirm[0] != 'Y' {
return errors.New("aborted")
}
}
// Order the uploads. They are organized in groups; all uploads in a group
// must be complete before moving on to the next group.
uploadGroups := applyOrdering(d.ordering, uploads)
// Apply the changes in parallel, using an inverted worker
// pool (https://www.youtube.com/watch?v=5zXAHh5tJqQ&t=26m58s).
// sem prevents more than nParallel concurrent goroutines.
const nParallel = 10
var errs []error
var errMu sync.Mutex // protects errs
for _, uploads := range uploadGroups {
// Short-circuit for an empty group.
if len(uploads) == 0 {
continue
}
// Within the group, apply uploads in parallel.
sem := make(chan struct{}, nParallel)
for _, upload := range uploads {
if d.dryRun {
if !d.quiet {
jww.FEEDBACK.Printf("[DRY RUN] Would upload: %v\n", upload)
}
continue
}
sem <- struct{}{}
go func(upload *fileToUpload) {
if err := doSingleUpload(ctx, bucket, upload); err != nil {
errMu.Lock()
defer errMu.Unlock()
errs = append(errs, err)
}
<-sem
}(upload)
}
// Wait for all uploads in the group to finish.
for n := nParallel; n > 0; n-- {
sem <- struct{}{}
}
}
if d.maxDeletes != -1 && len(deletes) > d.maxDeletes {
jww.WARN.Printf("Skipping %d deletes because it is more than --maxDeletes (%d). If this is expected, set --maxDeletes to a larger number, or -1 to disable this check.\n", len(deletes), d.maxDeletes)
d.summary.NumDeletes = 0
} else {
// Apply deletes in parallel.
sort.Slice(deletes, func(i, j int) bool { return deletes[i] < deletes[j] })
sem := make(chan struct{}, nParallel)
for _, del := range deletes {
if d.dryRun {
if !d.quiet {
jww.FEEDBACK.Printf("[DRY RUN] Would delete %s\n", del)
}
continue
}
sem <- struct{}{}
go func(del string) {
jww.INFO.Printf("Deleting %s...\n", del)
if err := bucket.Delete(ctx, del); err != nil {
errMu.Lock()
defer errMu.Unlock()
errs = append(errs, err)
}
<-sem
}(del)
}
// Wait for all deletes to finish.
for n := nParallel; n > 0; n-- {
sem <- struct{}{}
}
}
if len(errs) > 0 {
if !d.quiet {
jww.FEEDBACK.Printf("Encountered %d errors.\n", len(errs))
}
return errs[0]
}
if !d.quiet {
jww.FEEDBACK.Println("Success!")
}
if d.invalidateCDN {
if d.target.CloudFrontDistributionID != "" {
jww.FEEDBACK.Println("Invalidating CloudFront CDN...")
if err := InvalidateCloudFront(ctx, d.target.CloudFrontDistributionID); err != nil {
jww.FEEDBACK.Printf("Failed to invalidate CloudFront CDN: %v\n", err)
return err
}
}
if d.target.GoogleCloudCDNOrigin != "" {
jww.FEEDBACK.Println("Invalidating Google Cloud CDN...")
if err := InvalidateGoogleCloudCDN(ctx, d.target.GoogleCloudCDNOrigin); err != nil {
jww.FEEDBACK.Printf("Failed to invalidate Google Cloud CDN: %v\n", err)
return err
}
}
jww.FEEDBACK.Println("Success!")
}
return nil
}
// summarizeChanges creates a text description of the proposed changes.
func summarizeChanges(uploads []*fileToUpload, deletes []string) string {
uploadSize := int64(0)
for _, u := range uploads {
uploadSize += u.Local.UploadSize
}
return fmt.Sprintf("Identified %d file(s) to upload, totaling %s, and %d file(s) to delete.", len(uploads), humanize.Bytes(uint64(uploadSize)), len(deletes))
}
// doSingleUpload executes a single file upload.
func doSingleUpload(ctx context.Context, bucket *blob.Bucket, upload *fileToUpload) error {
jww.INFO.Printf("Uploading %v...\n", upload)
opts := &blob.WriterOptions{
CacheControl: upload.Local.CacheControl(),
ContentEncoding: upload.Local.ContentEncoding(),
ContentType: upload.Local.ContentType(),
}
w, err := bucket.NewWriter(ctx, upload.Local.SlashPath, opts)
if err != nil {
return err
}
r, err := upload.Local.Reader()
if err != nil {
return err
}
defer r.Close()
_, err = io.Copy(w, r)
if err != nil {
return err
}
if err := w.Close(); err != nil {
return err
}
return nil
}
// localFile represents a local file from the source. Use newLocalFile to
// construct one.
type localFile struct {
// NativePath is the native path to the file (using file.Separator).
NativePath string
// SlashPath is NativePath converted to use /.
SlashPath string
// UploadSize is the size of the content to be uploaded. It may not
// be the same as the local file size if the content will be
// gzipped before upload.
UploadSize int64
fs afero.Fs
matcher *matcher
md5 []byte // cache
gzipped bytes.Buffer // cached of gzipped contents if gzipping
}
// newLocalFile initializes a *localFile.
func newLocalFile(fs afero.Fs, nativePath, slashpath string, m *matcher) (*localFile, error) {
f, err := fs.Open(nativePath)
if err != nil {
return nil, err
}
defer f.Close()
lf := &localFile{
NativePath: nativePath,
SlashPath: slashpath,
fs: fs,
matcher: m,
}
if m != nil && m.Gzip {
// We're going to gzip the content. Do it once now, and cache the result
// in gzipped. The UploadSize is the size of the gzipped content.
gz := gzip.NewWriter(&lf.gzipped)
if _, err := io.Copy(gz, f); err != nil {
return nil, err
}
if err := gz.Close(); err != nil {
return nil, err
}
lf.UploadSize = int64(lf.gzipped.Len())
} else {
// Raw content. Just get the UploadSize.
info, err := f.Stat()
if err != nil {
return nil, err
}
lf.UploadSize = info.Size()
}
return lf, nil
}
// Reader returns an io.ReadCloser for reading the content to be uploaded.
// The caller must call Close on the returned ReaderCloser.
// The reader content may not be the same as the local file content due to
// gzipping.
func (lf *localFile) Reader() (io.ReadCloser, error) {
if lf.matcher != nil && lf.matcher.Gzip {
// We've got the gzipped contents cached in gzipped.
// Note: we can't use lf.gzipped directly as a Reader, since we it discards
// data after it is read, and we may read it more than once.
return ioutil.NopCloser(bytes.NewReader(lf.gzipped.Bytes())), nil
}
// Not expected to fail since we did it successfully earlier in newLocalFile,
// but could happen due to changes in the underlying filesystem.
return lf.fs.Open(lf.NativePath)
}
// CacheControl returns the Cache-Control header to use for lf, based on the
// first matching matcher (if any).
func (lf *localFile) CacheControl() string {
if lf.matcher == nil {
return ""
}
return lf.matcher.CacheControl
}
// ContentEncoding returns the Content-Encoding header to use for lf, based
// on the matcher's Content-Encoding and Gzip fields.
func (lf *localFile) ContentEncoding() string {
if lf.matcher == nil {
return ""
}
if lf.matcher.Gzip {
return "gzip"
}
return lf.matcher.ContentEncoding
}
// ContentType returns the Content-Type header to use for lf.
// It first checks if there's a Content-Type header configured via a matching
// matcher; if not, it tries to generate one based on the filename extension.
// If this fails, the Content-Type will be the empty string. In this case, Go
// Cloud will automatically try to infer a Content-Type based on the file
// content.
func (lf *localFile) ContentType() string {
if lf.matcher != nil && lf.matcher.ContentType != "" {
return lf.matcher.ContentType
}
// TODO: Hugo has a MediaType and a MediaTypes list and also a concept
// of custom MIME types.
// Use 1) The matcher 2) Hugo's MIME types 3) TypeByExtension.
return mime.TypeByExtension(filepath.Ext(lf.NativePath))
}
// Force returns true if the file should be forced to re-upload based on the
// matching matcher.
func (lf *localFile) Force() bool {
return lf.matcher != nil && lf.matcher.Force
}
// MD5 returns an MD5 hash of the content to be uploaded.
func (lf *localFile) MD5() []byte {
if len(lf.md5) > 0 {
return lf.md5
}
h := md5.New()
r, err := lf.Reader()
if err != nil {
return nil
}
defer r.Close()
if _, err := io.Copy(h, r); err != nil {
return nil
}
lf.md5 = h.Sum(nil)
return lf.md5
}
// knownHiddenDirectory checks if the specified name is a well known
// hidden directory.
func knownHiddenDirectory(name string) bool {
var knownDirectories = []string{
".well-known",
}
for _, dir := range knownDirectories {
if name == dir {
return true
}
}
return false
}
// walkLocal walks the source directory and returns a flat list of files,
// using localFile.SlashPath as the map keys.
func walkLocal(fs afero.Fs, matchers []*matcher, include, exclude glob.Glob) (map[string]*localFile, error) {
retval := map[string]*localFile{}
err := afero.Walk(fs, "", func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info.IsDir() {
// Skip hidden directories.
if path != "" && strings.HasPrefix(info.Name(), ".") {
// Except for specific hidden directories
if !knownHiddenDirectory(info.Name()) {
return filepath.SkipDir
}
}
return nil
}
// .DS_Store is an internal MacOS attribute file; skip it.
if info.Name() == ".DS_Store" {
return nil
}
// When a file system is HFS+, its filepath is in NFD form.
if runtime.GOOS == "darwin" {
path = norm.NFC.String(path)
}
// Check include/exclude matchers.
slashpath := filepath.ToSlash(path)
if include != nil && !include.Match(slashpath) {
jww.INFO.Printf(" dropping %q due to include\n", slashpath)
return nil
}
if exclude != nil && exclude.Match(slashpath) {
jww.INFO.Printf(" dropping %q due to exclude\n", slashpath)
return nil
}
// Find the first matching matcher (if any).
var m *matcher
for _, cur := range matchers {
if cur.Matches(slashpath) {
m = cur
break
}
}
lf, err := newLocalFile(fs, path, slashpath, m)
if err != nil {
return err
}
retval[lf.SlashPath] = lf
return nil
})
if err != nil {
return nil, err
}
return retval, nil
}
// walkRemote walks the target bucket and returns a flat list.
func walkRemote(ctx context.Context, bucket *blob.Bucket, include, exclude glob.Glob) (map[string]*blob.ListObject, error) {
retval := map[string]*blob.ListObject{}
iter := bucket.List(nil)
for {
obj, err := iter.Next(ctx)
if err == io.EOF {
break
}
if err != nil {
return nil, err
}
// Check include/exclude matchers.
if include != nil && !include.Match(obj.Key) {
jww.INFO.Printf(" remote dropping %q due to include\n", obj.Key)
continue
}
if exclude != nil && exclude.Match(obj.Key) {
jww.INFO.Printf(" remote dropping %q due to exclude\n", obj.Key)
continue
}
// If the remote didn't give us an MD5, compute one.
// This can happen for some providers (e.g., fileblob, which uses the
// local filesystem), but not for the most common Cloud providers
// (S3, GCS, Azure). Although, it can happen for S3 if the blob was uploaded
// via a multi-part upload.
// Although it's unfortunate to have to read the file, it's likely better
// than assuming a delta and re-uploading it.
if len(obj.MD5) == 0 {
r, err := bucket.NewReader(ctx, obj.Key, nil)
if err == nil {
h := md5.New()
if _, err := io.Copy(h, r); err == nil {
obj.MD5 = h.Sum(nil)
}
r.Close()
}
}
retval[obj.Key] = obj
}
return retval, nil
}
// uploadReason is an enum of reasons why a file must be uploaded.
type uploadReason string
const (
reasonUnknown uploadReason = "unknown"
reasonNotFound uploadReason = "not found at target"
reasonForce uploadReason = "--force"
reasonSize uploadReason = "size differs"
reasonMD5Differs uploadReason = "md5 differs"
reasonMD5Missing uploadReason = "remote md5 missing"
)
// fileToUpload represents a single local file that should be uploaded to
// the target.
type fileToUpload struct {
Local *localFile
Reason uploadReason
}
func (u *fileToUpload) String() string {
details := []string{humanize.Bytes(uint64(u.Local.UploadSize))}
if s := u.Local.CacheControl(); s != "" {
details = append(details, fmt.Sprintf("Cache-Control: %q", s))
}
if s := u.Local.ContentEncoding(); s != "" {
details = append(details, fmt.Sprintf("Content-Encoding: %q", s))
}
if s := u.Local.ContentType(); s != "" {
details = append(details, fmt.Sprintf("Content-Type: %q", s))
}
return fmt.Sprintf("%s (%s): %v", u.Local.SlashPath, strings.Join(details, ", "), u.Reason)
}
// findDiffs diffs localFiles vs remoteFiles to see what changes should be
// applied to the remote target. It returns a slice of *fileToUpload and a
// slice of paths for files to delete.
func findDiffs(localFiles map[string]*localFile, remoteFiles map[string]*blob.ListObject, force bool) ([]*fileToUpload, []string) {
var uploads []*fileToUpload
var deletes []string
found := map[string]bool{}
for path, lf := range localFiles {
upload := false
reason := reasonUnknown
if remoteFile, ok := remoteFiles[path]; ok {
// The file exists in remote. Let's see if we need to upload it anyway.
// TODO: We don't register a diff if the metadata (e.g., Content-Type
// header) has changed. This would be difficult/expensive to detect; some
// providers return metadata along with their "List" result, but others
// (notably AWS S3) do not, so gocloud.dev's blob.Bucket doesn't expose
// it in the list result. It would require a separate request per blob
// to fetch. At least for now, we work around this by documenting it and
// providing a "force" flag (to re-upload everything) and a "force" bool
// per matcher (to re-upload all files in a matcher whose headers may have
// changed).
// Idea: extract a sample set of 1 file per extension + 1 file per matcher
// and check those files?
if force {
upload = true
reason = reasonForce
} else if lf.Force() {
upload = true
reason = reasonForce
} else if lf.UploadSize != remoteFile.Size {
upload = true
reason = reasonSize
} else if len(remoteFile.MD5) == 0 {
// This shouldn't happen unless the remote didn't give us an MD5 hash
// from List, AND we failed to compute one by reading the remote file.
// Default to considering the files different.
upload = true
reason = reasonMD5Missing
} else if !bytes.Equal(lf.MD5(), remoteFile.MD5) {
upload = true
reason = reasonMD5Differs
} else {
// Nope! Leave uploaded = false.
}
found[path] = true
} else {
// The file doesn't exist in remote.
upload = true
reason = reasonNotFound
}
if upload {
jww.DEBUG.Printf("%s needs to be uploaded: %v\n", path, reason)
uploads = append(uploads, &fileToUpload{lf, reason})
} else {
jww.DEBUG.Printf("%s exists at target and does not need to be uploaded", path)
}
}
// Remote files that weren't found locally should be deleted.
for path := range remoteFiles {
if !found[path] {
deletes = append(deletes, path)
}
}
return uploads, deletes
}
// applyOrdering returns an ordered slice of slices of uploads.
//
// The returned slice will have length len(ordering)+1.
//
// The subslice at index i, for i = 0 ... len(ordering)-1, will have all of the
// uploads whose Local.SlashPath matched the regex at ordering[i] (but not any
// previous ordering regex).
// The subslice at index len(ordering) will have the remaining uploads that
// didn't match any ordering regex.
//
// The subslices are sorted by Local.SlashPath.
func applyOrdering(ordering []*regexp.Regexp, uploads []*fileToUpload) [][]*fileToUpload {
// Sort the whole slice by Local.SlashPath first.
sort.Slice(uploads, func(i, j int) bool { return uploads[i].Local.SlashPath < uploads[j].Local.SlashPath })
retval := make([][]*fileToUpload, len(ordering)+1)
for _, u := range uploads {
matched := false
for i, re := range ordering {
if re.MatchString(u.Local.SlashPath) {
retval[i] = append(retval[i], u)
matched = true
break
}
}
if !matched {
retval[len(ordering)] = append(retval[len(ordering)], u)
}
}
return retval
}
+138
View File
@@ -0,0 +1,138 @@
// Copyright 2019 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package deploy
import (
"fmt"
"regexp"
"github.com/gobwas/glob"
"github.com/gohugoio/hugo/config"
hglob "github.com/gohugoio/hugo/hugofs/glob"
"github.com/mitchellh/mapstructure"
)
const deploymentConfigKey = "deployment"
// deployConfig is the complete configuration for deployment.
type deployConfig struct {
Targets []*target
Matchers []*matcher
Order []string
ordering []*regexp.Regexp // compiled Order
}
type target struct {
Name string
URL string
CloudFrontDistributionID string
// GoogleCloudCDNOrigin specifies the Google Cloud project and CDN origin to
// invalidate when deploying this target. It is specified as <project>/<origin>.
GoogleCloudCDNOrigin string
// Optional patterns of files to include/exclude for this target.
// Parsed using github.com/gobwas/glob.
Include string
Exclude string
// Parsed versions of Include/Exclude.
includeGlob glob.Glob
excludeGlob glob.Glob
}
func (tgt *target) parseIncludeExclude() error {
var err error
if tgt.Include != "" {
tgt.includeGlob, err = hglob.GetGlob(tgt.Include)
if err != nil {
return fmt.Errorf("invalid deployment.target.include %q: %v", tgt.Include, err)
}
}
if tgt.Exclude != "" {
tgt.excludeGlob, err = hglob.GetGlob(tgt.Exclude)
if err != nil {
return fmt.Errorf("invalid deployment.target.exclude %q: %v", tgt.Exclude, err)
}
}
return nil
}
// matcher represents configuration to be applied to files whose paths match
// a specified pattern.
type matcher struct {
// Pattern is the string pattern to match against paths.
// Matching is done against paths converted to use / as the path separator.
Pattern string
// CacheControl specifies caching attributes to use when serving the blob.
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control
CacheControl string
// ContentEncoding specifies the encoding used for the blob's content, if any.
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding
ContentEncoding string
// ContentType specifies the MIME type of the blob being written.
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type
ContentType string
// Gzip determines whether the file should be gzipped before upload.
// If so, the ContentEncoding field will automatically be set to "gzip".
Gzip bool
// Force indicates that matching files should be re-uploaded. Useful when
// other route-determined metadata (e.g., ContentType) has changed.
Force bool
// re is Pattern compiled.
re *regexp.Regexp
}
func (m *matcher) Matches(path string) bool {
return m.re.MatchString(path)
}
// decode creates a config from a given Hugo configuration.
func decodeConfig(cfg config.Provider) (deployConfig, error) {
var dcfg deployConfig
if !cfg.IsSet(deploymentConfigKey) {
return dcfg, nil
}
if err := mapstructure.WeakDecode(cfg.GetStringMap(deploymentConfigKey), &dcfg); err != nil {
return dcfg, err
}
for _, tgt := range dcfg.Targets {
if err := tgt.parseIncludeExclude(); err != nil {
return dcfg, err
}
}
var err error
for _, m := range dcfg.Matchers {
m.re, err = regexp.Compile(m.Pattern)
if err != nil {
return dcfg, fmt.Errorf("invalid deployment.matchers.pattern: %v", err)
}
}
for _, o := range dcfg.Order {
re, err := regexp.Compile(o)
if err != nil {
return dcfg, fmt.Errorf("invalid deployment.orderings.pattern: %v", err)
}
dcfg.ordering = append(dcfg.ordering, re)
}
return dcfg, nil
}

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