Compare commits

...

414 Commits

Author SHA1 Message Date
hugoreleaser f14d773841 releaser: Add release notes to /docs for release of 0.46
[ci skip]
2018-08-01 09:00:52 +00:00
hugoreleaser 3aa838cf2b releaser: Bump versions for release of 0.46
[ci skip]
2018-08-01 09:00:52 +00:00
Bjørn Erik Pedersen a3a26597cf Release 0.46 2018-08-01 10:52:45 +02:00
hugoreleaser 92d776b0df releaser: Add release notes draft for 0.46
Rename to *-ready.md to continue. [ci skip]
2018-08-01 08:10:57 +00:00
Bjørn Erik Pedersen e6dd54943f Merge commit '766085c2dc6fc95ac30fda2a9ebde2355fc12554' 2018-08-01 10:01:49 +02:00
Bjørn Erik Pedersen 766085c2dc Squashed 'docs/' changes from a4fa0d1d6..81847981f
81847981f Add notes for installing "extended" Sass/SCSS version
02da3bb58 Include usage of disqus internal template
9b53380c4 Update sitemap-template.md
f3417dd52 Update sitemap-template.md
aae33d9a8 Update sitemap-template.md
834edc205 Release 0.45.1
fb93ab905 Merge branch 'temp451'
79f350906 releaser: Prepare repository for 0.46-DEV
25cd2352c releaser: Add release notes to /docs for release of 0.45.1
e60377c71 releaser: Bump versions for release of 0.45.1
873f6dce2 Update features.md
ecc116642 Update link for Azure
cb88c3185 Added .Site.Home to Site Variiables (#541)
975a88791 Document includePaths
56c4e332f Release Hugo 0.45
c22b25210 Merge branch 'temp45'
0ffad3ada releaser: Prepare repository for 0.46-DEV
08d494cc3 releaser: Add release notes to /docs for release of 0.45
ad546ba45 releaser: Bump versions for release of 0.45
971c46bb2 Fixed "Sratch" to become "Scratch" on line 44
a28255bf3 Clarify the meaning of .Pages vs .Site.Pages
127aeee09 docs: Update ref, relref, GetPage docs
350d674ec resources.Concat doesn't have an alias
1fd1219b0 docs: Document refLinksErrorLevel and refLinksNotFoundURL
af2252ff6 Merge commit 'a3535c8486b2ce762b1a8a9c30b03985c3e02cee'
a11486805 Merge commit 'b6b37a1f00f808f3c0d2715f65ca2d3091f36495'
1c8896cb1 Fix addkit link to account for i18n
468aef3fc releaser: Prepare repository for 0.45-DEV
c6f4b97a2 releaser: Add release notes to /docs for release of 0.44
d3985afb7 releaser: Bump versions for release of 0.44
2c59a330c Adjust release notes
83966769a releaser: Prepare repository for 0.44-DEV
e539613f7 releaser: Add release notes to /docs for release of 0.43
2bf648944 releaser: Bump versions for release of 0.43
d9d6e4bf7 Fix typos
d6798afda Merge commit '98293eaa1570b5aff4452021c8b6d6c8560b3f06'
37cc52261 Add a newScratch template func
1f7f09613 Merge branch 'release-0.42.2'
857b0b26a releaser: Prepare repository for 0.43-DEV

git-subtree-dir: docs
git-subtree-split: 81847981f1
2018-08-01 10:01:05 +02:00
Bjørn Erik Pedersen b5d13ca16b Update Chroma
And since I have updated Dep locally, I get a bunch of other totally unrelated diffs. Which looks innocent enough.

Fixes #5019
2018-08-01 09:34:28 +02:00
Bjørn Erik Pedersen 6b02f5c0f4 Make resources fetched via resources.Get and similar language agnostic
With the newly released Hugo Pipes, resources fetched and processed via `resources.Get` and similar was published to the relevant language sub folder when in multilingual mode.

The thought behind that was maximum flexibility with support for `assetDir` per language.

In practice this was a bad idea:

* You get duplication of identical content, with added processing time
* You end up with path issues that seem to be hard to find a way around (`@fa-font-path` is one example)

This commit changes that. Now there is only one `assetDir` and if you, as one example, need to generate a CSS per langugage, you need to set the paths yourself.

Fixes #5017
2018-07-31 23:33:04 +02:00
Bjørn Erik Pedersen 88e447c449 tocss/scss: Improve _ prefix handling in SCSS imports
See #5008
2018-07-31 16:53:03 +02:00
Rob Jackson b718d743b7 Fix file paths for uncached transformed images
This commit also fixes an existing test to work according to the correct logic. The test was written based on erroneous behavior. We resize the image to 300x200px, and are now trying to fit it within a 50px square. The longest edge is 300 pixels, so we need to divide it by 6 (300 / 50 == 6). And then scale the shortest edge with the same proportion (200 / 6 == 33.33).

The original test was transforming the original source image, hence the previous values:

900 x 562
900 / 50 == 18
562 / 18 == 31.22

Fixes #5012
2018-07-31 13:31:35 +02:00
Bjørn Erik Pedersen 0ba19c57f1 tpl/partials: Add templates.Exists
Fixes #5010
2018-07-31 13:28:15 +02:00
Bjørn Erik Pedersen 0afa2897a0 tpl/partials: Remove superflous loop
No need to check the themes template prefix.
2018-07-31 13:28:15 +02:00
Bjørn Erik Pedersen f219ac09f6 tocss/scss: Improve SCSS project vs themes import resolution
Before this commit, only SASS/SCSS  components imported from main.scss at first level can be overwritten by homonymous files in projects or over-preceding theme components.

This commit fixes that by implementing a custom import resolver which will be tried first. This resolver will make sure that the project/theme hierarchy is always respected.

Fixes #5008
2018-07-31 10:54:10 +02:00
Bjørn Erik Pedersen 786f72302f Fix image cache eviction for sites with subdir in baseURL
Fixes #5006
2018-07-29 14:26:45 +02:00
hugoreleaser 0cae1cf828 releaser: Prepare repository for 0.46-DEV
[ci skip]
2018-07-25 08:58:54 +00:00
hugoreleaser 3b18042ee6 releaser: Add release notes to /docs for release of 0.45.1
[ci skip]
2018-07-25 08:56:21 +00:00
hugoreleaser e38843f4bf releaser: Bump versions for release of 0.45.1
[ci skip]
2018-07-25 08:56:21 +00:00
Bjørn Erik Pedersen 87f0dc14ab Release 0.45.1 2018-07-25 10:51:27 +02:00
hugoreleaser b7d9ab136d releaser: Add release notes draft for 0.45.1
Rename to *-ready.md to continue. [ci skip]
2018-07-25 08:37:50 +00:00
Bjørn Erik Pedersen 04d4c08dbc hugolib: Fix .Site.GetPage regression
In Hugo 0.44 we simplified the `.Site.GetPage` API and added code to handle the old-style syntax in most cases.

This logic did not handle the lookup of the home page via `.Site.GetPage "section" ""` and similar. This commit fixes that.

Fixes #4989
2018-07-24 11:37:59 +02:00
Bjørn Erik Pedersen 016dd4a69a Add Page.FirstSection
It was added and then removed by accident some time ago. Let us add it again, as it is useful.
2018-07-23 20:20:19 +02:00
Bjørn Erik Pedersen c6b599a06d hugolib: Fix "borrow content from another language" issue
If a content file contains shortcode(s), we have logic in place to re-render it per output format.

We also have logic in place that avoids making a copy of the content used for this process if we don't need it.

This was before this commit limited to server mode and if the page should be output to multiple formats.

But there is a third case: If a site (language) borrows and renders `.Content` from another language. This would, before this commit, behave oddly for content with shortcodes.

Fixes #4986
2018-07-23 20:12:41 +02:00
hugoreleaser 3a6784b162 releaser: Prepare repository for 0.46-DEV
[ci skip]
2018-07-22 12:12:08 +00:00
hugoreleaser 48d7a641d0 releaser: Add release notes to /docs for release of 0.45
[ci skip]
2018-07-22 12:09:26 +00:00
hugoreleaser 2c5a036def releaser: Bump versions for release of 0.45
[ci skip]
2018-07-22 12:09:26 +00:00
Bjørn Erik Pedersen 592c5b3072 Update release notes 0.45 2018-07-22 14:04:01 +02:00
hugoreleaser a0c4a3660e releaser: Add release notes draft for 0.45
Rename to *-ready.md to continue. [ci skip]
2018-07-22 10:07:03 +00:00
Bjørn Erik Pedersen 062510cf1f Get rid of the utils package 2018-07-22 00:35:09 +02:00
Bjørn Erik Pedersen 4e1d0cd9f1 Update hugo_windows.go 2018-07-22 00:09:46 +02:00
Bjørn Erik Pedersen a451c49fde hugolib: Print a WARNING about relative non-relative ref/relref matches
Fixes #4973
2018-07-21 11:42:07 +02:00
Bjørn Erik Pedersen ff16c42ed0 hugolib: Allow untyped nil to be merged in lang.Merge
Fixes #4977
2018-07-21 11:41:23 +02:00
Bjørn Erik Pedersen 166483fe12 resource/scss: Add IncludePaths config option
Takes paths relative to the current working dir.

Fixes #4921
2018-07-20 17:50:44 +02:00
Bjørn Erik Pedersen f01505c910 resource/scss: Fix source maps on Windows
I have tested this OK on

* Windows 10 (it did not work before this commit)
* MacOS

Fixes #4968
2018-07-20 08:00:26 +02:00
Vas Sudanagunta 8278384b96 Increase refLinker test coverage 2018-07-20 07:02:41 +02:00
Bjørn Erik Pedersen 65e610e161 hugolib: Avoid nilpointer in absoluteSourceRef 2018-07-19 22:39:24 +02:00
Vas Sudanagunta b56d9a1294 Fix typo-logic bug in GetPage 2018-07-19 21:36:10 +02:00
Vas Sudanagunta d6fde8fa13 Enable test case fixed by commit 501543d4 2018-07-19 20:40:50 +02:00
Vas Sudanagunta 2bac371544 Add test coverage for recent ref overhaul
Closes #4969
2018-07-19 18:32:23 +02:00
Bjørn Erik Pedersen 9b4b97a722 hugolib: Create an adapter from old to new getPage
To make sure we confirm that the existing tests run the correct code path.

Updates #4969
2018-07-19 18:26:10 +02:00
Bjørn Erik Pedersen 501543d4b6 hugolib: Only do page-relative getPage for relative paths
Updates #4969
2018-07-19 17:47:05 +02:00
Bjørn Erik Pedersen 6ffa882349 hugolib: Improve error handling in refLink 2018-07-19 17:17:35 +02:00
Bjørn Erik Pedersen 1eb8b36b38 docs: Update ref, relref, GetPage docs 2018-07-19 17:02:03 +02:00
Bjørn Erik Pedersen 00c74ee7ff docs: Document refLinksErrorLevel and refLinksNotFoundURL
See #4964
2018-07-19 15:04:00 +02:00
Bjørn Erik Pedersen e25aa655f4 Add configurable ref/relref error handling and notFoundURL
Two new settings:

* refLinksErrorLevel: ERROR (default) or WARNING. ERROR will fail the build.
* refLinksNotFoundURL: Used as a placeholder when page references cannot be found.

Fixes #4964
2018-07-19 14:32:43 +02:00
Bjørn Erik Pedersen 12679b4083 hugolib: Mark shortcode changes as content changes in server mode
This is unfortunate, but is needed to re-create the taxonomies collections etc. that may be referenced from them.

Fixes #4965
2018-07-19 13:58:18 +02:00
Bjørn Erik Pedersen c39ac5738d Revert "hugolib: Fix potential server panic with drafts/future enabled"
This had a side-effect. I have understand this better to apply the correct fix. Will come soon.

This reverts commit 1ab4658c0d.
2018-07-19 12:20:01 +02:00
Bjørn Erik Pedersen a3535c8486 Squashed 'docs/' changes from cfe89ecbc..a4fa0d1d6
a4fa0d1d6 Typos and grammatical changes
513884600 Add hugo pipes documentation

git-subtree-dir: docs
git-subtree-split: a4fa0d1d64
2018-07-19 09:18:11 +02:00
Bjørn Erik Pedersen 9da617912b Merge commit 'a3535c8486b2ce762b1a8a9c30b03985c3e02cee' 2018-07-19 09:18:11 +02:00
Bjørn Erik Pedersen 1ab4658c0d hugolib: Fix potential server panic with drafts/future enabled
Fixes #4965
2018-07-18 17:01:50 +02:00
Bjørn Erik Pedersen 75acff5f20 hugolib: Avoid server panic on TOML mistake in i18n
Fixes #4942
2018-07-18 11:53:04 +02:00
Bjørn Erik Pedersen 5c9d5413a4 hugolib/filesystems: Fix theme config for Work Fs
Which was the reason why `PostCSS´ from theme(s) was not picked up.

Fixes #4951
2018-07-18 11:39:04 +02:00
Bjørn Erik Pedersen 59ebc83d72 Merge commit 'b6b37a1f00f808f3c0d2715f65ca2d3091f36495' 2018-07-18 11:05:58 +02:00
Bjørn Erik Pedersen b6b37a1f00 Squashed 'docs/' changes from f59b3ab06..cfe89ecbc
cfe89ecbc Set all *.png files under static/images to mode 0644
d847ccd8b More spelling error fixes
bf1405d92 Correction: .Pages on homepage is same as .Site.RegularPages
7efa41ff5 Merge commit 'd137efe0222269e09b427325176f0044558e3cc5'
d137efe02 Squashed 'themes/gohugoioTheme/' changes from f31a3dc8..66249819
50df8bfb8 Replace .Data.Pages with .Pages
85d3712d0 Mention the newScratch template func
1c234db1b Release 0.44
a51cb3e36 Merge branch 'temp44'
ec424a5e2 releaser: Prepare repository for 0.45-DEV
425e85574 releaser: Add release notes to /docs for release of 0.44
e6f9c65a2 releaser: Bump versions for release of 0.44
45548a5c9 Arch Linux: Partial upgrades are unsupported
c0430f8f9 Update MenuEntry properties documentation
79109b685 Refresh the documentation on staticDir config parameter
80ed4592b Remove duplicate links; also sort them alphabetically
f00a4e232 HTTPS links to third-party sites
2f6f682ba Fixed a typo
4be105202 add openbsd howto install
39808f50a Fix typo
b55c0f3a0 Fix URL to hugotest
2fb157237 Release Hugo 0.43
e8af6a970 Merge branch 'temp43'
563dd4173 Adjust release notes
50aed2e52 releaser: Prepare repository for 0.44-DEV
363b363ff releaser: Add release notes to /docs for release of 0.43
93bfbef62 releaser: Bump versions for release of 0.43
893a27d33 Fix typos
fe5908257 Celebrate: a few typo and grammar fixes
bb20442df Merge commit '98293eaa1570b5aff4452021c8b6d6c8560b3f06'
ef3d63936 Add a newScratch template func
bf100a3cd Merge branch 'release-0.42.2'
f1133c544 releaser: Prepare repository for 0.43-DEV
2ce058057 releaser: Add release notes to /docs for release of 0.42.2
6073927c6 releaser: Bump versions for release of 0.42.2
3bafddd52 releaser: Prepare repository for 0.43-DEV
8b9f805bd releaser: Add release notes to /docs for release of 0.42.1
efb6638ba releaser: Bump versions for release of 0.42.1
1e74ffbe0 releaser: Prepare repository for 0.43-DEV
2d2d0f8ab releaser: Add release notes to /docs for release of 0.42
17f685813 releaser: Bump versions for release of 0.42
67ef1a0e1 docs: Update theme documentation
d74874e1e docs: Remove some files now moved
771d50cf3 Merge commit 'b239595af5a9fc1fc9a1ccc666c3ab06ccc32f04'
f9b5fd2d2 tplimpl: Remove speakerdeck shortcode
523206579 tpl/strings: strings.RuneCount
b389efc88 tpl: Add strings.Repeat
a41ad0254 Add a BlackFriday option for rel="noreferrer" on external links
a6e279362 Add a BlackFriday option for rel="nofollow" on external links
7e2c9846e releaser: Prepare repository for 0.42-DEV
b4f81c38a releaser: Add release notes to /docs for release of 0.41
55667b3a1 releaser: Bump versions for release of 0.41
afceb02d3 docs: Document the GDPR Privacy Config
8b8289027 Merge commit 'd2b1030060d3c91d5f9ffa3456418da16bd74f1d'
be04a8886 Merge branch 'release-0.40.3'
33ca0b8da releaser: Prepare repository for 0.41-DEV
8c9a5a850 releaser: Add release notes to /docs for release of 0.40.3
85845a4fd releaser: Bump versions for release of 0.40.3
9af79e531 Merge commit '83bef6955e014d40c0f00db9cebe09113154e999'
c4200dd0e Fix typo
8f8323336 releaser: Prepare repository for 0.41-DEV
9fab87505 releaser: Add release notes to /docs for release of 0.40.2
83648c666 releaser: Bump versions for release of 0.40.2
e6434d104 releaser: Prepare repository for 0.41-DEV
9389b2973 releaser: Add release notes to /docs for release of 0.40.1
32979e28a releaser: Bump versions for release of 0.40.1
196174a76 releaser: Prepare repository for 0.41-DEV
490a997bb releaser: Add release notes to /docs for release of 0.40
018aa6471 releaser: Bump versions for release of 0.40
92221934c Merge commit 'a215abf70e018f4bf40d6c09d8bd148d8684b33d'
0a58ef56e Merge commit 'd2ec1a06df8ab6b17ad05cb008d5701b40327d47'
312ab58c6 Improve .Get docs
e43e8cee3 .Get function: fix syntax signature
bb16150bc releaser: Prepare repository for 0.40-DEV
8cc80fed9 releaser: Add release notes to /docs for release of 0.39
f7aa0d1c5 releaser: Bump versions for release of 0.39
42e48706a Merge commit '047c4188dfc854f658d16f1e4a9501f9c97a31c7'
76acab68b releaser: Prepare repository for 0.39-DEV
d270600b0 releaser: Add release notes to /docs for release of 0.38.2
97be36992 releaser: Bump versions for release of 0.38.2
cd29b8b79 releaser: Prepare repository for 0.39-DEV
9983a4bdf releaser: Add release notes to /docs for release of 0.38.1
7774afd01 releaser: Bump versions for release of 0.38.1
b89157f20 releaser: Prepare repository for 0.39-DEV
af4d0bf62 releaser: Add release notes to /docs for release of 0.38
ca98e7d4f releaser: Bump versions for release of 0.38
8b773833a Merge commit 'ed8bf081fdbf336e026517b7e1b123c039014ab5'
24202bb71 docs: Generate docshelper data
43d15975d Add .Site.IsServer
6f99d3d65 Merge commit '0a23baa6a90901f772c234107c4f12c16c76f4aa'
17487ccdd hugolib: Add Reset method to delete key from Scratch
ccbf7a05c docs: Add docs for lang.Merge
5ad46d78e Merge commit '3886fc1fef6ac19d58b9ba1bb642d0c6c9a54031'
ac403c280 docs: Add docs on the new front matter configuration
6066c60e6 Merge commit 'c0290655825e7bb36e13fb39f89d85b392cf1adc'
ee605c7ae releaser: Prepare repository for 0.38-DEV
31a4de966 releaser: Add release notes to /docs for release of 0.37.1
9dd3dafe1 releaser: Bump versions for release of 0.37.1
141750aec releaser: Prepare repository for 0.38-DEV
c9bb39bc3 releaser: Add release notes to /docs for release of 0.37
c7009f064 releaser: Bump versions for release of 0.37
9f727d916 Merge commit '900b5f6cfe5a377ef369d26cd700201be4cf6b06'
87fd97853 Merge commit '374d184e6747678364fd61f5faf328ec9205eb6b'
244deafc2 Fix typos in development contribution doc
608c80f72 Merge branch 'release-0.36.1'
0f8ffbd5c releaser: Prepare repository for 0.37-DEV
5028ee849 releaser: Add release notes to /docs for release of 0.36.1
9ccc7cb11 releaser: Bump versions for release of 0.36.1
3db31be07 Merge commit '9cc9bab46288d8d5f9fda7009c5f746258cec1b4'
9468246c5 Add "target" and "rel" parameters to figure shortcode
6d7fa89f9 releaser: Prepare repository for 0.37-DEV
1aec7ad81 releaser: Add release notes to /docs for release of 0.36
b522da389 releaser: Bump versions for release of 0.36
bb78bea13 docs: Add documentation for smart cropping etc.
930f16cae Merge commit 'c305e44f5f081e4436195923a4593e396f07cd49'
0e4c80ab9 releaser: Prepare repository for 0.36-DEV
e0d4c6bcd releaser: Add release notes to /docs for release of 0.35
f4ac67eb3 releaser: Bump versions for release of 0.35
229a50b1f docs: Regenerate CLI docs
72958eb9c Merge commit '337d0c5f516ee085205e8abefdb7f87e6d33ca05'
d998ca4c0 command: Remove undraft command
34a0052ef docs: Re-generate CLI docs
fa04ff331 releaser: Prepare repository for 0.35-DEV
55e595720 releaser: Add release notes to /docs for release of 0.34
bf4d0e8fb releaser: Bump versions for release of 0.34
07673370e releaser: Prepare repository for 0.34-DEV
921ea8920 releaser: Add release notes to /docs for release of 0.33
3307f61bd releaser: Bump versions for release of 0.33
792a4410d Merge commit '3cf4300097610bb8b5bd0686d96d1df5db641895'
6d8a9f657 releaser: Prepare repository for 0.33-DEV
e3afccf6f releaser: Add release notes to /docs for release of 0.32.4
7f29cb196 releaser: Bump versions for release of 0.32.4
baa364436 releaser: Prepare repository for 0.33-DEV
60c775166 releaser: Add release notes to /docs for release of 0.32.3
9cbab1803 releaser: Bump versions for release of 0.32.3
51823efee releaser: Prepare repository for 0.33-DEV
71e03684c releaser: Add release notes to /docs for release of 0.32.2
e18bf56fb releaser: Bump versions for release of 0.32.2
54aa93927 Merge commit 'eb738cd35cca1ffc68c5ed688dbe2a19108e8761'
5e8123994 releaser: Prepare repository for 0.33-DEV
a55b78124 releaser: Add release notes to /docs for release of 0.32.1
7de53ff41 releaser: Bump versions for release of 0.32.1
e6e58785d releaser: Prepare repository for 0.33-DEV
58cf5009d releaser: Add release notes to /docs for release of 0.32
031719821 Merge commit 'f3cd083961f36dc96d05e98aaf67f650102bc757'
b9183604b Add Pandoc support, refactor external helpers
3f9b9474c releaser: Prepare repository for 0.32-DEV
11e4ce514 releaser: Add release notes to /docs for release of 0.31.1
aebb1504b releaser: Bump versions for release of 0.31.1
d70b54d4a releaser: Prepare repository for 0.32-DEV
cdc10468e releaser: Add release notes to /docs for release of 0.31
38bd41cab releaser: Bump versions for release of 0.31
1c581a11d Merge commit '30c0d485eaff6d70df1be0353911ddca485d52bf'
b88e46d02 Merge commit '05e42bc643f1840ed2ad9c2eff82a269d1381683'
a45ab174e Handle Taxonomy permalinks
9f27354f6 Add support for height argument to figure shortcode
acc8e49c1 releaser: Prepare repository for 0.31-DEV
977266b19 releaser: Add release notes to /docs for release of 0.30.2
31b672844 releaser: Bump versions for release of 0.30.2
b8f6b72a8 Merge commit '325009c3fd4ac90021897b7e3e025c14e70ce162'
c6e3dae71 releaser: Prepare repository for 0.31-DEV
2a3c7c7d9 releaser: Add release notes to /docs for release of 0.30.1
4c014117a releaser: Bump versions for release of 0.30.1
1da61da06 releaser: Prepare repository for 0.31-DEV
24864a46b releaser: Add release notes to /docs for release of 0.30
3011aa44a releaser: Bump versions for release of 0.30
bcbf3237b Merge commit 'ecf5e081b5540e69f4af330233f39a07baf53846'
ab68b99ed Merge commit 'dae5a7c61cceeb0de59f2d755f63e453f71dd9b2'
0ae435725 tpl: Add errorf template function
ac3fb3808 Change SummaryLength to be configurable (#3924)
3c0e4fa70 tpl: Add os.fileExists template function
9290f3983 Merge commit '9d68f695e782c6a83c77aff13317c7a22c694c98'
394e8b3f6 tpl: Add float template function
c0c48c2ea releaser: Prepare repository for 0.30-DEV
0806d910b releaser: Add release notes to /docs for release of 0.29
0d1101836 releaser: Bump versions for release of 0.29
5d92b552b releaser: Prepare repository for 0.29-DEV
1ef521182 releaser: Add release notes to /docs for release of 0.28
c5441cff1 releaser: Bump versions for release of 0.28
46c2786f1 Merge commit '61c27b58b353c73772aae572c7d822fdfdf7791b'
6fed4008f Merge commit '30694a133a88d5f76a51d0372646e10cbeca7691'
595752e2f Merge commit '7a89dce53bfbd67a17442a8f9be8fa895fc4f9b1'
af14cae0c Merge commit 'ba45da9d03056447e4873de13d4e0f8d658a769b'
d0bb30963 releaser: Prepare repository for 0.28-DEV
469bf26aa releaser: Add release notes to /docs for release of 0.27.1
06ea00c12 releaser: Bump versions for release of 0.27.1
0668af58e releaser: Prepare repository for 0.28-DEV
4ce00c84d releaser: Add release notes to /docs for release of 0.27
68f318d0b releaser: Bump versions for release of 0.27
509ad6cc0 docs: Merge commit '1b4319be62ba071f79e90ef32dbe92eb893429f7'
c625ae1ce docs: Document Related Content
ecd5c24f5 docs: Merge commit '7d63a23b0c68d9cd7c7c09c2755619237bc03485'
b97b84f9d Update docs versiona and README
2238f7a4a Merge commit 'ec4e6f9df2ab9ffdc62a3f59675369096e0d3f77' as 'docs'

git-subtree-dir: docs
git-subtree-split: cfe89ecbc2
2018-07-18 11:04:57 +02:00
Bjørn Erik Pedersen ebe4d39f17 resource/postcss: Try node_modules/postcss-cli/bin/postcss first
Fixes #4952
2018-07-18 10:00:50 +02:00
Bjørn Erik Pedersen 1b0aeeaaf0 commands: Disable flaky server tests on Windows CI 2018-07-18 09:43:31 +02:00
Bjørn Erik Pedersen a4c513caeb commands: Increase sleep in server teset to make it less shaky on Windows 2018-07-18 00:35:42 +02:00
Bjørn Erik Pedersen d741064beb Add optional lang as argument to rel/relref
Fixes #4956
2018-07-18 00:07:20 +02:00
Bjørn Erik Pedersen 3eb313fef4 Simplify .Site.GetPage etc.
This commit is a follow up to a recent overhaul of the GetPage/ref/relref implemenation.

The most important change in this commit is the update to `.Site.GetPage`:

* To reduce the amount of breakage in the wild to its minimum, I have reworked .Site.GetPage with some rules:

* We cannot support more than 2 arguments, i.e. .Site.GetPage "page" "posts" "mypage.md" will now throw an error. I think this is the most uncommon syntax and should be OK. It is an easy fix to change the above to .Site.GetPage "/posts/mypage.md" or similar.
* .Site.GetPage "home", .Site.GetPage "home" "" and .Site.GetPage "home" "/" will give you the home page. This means that if you have page in root with the name home.md you need to do .Site.GetPage "/home.md" or similar

This commit also fixes some multilingual issues, most notable it is now possible to do cross-language ref/relref lookups by prepending the language code to the path, e.g. `/jp/posts/mypage.md`.

This commit also reverts the site building tests related to this to "Hugo 0.44 state", to get better control of the changes made.

Closes #4147
Closes #4727
Closes #4728
Closes #4728
Closes #4726
Closes #4652
2018-07-18 00:07:20 +02:00
Vas Sudanagunta b93417aa1d Unify page lookups
This commit unifies the core internal page index for all page kinds.

This enables the `ref` and `relref` shortcodes to support all pages kinds, and adds a new page-relative  `.GetPage` method with simplified signature.

See #4147
See #4727
See #4728
See #4728
See #4726
See #4652
2018-07-18 00:07:20 +02:00
Lucas Bickel fd1f4a7860 Fix addkit link to account for i18n 2018-07-16 21:23:27 +02:00
Bjørn Erik Pedersen 4c240800a4 resource/bundler: Improve error message 2018-07-16 10:42:07 +02:00
Garry McNulty 38204c4ab6 hugolib: Only set 'allThemes' if there are themes in the config file
When the 'allThemes' configuration setting is read, it will panic if
there are no themes. This was a regression introduced in Hugo 0.42.

Also updated a unit test to check for this.

Fixes #4851
2018-07-15 16:13:48 +02:00
Bjørn Erik Pedersen 2f2bc7ff70 resource/integrity: Remove unused code 2018-07-14 11:17:48 +02:00
Bjørn Erik Pedersen 242b297f57 releaser: Remove flag on Windows build 2018-07-13 08:40:09 +02:00
hugoreleaser f44c9ab9cd releaser: Prepare repository for 0.45-DEV
[ci skip]
2018-07-13 06:05:41 +00:00
hugoreleaser 9f9695cf7b releaser: Add release notes to /docs for release of 0.44
[ci skip]
2018-07-13 06:03:09 +00:00
hugoreleaser 0831d8ccaf releaser: Bump versions for release of 0.44
[ci skip]
2018-07-13 06:03:09 +00:00
Bjørn Erik Pedersen 1d4ff024ca Finish release notes 0.44 2018-07-13 07:53:33 +02:00
hugoreleaser 521e63ac7c releaser: Add release notes draft for 0.44
Rename to *-ready.md to continue. [ci skip]
2018-07-13 05:27:58 +00:00
Bjørn Erik Pedersen 47d38628ec resource: Clean up the in-memory Resource reader usage
Turns out `strings.Reader` implements both `io.Reader` and `io.Seeker`, so we don't need anything special.

Updates #4936
2018-07-12 21:32:52 +02:00
Bjørn Erik Pedersen 0024dcfe3e resource: Move opening of the transformed resources after cache check
The old version should be functionally the same, but opening up these readers (potentially files) every time is wasteful if we don't read from them.
2018-07-12 19:36:12 +02:00
Bjørn Erik Pedersen beec1fc98e resource: Fix resources.Concat for transformed resources
Fixes #4936
2018-07-12 19:36:12 +02:00
Bjørn Erik Pedersen 306573def0 Improve type support in resources.Concat
This allows the result of `.Resources.Match` and similar to be concatenated.

Fixes #4934
2018-07-12 13:43:27 +02:00
Bjørn Erik Pedersen 80c8f3b81a hugolib: Fix static filesystem for themed multihost sites
Multihost is where each language has its own `baseURL`. In this configuration, static files from the theme was not picked up.

This was a regression in Hugo `0.42`. This commit also adds proper tests for this, so that does not happen again.

Fixes #4929
2018-07-12 12:18:56 +02:00
Bjørn Erik Pedersen 6b6dcb44a0 Flush partialCached cache on rebuilds
Fixes #4931
2018-07-11 20:40:04 +02:00
Bjørn Erik Pedersen d96f2a460f resource: Include the transformation step in the error message
Fixes #4924
2018-07-11 11:03:15 +02:00
Bjørn Erik Pedersen ac53035030 media: Only show deprecation warning when needed
Fixes #4927
2018-07-10 23:21:48 +02:00
Bjørn Erik Pedersen b874a1ba7a media: Allow multiple file suffixes per media type
Before this commit, `Suffix` on `MediaType` was used both to set a custom file suffix and as a way to augment the mediatype definition (what you see after the "+", e.g. "image/svg+xml").

This had its limitations. For one, it was only possible with one file extension per MIME type.

Now you can specify multiple file suffixes using "suffixes", but you need to specify the full MIME type
identifier:

[mediaTypes]
[mediaTypes."image/svg+xml"]
suffixes = ["svg", "abc ]

In most cases, it will be enough to just change:

[mediaTypes]
[mediaTypes."my/custom-mediatype"]
suffix = "txt"

To:

[mediaTypes]
[mediaTypes."my/custom-mediatype"]
suffixes = ["txt"]

Hugo will still respect values set in "suffix" if no value for "suffixes" is provided, but this will be removed in a future release.

Note that you can still get the Media Type's suffix from a template: {{ $mediaType.Suffix }}. But this will now map to the MIME type filename.

Fixes #4920
2018-07-10 22:13:52 +02:00
Anthony Fok 4108705934 hugolib: Remove empty resources/ dir after TestNewSiteDefaultLang 2018-07-10 09:01:54 +02:00
Anthony Fok 9c1e82085e .gitattributes: Exclude *.svg from CRLF/LF conversion
I ran into trouble after importing the Hugo v0.43 release tarball
into the Debian packaging git repository...
2018-07-09 21:06:15 -06:00
Anthony Fok 2b73e89d6d tpl: Set permission of embedded templates to 0644 2018-07-09 12:57:08 -06:00
Bjørn Erik Pedersen febf0aec8b Build a fully static Windows extended binary 2018-07-09 20:42:08 +02:00
Bjørn Erik Pedersen a4fad5be6b Adjust release notes
[ci skip]
2018-07-09 12:11:57 +02:00
hugoreleaser 6084f0433c releaser: Prepare repository for 0.44-DEV
[ci skip]
2018-07-09 10:03:30 +00:00
hugoreleaser cbb7214b6c releaser: Add release notes to /docs for release of 0.43
[ci skip]
2018-07-09 10:00:04 +00:00
hugoreleaser e6136b36f3 releaser: Bump versions for release of 0.43
[ci skip]
2018-07-09 10:00:04 +00:00
Bjørn Erik Pedersen 659917a002 releaser: Revert to the old versions of the release pipeline 2018-07-09 11:54:10 +02:00
hugoreleaser 9d194ab904 releaser: Add release for 0.43 2018-07-09 10:52:02 +02:00
Anthony Fok a305609e18 snap: Migrate from deprecated keywords to "override-build"
Also add verbosity and echo messages to aid debugging.

See #4908
2018-07-09 02:41:10 -06:00
Bjørn Erik Pedersen 179de5f5bc Revert "Consider root and current section's content type if set in front matter"
This reverts commit c790029e1d.
2018-07-09 10:29:18 +02:00
Bjørn Erik Pedersen 5dc1f95b63 Revert "Restrict the new type layout resolution to page and section kinds"
This reverts commit 78e8a744b3.
2018-07-09 10:29:16 +02:00
Bjørn Erik Pedersen 6bc892fc24 Revert "output: gofmt -l -w output/layout.go"
This reverts commit f465571b33.
2018-07-09 10:29:13 +02:00
Bjørn Erik Pedersen 5f06dbf779 Revert "snap: Build both hugo and hugo.extended for 0.43"
This reverts commit e1027c5846.
2018-07-09 09:45:18 +02:00
Bjørn Erik Pedersen 0850e97984 Revert "Revert "Add Goreleaser extended config""
I reverted the wrong commit.

This reverts commit a3b4b10f65.
2018-07-09 09:44:51 +02:00
Bjørn Erik Pedersen a3b4b10f65 Revert "Add Goreleaser extended config"
@anthonyfok we need to discuss how we want the Snap build to look before we implement it. I don't think this is how.

People who want SCSS builds can download from the release page for this release.

This reverts commit 626afc9825.
2018-07-09 09:30:10 +02:00
Bjørn Erik Pedersen e3df6478f0 Bump CircleCI image 2018-07-09 09:24:34 +02:00
Bjørn Erik Pedersen 626afc9825 Add Goreleaser extended config
See #4908
2018-07-09 09:24:34 +02:00
Anthony Fok e1027c5846 snap: Build both hugo and hugo.extended for 0.43
Due to snap's design, the name "hugo_extended" needs to be created
via an automatic alias request, see
https://forum.snapcraft.io/t/hugo-auto-alias-request-for-hugo-extended-hugo-extended/6297

Also migrate from deprecated "prepare", "build" and "install" keywords
to "override-build".

See #4908
2018-07-09 01:15:21 -06:00
Carlos Alexandro Becker e1a052ecb8 fix: nfpm replacements
refs https://github.com/goreleaser/goreleaser/issues/715
2018-07-09 08:06:13 +02:00
Bjørn Erik Pedersen bfc3488b8e Add temporary build script 2018-07-08 16:08:22 +02:00
Anthony Fok ce84b524f4 Add "extended" to "hugo version"
Fixes #4913
2018-07-08 11:08:54 +02:00
Yang Li 3cea2932e1 Fix typos 2018-07-07 12:29:56 +02:00
Bjørn Erik Pedersen 0efd374805 Merge commit '98293eaa1570b5aff4452021c8b6d6c8560b3f06' 2018-07-06 17:53:17 +02:00
Bjørn Erik Pedersen 98293eaa15 Squashed 'docs/' changes from 501c6e233..f59b3ab06
f59b3ab06 Fix typo in template lookup order
1e5536d6c Mutlilingual: Document "content directory per language" system (#509)
849a86048 Update index.md
0c24d229b Polish Hugo Next
a4c9b0ee2 Polish
bbec2c76e Some more in birthday post
fc9681e21 More on contributors
09fe3ea31 Some more on the birthday post
8da357240 Content and images for the 5th birthday blog post
fb45bb8dc Add draft for anniversary blog post
4666d0a18 Release 0.42.2
9b74d286a Merge branch 'temp422'
354e7b66b releaser: Add release notes to /docs for release of 0.42.2
57a617f34 releaser: Bump versions for release of 0.42.2
ccc3ac1b8 Update errorf.md
35706c21a Update errorf.md
1c0f35fd1 Update errorf.md
b6170774b Add syntax highlighting gallery links for Chroma
f91d9da47 Update usage.md
c9a8f0190 Improve theme components documentation
3c4e39ddd Release 0.42.1
b45eb453f Merge branch 'temp421'
c74682a10 releaser: Prepare repository for 0.43-DEV
321e07fa5 releaser: Add release notes to /docs for release of 0.42.1
7154271e0 releaser: Bump versions for release of 0.42.1
360d8244f Add link to Privacy Config
1f2454247 Fix typo
a8f5f994e Fix typo
d9f3f078c Update simple variants documentation (#500)
f5cfd44e0 Release 0.42
fe604b321 releaser: Prepare repository for 0.43-DEV
c3e5b3ca0 releaser: Add release notes to /docs for release of 0.42
3174d1b37 releaser: Bump versions for release of 0.42
48cc2d51f docs: Update theme documentation
1922fb1a6 docs: Remove some files now moved
d7e4c453a Merge commit 'b239595af5a9fc1fc9a1ccc666c3ab06ccc32f04'
c40964c1b tplimpl: Remove speakerdeck shortcode
081f8a0f9 tpl/strings: strings.RuneCount
828ea5f15 tpl: Add strings.Repeat
a6b9f654a Add a BlackFriday option for rel="noreferrer" on external links
edb786516 Add a BlackFriday option for rel="nofollow" on external links
e4374971f releaser: Prepare repository for 0.42-DEV

git-subtree-dir: docs
git-subtree-split: f59b3ab06f
2018-07-06 17:52:13 +02:00
Bjørn Erik Pedersen 2b8d907ab7 Add a newScratch template func
Fixes #4685
2018-07-06 17:51:38 +02:00
Bjørn Erik Pedersen 43338c3a99 hugolib: Do not create paginator pages for the other output formats
This is a recent regression in Hugo, where we have started to produce `/page/30/index.json` when the main output format (usually `HTML`) is set up with pagination.

For JSON this is potentially lot of superflous work and hurts performance.

This commit reinstates the earlier behaviour: We only create paginators if in use in the main output format.

And add a test for it to prevent this from happening again.

Fixes #4890
2018-07-06 14:01:27 +02:00
Bjørn Erik Pedersen dea71670c0 Add Hugo Piper with SCSS support and much more
Before this commit, you would have to use page bundles to do image processing etc. in Hugo.

This commit adds

* A new `/assets` top-level project or theme dir (configurable via `assetDir`)
* A new template func, `resources.Get` which can be used to "get a resource" that can be further processed.

This means that you can now do this in your templates (or shortcodes):

```bash
{{ $sunset := (resources.Get "images/sunset.jpg").Fill "300x200" }}
```

This also adds a new `extended` build tag that enables powerful SCSS/SASS support with source maps. To compile this from source, you will also need a C compiler installed:

```
HUGO_BUILD_TAGS=extended mage install
```

Note that you can use output of the SCSS processing later in a non-SCSSS-enabled Hugo.

The `SCSS` processor is a _Resource transformation step_ and it can be chained with the many others in a pipeline:

```bash
{{ $css := resources.Get "styles.scss" | resources.ToCSS | resources.PostCSS | resources.Minify | resources.Fingerprint }}
<link rel="stylesheet" href="{{ $styles.RelPermalink }}" integrity="{{ $styles.Data.Digest }}" media="screen">
```

The transformation funcs above have aliases, so it can be shortened to:

```bash
{{ $css := resources.Get "styles.scss" | toCSS | postCSS | minify | fingerprint }}
<link rel="stylesheet" href="{{ $styles.RelPermalink }}" integrity="{{ $styles.Data.Digest }}" media="screen">
```

A quick tip would be to avoid the fingerprinting part, and possibly also the not-superfast `postCSS` when you're doing development, as it allows Hugo to be smarter about the rebuilding.

Documentation will follow, but have a look at the demo repo in https://github.com/bep/hugo-sass-test

New functions to create `Resource` objects:

* `resources.Get` (see above)
* `resources.FromString`: Create a Resource from a string.

New `Resource` transformation funcs:

* `resources.ToCSS`: Compile `SCSS` or `SASS` into `CSS`.
* `resources.PostCSS`: Process your CSS with PostCSS. Config file support (project or theme or passed as an option).
* `resources.Minify`: Currently supports `css`, `js`, `json`, `html`, `svg`, `xml`.
* `resources.Fingerprint`: Creates a fingerprinted version of the given Resource with Subresource Integrity..
* `resources.Concat`: Concatenates a list of Resource objects. Think of this as a poor man's bundler.
* `resources.ExecuteAsTemplate`: Parses and executes the given Resource and data context (e.g. .Site) as a Go template.

Fixes #4381
Fixes #4903
Fixes #4858
2018-07-06 11:46:12 +02:00
Bjørn Erik Pedersen a5d0a57e6b output: Fix the shortcodes/partials vs base template detection
Fixes #4897
2018-07-02 10:34:38 +02:00
Anthony Fok f465571b33 output: gofmt -l -w output/layout.go 2018-07-02 00:08:43 -06:00
Bjørn Erik Pedersen f8212d2000 tpl/collections: Return en empty slice in after instead of error
When the given index is out of bounds. So it can safely be used with `with` etc. without extra length checking.

Fixes #4894
2018-07-01 20:34:02 +02:00
Bjørn Erik Pedersen 78e8a744b3 Restrict the new type layout resolution to page and section kinds
Will have to test and evaluate this a little.

See  #4891
2018-06-30 16:50:02 +02:00
Bjørn Erik Pedersen c790029e1d Consider root and current section's content type if set in front matter
This should allow for less duplication of templates. Before this commit it was possible to override the content page of a given page/section, but only one page at a time.

Full "template sets" can now be inherited by setting `type: blog` etc. in the section content page's front matter, and that type will be considered when looking for layouts for all pages in that section.

For nested sections, it will use consider both `type` set in the current section first, then `type` set in the first section below home, e.g. `/docs`.

This commit also adds a new Page method: `FirstSection`. This navigates up to the first section below home (e.g. `/docs`). For the home page it will return itself.

Fixes #4891
2018-06-30 13:10:04 +02:00
Bjørn Erik Pedersen 554553c09c circleci: Update docker image
With Go 10.3 and newest Goreleaser and Mage.
2018-06-29 10:46:21 +02:00
Bjørn Erik Pedersen de37455ec7 hugolib: Allow forward slash in shortcode names
Fixes #4886
2018-06-28 16:06:16 +02:00
Bjørn Erik Pedersen 282f6035e7 Merge branch 'release-0.42.2' 2018-06-28 14:40:23 +02:00
hugoreleaser 360fa12213 releaser: Prepare repository for 0.43-DEV
[ci skip]
2018-06-28 12:38:48 +00:00
hugoreleaser 02aa320030 releaser: Add release notes to /docs for release of 0.42.2
[ci skip]
2018-06-28 12:36:15 +00:00
hugoreleaser d2640fbc19 releaser: Bump versions for release of 0.42.2
[ci skip]
2018-06-28 12:36:15 +00:00
hugoreleaser 1637d12e37 Release 0.42.2 2018-06-28 14:32:27 +02:00
Bjørn Erik Pedersen 3a7706b069 commands: Fix broken server-reload on config changes
This was accidently broken in Hugo 0.42.

Fixes #4878
2018-06-28 14:08:52 +02:00
Bjørn Erik Pedersen 2955f93fc6 commands: Fix broken server-reload on config changes
This was accidently broken in Hugo 0.42.

Fixes #4878
2018-06-28 12:22:00 +02:00
Carlos Alexandro Becker 1f0c4e1fb3 Update GoReleaser config 2018-06-28 07:54:18 +02:00
Bjørn Erik Pedersen 91ab455d84 tpl: Remove some "debug info"
See #4881
2018-06-26 11:33:12 +02:00
Bjørn Erik Pedersen ca1e46efb9 tpl: Update internal pagination template to support Bootstrap 4
Fixes #4881
2018-06-26 11:31:46 +02:00
openscript fd71fa89bd Create missing head.html partial on new theme generation 2018-06-25 12:06:45 -06:00
openscript b5a3aa7082 Add html doctype to baseof.html template for new themes 2018-06-25 12:06:45 -06:00
Anthony Fok 3d5928889a Revert "tpl: Support text/template/parse API change in go1.11"
Go developers have undone the breaking API changes
in the following commit:

commit bedfa4e1c37bd08063865da628f242d27ca06ec4
Author: Daniel Theophanes <kardianos@gmail.com>
Date:   Thu Jun 21 10:41:26 2018 -0700

    text/template/parse: undo breaking API changes

    golang.org/cl/84480 altered the API for the parse package for
    clarity and consistency. However, the changes also broke the
    API for consumers of the package. This CL reverts the API
    to the previous spelling, adding only a single new exported
    symbol.

    Fixes #25968

    Change-Id: Ieb81054b61eeac7df3bc3864ef446df43c26b80f
    Reviewed-on: https://go-review.googlesource.com/120355
    Reviewed-by: Daniel Martí <mvdan@mvdan.cc>
    Reviewed-by: Rob Pike <r@golang.org>
    Run-TryBot: Daniel Martí <mvdan@mvdan.cc>
    TryBot-Result: Gobot Gobot <gobot@golang.org>

See https://github.com/golang/go/issues/25968

This reverts commit 9f27091e10.

Closes #4784
Fixes #4873
2018-06-23 15:07:52 -06:00
Bjørn Erik Pedersen dc7bc7b4d2 appveyor: Disable asciidoctor for now
It fails on installation.
2018-06-23 21:42:21 +02:00
Anthony Fok 42ed602580 hugolib: Replace deprecated {Get,}ByPrefix with {Get,}Match 2018-06-15 09:03:56 +02:00
Brian Fitzgerald 6a2968fd5c Adds .gitattributes to force Go files to LF
Even on Windows machines, we want *.go files to have LF line
endings (go fmt insists). This leaves other files as auto, but
makes *.go files always be LF on Windows machines. With this
change, running go fmt will be a pleasant operation, not a
painful one.

Note that changing .gitattributes only affects files at initial
checkout. To update an entire working directory after making a
change like this, do this (but only after committing all work in
progress, this will destroy uncommitted changes):

$ git rm --cached -r .
$ git reset --hard

Again - do not do this to a working directory with uncommitted
work in it.
2018-06-14 16:08:34 -06:00
Anthony Fok 23d5fc82ee Update to Go 1.9.7 and Go 1.10.3
for Travis CI, Docker and Snap
2018-06-14 15:50:25 -06:00
Ryan Skoblenick 8531ec7ca3 Update Dockerfile to a multi-stage build
- Hugo container is based on SCRATCH to further reduce the footprint
  and the vulnerability surface
- Update Alpine image to 3.7 in the build container
- Update Go Lang to 1.10 in the build container
- Add .dockerignore file per the Docker best practices

Closes #4154, #4155, #4157
2018-06-14 15:47:04 -06:00
Anthony Fok 9f27091e10 tpl: Support text/template/parse API change in go1.11
Thanks to @rjoleary for the investigation.

Fixes #4784
2018-06-14 08:58:42 +02:00
hugoreleaser 187621ae24 releaser: Prepare repository for 0.43-DEV
[ci skip]
2018-06-13 10:19:00 +00:00
hugoreleaser 4172a835e5 releaser: Add release notes to /docs for release of 0.42.1
[ci skip]
2018-06-13 10:16:33 +00:00
hugoreleaser fc97388968 releaser: Bump versions for release of 0.42.1
[ci skip]
2018-06-13 10:16:33 +00:00
Bjørn Erik Pedersen d67e843c12 Release 0.42.1 2018-06-13 12:11:30 +02:00
hugoreleaser 6e33c557b0 releaser: Add release notes draft for 0.42.1
Rename to *-ready.md to continue. [ci skip]
2018-06-13 10:09:45 +00:00
Bjørn Erik Pedersen 128f14efad hugolib: Reset the global pages cache on server rebuilds
In Hugo 0.42, this could lead to errors of type `runtime error: invalid memory address or nil pointer dereference` in some rare situations.

Note that this was also an issue before 0.42, but the symptom was then potentially stale list content on rebuilds on content changes.

This commit also improves the above error message.

Fixes #4845
2018-06-13 12:00:30 +02:00
Bjørn Erik Pedersen 34ee27a78b commands: Do not fail server build when /static is missing
This was a un-intended change in Hugo 0.42. Most sites will have a static directory so this should not be a big issue, but this commit will revert back to old behaviour.

Fixes #4846
2018-06-13 08:48:20 +02:00
hugoreleaser 0f1fc01ef2 releaser: Prepare repository for 0.43-DEV
[ci skip]
2018-06-12 08:45:06 +02:00
Bjørn Erik Pedersen f32ccd018f Merge tag 'v0.42'
releaser: 0.42 [ci skip]
2018-06-12 08:42:25 +02:00
hugoreleaser ffb609f4ab releaser: Add release notes to /docs for release of 0.42
[ci skip]
2018-06-12 06:37:19 +00:00
hugoreleaser 19d91abc92 releaser: Bump versions for release of 0.42
[ci skip]
2018-06-12 06:37:19 +00:00
Bjørn Erik Pedersen f5c0a2b4b2 Release 0.42 2018-06-12 08:32:10 +02:00
hugoreleaser 31828026a1 releaser: Add release notes draft for 0.42
Rename to *-ready.md to continue. [ci skip]
2018-06-12 05:50:33 +00:00
Bjørn Erik Pedersen c74b0f8f9b docs: Update theme documentation
See #4460
2018-06-12 07:38:41 +02:00
Bjørn Erik Pedersen 80949dc73f docs: Remove some files now moved 2018-06-12 06:43:21 +02:00
Bjørn Erik Pedersen e02629f81a Merge commit 'b239595af5a9fc1fc9a1ccc666c3ab06ccc32f04' 2018-06-11 22:32:19 +02:00
Bjørn Erik Pedersen b239595af5 Squashed 'docs/' changes from 0fd7b4169..501c6e233
501c6e233 Remoe speakerdeck example
9529bd27d Fix typos
530f22cd3 Remove language assuming knowledge of GitHub OAuth
c618809e7 Refer to Go by its proper name, not its domain name
06e23168b Add timeout parameter to configuration docs
034fa62a7 Update shortcodes.md
10ea79335 Document .Ordinal on shortcode
0bfd85fb9 Formatting
e44f80fdf Release 0.41
76164258c releaser: Add release notes to /docs for release of 0.41
8d87505eb releaser: Bump versions for release of 0.41
2bbc003ee docs: Document the GDPR Privacy Config
e2d11564d Merge commit 'd2b1030060d3c91d5f9ffa3456418da16bd74f1d'

git-subtree-dir: docs
git-subtree-split: 501c6e2337
2018-06-11 22:31:02 +02:00
Anthony Fok ed4a345efe commands: Create LICENSE rather than LICENSE.md in "new theme"
See also #4623
2018-06-11 10:40:22 +02:00
Anthony Fok 9717ac7dce commands: Create _default/baseof.html in "new theme"
Thanks to @digitalcraftsman, @bep and @rdwatters for providing the
actual content of the default baseof.html file.

Fixes #3576
2018-06-11 10:40:22 +02:00
Anthony Fok 692ec00872 commands: Make "new theme" feedback more intuitive 2018-06-11 10:40:22 +02:00
Anthony Fok d3dd74fd65 commands: Move nextStepsText() to new_site.go 2018-06-11 10:40:22 +02:00
Bjørn Erik Pedersen 80230f26a3 Add support for theme composition and inheritance
This commit adds support for theme composition and inheritance in Hugo.

With this, it helps thinking about a theme as a set of ordered components:

```toml
theme = ["my-shortcodes", "base-theme", "hyde"]
```

The theme definition example above in `config.toml` creates a theme with the 3 components with presedence from left to right.

So, Hugo will, for any given file, data entry etc., look first in the project, and then in `my-shortcode`, `base-theme` and lastly `hyde`.

Hugo uses two different algorithms to merge the filesystems, depending on the file type:

* For `i18n` and `data` files, Hugo merges deeply using the translation id and data key inside the files.
* For `static`, `layouts` (templates) and `archetypes` files, these are merged on file level. So the left-most file will be chosen.

The name used in the `theme` definition above must match a folder in `/your-site/themes`, e.g. `/your-site/themes/my-shortcodes`. There are  plans to improve on this and get a URL scheme so this can be resolved automatically.

Also note that a component that is part of a theme can have its own configuration file, e.g. `config.toml`. There are currently some restrictions to what a theme component can configure:

* `params` (global and per language)
* `menu` (global and per language)
* `outputformats` and `mediatypes`

The same rules apply here: The left-most param/menu etc. with the same ID will win. There are some hidden and experimental namespace support in the above, which we will work to improve in the future, but theme authors are encouraged to create their own namespaces to avoid naming conflicts.

A final note: Themes/components can also have a `theme` definition in their `config.toml` and similar, which is the "inheritance" part of this commit's title. This is currently not supported by the Hugo theme site. We will have to wait for some "auto dependency" feature to be implemented for that to happen, but this can be a powerful feature if you want to create your own theme-variant based on others.

Fixes #4460
Fixes #4450
2018-06-10 23:55:20 +02:00
Bjørn Erik Pedersen 6464981adb hugolib: Make sure that .Site.Taxonomies is always set on rebuilds
Fixes #4838
2018-06-10 20:55:17 +02:00
Christian Oliff 2e6712e281 tpl: Always load GA script over HTTPS 2018-06-09 23:47:44 +02:00
Alexandros 65deb72dc4 tplimpl: Remove speakerdeck shortcode
Fixes #4830
2018-06-09 11:13:36 +02:00
Bjørn Erik Pedersen dc4226a8b2 hugolib: Reset Page's main output on server rebuilds
Not doing so prevents the paginators to be rebuilt on changes.

Fixes #4819
2018-06-05 10:45:24 +03:00
Bjørn Erik Pedersen bf5f10faa9 Reset the "distinct error logger" on rebuilds
Fixes #4818
2018-06-05 10:45:24 +03:00
David E. Wheeler 019bd5576b tpl/strings: strings.RuneCount 2018-06-04 20:47:03 +03:00
Anthony Fok c3115292a7 tpl: Prevent isBaseTemplate() from matching "baseof" in dir
Fixes #4809
2018-06-04 10:09:55 +03:00
Bjørn Erik Pedersen 0c6c98e401 tpl/strings: Remove overflow check in strings.Repeat
The test fails on 32 bit systems. Let it panic instead.
2018-06-03 23:23:48 +03:00
Bjørn Erik Pedersen 90c7749085 tpl/strings: Adjust the overflow validation in strings.Repeat
This now matches the validation in the stdlib, but we return an error instead.
2018-06-03 10:35:45 +03:00
David E. Wheeler 13435a6f60 tpl: Add strings.Repeat 2018-06-03 09:55:37 +03:00
Alex 07b96d16e8 Fixes #4798 2018-05-31 18:05:38 +02:00
Alex ceaff7cafc tpl: Remove frameborder attr YT iframe + CSS fixes 2018-05-30 14:06:32 +02:00
Alex b84389c5e0 Fix vimeo_simple thumb scaling 2018-05-30 11:30:28 +02:00
Alexandros 8de5324479 Add vimeo_simple
Fixes #4749
2018-05-30 00:48:36 +02:00
Stefan Neuhaus 20cbc2c785 Add a BlackFriday option for rel="noreferrer" on external links
Add a configuration option "noreferrerLinks". When set to "true" the "HTML_NOREFERRER_LINKS" flag is being passed to Blackfriday. Thereby all *absolute* links will get a "noreferrer" value for their "rel" attribute.

See #4722
2018-05-29 16:54:43 +02:00
Bjørn Erik Pedersen 2174525cec hugolib: A little more on shortcode ordinal 2018-05-28 10:29:48 +02:00
Stefan Neuhaus 7a6192647a Add a BlackFriday option for rel="nofollow" on external links
Add a configuration option "nofollowLinks". When set to "true" the "HTML_NOFOLLOW_LINKS" flag is being passed to Blackfriday. Thereby all *absolute* links will get a "nofollow" value for the "rel" attribute.

Fixes #4722
2018-05-28 01:21:36 +02:00
Alex d68367cbe7 fix typo instagram_simple 2018-05-27 11:06:40 +02:00
hugoreleaser 5241f0baee releaser: Prepare repository for 0.42-DEV
[ci skip]
2018-05-27 10:30:06 +02:00
Bjørn Erik Pedersen b5b36e3200 dep: Update Chroma
And be explicit about the revision. Chroma seem to be a little bit lazy with tagging.

Fixes #4779
2018-05-26 15:26:49 +02:00
Vas Sudanagunta 4f0665f476 Enhance Page and Resource String() 2018-05-26 09:43:47 +02:00
Bjørn Erik Pedersen fc8c5ad824 Merge tag 'v0.41'
releaser: 0.41 [ci skip]
2018-05-25 19:07:52 +02:00
hugoreleaser 171caf28a9 releaser: Add release notes to /docs for release of 0.41
[ci skip]
2018-05-25 16:57:18 +00:00
hugoreleaser 0e77f5d4e7 releaser: Bump versions for release of 0.41
[ci skip]
2018-05-25 16:57:17 +00:00
Bjørn Erik Pedersen 9e7e322ded Release 0.41 2018-05-25 18:46:45 +02:00
hugoreleaser 06827398f9 releaser: Add release notes draft for 0.41
Rename to *-ready.md to continue. [ci skip]
2018-05-25 16:01:30 +00:00
Bjørn Erik Pedersen cfc5096e83 releaser: Put release notes below /en
Fixes #4712
2018-05-25 17:53:03 +02:00
Bjørn Erik Pedersen ab02594e09 create: Provide the correct .Site object to archetype templates
Fixes #4732
2018-05-25 17:35:06 +02:00
Bjørn Erik Pedersen c71f201fd9 docs: Document the GDPR Privacy Config
See #4751
2018-05-25 17:25:33 +02:00
Bjørn Erik Pedersen 4ed1228d55 Fix GA anonymizeIp order 2018-05-25 16:05:45 +02:00
Bjørn Erik Pedersen a51945ea4b Add no-cookie variants of the Google Analytics templates
The current full set of options for GA is now:

```toml
[privacy]
[privacy.googleAnalytics]
disable = false
respectDoNotTrack = true
anonymizeIP = true
useSessionStorage = true
```

Fixes #4775
2018-05-25 15:56:10 +02:00
Bjørn Erik Pedersen 7b9dbef41a Merge commit 'd2b1030060d3c91d5f9ffa3456418da16bd74f1d' 2018-05-25 15:05:23 +02:00
Bjørn Erik Pedersen d2b1030060 Squashed 'docs/' changes from e161ea09d..0fd7b4169
0fd7b4169 Fix typo: pygmentsUseClasses -> pygmentsUseClassic
9a3e1c19a Clarify that lower weight gets higher precedence
820d8b581 Clarify the true behavior of hrefTargetBlank #blackfriday
eb3aa5e46 Fix typo
9aedb9269 Add examples for removing default taxonomies
772a26f84 Fix source link on maintainance
975c215ae Minor edits.
2bdb1a150 Fix invalid iink
991d2e139 Fix misspelling
60af8dfb0 Update eSolia link
d7426b76e Release 0.40.3
4977bd9cf Merge branch 'release-0.40.3'
9946f7108 releaser: Prepare repository for 0.41-DEV
beef16b01 releaser: Add release notes to /docs for release of 0.40.3
80c51c55a releaser: Bump versions for release of 0.40.3
21e2934c5 rename `taxonomies.html` to `taxonomy.html`
34a02c289 Add release notes from Hugo 0.7 to 0.15 for completeness
b593f512e Update related.md
7c2bf528b Fix the "edit this page" link
e8fbc163e Add warning about cond
ae15a8831 Add link to Markdown Guide
e077dfd65 Added documentation for a new migration tool: BlogMl2Hugo
957bfb6a8 Add Talkayrd, a new commenting system, & fix txtpen link
86acea7f8 Tomango showcase
3c2fc32f1 Fix snap classic command in installing.md
9a76f1737 Merge commit '83bef6955e014d40c0f00db9cebe09113154e999'
a4b71fb84 Fix typo

git-subtree-dir: docs
git-subtree-split: 0fd7b41699
2018-05-25 15:04:07 +02:00
Bjørn Erik Pedersen 0bf0e1972d tpl: Remove the shortcode assets for now
Not in use.
2018-05-25 14:34:40 +02:00
Bjørn Erik Pedersen 1f244b802e tpl: Adjust instagram_simple margins 2018-05-25 12:38:25 +02:00
Bjørn Erik Pedersen 448081b840 Remove youtube_simple for now
We need to revisit and complete that.

See #4751
2018-05-25 11:16:23 +02:00
Bjørn Erik Pedersen 1f1d955b56 Add anonymizeIP to GA privacy config
See #4751
2018-05-25 10:53:39 +02:00
Bjørn Erik Pedersen ffcf26e68c Fix broken test 2018-05-24 13:03:23 +02:00
Bjørn Erik Pedersen 9753cb59f1 Support DNT in Twitter shortcode for GDPR
Fixes #4765
2018-05-24 12:25:52 +02:00
Bjørn Erik Pedersen 3bfe8f4be6 tpl: Alias tweet shortode to twitter
See #4765
2018-05-24 11:40:47 +02:00
Bjørn Erik Pedersen 6aa2c38507 Regenerate embedded templates
See #4761
2018-05-23 21:25:04 +02:00
Alexandros 6d69dac9da Fix youtube_simple thumb scaling
Fixes #4761
2018-05-23 21:22:25 +02:00
Bjørn Erik Pedersen 9ad46a2035 Add instagram_simple shortcode
Fixes #4748
2018-05-23 16:52:08 +02:00
Bjørn Erik Pedersen 4256de3392 deps: Go fmt 2018-05-23 16:33:11 +02:00
Bjørn Erik Pedersen bed7a0faff Remove the id from youtube_simple
For now, anyway.

See #4751
2018-05-23 10:24:01 +02:00
Bjørn Erik Pedersen 35ccf06dae Fix some recently broken embedded templates
And add tests for them.

Fixes #4757
2018-05-23 10:03:11 +02:00
Bjørn Erik Pedersen 4ddcf52ccc Add an unified .Site.Config with a services section
Fixes #4751
2018-05-22 18:11:03 +02:00
Bjørn Erik Pedersen 353148c2bc Move the privacy config into a parent
See #4751
2018-05-22 18:11:03 +02:00
Lorenz Cuno Klopfenstein 568b4335c2 commands: Avoid ANSI character output on Windows
Fixes #4462
2018-05-22 17:15:19 +02:00
Bjørn Erik Pedersen 14705ecead tpl: Add another class and an id to youtube_simple
To provide some more styling options.

See #4616
2018-05-22 09:11:34 +02:00
Bjørn Erik Pedersen 69ee6b41e3 Make the simple mode YouTube links schemaless
See #4616
2018-05-21 22:25:04 +02:00
Bjørn Erik Pedersen 88e3568680 Add YouTube shortcode simple mode
Adapted from the work of @onedrawingperday.

See #4616
2018-05-21 21:56:42 +02:00
Bjørn Erik Pedersen 2f17f9378a Do not return error on .Get "class" and vice versa in shortcodes
The current error handling makes parameter checking in shortcodes too verbose for no good reason.

Fixes #4745
2018-05-21 18:52:13 +02:00
Christian Oliff 0a7027e2a8 Create SUPPORT.md
To help cut down on the number of general questions, it'd be good to add a `SUPPORT.md` to the `.github` folder.

A link to this would then be displayed automatically when a user opens a New Issue (https://github.com/gohugoio/hugo/issues/new).

To see an example of this take a look at: https://github.com/twbs/bootstrap/issues/new
2018-05-21 16:56:30 +02:00
Bjørn Erik Pedersen 5f24a2c047 Add PrivacyEnhanced mode for YouTube to the GDPR Policy
See #4616
2018-05-21 16:49:00 +02:00
Bjørn Erik Pedersen 710142016b Add RespectDoNotTrack to GDPR privacy policy for Google Analytics
See #4616
2018-05-21 13:16:43 +02:00
Bjørn Erik Pedersen f45b522ebf tpl/tplimpl: Adjust GA templates
See #4616
2018-05-21 10:21:36 +02:00
Bjørn Erik Pedersen 6789207347 tpl/tplimpl/embedded: Wrap the relevant templates with the privacy policy disable check
See #4616
2018-05-21 00:41:42 +02:00
Bjørn Erik Pedersen 0bbdef986d config: Add the foundation for GDPR privacy configuration
See #4616
2018-05-21 00:41:42 +02:00
Anthony Fok 9bd4236e1b Show site build warning in TestPageBundlerSiteRegular
So that a timeout warning does appear if it does happen
especially on a slow machine with soft floating-point CPU.

Special thanks to @bep for the solution.

See #4672
2018-05-14 00:09:39 -06:00
Anthony Fok 4eedb377b6 commands: Do not show empty BuildDate in version 2018-05-14 00:08:12 -06:00
Anthony Fok b2b500f563 hugolib: Use double quotes instead of back quotes
so that '\n' is interpreted in the timeout warning.
2018-05-14 00:03:03 -06:00
Vas Sudanagunta 2fb9af59c1 Improve markup determination logic
Sets Page.markup earlier (as early as possible, when the page is
loaded). Sets it once and only once, removing many redundant calls
to determineMarkupType().

This kills a sleeping bug that was avoided by the parts of the
code depending on this value making those redundant calls.
2018-05-12 20:16:26 +02:00
Bjørn Erik Pedersen 00e36a4164 Merge branch 'release-0.40.3' 2018-05-09 09:54:25 +02:00
hugoreleaser bfb7744902 releaser: Prepare repository for 0.41-DEV
[ci skip]
2018-05-09 07:48:57 +00:00
hugoreleaser ecae2106b9 releaser: Add release notes to /docs for release of 0.40.3
[ci skip]
2018-05-09 07:46:30 +00:00
hugoreleaser 315a73c9fe releaser: Bump versions for release of 0.40.3
[ci skip]
2018-05-09 07:46:30 +00:00
Bjørn Erik Pedersen 46dc006f17 Release 0.40.3 2018-05-09 09:42:15 +02:00
hugoreleaser d089e9d45a releaser: Add release notes draft for 0.40.3
Rename to *-ready.md to continue. [ci skip]
2018-05-09 07:16:28 +00:00
Bjørn Erik Pedersen 90d0d83097 hugolib: Fix possible .Content cut
There have been one report of a site with truncated `.Content` after the Hugo `0.40.1` release.

This commit fixes this so that race should not be possible anymore. It also adds a stress test with focus on content rendering and multiple output formats.

Fixes #4706
2018-05-09 09:07:30 +02:00
Bjørn Erik Pedersen 086ae81a98 hugolib: Fix possible .Content cut
There have been one report of a site with truncated `.Content` after the Hugo `0.40.1` release.

This commit fixes this so that race should not be possible anymore. It also adds a stress test with focus on content rendering and multiple output formats.

Fixes #4706
2018-05-08 16:52:51 +02:00
Bjørn Erik Pedersen c2bb62d63e tpl/tplimpl: Move README one level up 2018-05-05 11:00:39 +02:00
Bjørn Erik Pedersen 34ad9a4f17 tpl/tplimpl: Extract internal templates
Having them in separate files should make maintainance easier.

When adding new or making changes to the templates:

```bash
mage generate
```

This will get the Go code in sync.

Fixes #4457
2018-05-04 23:12:10 +02:00
Bjørn Erik Pedersen 914cc85e22 Merge commit '83bef6955e014d40c0f00db9cebe09113154e999' 2018-05-04 09:44:59 +02:00
Bjørn Erik Pedersen 83bef6955e Squashed 'docs/' changes from 896bad9f4..e161ea09d
e161ea09d Add one more Chinese file to workaround reflect: Zero(nil)
b595b3a21 Add more Chinese translation
56e4e95d9 Use lang.Merge to "fill in the gaps" for untranslated pages
ef079406c Merge commit '650fac3a4e7d256f4505402ab44cfc3c804b8dea'
650fac3a4 Squashed 'themes/gohugoioTheme/' changes from a1768ebb..f31a3dc8
322eff899 Add Chinese language for menus
d90b886e0 Fix Markdown table syntax in previous commit
737f3dfca Update the leaf bundle vs branch bundle table
09fa1bc4e Clarify that `.Now` is obsolete
879ea3f6a Make release notes somewhat more consistent
0113e2051 Move 0.40.2-relnotes into content/en/news
77578f5bf Move content/ into new contentDir content/en/
4dcf7c709 Fix "reflect: Zero(nil)" error in showcase
63dd25505 Release 0.40.2
2076c0d56 releaser: Prepare repository for 0.41-DEV
070fe565e releaser: Add release notes to /docs for release of 0.40.2
4ce52e913 releaser: Bump versions for release of 0.40.2
41907c487 Fix typos in syntax-highlighting.md
91753ef3d Add missing backtick
b77274301 Remove duplicate release notes (0.27, 0.27.1, 0.35)
6e00da316 Remove obsolete content/release-notes/ directory
00a6d8c02 Change en dash back to `--` in 0.38.2-relnotes
51b32dc00 Update archetypes.md
d0e5c2307 Release 0.40.1
4538a6d5b releaser: Prepare repository for 0.41-DEV
91b391d70 releaser: Add release notes to /docs for release of 0.40.1
e0979d143 releaser: Bump versions for release of 0.40.1
7983967c2 Clean images
fe3fdd77d Polish showcase for Flesland Flis
e6dde3989 Showcase - Flesland Flis AS by Absoluttweb
73aa62290 Revive @spf13's special Hugo font
add67b335 Release Hugo 0.40
c0a26e5a6 Merge branch 'temp40'
beeabaaae releaser: Prepare repository for 0.41-DEV
e67d5e985 releaser: Add release notes to /docs for release of 0.40
6cdd95273 releaser: Bump versions for release of 0.40
bee21fb9b Revive the other Hugo logos too
4f45e8fe1 Fix the link type attribute for RSS in examples
8c67dc89a Fix example in delimit doc
e7f6c00d5 Revive the logo used on the forum
82b0cd26e Merge commit 'a215abf70e018f4bf40d6c09d8bd148d8684b33d'
119c8ca58 Merge commit 'd2ec1a06df8ab6b17ad05cb008d5701b40327d47'
db4683bd2 Improve .Get docs
05260b886 .Get function: fix syntax signature

git-subtree-dir: docs
git-subtree-split: e161ea09d3
2018-05-04 09:44:21 +02:00
Hélène Martin a6816db775 Fix typo
This could either be "check out Hugo's themes" or "check out the Hugo themes". I think the latter reads better.
2018-05-03 07:05:35 +02:00
Adam Jones b6ededf059 Update CONTRIBUTING.md
Fix typos, simplify language
2018-05-01 18:02:08 +02:00
hugoreleaser 8b03c51eae releaser: Prepare repository for 0.41-DEV
[ci skip]
2018-04-30 06:50:00 +00:00
hugoreleaser 5a9d1324d8 releaser: Add release notes to /docs for release of 0.40.2
[ci skip]
2018-04-30 06:47:41 +00:00
hugoreleaser f1269a6d00 releaser: Bump versions for release of 0.40.2
[ci skip]
2018-04-30 06:47:41 +00:00
Bjørn Erik Pedersen 669b3d3a99 Release 0.40.2 2018-04-30 08:42:04 +02:00
hugoreleaser 317d81ec48 releaser: Add release notes draft for 0.40.2
Rename to *-ready.md to continue. [ci skip]
2018-04-30 06:39:05 +00:00
Bjørn Erik Pedersen 655983a22d Reset .Page.Scratch on live-reload
Fixes #4683
2018-04-30 08:21:22 +02:00
Bjørn Erik Pedersen 001a28c2f9 Fix .WordCount, .FuzzyWordCount, .ReadingTime when summary marker is set
This bug was introduced in Hugo 0.40. It is when you use the `<!--more-->` summary marker.

Note that this affects the word stats only. The related `PlainWords`, `Plain`, `Content` all return correct values.

Fixes #4675
Fixes #4682
2018-04-29 10:58:58 +02:00
hugoreleaser 391f59f996 releaser: Prepare repository for 0.41-DEV
[ci skip]
2018-04-25 13:23:15 +00:00
hugoreleaser 459935b291 releaser: Add release notes to /docs for release of 0.40.1
[ci skip]
2018-04-25 13:20:44 +00:00
hugoreleaser b5dafb0f23 releaser: Bump versions for release of 0.40.1
[ci skip]
2018-04-25 13:20:44 +00:00
Bjørn Erik Pedersen 88cb2697e2 Release 0.40.1 2018-04-25 15:17:21 +02:00
hugoreleaser 6fb2d30d21 releaser: Add release notes draft for 0.40.1
Rename to *-ready.md to continue. [ci skip]
2018-04-25 12:58:03 +00:00
Bjørn Erik Pedersen 288c396439 hugolib: Fix some shortcode vs .Content corner cases
This is a follow-up to #4632. There were some assumptions in that implementation that did not hold water in all situations.

This commit simplifies the content lazy initalization making it more robust.

Fixes #4664
2018-04-25 08:56:46 +02:00
hugoreleaser 44e47478d0 releaser: Prepare repository for 0.41-DEV
[ci skip]
2018-04-23 07:43:27 +00:00
hugoreleaser c7e59367d8 releaser: Add release notes to /docs for release of 0.40
[ci skip]
2018-04-23 07:40:57 +00:00
hugoreleaser 3aed268379 releaser: Bump versions for release of 0.40
[ci skip]
2018-04-23 07:40:57 +00:00
Bjørn Erik Pedersen 7ef118392a Release 0.40 2018-04-23 09:37:32 +02:00
hugoreleaser 2e77cc07a2 releaser: Add release notes draft for 0.40
Rename to *-ready.md to continue. [ci skip]
2018-04-23 09:37:32 +02:00
Bjørn Erik Pedersen 402f6788ee hugolib: Add .Page.BundleType
I eturn either:

1. leaf
2. branch
3. empty string

The above sits well with constructs like:

```
{{ with .BundleType }}
// Now we know it is a bundle
{{ end }}
```

Fixes #4662
2018-04-23 08:41:19 +02:00
Bjørn Erik Pedersen 3decf4a327 hugolib: Add zero-based Ordinal to shortcode
The count starts at 0 relative to the shortcode's parent: Either the page or the surrounding shortcode.

Access it in a shortcode like this:

```bash
Ordinal is {{ .Ordinal }}
```

Note that this is a shared ordinal for all shortcodes in the relevant context, so, as an example, you have this in a content page:

```markdown
This is a shortcode:

{{< hello >}}

This is another shortcode:

{{< hugo >}}

The `.Ordinal` you get in the two shortcodes above is 0 and 1.
```

See #3359
2018-04-23 08:09:56 +02:00
Bjørn Erik Pedersen 24c662ce6b hugolib: Defer the unlock in orderedMap.Add
Just in case someone tries to recover from the potential panic.
2018-04-22 21:32:05 +02:00
Bjørn Erik Pedersen a215abf70e Squashed 'docs/' changes from 76e881257..896bad9f4
896bad9f4 Remove unused files below /static

git-subtree-dir: docs
git-subtree-split: 896bad9f4f
2018-04-22 17:57:24 +02:00
Bjørn Erik Pedersen 474bad34ca Merge commit 'a215abf70e018f4bf40d6c09d8bd148d8684b33d' 2018-04-22 17:57:24 +02:00
Bjørn Erik Pedersen 85535084de hugolib: Process and render shortcodes in their order of appearance
Fixes #3359
2018-04-22 17:40:51 +02:00
Bjørn Erik Pedersen 19084eaf74 hugolib: Init the content and shortcodes early
In most cases we could delay the content init until rendering time, but there could be use cases where the templates would depend on state set in the shortcodes (.Page.Scratch.Set), so we  need to do this early.

See #4632
2018-04-22 12:03:01 +02:00
Bjørn Erik Pedersen 47e7788b3c tpl/path: Add path.Ext, path.Dir and path.Base 2018-04-22 10:57:37 +02:00
Bjørn Erik Pedersen 51af1d2ead tpl/os: Make fileExist use the same filesystem as readFile
Fixes #4633
2018-04-21 23:46:34 +02:00
Bjørn Erik Pedersen 1b9dc52ef5 Merge commit 'd2ec1a06df8ab6b17ad05cb008d5701b40327d47' 2018-04-21 23:02:48 +02:00
Bjørn Erik Pedersen d2ec1a06df Squashed 'docs/' changes from f9a5dc59b..76e881257
76e881257 Improve .Scratch entry (#454)
37ed09702 Remove zero-byte .gitmodules file altogether
943f21619 Add a note about valid values for taxonomies in front-matter
ebcfa30d7 Update definition list formatting
46050042a Corrected formatting
87c539101 Updated readFile documentation
8fd130395 commands: Regenerate the CLI docs
6ce0ce8d6 data: Regenereate the docshelper
9fe78fabd Release 0.39
33039c6ba releaser: Prepare repository for 0.40-DEV
e3a780907 releaser: Add release notes to /docs for release of 0.39
54406e3fa releaser: Bump versions for release of 0.39
21017660b Merge commit '047c4188dfc854f658d16f1e4a9501f9c97a31c7'

git-subtree-dir: docs
git-subtree-split: 76e8812576
2018-04-21 23:01:55 +02:00
Bjørn Erik Pedersen 4d26ab33dc Make .Content (almost) always available in shortcodes
This resolves some surprising behaviour when reading other pages' content from shortcodes. Before this commit, that behaviour was undefined. Note that this has never been an issue from regular templates.

It will still not be possible to get **the current shortcode's  page's rendered content**. That would have impressed Einstein.

The new and well defined rules are:

* `.Page.Content` from a shortcode will be empty. The related `.Page.Truncated` `.Page.Summary`, `.Page.WordCount`, `.Page.ReadingTime`, `.Page.Plain` and `.Page.PlainWords` will also have empty values.
* For _other pages_ (retrieved via `.Page.Site.GetPage`, `.Site.Pages` etc.) the `.Content` is there to use as you please as long as you don't have infinite content recursion in your shortcode/content setup. See below.
* `.Page.TableOfContents` is good to go (but does not support shortcodes in headlines; this is unchanged)

If you get into a situation of infinite recursion, the `.Content` will be empty. Run `hugo -v` for more information.

Fixes #4632
Fixes #4653
Fixes #4655
2018-04-21 22:02:56 +02:00
Bjørn Erik Pedersen d6a2024e6b Revert "Improve .Content vs shortcodes"
This reverts commit e590cc26eb.
2018-04-19 17:40:57 +02:00
Bjørn Erik Pedersen d6982ac0ac Revert "hugolib: Prepare child page resources before the page itself"
This reverts commit 3238e14fdf.
2018-04-19 17:40:54 +02:00
Bjørn Erik Pedersen 3238e14fdf hugolib: Prepare child page resources before the page itself
To make sure that the child resources' content is ready before any shortcode is processed in their owner.

See #4632
2018-04-19 16:35:21 +02:00
Bjørn Erik Pedersen 47c05c47e0 Add language merge support for Pages in resource.Resources
Fixes #4644
2018-04-19 16:23:00 +02:00
Bjørn Erik Pedersen e590cc26eb Improve .Content vs shortcodes
For the content from other pages in shortcodes there are some chicken and
egg dependencies that is hard to get around. But we can improve on this  by preparing the pages in a certain order:

 1. The headless bundles goes first. These are page typically page and image collections..
 2. Leaf bundles
 3. Regular single pages
 4. Branch bundles

Fixes #4632
2018-04-19 14:46:50 +02:00
cmal 74520d2cfd Improve .Get docs 2018-04-17 15:39:33 +02:00
cmal e2b277bba5 Update missing positional parameter test for .Get 2018-04-17 15:39:33 +02:00
cmal 236f0c840b .Get doesn't crash on missing positional param
fixes #4619
2018-04-17 15:39:33 +02:00
cmal cd6a261242 .Get function: fix syntax signature 2018-04-17 15:39:33 +02:00
Bjørn Erik Pedersen d681ea55a0 Improve error message in metadata parse
Fixes #3696
2018-04-17 15:37:05 +02:00
Bjørn Erik Pedersen a96ad5c211 hugolib: Fix broken test 2018-04-17 10:28:32 +02:00
Bjørn Erik Pedersen 159bed34c3 parser: Add some context to front matter parse error
Fixes #4638
2018-04-17 10:20:38 +02:00
Lucas Liberacki 5cc944ffd7 Updated GetCSV error message (#4636) 2018-04-17 07:20:14 +02:00
hugoreleaser 89d2cf49ac releaser: Prepare repository for 0.40-DEV
[ci skip]
2018-04-16 07:33:49 +00:00
hugoreleaser 933a16b109 releaser: Add release notes to /docs for release of 0.39
[ci skip]
2018-04-16 07:31:26 +00:00
hugoreleaser 60845a5a0e releaser: Bump versions for release of 0.39
[ci skip]
2018-04-16 07:31:26 +00:00
Bjørn Erik Pedersen 9a39146edf releaser: Fix LICENSE vs LICENSE.md
Fixes #4631
2018-04-16 09:27:39 +02:00
Bjørn Erik Pedersen 1a6a0fa6f2 Release 0.39 2018-04-16 09:08:36 +02:00
hugoreleaser 936fc76ad6 releaser: Add release notes draft for 0.39
Rename to *-ready.md to continue. [ci skip]
2018-04-16 06:27:26 +00:00
Bjørn Erik Pedersen f21b827f7b commands: Re-add the missing releaser command 2018-04-16 08:23:32 +02:00
Bjørn Erik Pedersen 7c597c7d75 Merge commit '047c4188dfc854f658d16f1e4a9501f9c97a31c7' 2018-04-16 07:45:38 +02:00
Bjørn Erik Pedersen 047c4188df Squashed 'docs/' changes from d9c8fc220..f9a5dc59b
f9a5dc59b Code Toggle block added to doc site final batch Templates  Variables 
4d4107968 Add eSolia as new sponsor
000fed94e Add missing closing tags for li in menu template example
f462b620f Clarify that local CSV files cannot be inside data dir
ae083641a Added hugo-search-index to list of search tools
e2b64d0b7 Remove extra link
2fb4c9af5 Release 0.38.2
59b1c9853 releaser: Prepare repository for 0.39-DEV
92f6a05ea releaser: Add release notes to /docs for release of 0.38.2
76244729e releaser: Bump versions for release of 0.38.2
0960c5fb3 Adjust gray color of tab vs pane in code-toggle.
8ae3aadd7 use code-toggle shortcode when relevant Content Management 
455b8b53b Update related.md
6e8d19090 Release 0.38.1
079ba044c releaser: Prepare repository for 0.39-DEV
6f23e6ec1 releaser: Add release notes to /docs for release of 0.38.1
c51692ceb releaser: Bump versions for release of 0.38.1
d37ea6a5e Update related.md
faa2707d0 Update index.md
9ce901dcb Add a forgotten language tag (go-html-template) for code
b05aaed14 Update where.md
4d4760819 Fix typo in code-toggle.md
c5a5250a1 Use the new go-html-template Chroma lexer
2de831f4b Add the full list of Chroma lexers
18114d4b4 Update Output Formats
b069d7f84 Release 0.38
caaa8355a releaser: Prepare repository for 0.39-DEV
e45b7cc9f releaser: Add release notes to /docs for release of 0.38
40f40906e releaser: Bump versions for release of 0.38
2d52e2e4e Merge commit 'ed8bf081fdbf336e026517b7e1b123c039014ab5'
1439f64a0 docs: Generate docshelper data
5b0edfd79 Add .Site.IsServer
fdb579ad1 Merge commit '0a23baa6a90901f772c234107c4f12c16c76f4aa'
7b71da1f8 hugolib: Add Reset method to delete key from Scratch
63a131664 docs: Add docs for lang.Merge
55cba056d Merge commit '3886fc1fef6ac19d58b9ba1bb642d0c6c9a54031'
6f301ebcc docs: Add docs on the new front matter configuration
7ba35ef56 Merge commit 'c0290655825e7bb36e13fb39f89d85b392cf1adc'
3d2cab754 releaser: Prepare repository for 0.38-DEV
095e888e1 releaser: Add release notes to /docs for release of 0.37.1
593fa0dcb releaser: Bump versions for release of 0.37.1
c18c1df54 releaser: Prepare repository for 0.38-DEV

git-subtree-dir: docs
git-subtree-split: f9a5dc59b7
2018-04-16 07:43:59 +02:00
Bjørn Erik Pedersen e136c26d0c Remove old LICENSE.md
Closes #4623
2018-04-16 00:03:56 +02:00
Bjørn Erik Pedersen dd48277497 Add a GitHub compatible Apache 2 license text 2018-04-16 00:03:30 +02:00
Bjørn Erik Pedersen 4dba6ce15a tpl/urls: Add anchorize template func 2018-04-15 23:17:50 +02:00
Bjørn Erik Pedersen 880ca19f20 tpl/path: Add path.Join 2018-04-15 22:19:12 +02:00
Bjørn Erik Pedersen 01b72eb592 tpl: Add path.Split template func 2018-04-15 22:19:12 +02:00
Bjørn Erik Pedersen 61d52f1462 hugolib: Do not reset .Page.Scratch on rebuilds
Fixes #4627
2018-04-15 19:31:42 +02:00
Bjørn Erik Pedersen 0e7716a424 resource: Implement Resource.Content
Fixes #4622
2018-04-15 18:08:06 +02:00
Bjørn Erik Pedersen 417c5e2b67 Make Page.Content a method that returns interface{}
To prepare for a `Resource.Content` method.

See #4622
2018-04-15 18:08:06 +02:00
Bjørn Erik Pedersen 94c8b29c39 source: Remove deprecated File.Bytes 2018-04-15 14:34:34 +02:00
Bjørn Erik Pedersen 1b4e0c4161 commands: Remove accidental and breaking space in baseURL flag
And added key-trimming to prevent future mishaps.

See #4607
2018-04-15 11:20:04 +02:00
Bjørn Erik Pedersen 27a524b090 commands: Properly handle CLI slice arguments
Like `--disableKinds` -- this handling was kind of broken when we recently moved this from global vars

See #4607
2018-04-14 11:32:25 +02:00
Bjørn Erik Pedersen bede93de00 commands: Correctly handle destination and i18n-warnings
And add some more CLI tests.

See #4607
2018-04-14 11:32:25 +02:00
Bjørn Erik Pedersen 2aab6dee85 commands: Fix handling of persistent CLI flags
See #4607
2018-04-13 09:08:49 +02:00
Bjørn Erik Pedersen f3775877c6 hugolib: Fix livereload of bundled pages
Fixes #4607
2018-04-12 12:19:46 +02:00
Bjørn Erik Pedersen 9c782d5147 commands: Fix failing Travis server test 2018-04-12 09:31:53 +02:00
Bjørn Erik Pedersen 14c35c8a56 Allow "*/" inside commented out shortcodes
Fixes #4608
2018-04-11 22:41:48 +02:00
Bjørn Erik Pedersen 96689a5c31 commands: Make commands.Execute return a Response object
We have no global `Hugo` object no more (yay!), and there are some external tools that depends on that value.

These tools need to use get that value from `Response.Result`.

Note that `commands.Execute` now also takes the arguments as a string slice. This should also make it easier to use, not having to modify `os.Args`.

This commit also wraps up this particular issue. Phew!

Test coverage in /commands before: 14.4%
Now:  53.5%

Still work to do, now it is at least possible.

Closes #4598
2018-04-11 20:37:08 +02:00
Bjørn Erik Pedersen e7010c1b62 commands: Remove some TODOs
See #4598
2018-04-11 10:16:30 +02:00
Bjørn Erik Pedersen f396cffa23 commands: Fix the config command
It now also accepts the `-s` (source) flag.

See #4598
2018-04-11 10:09:45 +02:00
Bjørn Erik Pedersen 24d5c21942 commands: Fix some flag diff
The CLI docs output is now identical with the master version.

See #4598
2018-04-11 09:57:43 +02:00
Bjørn Erik Pedersen a7d00fc39e commands: Add basic server test
See #4598
2018-04-11 09:51:07 +02:00
Bjørn Erik Pedersen 1e233b1c45 commands: Fix TestFixURL
See #4598
2018-04-11 09:50:19 +02:00
Bjørn Erik Pedersen b110d0ae04 commands: Remove the Hugo global
There are still some cleaning to do, but that felt good.

See #4598
2018-04-11 09:50:19 +02:00
Bjørn Erik Pedersen 73825cfc1c commands: Make the limit command work again
See #4598
2018-04-11 09:50:19 +02:00
Bjørn Erik Pedersen a8f7fbbb10 commands: Move the commands related logic to its own file
See #4598
2018-04-11 09:50:19 +02:00
Bjørn Erik Pedersen e8d6ca9531 commands: Add CLI tests
See #4598
2018-04-11 09:50:19 +02:00
Bjørn Erik Pedersen 4d32f2fa89 commands: Make the hugo command non-global
See #4598
2018-04-11 09:50:19 +02:00
Bjørn Erik Pedersen 018602c46d commands: Extract some common types into its own file
See #4598
2018-04-11 09:50:19 +02:00
Bjørn Erik Pedersen 2f0d98a19b commands: Make the server command non-global
See #4598
2018-04-11 09:50:18 +02:00
Bjørn Erik Pedersen e0621d207c commands: Make the gen commands non-global
See #4598
2018-04-11 09:50:18 +02:00
Bjørn Erik Pedersen e26a8b242a commands: Make the list commands non-global
See #4598
2018-04-11 09:48:56 +02:00
Bjørn Erik Pedersen 2a2c983867 commands: Make the import commands non-global
See #4598
2018-04-11 09:48:56 +02:00
Bjørn Erik Pedersen 15b1e269ad comands: Make the config command non-global
See #4598
2018-04-11 09:48:56 +02:00
Bjørn Erik Pedersen 56a1308044 commands: Make the new commands non-global
See #4598
2018-04-11 09:48:56 +02:00
Bjørn Erik Pedersen 4b780ca778 commands: Make convert command non-global
See #4598
2018-04-11 09:48:56 +02:00
Bjørn Erik Pedersen 7bc5e89fba commands: Make more commands non-global
See #4598
2018-04-11 09:48:56 +02:00
Bjørn Erik Pedersen fdf1d94ebc commands: Make benchmark non-global
See #4598
2018-04-11 09:48:56 +02:00
Bjørn Erik Pedersen 1157fef859 commands: Start of flag cleaning
See #4598
2018-04-11 09:48:55 +02:00
Bjørn Erik Pedersen e614d8a57c commands: Use short date format in CLI docs
To make it possible to compare the output.

See #4598
2018-04-11 09:48:34 +02:00
Hudson Muff fca49d6c60 Update README.md
I discovered an inconsistency between the website documentation (https://gohugo.io/getting-started/installing/#source) and this README, for installing from source. I checked them both and the website seems to be newer so I would like to propose updating this README to install Hugo using mage (unless it doesn't really matter).
2018-04-09 18:06:21 +02:00
Bjørn Erik Pedersen 0e8b3cbcd2 Sync dependencies 2018-04-09 11:12:05 +02:00
Bjørn Erik Pedersen 230f2b8c4f Bump Go versions
Fixes #4545
2018-04-09 11:01:01 +02:00
hugoreleaser d7f47b780c releaser: Prepare repository for 0.39-DEV
[ci skip]
2018-04-09 08:19:32 +00:00
hugoreleaser 712c0fdfe6 releaser: Add release notes to /docs for release of 0.38.2
[ci skip]
2018-04-09 08:17:15 +00:00
hugoreleaser 62e7588262 releaser: Bump versions for release of 0.38.2
[ci skip]
2018-04-09 08:17:14 +00:00
Bjørn Erik Pedersen 47da0dca52 Release 0.38.2 2018-04-09 10:08:33 +02:00
hugoreleaser 8d87bfd5ee releaser: Add release notes draft for 0.38.2
Rename to *-ready.md to continue. [ci skip]
2018-04-09 08:00:48 +00:00
Bjørn Erik Pedersen 719251c1af Bump the debouncer dependency
No practical difference.
2018-04-08 10:20:39 +02:00
Bjørn Erik Pedersen 8b2ef83bb1 Use a versioned debounce dependency 2018-04-07 18:09:31 +02:00
Bjørn Erik Pedersen 080302eb87 Fix handling of --contentDir etc. flag
We need to revisit the commands package re globals and tests, but this should fix the init order of flags and languages.

Fixes #4589
2018-04-07 16:40:45 +02:00
Anthony Fok 094ec17142 travis: Disable shallow clone to fix TestPageWithLastmodFromGitInfo
Fixes #4584
2018-04-07 06:54:24 -06:00
Anthony Fok e84b7ade65 Revert "Disable failing test on Travis"
This reverts commit 2170943ae6
and commit 623c9afa84.
2018-04-07 06:53:47 -06:00
Bjørn Erik Pedersen 2817e84240 Fix handling of content files with "." in them
As in, more dots than just to separate the extension and any language indicator.

Fixes #4559
2018-04-07 10:57:29 +02:00
Bjørn Erik Pedersen 623c9afa84 And now really disable failing test on Travis
See #4584
2018-04-06 18:14:11 +02:00
Bjørn Erik Pedersen 2170943ae6 Disable failing test on Travis
See #4584
2018-04-06 17:31:13 +02:00
Bjørn Erik Pedersen 9cd4d35977 Revert "Try an older GitMap version"
This reverts commit 3a3261a3b9.
2018-04-06 12:01:38 +02:00
Bjørn Erik Pedersen 3a3261a3b9 Try an older GitMap version
To test if the test failures goes away.
2018-04-06 10:59:47 +02:00
Bjørn Erik Pedersen 6792d86ad0 hugolib: Set .Parent in bundled pages to its owner
Fixes #4582
2018-04-06 10:41:28 +02:00
hugoreleaser e7d87e2410 releaser: Prepare repository for 0.39-DEV
[ci skip]
2018-04-05 16:39:05 +00:00
hugoreleaser c475eab474 releaser: Add release notes to /docs for release of 0.38.1
[ci skip]
2018-04-05 16:35:25 +00:00
hugoreleaser 3a96fa40bf releaser: Bump versions for release of 0.38.1
[ci skip]
2018-04-05 16:35:25 +00:00
Bjørn Erik Pedersen c356f1d417 Release 0.38.1 2018-04-05 18:31:17 +02:00
hugoreleaser 30c2c2f8ec releaser: Add release notes draft for 0.38.1
Rename to *-ready.md to continue. [ci skip]
2018-04-05 16:27:24 +00:00
Bjørn Erik Pedersen f87239e4ca Fix livereload for the home page bundle
Fixes #4576
2018-04-05 18:03:33 +02:00
Anthony Fok db0633c1a4 snap: Revert to "mage test" because "mage check" fails
"mage check", which runs "go test", gofmt, "go vet", and
"go test -race", fails one way or another especially on
on non-amd64 architectures, and sometimes even on amd64 too.

Partially reverting my undocumented change in commit 294c0f8.

Fixes #4578
2018-04-05 09:35:47 -06:00
Anthony Fok 874159b543 snap: Add bash completion 2018-04-05 15:51:11 +02:00
Anthony Fok 294c0f8001 snap: Fix empty BuildDate in "hugo version"
Previously, "snap run hugo version" returns an empty BuildDate like so:

    Hugo Static Site Generator v0.38 linux/amd64 BuildDate:

Fix by overriding the default build target of snapcraft's go plugin.
2018-04-05 15:51:11 +02:00
Bjørn Erik Pedersen a4deaeff0c Fix some livereload content regressions
Introduced in Hugo 0.38.

Fixes #4566
2018-04-05 14:28:45 +02:00
Anthony Fok 4d115c56fa Update github.com/bep/gitmap to fix snap build
Fixes #4538
2018-04-05 14:20:39 +02:00
Brian Fitzgerald 26f34fd59d Fix two tests that are broken on Windows
Put guards around TestPageBundlerCaptureSymlinks and
TestPageBundlerSiteWitSymbolicLinksInContent so that they aren't
run on Windows (they both use symbolic links and the Go library
implementation requires administrator mode on Windows).
2018-04-05 08:35:06 +02:00
Bjørn Erik Pedersen 730b66b652 commands: Handle mass content etc. edits in server mode
Fixes #4563
2018-04-04 09:29:59 +02:00
hugoreleaser 4f639d6bd5 releaser: Prepare repository for 0.39-DEV
[ci skip]
2018-04-02 11:06:04 +00:00
hugoreleaser f7bc28c529 releaser: Add release notes to /docs for release of 0.38
[ci skip]
2018-04-02 11:03:32 +00:00
hugoreleaser 20e9c08e1f releaser: Bump versions for release of 0.38
[ci skip]
2018-04-02 11:03:32 +00:00
Bjørn Erik Pedersen 37140a093b Release 0.38 2018-04-02 12:58:13 +02:00
hugoreleaser da80163c75 releaser: Add release notes draft for 0.38
Rename to *-ready.md to continue. [ci skip]
2018-04-02 12:58:13 +02:00
Anthony Fok 60e66d12ea travis: Clean up and increase verbosity 2018-04-02 09:20:58 +02:00
Bjørn Erik Pedersen ed8bf081fd Squashed 'docs/' changes from 3068989b9..d9c8fc220
d9c8fc220 Rebuild Chroma CSS
a9168b106 Adds missing word
ebaa172af Remove note about enabling custom GitLab domains
2ef3918b2 Add code toggler
41878b6ca Clarify the use of .GetPage with page bundles
ffcb26270 Fix broken link for configuration.md
1e72e2b3e Fixed typo in heading - Hightlighter
72b2db77c Change "on the form" to "of the form"
e15e6966f Fix example GitHub url

git-subtree-dir: docs
git-subtree-split: d9c8fc2207
2018-04-02 08:53:34 +02:00
Bjørn Erik Pedersen 558825cc20 Merge commit 'ed8bf081fdbf336e026517b7e1b123c039014ab5' 2018-04-02 08:53:34 +02:00
Bjørn Erik Pedersen 10c33c17cd docs: Generate docshelper data
And fix build ...
2018-04-02 08:52:42 +02:00
Bjørn Erik Pedersen 2c54f1ad48 docshelper: List Chroma lexers
Fixes #4554
2018-04-02 08:50:42 +02:00
Anthony Fok eb15ac37ef travis: Run "gem install" without sudo
Running "sudo gem install" was causing random errors like the following:

ERROR:  While executing gem ... (Errno::EACCES)
    Permission denied @ rb_sysopen - /home/travis/.rvm/gems/ruby-2.4.1/cache/asciidoctor-1.5.6.2.gem

Perhaps sudo is no longer necessary, even on OS X?  :-)
2018-04-02 08:15:35 +02:00
Bjørn Erik Pedersen eb42774e58 Add support for a content dir set per language
A sample config:

```toml
defaultContentLanguage = "en"
defaultContentLanguageInSubdir = true

[Languages]
[Languages.en]
weight = 10
title = "In English"
languageName = "English"
contentDir = "content/english"

[Languages.nn]
weight = 20
title = "På Norsk"
languageName = "Norsk"
contentDir = "content/norwegian"
```

The value of `contentDir` can be any valid path, even absolute path references. The only restriction is that the content dirs cannot overlap.

The content files will be assigned a language by

1. The placement: `content/norwegian/post/my-post.md` will be read as Norwegian content.
2. The filename: `content/english/post/my-post.nn.md` will be read as Norwegian even if it lives in the English content folder.

The content directories will be merged into a big virtual filesystem with one simple rule: The most specific language file will win.
This means that if both `content/norwegian/post/my-post.md` and `content/english/post/my-post.nn.md` exists, they will be considered duplicates and the version inside `content/norwegian` will win.

Note that translations will be automatically assigned by Hugo by the content file's relative placement, so `content/norwegian/post/my-post.md` will be a translation of `content/english/post/my-post.md`.

If this does not work for you, you can connect the translations together by setting a `translationKey` in the content files' front matter.

Fixes #4523
Fixes #4552
Fixes #4553
2018-04-02 08:06:21 +02:00
Bjørn Erik Pedersen f27977809c Update stale.yml 2018-04-01 21:36:00 +02:00
Bjørn Erik Pedersen 7a634898c3 Update Chroma
Fixes #4549
2018-03-31 10:51:01 +02:00
Ricardo N Feliciano 1823c053c8 Add .Site.IsServer
Fixes #4478
2018-03-30 20:15:22 +02:00
Anthony Fok 511d5d3b76 travis: Move to Ubuntu Trusty image 2018-03-26 09:09:58 -06:00
Anthony Fok 8299fa885c snap: Remove "make" from build-packages because we use mage now 2018-03-26 07:02:45 -06:00
Anthony Fok 06495f713b snapcraft.yaml: Call mage with "-v" for debugging
See #4538
2018-03-26 04:56:15 -06:00
Bjørn Erik Pedersen 93e24a03ce hugolib: Fix freeze in invalid front matter error case
Fixes #4526
2018-03-24 10:06:58 +01:00
Bjørn Erik Pedersen e9c7b6205f Allow themes to define output formats, media types and params
This allows a `config.toml` (or `yaml`, ´yml`, or `json`)  in the theme to set:

1) `params` (but cannot override params in project. Will also get its own "namespace", i.e. `{{ .Site.Params.mytheme.my_param }}` will be the same as `{{ .Site.Params.my_param }}` providing that the main project does not define a param with that key.
2) `menu` -- but cannot redefine/add menus in the project. Must create its own menus with its own identifiers.
3) `languages` -- only `params` and `menu`. Same rules as above.
4) **new** `outputFormats`
5) **new** `mediaTypes`

This should help with the "theme portability" issue and people having to copy and paste lots of setting into their projects.

Fixes #4490
2018-03-21 09:22:19 +01:00
Bjørn Erik Pedersen 3d1a6e109c hugolib: Add ConfigSourceDescriptor
To prepare for config in themes

See #4490
2018-03-20 21:30:43 +01:00
Bjørn Erik Pedersen b6798ee867 Bump some deprecations 2018-03-20 21:13:44 +01:00
Bjørn Erik Pedersen 0a23baa6a9 Squashed 'docs/' changes from 211a3c613..3068989b9
3068989b9 Merge commit '7ae9cf2ccb3eecc1ff50f686925249d01cf37c6c'
7ae9cf2cc Squashed 'themes/gohugoioTheme/' changes from d7a475e7..a1768ebb
b55157fae Revert "Anchorify headings up to h4"
b63dd5566 Anchorify headings up to h4
edfe36a19 Test out trac as highlighter style
98dc8d269 Update multilingual.md
a6e4d92c0 Update multilingual.md
86a90edf9 Fix typo 'If will' to 'It will' line 41
6b626fac6 Add a tip for testing custom 404.html on hugo server
6bfc17cfc Update few links to now point to gohugoio organization repos
f66bad971 Remove unintended alias
3bc56e9ec Fix shortcode name in example: image -> img
251142388 Fix broken link
27245af6a Fix the minimum required git version for GH Pages flow
aefc87b4d Fix link in Forestry showcase
489ec5ea0 Squashed 'themes/gohugoioTheme/' changes from 6f3a8bf5..d7a475e7
308a616fd Merge commit '489ec5ea03799fa092d891838c1655e60b34f337'
a80859814 Adjust showcase description

git-subtree-dir: docs
git-subtree-split: 3068989b9c
2018-03-20 21:11:45 +01:00
Bjørn Erik Pedersen 84f4b731d2 Merge commit '0a23baa6a90901f772c234107c4f12c16c76f4aa' 2018-03-20 21:11:45 +01:00
Bjørn Erik Pedersen 61f6e9f63b tpl/transform: Add a comments test for Remarshal
See #4521
2018-03-20 18:23:32 +01:00
Bjørn Erik Pedersen 904a3d9ddf Update Chroma to get Go template support
Fixes #4515
2018-03-19 09:19:47 +01:00
Bjørn Erik Pedersen f0052b6d0f commands: Recover from error in server
Issue introduced some days ago.

Fixes #4516
2018-03-18 12:54:06 +01:00
Bjørn Erik Pedersen da88015776 Spring test cleaning, take 2 2018-03-18 09:54:32 +01:00
Bjørn Erik Pedersen debd3663dd hugolib: Test cleaning #1 2018-03-17 18:59:07 +01:00
Bjørn Erik Pedersen af67ad8af1 hugolib: Trim some now superflous tests
These were written as a development aid in some kind of structural change at some point.

They served their purpose then, but these are tests covered elsewhere and is deleted to reduce maintainance.

The reported test covrage is not reduced because of this.
2018-03-17 18:59:07 +01:00
cmal e46ab29bd2 hugolib: Add Reset method to delete key from Scratch 2018-03-17 00:13:23 +01:00
Bjørn Erik Pedersen 10fef32de6 releaser: Adjust the "thank you" section 2018-03-16 20:56:28 +01:00
Bjørn Erik Pedersen 70005364a2 docs: Add docs for lang.Merge
See https://github.com/gohugoio/hugo/issues/4463
2018-03-16 10:10:01 +01:00
Bjørn Erik Pedersen ffaec4ca8c Add a way to merge pages by language
As an example:

```html
{{ $pages := .Site.RegularPages | lang.Merge $frSite.RegularPages | lang.Merge $enSite.RegularPages }}
```

Will "fill in the gaps" in the current site with, from left to right, content from the French site, and lastly the English.

Fixes #4463
2018-03-16 10:10:01 +01:00
Bjørn Erik Pedersen 3886fc1fef Squashed 'docs/' changes from 4e7e1815b..211a3c613
211a3c613 Prepare the forestry.io article for release
23995d6b4 Add forestry.io to showcase
3f177c94e Fix some typos (found by codespell)
dc26e0a5a Clarify the default for site config files and multiple config files
c87c9c62e Review and update the Site config documentation for consistency
a29edc50c Fix the default value of rssLimit site config
83f3c46b0 Minor style fix
4f860d1a2 Typo capitalization fixes
7851345c8 Add docs about comments within templates
d129b4a28 Make the recommendation to use partial over template consistent
6cd260a41 Update index.md
a2787e1a4 Add Let’s Encrypt showcase
7e664f69e Update configuration.md
8002120f1 Update multilingual.md
702b46a62 Add documentation for the disableLanguages setting
cb3d395de Fix content type reference
d33226924 Update Page Kinds documentation
8203f649d Fix misformed markdown link
19e99c957 Add Section definition

git-subtree-dir: docs
git-subtree-split: 211a3c6136
2018-03-16 09:44:54 +01:00
Bjørn Erik Pedersen 91fb8f1b59 Merge commit '3886fc1fef6ac19d58b9ba1bb642d0c6c9a54031' 2018-03-16 09:44:54 +01:00
Bjørn Erik Pedersen ac12d51e7e create: Remove archetype title/date warning
Closes #4504
2018-03-15 08:52:20 +01:00
Bjørn Erik Pedersen 3fbc75534d resource: Fix path duplication/flattening in processed images
Fixes #4502
Closes #4501
2018-03-14 17:04:14 +01:00
Bjørn Erik Pedersen e427ba4268 hugolib: Remove superflous debug file 2018-03-12 23:36:20 +01:00
Bjørn Erik Pedersen 79dd7cb31a hugolib: Simplify Prev/Next 2018-03-12 22:13:25 +01:00
Bjørn Erik Pedersen 0dbf79c2f8 docs: Add docs on the new front matter configuration
See #4495
2018-03-11 22:51:11 +01:00
Bjørn Erik Pedersen f12ad7d56a hugolib: Adjust GitInfo author date test
Now that we have a commit to assert against.

See #4495
2018-03-11 21:32:15 +01:00
Bjørn Erik Pedersen ce6e4310fe Refactor the GitInfo into the date handlers
Fixes #4495
2018-03-11 21:32:05 +01:00
Bjørn Erik Pedersen 95d62004a0 Merge commit 'c0290655825e7bb36e13fb39f89d85b392cf1adc' 2018-03-11 20:40:26 +01:00
Bjørn Erik Pedersen c029065582 Squashed 'docs/' changes from 715741f73..4e7e1815b
4e7e1815b Fix some typos
d23d8f5c4 Remove 'fundamentals' category from function pages
52fa65e15 Mention Chroma as the preferred syntax highlighter
64ca535db Merge commit '8762aee8afe30bec6f1fbc9560749983dc44d60b'
8762aee8a Squashed 'themes/gohugoioTheme/' changes from 396b859f..6f3a8bf5
03f0673a9 Move the gopher to the theme
320e268cd Spelling
e45b640f7 More layout lookup work
fe0ad9d9d Sync the YAML config menu example with TOML's
b9505fc70 Remove template reference to ordinal numbers
0fa2532d3 Remove deprecated Hugoidx, add native hugo solution
2152b907c Fix a link in the last commit
47614f416 Manually specifying heading anchors in Markdown content
9d6770d2a Release notes 0.37.1
e1eed8b27 Remove some unused images
e960046f5 releaser: Prepare repository for 0.38-DEV
4fa83a4ee releaser: Add release notes to /docs for release of 0.37.1
46c879995 releaser: Bump versions for release of 0.37.1
fb3ac5a3e releaser: Prepare repository for 0.38-DEV
4870c8e7b Update archetypes.md
232c0b578 Merge commit '2b18014fd0aa99e9f1a5610ba875101351a90de3'
2b18014fd Squashed 'themes/gohugoioTheme/' changes from fe71e360..396b859f
62567e9aa Add some "writing guidelines"
7cfd530d2 Revise the archetype docs
5d4c3c03c Update data-templates.md
e5fee3099 Update page-bundles.md
ca7f03c8d Update page-bundles.md
2a7fdc269 Fix typo 'vailable' to 'available' line 53
999b75201 LastMod should be Lastmod?
099f46ca5 Fix spacing in content-management/types.md
6bcdc58ef Word choice improvements
20e8a21f6 update rss linking docs
7ef44d262 Add some missing configuration entries
f1c7aa568 Sort config list
5cb8ceade Create a proper definition list for the configuration settings
25dffe4ac Send custom dimensions in GA
55df01a34 Fix broken gtag
6c8772aad Add site to GA config
e63acb894 Remove conflicting release note for 0.35
f30083a23 Add branch to GA config
99caedb96 Set the small-multiples to draft
4a33c70ab Polish the Small Multiples showcase
7b2f1ea2e Add small multiples showcase
e78e96bae Add new sponsor
c42943041 updated to new Forestry logo
e07eda273 Add OS env to faq
414f0dbc6 Release Hugo 0.37
85f0cc324 Merge branch 'temp37'
1e6da9497 Rebuild images
75e97adfc releaser: Add release notes to /docs for release of 0.37
50b887cb0 releaser: Bump versions for release of 0.37
7acf73ba3 Merge commit '900b5f6cfe5a377ef369d26cd700201be4cf6b06'
819d02c30 Merge commit '374d184e6747678364fd61f5faf328ec9205eb6b'
c7eacf018 Fix typos in development contribution doc

git-subtree-dir: docs
git-subtree-split: 4e7e1815b7
2018-03-11 20:39:20 +01:00
Bjørn Erik Pedersen 68bf1511f2 hugolib: Extract date and slug from filename
This commit makes it possible to extract the date from the content filename. Also, the filenames in these cases will make for very poor permalinks, so we will also use the remaining part as the page `slug` if that value is not set in front matter.

This should make it easier to move content from Jekyll to Hugo.

To enable, put this in your `config.toml`:

```toml
[frontmatter]
date  = [":filename", ":default"]
```

This commit is also a spring cleaning of how the different dates are configured in Hugo. Hugo will check for dates following the configuration from left to right, starting with `:filename` etc.

So, if you want to use the `file modification time`, this can be a good configuration:

 ```toml
[frontmatter]
date = [ "date",":fileModTime", ":default"]
lastmod = ["lastmod" ,":fileModTime", ":default"]
```

The current `:default` values for the different dates are

```toml
[frontmatter]
date = ["date","publishDate", "lastmod"]
lastmod = ["lastmod", "date","publishDate"]
publishDate = ["publishDate", "date"]
expiryDate = ["expiryDate"]
```

The above will now be the same as:

```toml
[frontmatter]
date = [":default"]
lastmod = [":default"]
publishDate = [":default"]
expiryDate = [":default"]
```

Note:

* We have some built-in aliases to the above: lastmod => modified, publishDate => pubdate, published and expiryDate => unpublishdate.
* If you want a new configuration for, say, `date`, you can provide only that line, and the rest will be preserved.
* All the keywords to the right that does not start with a ":" maps to front matter parameters, and can be any date param (e.g. `myCustomDateParam`).
* The keywords to the left are the **4 predefined dates in Hugo**, i.e. they are constant values.
* The current "special date handlers" are `:fileModTime` and `:filename`. We will soon add `:git` to that list.

Fixes #285
Closes #3310
Closes #3762
Closes #4340
2018-03-11 18:26:18 +01:00
Bjørn Erik Pedersen f8dc47eeff Allow partial redefinition of the ouputs config
Fixes #4487
2018-03-10 16:57:25 +01:00
Bjørn Erik Pedersen ae3fa349de output: Fix build
See #4484
2018-03-09 17:28:20 +01:00
Bjørn Erik Pedersen 64cec07293 outputs: Adjust the layout examples 2018-03-09 13:26:28 +01:00
hugoreleaser 9ac6206584 releaser: Prepare repository for 0.38-DEV
[ci skip]
2018-03-07 17:58:48 +00:00
hugoreleaser f414966b94 releaser: Add release notes to /docs for release of 0.37.1
[ci skip]
2018-03-07 17:56:23 +00:00
hugoreleaser c29a2ed2f5 releaser: Bump versions for release of 0.37.1
[ci skip]
2018-03-07 17:56:23 +00:00
Bjørn Erik Pedersen dfb6484a41 Release 0.37.1 2018-03-07 18:52:14 +01:00
hugoreleaser 8a02968393 releaser: Add release notes draft for 0.37.1
Rename to *-ready.md to continue. [ci skip]
2018-03-07 17:45:56 +00:00
Bjørn Erik Pedersen e7fda289b1 Remove defaultLayout config
Not in use.
2018-03-01 17:19:49 +01:00
Bjørn Erik Pedersen 50a03a5acc commands: Do not print build total when --quiet is set
Fixes #4456
2018-02-27 21:04:39 +01:00
Bjørn Erik Pedersen ba94abbf5d resource: Fix SVG and similar resource handling
The validation of if we could process the image (resize etc.) was moved up in Hugo 0.37, which meant SVG and other "non-processable" images would fail.

This commit fixes that by creating a regular resource for these image formats. They will not have `.Resize` or any of the other image methods.

Fixes #4455
2018-02-27 18:29:15 +01:00
Bjørn Erik Pedersen 55fb0eac20 releaser: Remove suplerflous release notes slug 2018-02-27 10:33:35 +01:00
hugoreleaser 06e5ee6526 releaser: Prepare repository for 0.38-DEV
[ci skip]
2018-02-27 09:17:53 +00:00
1136 changed files with 38744 additions and 15691 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
defaults: &defaults
working_directory: /go/src/github.com/gohugoio
docker:
- image: bepsays/ci-goreleaser:0.34.2-10
- image: bepsays/ci-goreleaser:0.34.2-11
version: 2
jobs:
+8
View File
@@ -0,0 +1,8 @@
*.md
*.log
*.txt
.git
.github
.circleci
docs
examples
+8
View File
@@ -0,0 +1,8 @@
# Text files have auto line endings
* text=auto
# Go source files always have LF line endings
*.go text eol=lf
# SVG files should not be modified
*.svg -text
+3
View File
@@ -0,0 +1,3 @@
### Asking Support Questions
We have an active [discussion forum](https://discourse.gohugo.io) where users and developers can ask questions. Please don't use the GitHub issue tracker to ask questions.
+3 -3
View File
@@ -1,7 +1,7 @@
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 90
daysUntilStale: 120
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 14
daysUntilClose: 30
# Issues with these labels will never be considered stale
exemptLabels:
- Keep
@@ -20,4 +20,4 @@ markComment: >
This issue will automatically be closed in the near future if no further activity occurs. Thank you for all your contributions.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false
closeComment: false
+3
View File
@@ -12,7 +12,10 @@ cover.out
*~
vendor/*/
*.bench
*.debug
coverage*.out
dock.sh
GoBuilds
dist
+13 -8
View File
@@ -1,9 +1,13 @@
language: go
sudo: required
dist: precise
sudo: false
dist: trusty
env:
HUGO_BUILD_TAGS="extended"
git:
depth: false
go:
- 1.9.4
- "1.10"
- 1.9.7
- "1.10.3"
- tip
os:
- linux
@@ -14,12 +18,13 @@ matrix:
fast_finish: true
install:
- go get github.com/magefile/mage
- mage vendor
- mage -v vendor
script:
- mage hugoRace
- mage -v test
- mage -v check
- mage -v hugo
- ./hugo -s docs/
- ./hugo --renderToMemory -s docs/
before_install:
# gem install must be run with sudo on OSX
- sudo gem install asciidoctor | gem install asciidoctor
- gem install asciidoctor
- type asciidoctor
+26 -21
View File
@@ -9,7 +9,7 @@ The Hugo community and maintainers are [very active](https://github.com/gohugoio
*Note that this repository only contains the actual source code of Hugo. For **only** documentation-related pull requests / issues please refer to the [hugoDocs](https://github.com/gohugoio/hugoDocs) repository.*
*Pull requests that contain changes on the code base **and** related documentation, e.g. for a new feature, shall remain a single, atomic one.*
*Changes to the codebase **and** related documentation, e.g. for a new feature, should still use a single pull request.*
## Table of Contents
@@ -32,21 +32,24 @@ 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 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.
the GitHub [issue tracker](https://github.com/gohugoio/hugo/issues) 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.
## Code Contribution
Hugo has become a fully featured static site generator, so any new functionality must meet these criterias:
Hugo has become a fully featured static site generator, so any new functionality must:
* It must be useful to many.
* It must fit natural into _what Hugo does best._
* It must strive not to break existing sites.
* It must close ur 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.).
* be useful to many.
* fit naturally into _what Hugo does best._
* strive not to break existing sites.
* close or update an open [Hugo issue](https://github.com/gohugoio/hugo/issues)
So, to avoid doing unneeded work, it is recommended to open up a discussion on the [Hugo Forum](https://discourse.gohugo.io/) to get some acceptance that this is a good idea. Also, if this is a complex feature, create a small design proposal on the [Hugo issue tracker](https://github.com/gohugoio/hugo/issues) before you start coding.
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.).
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.
**Bug fixes are, of course, always welcome.**
@@ -55,16 +58,12 @@ So, to avoid doing unneeded work, it is recommended to open up a discussion on t
## 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.
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 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.
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.
### Code Contribution Guidelines
Because 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.
To make the contribution process as seamless as possible, we ask for the following:
* Go ahead and fork the project and make your changes. We encourage pull requests to allow for review and discussion of code changes.
@@ -86,11 +85,11 @@ the most important part being that each commit message should have a title/subje
Also, if your commit references one or more GitHub issues, always end your commit message body with *See #1234* or *Fixes #1234*.
Replace *1234* with the GitHub issue ID. The last example will close the issue when the commit is merged into *master*.
Sometimes it makes sense to prefix the commit message with the packagename (or docs folder) all lowercased ending with a colon.
Sometimes it makes sense to prefix the commit message with the package name (or docs folder) all lowercased ending with a colon.
That is fine, but the rest of the rules above apply.
So it is "tpl: Add emojify template func", not "tpl: add emojify template func.", and "docs: Document emoji", not "doc: document emoji."
Please consider to use a short and descriptive branch name, e.g. **NOT** "patch-1". It's very common but creates a naming conflict each time when a submission is pulled for a review.
Please use a short and descriptive branch name, e.g. **NOT** "patch-1". It's very common but creates a naming conflict each time when a submission is pulled for a review.
An example:
@@ -130,7 +129,7 @@ started:
mage vendor
```
Note that Hugo uses [Go Dep](https://github.com/golang/dep) to vendor dependencies, rather than a a simple `go get`. We don't commit the vendored packages themselves to the Hugo git repository. The call to `mage vendor` takes care of all this for you.
Note that Hugo uses [Go Dep](https://github.com/golang/dep) to vendor dependencies, rather than a simple `go get`. We don't commit the vendored packages themselves to the Hugo git repository. The call to `mage vendor` takes care of all this for you.
1. Create a new branch for your changes (the branch name is arbitrary):
@@ -193,6 +192,12 @@ To list all available commands along with descriptions:
mage -l
```
**Note:** From Hugo 0.43 we have added a build tag, `extended` that adds **SCSS support**. This needs a C compiler installed to build. You can enable this when building by:
```bash
HUGO_BUILD_TAGS=extended mage install
````
### Updating the Hugo Sources
If you want to stay in sync with the Hugo repository, you can easily pull down
Regular → Executable
+19 -15
View File
@@ -1,23 +1,27 @@
FROM golang:1.9.0-alpine3.6 AS build
# GitHub: https://github.com/gohugoio
# Twitter: https://twitter.com/gohugoio
# Website: https://gohugo.io/
RUN apk add --no-cache --virtual git musl-dev
RUN go get github.com/golang/dep/cmd/dep
FROM golang:1.10.3-alpine3.7 AS build
ENV CGO_ENABLED=0
ENV GOOS=linux
WORKDIR /go/src/github.com/gohugoio/hugo
ADD . /go/src/github.com/gohugoio/hugo/
RUN dep ensure
RUN go install -ldflags '-s -w'
RUN apk add --no-cache \
git \
musl-dev && \
go get github.com/golang/dep/cmd/dep
COPY . /go/src/github.com/gohugoio/hugo/
RUN dep ensure -vendor-only && \
go install -ldflags '-s -w'
FROM alpine:3.6
RUN \
adduser -h /site -s /sbin/nologin -u 1000 -D hugo && \
apk add --no-cache \
dumb-init
COPY --from=build /go/bin/hugo /bin/hugo
USER hugo
# ---
FROM scratch
COPY --from=build /go/bin/hugo /hugo
WORKDIR /site
VOLUME /site
EXPOSE 1313
ENTRYPOINT ["/usr/bin/dumb-init", "--", "hugo"]
ENTRYPOINT [ "/hugo" ]
CMD [ "--help" ]
Generated
+332 -39
View File
@@ -3,23 +3,46 @@
[[projects]]
branch = "master"
digest = "1:f6a10073544cc0bd1eb9fd9f8d9bf4644971910a0f8393d51b5b4d286e554849"
name = "github.com/BurntSushi/locker"
packages = ["."]
pruneopts = ""
revision = "a6e239ea1c69bff1cfdb20c4b73dadf52f784b6a"
[[projects]]
branch = "master"
digest = "1:fe421c7102aa7290dc831e2772971a2c74155013b68c2769c0da44383f7aa6be"
name = "github.com/BurntSushi/toml"
packages = ["."]
pruneopts = ""
revision = "a368813c5e648fee92e5f6c30e3944ff9d5e8895"
[[projects]]
digest = "1:8e47871087b94913898333f37af26732faaab30cdb41571136cf7aec9921dae7"
name = "github.com/PuerkitoBio/purell"
packages = ["."]
pruneopts = ""
revision = "0bcb03f4b4d0a9428594752bd2a3b9aa0a9d4bd4"
version = "v1.1.0"
[[projects]]
branch = "master"
digest = "1:331a419049c2be691e5ba1d24342fc77c7e767a80c666a18fd8a9f7b82419c1c"
name = "github.com/PuerkitoBio/urlesc"
packages = ["."]
pruneopts = ""
revision = "de5bf2ad457846296e2031421a34e2568e304e35"
[[projects]]
branch = "master"
digest = "1:587118db822769eb67defc43c6d9363f4d6f615106fa6f510c668b78063e21bc"
name = "github.com/alecthomas/assert"
packages = ["."]
pruneopts = ""
revision = "405dbfeb8e38effee6e723317226e93fff912d06"
[[projects]]
digest = "1:421ef03adc58e8acd0e87e521b9e578c62eff3d5efebb73e8f18cbea191f9417"
name = "github.com/alecthomas/chroma"
packages = [
".",
@@ -29,6 +52,7 @@
"lexers/a",
"lexers/b",
"lexers/c",
"lexers/circular",
"lexers/d",
"lexers/e",
"lexers/f",
@@ -51,78 +75,135 @@
"lexers/w",
"lexers/x",
"lexers/y",
"styles"
"styles",
]
revision = "563aadc53c53292c4c1def1b0a547be498bba83e"
version = "v0.3.0"
pruneopts = ""
revision = "e4dff9a08cad984e9cf8eaa39fb80f2beae10484"
[[projects]]
branch = "master"
name = "github.com/bep/gitmap"
digest = "1:ba0a389824c3c3d378f5f334370524b7d04b5a5ccedce7dd2da05ae8d3868609"
name = "github.com/alecthomas/colour"
packages = ["."]
revision = "de8030ebafb76c6e84d50ee6d143382637c00598"
pruneopts = ""
revision = "60882d9e27213e8552dcff6328914fe4c2b44bc9"
[[projects]]
branch = "master"
digest = "1:5723237c9114bb92b4571532d9580dd0ed885ec3eb371d58085c074895c04a51"
name = "github.com/alecthomas/repr"
packages = ["."]
pruneopts = ""
revision = "f49988b46e025398b9f834f7c726afe001ec481f"
[[projects]]
digest = "1:05d0e4ae6b8d0273647964fe26762e3345d5d196aaeb858838e75336703451ba"
name = "github.com/bep/debounce"
packages = ["."]
pruneopts = ""
revision = "844797fa1dd9ba969d71b62797ff19d1e49d4eac"
version = "v1.1.0"
[[projects]]
branch = "master"
digest = "1:a296a56f979667c1a5404323f71eaf7499d9438987ec15f07fd970e56ec9619d"
name = "github.com/bep/gitmap"
packages = ["."]
pruneopts = ""
revision = "012701e8669671499fc43e9792335a1dcbfe2afb"
[[projects]]
branch = "master"
digest = "1:50f18fd801868be859fa7fdddfc3a56ec41b562176f84db31b2b78cedb530326"
name = "github.com/bep/go-tocss"
packages = [
"scss",
"scss/libsass",
"tocss",
]
pruneopts = ""
revision = "2abb118dc8688b6c7df44e12f4152c2bded9b19c"
[[projects]]
digest = "1:d814bbb551582d8f27085f6a9d941024ef20c3bee0132da6f9841c062cf338de"
name = "github.com/chaseadamsio/goorgeous"
packages = ["."]
pruneopts = ""
revision = "dcf1ef873b8987bf12596fe6951c48347986eb2f"
version = "v1.1.0"
[[projects]]
digest = "1:5b5e11b56adf922e0efc8856f86420a3467607975ff8ecb54bb0bac318c1548f"
name = "github.com/cpuguy83/go-md2man"
packages = ["md2man"]
pruneopts = ""
revision = "a65d4d2de4d5f7c74868dfa9b202a3c8be315aaa"
version = "v1.0.6"
[[projects]]
branch = "master"
digest = "1:8f6c36ee73ded871996ada894e20dfecde56557d08b4d1849d5489076679971f"
name = "github.com/danwakefield/fnmatch"
packages = ["."]
pruneopts = ""
revision = "cbb64ac3d964b81592e64f957ad53df015803288"
[[projects]]
digest = "1:56c130d885a4aacae1dd9c7b71cfe39912c7ebc1ff7d2b46083c8812996dc43b"
name = "github.com/davecgh/go-spew"
packages = ["spew"]
pruneopts = ""
revision = "346938d642f2ec3594ed81d874461961cd0faa76"
version = "v1.1.0"
[[projects]]
digest = "1:b218908776d4939d4ecfd8ae87918d17b01b491e219d09bedf24b4aeb0f0b7e9"
name = "github.com/disintegration/imaging"
packages = ["."]
pruneopts = ""
revision = "dd50a3ee9985ccd313a2f03c398fcaedc96dc707"
version = "v1.2.4"
[[projects]]
digest = "1:556b75e96f02319585d253d262c4ce5dfdf4b28be474f1e0877c5f4f9b10cf9e"
name = "github.com/dlclark/regexp2"
packages = [
".",
"syntax"
"syntax",
]
pruneopts = ""
revision = "487489b64fb796de2e55f4e8a4ad1e145f80e957"
version = "v1.1.6"
[[projects]]
branch = "master"
digest = "1:f0cd82a11574a06f08e22bf3c2ba0c259f4c84f73d95d011d7024b78febe17e9"
name = "github.com/eknkc/amber"
packages = [
".",
"parser"
"parser",
]
pruneopts = ""
revision = "cdade1c073850f4ffc70a829e31235ea6892853b"
[[projects]]
digest = "1:e5c807ac3b60699ccec9263f6eec756251b17e78582eb149f90ac345d9e58327"
name = "github.com/fortytw2/leaktest"
packages = ["."]
revision = "7dad53304f9614c1c365755c1176a8e876fee3e8"
version = "v1.1.0"
pruneopts = ""
revision = "a5ef70473c97b71626b9abeda80ee92ba2a7de9e"
version = "v1.2.0"
[[projects]]
digest = "1:eb53021a8aa3f599d29c7102e65026242bdedce998a54837dc67f14b6a97c5fd"
name = "github.com/fsnotify/fsnotify"
packages = ["."]
pruneopts = ""
revision = "c2828203cd70a50dcccfb2761f8b1f8ceef9a8e9"
version = "v1.4.7"
[[projects]]
digest = "1:9ab1b1c637d7c8f49e39d8538a650d7eb2137b076790cff69d160823b505964c"
name = "github.com/gobwas/glob"
packages = [
".",
@@ -132,224 +213,361 @@
"syntax/ast",
"syntax/lexer",
"util/runes",
"util/strings"
"util/strings",
]
pruneopts = ""
revision = "5ccd90ef52e1e632236f7326478d4faa74f99438"
version = "v0.2.3"
[[projects]]
digest = "1:64d212c703a2b94054be0ce470303286b177ad260b2f89a307e3d1bb6c073ef6"
name = "github.com/gorilla/websocket"
packages = ["."]
pruneopts = ""
revision = "ea4d1f681babbce9545c9c5f3d5194a789c89f5b"
version = "v1.2.0"
[[projects]]
branch = "master"
digest = "1:4423ee95d6ee30bb22f680445c58889bb5b91e1b955405bf34374a053784a8a2"
name = "github.com/hashicorp/go-immutable-radix"
packages = ["."]
pruneopts = ""
revision = "7f3cd4390caab3250a57f30efdb2a65dd7649ecf"
[[projects]]
branch = "master"
digest = "1:9c776d7d9c54b7ed89f119e449983c3f24c0023e75001d6092442412ebca6b94"
name = "github.com/hashicorp/golang-lru"
packages = ["simplelru"]
pruneopts = ""
revision = "0fb14efe8c47ae851c0034ed7a448854d3d34cf3"
[[projects]]
branch = "master"
digest = "1:9b7c5846d70f425d7fe279595e32a20994c6075e87be03b5c367ed07280877c5"
name = "github.com/hashicorp/hcl"
packages = [
".",
"hcl/ast",
"hcl/parser",
"hcl/printer",
"hcl/scanner",
"hcl/strconv",
"hcl/token",
"json/parser",
"json/scanner",
"json/token"
"json/token",
]
revision = "23c074d0eceb2b8a5bfdbb271ab780cde70f05a8"
pruneopts = ""
revision = "ef8a98b0bbce4a65b5aa4c368430a80ddc533168"
[[projects]]
digest = "1:870d441fe217b8e689d7949fef6e43efbc787e50f200cb1e70dbca9204a1d6be"
name = "github.com/inconshreveable/mousetrap"
packages = ["."]
pruneopts = ""
revision = "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75"
version = "v1.0"
[[projects]]
digest = "1:dddb389214f3ebf7c1f885d0e1f9498a17608f4a9b623c827cafb3c5f91f9ac4"
name = "github.com/jdkato/prose"
packages = [
"internal/util",
"transform"
"transform",
]
pruneopts = ""
revision = "20d3663d4bc9dd10d75abcde9d92e04b4861c674"
version = "v1.1.0"
[[projects]]
digest = "1:7089a8fdbe330c9ea88af46acacec584f11d8aa4736080ff4bd96bb0b407dcd1"
name = "github.com/kyokomi/emoji"
packages = ["."]
pruneopts = ""
revision = "7e06b236c489543f53868841f188a294e3383eab"
version = "v1.5"
[[projects]]
digest = "1:901c7dc16a166e57e940dee1350511ba5cb5e61eeca858edb76d21b65f9b7cff"
name = "github.com/magefile/mage"
packages = [
"mg",
"sh"
"sh",
]
pruneopts = ""
revision = "2f974307b636f59c13b88704cf350a4772fef271"
version = "v1.0.2"
[[projects]]
digest = "1:d244eb7b2d8e9f4c9355d215d65159c176603874ba10bfb7cbe6dcbd212813f5"
name = "github.com/magiconair/properties"
packages = ["."]
pruneopts = ""
revision = "c3beff4c2358b44d0493c7dda585e7db7ff28ae6"
version = "v1.7.6"
[[projects]]
digest = "1:fd46423a2fe75d52968baf37471b99e6f05cea3ac29c756128ead26af34e1c35"
name = "github.com/markbates/inflect"
packages = ["."]
pruneopts = ""
revision = "a12c3aec81a6a938bf584a4bac567afed9256586"
[[projects]]
digest = "1:78229b46ddb7434f881390029bd1af7661294af31f6802e0e1bedaad4ab0af3c"
name = "github.com/mattn/go-isatty"
packages = ["."]
pruneopts = ""
revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39"
version = "v0.0.3"
[[projects]]
digest = "1:81e673df85e765593a863f67cba4544cf40e8919590f04d67664940786c2b61a"
name = "github.com/mattn/go-runewidth"
packages = ["."]
pruneopts = ""
revision = "9e777a8366cce605130a531d2cd6363d07ad7317"
version = "v0.0.2"
[[projects]]
digest = "1:bb98cbb82602cde3cafa5e2ee9b8fb1de3d57d490c09f0988d7edf2b30afec2d"
name = "github.com/miekg/mmark"
packages = ["."]
pruneopts = ""
revision = "fd2f6c1403b37925bd7fe13af05853b8ae58ee5f"
version = "v1.3.6"
[[projects]]
branch = "master"
name = "github.com/mitchellh/mapstructure"
digest = "1:0de0f377aeccd41384e883c59c6f184c9db01c96db33a2724a1eaadd60f92629"
name = "github.com/mitchellh/hashstructure"
packages = ["."]
revision = "a4e142e9c047c904fa2f1e144d9a84e6133024bc"
pruneopts = ""
revision = "2bca23e0e452137f789efbc8610126fd8b94f73b"
[[projects]]
branch = "master"
digest = "1:59fa50d593e5673a0dfffa1852b66fd700c05b35e368680b4b89a68fdb2c1379"
name = "github.com/mitchellh/mapstructure"
packages = ["."]
pruneopts = ""
revision = "00c29f56e2386353d58c599509e8dc3801b0d716"
[[projects]]
branch = "master"
digest = "1:a21a59f6adec3256fd6f5bd0377cb95ff8128d3ab716fae9944e71b017c68b49"
name = "github.com/muesli/smartcrop"
packages = [
".",
"options"
"options",
]
revision = "1db484956b9ef929344e51701299a017beefdaaa"
pruneopts = ""
revision = "f6ebaa786a12a0fdb2d7c6dee72808e68c296464"
[[projects]]
digest = "1:9fa4a4a684dfb36f3ba1b0a163225140e19e3219e5576d0761d02dbd4c31b743"
name = "github.com/nicksnyder/go-i18n"
packages = [
"i18n/bundle",
"i18n/language",
"i18n/translation"
"i18n/translation",
]
pruneopts = ""
revision = "0dc1626d56435e9d605a29875701721c54bc9bbd"
version = "v1.10.0"
[[projects]]
branch = "master"
digest = "1:6ad32168a9cdb3585e45f44b2f914b4cefb0da0c23bac8482ed56d0942090be9"
name = "github.com/olekukonko/tablewriter"
packages = ["."]
pruneopts = ""
revision = "b8a9be070da40449e501c3c4730a889e42d87a9e"
[[projects]]
digest = "1:d60cfeee185019d4fcd35e8c89c83aff576e4723b6100300bf67b05be961388f"
name = "github.com/pelletier/go-toml"
packages = ["."]
pruneopts = ""
revision = "acdc4509485b587f5e675510c4f2c63e90ff68a8"
version = "v1.1.0"
[[projects]]
digest = "1:256484dbbcd271f9ecebc6795b2df8cad4c458dd0f5fd82a8c2fa0c29f233411"
name = "github.com/pmezard/go-difflib"
packages = ["difflib"]
pruneopts = ""
revision = "792786c7400a136282c1664665ae0a8db921c6c2"
version = "v1.0.0"
[[projects]]
branch = "master"
digest = "1:10bc894f31df5ca3366a50122ee2ade6b56f3f5531c523a8a551748a0663aa1b"
name = "github.com/russross/blackfriday"
packages = ["."]
revision = "55d61fa8aa702f59229e6cff85793c22e580eaf5"
pruneopts = ""
revision = "11635eb403ff09dbc3a6b5a007ab5ab09151c229"
[[projects]]
digest = "1:354988e51f0b9061a2d6b94e84ede12be35bc09ee3be23f61c9d18246b0c2c24"
name = "github.com/sanity-io/litter"
packages = ["."]
pruneopts = ""
revision = "ae543b7ba8fd6af63e4976198f146e1348ae53c1"
version = "v1.1.0"
[[projects]]
digest = "1:3962f553b77bf6c03fc07cd687a22dd3b00fe11aa14d31194f5505f5bb65cdc8"
name = "github.com/sergi/go-diff"
packages = ["diffmatchpatch"]
pruneopts = ""
revision = "1744e2970ca51c86172c8190fadad617561ed6e7"
version = "v1.0.0"
[[projects]]
branch = "master"
digest = "1:606fa779c7a80ab6a9ec5836cd12759f86cd6e1d82d5d60cf7ec5133e78c6cf8"
name = "github.com/shurcooL/sanitized_anchor_name"
packages = ["."]
pruneopts = ""
revision = "86672fcb3f950f35f2e675df2240550f2a50762f"
[[projects]]
digest = "1:7ba2551c9a8de293bc575dbe2c0d862c52252d26f267f784547f059f512471c8"
name = "github.com/spf13/afero"
packages = [
".",
"mem"
"mem",
]
revision = "bb8f1927f2a9d3ab41c9340aa034f6b803f4359c"
version = "v1.0.2"
pruneopts = ""
revision = "787d034dfe70e44075ccc060d346146ef53270ad"
version = "v1.1.1"
[[projects]]
digest = "1:d0b38ba6da419a6d4380700218eeec8623841d44a856bb57369c172fbf692ab4"
name = "github.com/spf13/cast"
packages = ["."]
pruneopts = ""
revision = "8965335b8c7107321228e3e3702cab9832751bac"
version = "v1.2.0"
[[projects]]
branch = "master"
digest = "1:74c32990510c9f188556aa17600313e867d1d06f5a9db244056a95d144ec34ce"
name = "github.com/spf13/cobra"
packages = [
".",
"doc"
"doc",
]
revision = "be77323fc05148ef091e83b3866c0d47c8e74a8b"
pruneopts = ""
revision = "a1f051bc3eba734da4772d60e2d677f47cf93ef4"
version = "v0.0.2"
[[projects]]
branch = "master"
digest = "1:7c00f445c89f468abd5ab86546ba1fa11bac66e63325ade8ca05aa7220791fc7"
name = "github.com/spf13/fsync"
packages = ["."]
pruneopts = ""
revision = "12a01e648f05a938100a26858d2d59a120307a18"
[[projects]]
branch = "master"
digest = "1:104517520aab91164020ab6524a5d6b7cafc641b2e42ac6236f6ac1deac4f66a"
name = "github.com/spf13/jwalterweatherman"
packages = ["."]
pruneopts = ""
revision = "7c0cea34c8ece3fbeb2b27ab9b59511d360fb394"
[[projects]]
branch = "master"
digest = "1:5082c0d57a199dabc0868010784039249af0932fad2990b51ad9404c9a6b6e5d"
name = "github.com/spf13/nitro"
packages = ["."]
pruneopts = ""
revision = "24d7ef30a12da0bdc5e2eb370a79c659ddccf0e8"
[[projects]]
digest = "1:261bc565833ef4f02121450d74eb88d5ae4bd74bfe5d0e862cddb8550ec35000"
name = "github.com/spf13/pflag"
packages = ["."]
pruneopts = ""
revision = "e57e3eeb33f795204c1ca35f56c44f83227c6e66"
version = "v1.0.0"
[[projects]]
digest = "1:3dab237cd3263a290d771d133fed777bb56c22e380b00ebe92e6531d5c8d3d0c"
name = "github.com/spf13/viper"
packages = ["."]
revision = "25b30aa063fc18e48662b86996252eabdcf2f0c7"
version = "v1.0.0"
pruneopts = ""
revision = "b5e8006cbee93ec955a89ab31e0e3ce3204f3736"
version = "v1.0.2"
[[projects]]
digest = "1:a30066593578732a356dc7e5d7f78d69184ca65aeeff5939241a3ab10559bb06"
name = "github.com/stretchr/testify"
packages = [
"assert",
"require"
"require",
]
pruneopts = ""
revision = "12b6f73e6084dad08a7c6e575284b177ecafbc71"
version = "v1.2.1"
[[projects]]
digest = "1:0308279931f894a1ba11e7d354d346c96ead9c7539a4fff1fce030845ec6c780"
name = "github.com/tdewolff/minify"
packages = [
".",
"css",
"html",
"js",
"json",
"svg",
"xml",
]
pruneopts = ""
revision = "8d72a4127ae33b755e95bffede9b92e396267ce2"
version = "v2.3.5"
[[projects]]
digest = "1:6e64aa755995f3185ee55306ada462999775b8faae39aec142b3fd54248dd5ee"
name = "github.com/tdewolff/parse"
packages = [
".",
"buffer",
"css",
"html",
"js",
"json",
"strconv",
"svg",
"xml",
]
pruneopts = ""
revision = "d739d6fccb0971177e06352fea02d3552625efb1"
version = "v2.3.3"
[[projects]]
branch = "master"
digest = "1:be92e3574c94090ee4659d49a4ab156301fd62c2bdad831ca52ad7ce3ee91e2e"
name = "github.com/wellington/go-libsass"
packages = ["libs"]
pruneopts = ""
revision = "615eaa47ef794d037c1906a0eb7bf85375a5decf"
[[projects]]
digest = "1:bf83d7fb8e87f39806ce3550657a8a31bbeb96a35eb105bd98e7362559fba27f"
name = "github.com/yosssi/ace"
packages = ["."]
pruneopts = ""
revision = "ea038f4770b6746c3f8f84f14fa60d9fe1205b56"
version = "v0.0.5"
[[projects]]
branch = "master"
digest = "1:baf32d4b565da5d3c4e44fb360f8e894a22ea2b9acfb08d029de9e09e71abe90"
name = "golang.org/x/image"
packages = [
"bmp",
@@ -360,39 +578,49 @@
"tiff/lzw",
"vp8",
"vp8l",
"webp"
"webp",
]
revision = "12117c17ca67ffa1ce22e9409f3b0b0a93ac08c7"
pruneopts = ""
revision = "f315e440302883054d0c2bd85486878cb4f8572c"
[[projects]]
branch = "master"
digest = "1:40dd5a4f1e82c4d3dc3de550a96152f6a8937bcfcb20c7ee34685f8764e1bda5"
name = "golang.org/x/net"
packages = [
"context",
"idna"
"idna",
]
revision = "136a25c244d3019482a795d728110278d6ba09a4"
pruneopts = ""
revision = "61147c48b25b599e5b561d2e9c4f3e1ef489ca41"
[[projects]]
branch = "master"
digest = "1:b2ea75de0ccb2db2ac79356407f8a4cd8f798fe15d41b381c00abf3ae8e55ed1"
name = "golang.org/x/sync"
packages = ["errgroup"]
revision = "fd80eb99c8f653c847d294a001bdf2a3a6f768f5"
pruneopts = ""
revision = "1d60e4601c6fd243af51cc01ddf169918a5407ca"
[[projects]]
branch = "master"
digest = "1:e9490adb0a1d5ac8f621a6430754822f87e565fd71d4cd1c9c4d90626f390624"
name = "golang.org/x/sys"
packages = ["unix"]
revision = "37707fdb30a5b38865cfb95e5aab41707daec7fd"
pruneopts = ""
revision = "3b87a42e500a6dc65dae1a55d0b641295971163e"
[[projects]]
branch = "master"
digest = "1:4ef18a942de1e9887751539663458408cd4b737703c145edb75bf0e07c928053"
name = "golang.org/x/text"
packages = [
"collate",
"collate/build",
"internal/colltab",
"internal/gen",
"internal/language",
"internal/language/compact",
"internal/tag",
"internal/triegen",
"internal/ucd",
@@ -403,19 +631,84 @@
"unicode/cldr",
"unicode/norm",
"unicode/rangetable",
"width"
"width",
]
revision = "4e4a3210bb54bb31f6ab2cdca2edcc0b50c420c1"
pruneopts = ""
revision = "2cb43934f0eece38629746959acc633cba083fe4"
[[projects]]
branch = "v2"
digest = "1:f0620375dd1f6251d9973b5f2596228cc8042e887cd7f827e4220bc1ce8c30e2"
name = "gopkg.in/yaml.v2"
packages = ["."]
revision = "d670f9405373e636a5a2765eea47fac0c9bc91a4"
pruneopts = ""
revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "960c7cc0b7d1739f5c1f116cc7fa31056b76cf16e63d865f31be875b8e674da7"
input-imports = [
"github.com/BurntSushi/locker",
"github.com/BurntSushi/toml",
"github.com/PuerkitoBio/purell",
"github.com/alecthomas/assert",
"github.com/alecthomas/chroma",
"github.com/alecthomas/chroma/formatters",
"github.com/alecthomas/chroma/formatters/html",
"github.com/alecthomas/chroma/lexers",
"github.com/alecthomas/chroma/styles",
"github.com/bep/debounce",
"github.com/bep/gitmap",
"github.com/bep/go-tocss/scss",
"github.com/bep/go-tocss/scss/libsass",
"github.com/bep/go-tocss/tocss",
"github.com/chaseadamsio/goorgeous",
"github.com/disintegration/imaging",
"github.com/eknkc/amber",
"github.com/fortytw2/leaktest",
"github.com/fsnotify/fsnotify",
"github.com/gobwas/glob",
"github.com/gorilla/websocket",
"github.com/hashicorp/go-immutable-radix",
"github.com/jdkato/prose/transform",
"github.com/kyokomi/emoji",
"github.com/magefile/mage/mg",
"github.com/magefile/mage/sh",
"github.com/markbates/inflect",
"github.com/miekg/mmark",
"github.com/mitchellh/hashstructure",
"github.com/mitchellh/mapstructure",
"github.com/muesli/smartcrop",
"github.com/nicksnyder/go-i18n/i18n/bundle",
"github.com/nicksnyder/go-i18n/i18n/language",
"github.com/olekukonko/tablewriter",
"github.com/russross/blackfriday",
"github.com/sanity-io/litter",
"github.com/spf13/afero",
"github.com/spf13/cast",
"github.com/spf13/cobra",
"github.com/spf13/cobra/doc",
"github.com/spf13/fsync",
"github.com/spf13/jwalterweatherman",
"github.com/spf13/nitro",
"github.com/spf13/pflag",
"github.com/spf13/viper",
"github.com/stretchr/testify/assert",
"github.com/stretchr/testify/require",
"github.com/tdewolff/minify",
"github.com/tdewolff/minify/css",
"github.com/tdewolff/minify/html",
"github.com/tdewolff/minify/js",
"github.com/tdewolff/minify/json",
"github.com/tdewolff/minify/svg",
"github.com/tdewolff/minify/xml",
"github.com/yosssi/ace",
"golang.org/x/image/webp",
"golang.org/x/net/context",
"golang.org/x/sync/errgroup",
"golang.org/x/text/transform",
"golang.org/x/text/unicode/norm",
"gopkg.in/yaml.v2",
]
solver-name = "gps-cdcl"
solver-version = 1
+31 -3
View File
@@ -10,12 +10,20 @@
[[constraint]]
name = "github.com/alecthomas/chroma"
version = "0.3.0"
revision = "e4dff9a08cad984e9cf8eaa39fb80f2beae10484"
[[constraint]]
branch = "master"
name = "github.com/bep/gitmap"
[[constraint]]
branch = "master"
name = "github.com/bep/go-tocss"
[[override]]
branch = "master"
name = "github.com/wellington/go-libsass"
[[constraint]]
name = "github.com/chaseadamsio/goorgeous"
version = "^1.1.0"
@@ -78,14 +86,14 @@
[[constraint]]
name = "github.com/spf13/afero"
version = "^1.0.1"
version = "^1.1.0"
[[constraint]]
name = "github.com/spf13/cast"
version = "^1.1.0"
[[constraint]]
branch = "master"
version = "^0.0.1"
name = "github.com/spf13/cobra"
[[constraint]]
@@ -141,3 +149,23 @@
name = "github.com/muesli/smartcrop"
branch = "master"
[[constraint]]
name = "github.com/sanity-io/litter"
version = "1.1.0"
[[constraint]]
name = "github.com/bep/debounce"
version = "^1.1.0"
[[constraint]]
name = "github.com/tdewolff/minify"
version = "^2.3.5"
[[constraint]]
branch = "master"
name = "github.com/BurntSushi/locker"
[[constraint]]
branch = "master"
name = "github.com/mitchellh/hashstructure"
+201
View File
@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.
-194
View File
@@ -1,194 +0,0 @@
Apache License
==============
_Version 2.0, January 2004_
_&lt;<http://www.apache.org/licenses/>&gt;_
### Terms and Conditions for use, reproduction, and distribution
#### 1. Definitions
“License” shall mean the terms and conditions for use, reproduction, and
distribution as defined by Sections 1 through 9 of this document.
“Licensor” shall mean the copyright owner or entity authorized by the copyright
owner that is granting the License.
“Legal Entity” shall mean the union of the acting entity and all other entities
that control, are controlled by, or are under common control with that entity.
For the purposes of this definition, “control” means **(i)** the power, direct or
indirect, to cause the direction or management of such entity, whether by
contract or otherwise, or **(ii)** ownership of fifty percent (50%) or more of the
outstanding shares, or **(iii)** beneficial ownership of such entity.
“You” (or “Your”) shall mean an individual or Legal Entity exercising
permissions granted by this License.
“Source” form shall mean the preferred form for making modifications, including
but not limited to software source code, documentation source, and configuration
files.
“Object” form shall mean any form resulting from mechanical transformation or
translation of a Source form, including but not limited to compiled object code,
generated documentation, and conversions to other media types.
“Work” shall mean the work of authorship, whether in Source or Object form, made
available under the License, as indicated by a copyright notice that is included
in or attached to the work (an example is provided in the Appendix below).
“Derivative Works” shall mean any work, whether in Source or Object form, that
is based on (or derived from) the Work and for which the editorial revisions,
annotations, elaborations, or other modifications represent, as a whole, an
original work of authorship. For the purposes of this License, Derivative Works
shall not include works that remain separable from, or merely link (or bind by
name) to the interfaces of, the Work and Derivative Works thereof.
“Contribution” shall mean any work of authorship, including the original version
of the Work and any modifications or additions to that Work or Derivative Works
thereof, that is intentionally submitted to Licensor for inclusion in the Work
by the copyright owner or by an individual or Legal Entity authorized to submit
on behalf of the copyright owner. For the purposes of this definition,
“submitted” means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems, and
issue tracking systems that are managed by, or on behalf of, the Licensor for
the purpose of discussing and improving the Work, but excluding communication
that is conspicuously marked or otherwise designated in writing by the copyright
owner as “Not a Contribution.”
“Contributor” shall mean Licensor and any individual or Legal Entity on behalf
of whom a Contribution has been received by Licensor and subsequently
incorporated within the Work.
#### 2. Grant of Copyright License
Subject to the terms and conditions of this License, each Contributor hereby
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
irrevocable copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the Work and such
Derivative Works in Source or Object form.
#### 3. Grant of Patent License
Subject to the terms and conditions of this License, each Contributor hereby
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
irrevocable (except as stated in this section) patent license to make, have
made, use, offer to sell, sell, import, and otherwise transfer the Work, where
such license applies only to those patent claims licensable by such Contributor
that are necessarily infringed by their Contribution(s) alone or by combination
of their Contribution(s) with the Work to which such Contribution(s) was
submitted. If You institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work or a
Contribution incorporated within the Work constitutes direct or contributory
patent infringement, then any patent licenses granted to You under this License
for that Work shall terminate as of the date such litigation is filed.
#### 4. Redistribution
You may reproduce and distribute copies of the Work or Derivative Works thereof
in any medium, with or without modifications, and in Source or Object form,
provided that You meet the following conditions:
* **(a)** You must give any other recipients of the Work or Derivative Works a copy of
this License; and
* **(b)** You must cause any modified files to carry prominent notices stating that You
changed the files; and
* **(c)** You must retain, in the Source form of any Derivative Works that You distribute,
all copyright, patent, trademark, and attribution notices from the Source form
of the Work, excluding those notices that do not pertain to any part of the
Derivative Works; and
* **(d)** If the Work includes a “NOTICE” text file as part of its distribution, then any
Derivative Works that You distribute must include a readable copy of the
attribution notices contained within such NOTICE file, excluding those notices
that do not pertain to any part of the Derivative Works, in at least one of the
following places: within a NOTICE text file distributed as part of the
Derivative Works; within the Source form or documentation, if provided along
with the Derivative Works; or, within a display generated by the Derivative
Works, if and wherever such third-party notices normally appear. The contents of
the NOTICE file are for informational purposes only and do not modify the
License. You may add Your own attribution notices within Derivative Works that
You distribute, alongside or as an addendum to the NOTICE text from the Work,
provided that such additional attribution notices cannot be construed as
modifying the License.
You may add Your own copyright statement to Your modifications and may provide
additional or different license terms and conditions for use, reproduction, or
distribution of Your modifications, or for any such Derivative Works as a whole,
provided Your use, reproduction, and distribution of the Work otherwise complies
with the conditions stated in this License.
#### 5. Submission of Contributions
Unless You explicitly state otherwise, any Contribution intentionally submitted
for inclusion in the Work by You to the Licensor shall be under the terms and
conditions of this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify the terms of
any separate license agreement you may have executed with Licensor regarding
such Contributions.
#### 6. Trademarks
This License does not grant permission to use the trade names, trademarks,
service marks, or product names of the Licensor, except as required for
reasonable and customary use in describing the origin of the Work and
reproducing the content of the NOTICE file.
#### 7. Disclaimer of Warranty
Unless required by applicable law or agreed to in writing, Licensor provides the
Work (and each Contributor provides its Contributions) on an “AS IS” BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
including, without limitation, any warranties or conditions of TITLE,
NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
solely responsible for determining the appropriateness of using or
redistributing the Work and assume any risks associated with Your exercise of
permissions under this License.
#### 8. Limitation of Liability
In no event and under no legal theory, whether in tort (including negligence),
contract, or otherwise, unless required by applicable law (such as deliberate
and grossly negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special, incidental,
or consequential damages of any character arising as a result of this License or
out of the use or inability to use the Work (including but not limited to
damages for loss of goodwill, work stoppage, computer failure or malfunction, or
any and all other commercial damages or losses), even if such Contributor has
been advised of the possibility of such damages.
#### 9. Accepting Warranty or Additional Liability
While redistributing the Work or Derivative Works thereof, You may choose to
offer, and charge a fee for, acceptance of support, warranty, indemnity, or
other liability obligations and/or rights consistent with this License. However,
in accepting such obligations, You may act only on Your own behalf and on Your
sole responsibility, not on behalf of any other Contributor, and only if You
agree to indemnify, defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason of your
accepting any such warranty or additional liability.
_END OF TERMS AND CONDITIONS_
### APPENDIX: How to apply the Apache License to your work
To apply the Apache License to your work, attach the following boilerplate
notice, with the fields enclosed by brackets `[]` replaced with your own
identifying information. (Don't include the brackets!) The text should be
enclosed in the appropriate comment syntax for the file format. We also
recommend that a file or class name and description of purpose be included on
the same “printed page” as the copyright notice for easier identification within
third-party archives.
Copyright [yyyy] [name of copyright owner]
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.
+18 -5
View File
@@ -54,15 +54,28 @@ Use the [installation instructions in the Hugo documentation](https://gohugo.io/
### Build and Install the Binaries from Source (Advanced Install)
Add Hugo and its package dependencies to your go `src` directory.
#### Prerequisite Tools
go get -v github.com/gohugoio/hugo
* [Git](http://git-scm.com/)
* [Go (latest or previous version)](https://golang.org/dl/)
Once the `get` completes, you should find your new `hugo` (or `hugo.exe`) executable sitting inside `$GOPATH/bin/`.
#### Vendored Dependencies
To update Hugos dependencies, use `go get` with the `-u` option.
Hugo uses [dep](https://github.com/golang/dep) to vendor dependencies, but we don't commit the vendored packages themselves to the Hugo git repository. Therefore, a simple `go get` is _not_ supported because the command is not vendor aware.
go get -u -v github.com/gohugoio/hugo
The simplest way is to use [mage](https://github.com/magefile/mage) (a Make alternative for Go projects.)
#### Fetch from GitHub
```bash
go get github.com/magefile/mage
go get -d github.com/gohugoio/hugo
cd ${GOPATH:-$HOME/go}/src/github.com/gohugoio/hugo
mage vendor
mage install
```
**If you are a Windows user, substitute the `$HOME` environment variable above with `%USERPROFILE%`.**
## The Hugo Documentation
+8 -2
View File
@@ -1,13 +1,19 @@
image: Visual Studio 2015
init:
- set PATH=%PATH%;C:\MinGW\bin;%GOPATH%\bin
- set PATH=%PATH%;C:\mingw-w64\x86_64-7.3.0-posix-seh-rt_v5-rev0\mingw64\bin;%GOPATH%\bin
- go version
- go env
environment:
GOPATH: C:\GOPATH\
HUGO_BUILD_TAGS: extended
# clones and cd's to path
clone_folder: C:\GOPATH\src\github.com\gohugoio\hugo
install:
- gem install asciidoctor
# - gem install asciidoctor
- pip install docutils
- go get github.com/magefile/mage
Executable
+2
View File
@@ -0,0 +1,2 @@
# Temp script used to test new builds.
docker run --rm --mount type=bind,source="$(pwd)",target=/go/src/github.com/gohugoio/hugo -w /go/src/github.com/gohugoio/hugo -i -t bepsays/ci-goreleaser:latest /bin/bash
+30 -11
View File
@@ -24,34 +24,52 @@ type Partition struct {
Load func() (map[string]interface{}, error)
}
type lazyPartition struct {
// Lazy represents a lazily loaded cache.
type Lazy struct {
initSync sync.Once
initErr error
cache map[string]interface{}
load func() (map[string]interface{}, error)
}
func (l *lazyPartition) init() error {
var err error
// NewLazy creates a lazy cache with the given load func.
func NewLazy(load func() (map[string]interface{}, error)) *Lazy {
return &Lazy{load: load}
}
func (l *Lazy) init() error {
l.initSync.Do(func() {
var c map[string]interface{}
c, err = l.load()
c, err := l.load()
l.cache = c
l.initErr = err
})
return err
return l.initErr
}
// Get initializes the cache if not already initialized, then looks up the
// given key.
func (l *Lazy) Get(key string) (interface{}, bool, error) {
l.init()
if l.initErr != nil {
return nil, false, l.initErr
}
v, found := l.cache[key]
return v, found, nil
}
// PartitionedLazyCache is a lazily loaded cache paritioned by a supplied string key.
type PartitionedLazyCache struct {
partitions map[string]*lazyPartition
partitions map[string]*Lazy
}
// NewPartitionedLazyCache creates a new NewPartitionedLazyCache with the supplied
// partitions.
func NewPartitionedLazyCache(partitions ...Partition) *PartitionedLazyCache {
lazyPartitions := make(map[string]*lazyPartition, len(partitions))
lazyPartitions := make(map[string]*Lazy, len(partitions))
for _, partition := range partitions {
lazyPartitions[partition.Key] = &lazyPartition{load: partition.Load}
lazyPartitions[partition.Key] = NewLazy(partition.Load)
}
cache := &PartitionedLazyCache{partitions: lazyPartitions}
@@ -67,11 +85,12 @@ func (c *PartitionedLazyCache) Get(partition, key string) (interface{}, error) {
return nil, nil
}
if err := p.init(); err != nil {
v, found, err := p.Get(key)
if err != nil {
return nil, err
}
if v, found := p.cache[key]; found {
if found {
return v, nil
}
+33 -29
View File
@@ -23,51 +23,55 @@ import (
jww "github.com/spf13/jwalterweatherman"
)
var (
type benchmarkCmd struct {
benchmarkTimes int
cpuProfileFile string
memProfileFile string
)
var benchmarkCmd = &cobra.Command{
Use: "benchmark",
Short: "Benchmark Hugo by building a site a number of times.",
Long: `Hugo can build a site many times over and analyze the running process
*baseBuilderCmd
}
func (b *commandsBuilder) newBenchmarkCmd() *benchmarkCmd {
cmd := &cobra.Command{
Use: "benchmark",
Short: "Benchmark Hugo by building a site a number of times.",
Long: `Hugo can build a site many times over and analyze the running process
creating a benchmark.`,
}
c := &benchmarkCmd{baseBuilderCmd: b.newBuilderCmd(cmd)}
cmd.Flags().StringVar(&c.cpuProfileFile, "cpuprofile", "", "path/filename for the CPU profile file")
cmd.Flags().StringVar(&c.memProfileFile, "memprofile", "", "path/filename for the memory profile file")
cmd.Flags().IntVarP(&c.benchmarkTimes, "count", "n", 13, "number of times to build the site")
cmd.Flags().Bool("renderToMemory", false, "render to memory (only useful for benchmark testing)")
cmd.RunE = c.benchmark
return c
}
func init() {
initHugoBuilderFlags(benchmarkCmd)
initBenchmarkBuildingFlags(benchmarkCmd)
benchmarkCmd.Flags().StringVar(&cpuProfileFile, "cpuprofile", "", "path/filename for the CPU profile file")
benchmarkCmd.Flags().StringVar(&memProfileFile, "memprofile", "", "path/filename for the memory profile file")
benchmarkCmd.Flags().IntVarP(&benchmarkTimes, "count", "n", 13, "number of times to build the site")
benchmarkCmd.RunE = benchmark
}
func benchmark(cmd *cobra.Command, args []string) error {
func (c *benchmarkCmd) benchmark(cmd *cobra.Command, args []string) error {
cfgInit := func(c *commandeer) error {
c.Set("renderToMemory", renderToMemory)
return nil
}
c, err := InitializeConfig(false, cfgInit, benchmarkCmd)
comm, err := initializeConfig(true, false, &c.hugoBuilderCommon, c, cfgInit)
if err != nil {
return err
}
var memProf *os.File
if memProfileFile != "" {
memProf, err = os.Create(memProfileFile)
if c.memProfileFile != "" {
memProf, err = os.Create(c.memProfileFile)
if err != nil {
return err
}
}
var cpuProf *os.File
if cpuProfileFile != "" {
cpuProf, err = os.Create(cpuProfileFile)
if c.cpuProfileFile != "" {
cpuProf, err = os.Create(c.cpuProfileFile)
if err != nil {
return err
}
@@ -82,8 +86,8 @@ func benchmark(cmd *cobra.Command, args []string) error {
}
t := time.Now()
for i := 0; i < benchmarkTimes; i++ {
if err = c.resetAndBuildSites(); err != nil {
for i := 0; i < c.benchmarkTimes; i++ {
if err = comm.resetAndBuildSites(); err != nil {
return err
}
}
@@ -103,9 +107,9 @@ func benchmark(cmd *cobra.Command, args []string) error {
totalMallocs := memStats.Mallocs - mallocs
jww.FEEDBACK.Println()
jww.FEEDBACK.Printf("Average time per operation: %vms\n", int(1000*totalTime.Seconds()/float64(benchmarkTimes)))
jww.FEEDBACK.Printf("Average memory allocated per operation: %vkB\n", totalMemAllocated/uint64(benchmarkTimes)/1024)
jww.FEEDBACK.Printf("Average allocations per operation: %v\n", totalMallocs/uint64(benchmarkTimes))
jww.FEEDBACK.Printf("Average time per operation: %vms\n", int(1000*totalTime.Seconds()/float64(c.benchmarkTimes)))
jww.FEEDBACK.Printf("Average memory allocated per operation: %vkB\n", totalMemAllocated/uint64(c.benchmarkTimes)/1024)
jww.FEEDBACK.Printf("Average allocations per operation: %v\n", totalMallocs/uint64(c.benchmarkTimes))
return nil
}
+15 -4
View File
@@ -1,4 +1,4 @@
// Copyright 2015 The Hugo Authors. All rights reserved.
// Copyright 2018 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -11,13 +11,24 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// +build !darwin
package commands
import (
"github.com/spf13/cobra"
)
var checkCmd = &cobra.Command{
Use: "check",
Short: "Contains some verification checks",
var _ cmder = (*checkCmd)(nil)
type checkCmd struct {
*baseCmd
}
func newCheckCmd() *checkCmd {
return &checkCmd{baseCmd: &baseCmd{cmd: &cobra.Command{
Use: "check",
Short: "Contains some verification checks",
},
}}
}
+36
View File
@@ -0,0 +1,36 @@
// Copyright 2018 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package commands
import (
"github.com/spf13/cobra"
)
var _ cmder = (*checkCmd)(nil)
type checkCmd struct {
*baseCmd
}
func newCheckCmd() *checkCmd {
cc := &checkCmd{baseCmd: &baseCmd{cmd: &cobra.Command{
Use: "check",
Short: "Contains some verification checks",
},
}}
cc.cmd.AddCommand(newLimitCmd().getCommand())
return cc
}
+289 -33
View File
@@ -1,4 +1,4 @@
// Copyright 2017 The Hugo Authors. All rights reserved.
// Copyright 2018 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -14,22 +14,60 @@
package commands
import (
"os"
"path/filepath"
"regexp"
"sync"
"time"
"github.com/gohugoio/hugo/config"
"github.com/spf13/cobra"
"github.com/spf13/afero"
"github.com/gohugoio/hugo/hugolib"
"github.com/bep/debounce"
"github.com/gohugoio/hugo/common/types"
"github.com/gohugoio/hugo/deps"
"github.com/gohugoio/hugo/helpers"
"github.com/gohugoio/hugo/hugofs"
src "github.com/gohugoio/hugo/source"
"github.com/gohugoio/hugo/langs"
)
type commandeer struct {
type commandeerHugoState struct {
*deps.DepsCfg
pathSpec *helpers.PathSpec
hugo *hugolib.HugoSites
fsCreate sync.Once
}
type commandeer struct {
*commandeerHugoState
// Currently only set when in "fast render mode". But it seems to
// be fast enough that we could maybe just add it for all server modes.
changeDetector *fileChangeDetector
// We need to reuse this on server rebuilds.
destinationFs afero.Fs
h *hugoBuilderCommon
ftch flagsToConfigHandler
visitedURLs *types.EvictingStringQueue
staticDirsConfig []*src.Dirs
doWithCommandeer func(c *commandeer) error
serverPorts []int
languages helpers.Languages
// We watch these for changes.
configFiles []string
// Used in cases where we get flooded with events in server mode.
debounce func(f func())
serverPorts []int
languagesConfigured bool
languages langs.Languages
configured bool
}
@@ -41,40 +79,258 @@ func (c *commandeer) Set(key string, value interface{}) {
c.Cfg.Set(key, value)
}
// PathSpec lazily creates a new PathSpec, as all the paths must
// be configured before it is created.
func (c *commandeer) PathSpec() *helpers.PathSpec {
c.configured = true
return c.pathSpec
}
func (c *commandeer) initFs(fs *hugofs.Fs) error {
c.destinationFs = fs.Destination
c.DepsCfg.Fs = fs
ps, err := helpers.NewPathSpec(fs, c.Cfg)
if err != nil {
return err
}
c.pathSpec = ps
dirsConfig, err := c.createStaticDirsConfig()
if err != nil {
return err
}
c.staticDirsConfig = dirsConfig
return nil
}
func newCommandeer(cfg *deps.DepsCfg, running bool) (*commandeer, error) {
cfg.Running = running
func newCommandeer(mustHaveConfigFile, running bool, h *hugoBuilderCommon, f flagsToConfigHandler, doWithCommandeer func(c *commandeer) error, subCmdVs ...*cobra.Command) (*commandeer, error) {
var languages helpers.Languages
if l, ok := cfg.Cfg.Get("languagesSorted").(helpers.Languages); ok {
languages = l
var rebuildDebouncer func(f func())
if running {
// The time value used is tested with mass content replacements in a fairly big Hugo site.
// It is better to wait for some seconds in those cases rather than get flooded
// with rebuilds.
rebuildDebouncer, _, _ = debounce.New(4 * time.Second)
}
c := &commandeer{DepsCfg: cfg, languages: languages, visitedURLs: types.NewEvictingStringQueue(10)}
c := &commandeer{
h: h,
ftch: f,
commandeerHugoState: &commandeerHugoState{},
doWithCommandeer: doWithCommandeer,
visitedURLs: types.NewEvictingStringQueue(10),
debounce: rebuildDebouncer,
}
return c, c.loadConfig(mustHaveConfigFile, running)
}
type fileChangeDetector struct {
sync.Mutex
current map[string]string
prev map[string]string
irrelevantRe *regexp.Regexp
}
func (f *fileChangeDetector) OnFileClose(name, md5sum string) {
f.Lock()
defer f.Unlock()
f.current[name] = md5sum
}
func (f *fileChangeDetector) changed() []string {
if f == nil {
return nil
}
f.Lock()
defer f.Unlock()
var c []string
for k, v := range f.current {
vv, found := f.prev[k]
if !found || v != vv {
c = append(c, k)
}
}
return f.filterIrrelevant(c)
}
func (f *fileChangeDetector) filterIrrelevant(in []string) []string {
var filtered []string
for _, v := range in {
if !f.irrelevantRe.MatchString(v) {
filtered = append(filtered, v)
}
}
return filtered
}
func (f *fileChangeDetector) PrepareNew() {
if f == nil {
return
}
f.Lock()
defer f.Unlock()
if f.current == nil {
f.current = make(map[string]string)
f.prev = make(map[string]string)
return
}
f.prev = make(map[string]string)
for k, v := range f.current {
f.prev[k] = v
}
f.current = make(map[string]string)
}
func (c *commandeer) loadConfig(mustHaveConfigFile, running bool) error {
if c.DepsCfg == nil {
c.DepsCfg = &deps.DepsCfg{}
}
cfg := c.DepsCfg
c.configured = false
cfg.Running = running
var dir string
if c.h.source != "" {
dir, _ = filepath.Abs(c.h.source)
} else {
dir, _ = os.Getwd()
}
var sourceFs afero.Fs = hugofs.Os
if c.DepsCfg.Fs != nil {
sourceFs = c.DepsCfg.Fs.Source
}
doWithConfig := func(cfg config.Provider) error {
if c.ftch != nil {
c.ftch.flagsToConfig(cfg)
}
cfg.Set("workingDir", dir)
return nil
}
doWithCommandeer := func(cfg config.Provider) error {
c.Cfg = cfg
if c.doWithCommandeer == nil {
return nil
}
err := c.doWithCommandeer(c)
return err
}
config, configFiles, err := hugolib.LoadConfig(
hugolib.ConfigSourceDescriptor{Fs: sourceFs, Path: c.h.source, WorkingDir: dir, Filename: c.h.cfgFile},
doWithCommandeer,
doWithConfig)
if err != nil {
if mustHaveConfigFile {
return err
}
if err != hugolib.ErrNoConfigFile {
return err
}
}
c.configFiles = configFiles
if l, ok := c.Cfg.Get("languagesSorted").(langs.Languages); ok {
c.languagesConfigured = true
c.languages = l
}
// 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 {
return err
}
}
logger, err := c.createLogger(config)
if err != nil {
return err
}
cfg.Logger = logger
createMemFs := config.GetBool("renderToMemory")
if createMemFs {
// Rendering to memoryFS, publish to Root regardless of publishDir.
config.Set("publishDir", "/")
}
c.fsCreate.Do(func() {
fs := hugofs.NewFrom(sourceFs, config)
if c.destinationFs != nil {
// Need to reuse the destination on server rebuilds.
fs.Destination = c.destinationFs
} else if createMemFs {
// Hugo writes the output to memory instead of the disk.
fs.Destination = new(afero.MemMapFs)
}
doLiveReload := !c.h.buildWatch && !config.GetBool("disableLiveReload")
fastRenderMode := doLiveReload && !config.GetBool("disableFastRender")
if fastRenderMode {
// For now, fast render mode only. It should, however, be fast enough
// for the full variant, too.
changeDetector := &fileChangeDetector{
// We use this detector to decide to do a Hot reload of a single path or not.
// We need to filter out source maps and possibly some other to be able
// to make that decision.
irrelevantRe: regexp.MustCompile(`\.map$`),
}
changeDetector.PrepareNew()
fs.Destination = hugofs.NewHashingFs(fs.Destination, changeDetector)
c.changeDetector = changeDetector
}
err = c.initFs(fs)
if err != nil {
return
}
var h *hugolib.HugoSites
h, err = hugolib.NewHugoSites(*c.DepsCfg)
c.hugo = h
})
if err != nil {
return err
}
cacheDir := config.GetString("cacheDir")
if cacheDir != "" {
if helpers.FilePathSeparator != cacheDir[len(cacheDir)-1:] {
cacheDir = cacheDir + helpers.FilePathSeparator
}
isDir, err := helpers.DirExists(cacheDir, sourceFs)
checkErr(cfg.Logger, err)
if !isDir {
mkdir(cacheDir)
}
config.Set("cacheDir", cacheDir)
} else {
config.Set("cacheDir", helpers.GetTempDir("hugo_cache", sourceFs))
}
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)
}
}
themeVersionMismatch, minVersion := c.isThemeVsHugoVersionMismatch(sourceFs)
if themeVersionMismatch {
cfg.Logger.ERROR.Printf("Current theme does not support Hugo version %s. Minimum version required is %s\n",
helpers.CurrentHugoVersion.ReleaseVersion(), minVersion)
}
return nil
return c, nil
}
+282
View File
@@ -0,0 +1,282 @@
// Copyright 2017 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package commands
import (
"os"
"github.com/gohugoio/hugo/config"
"github.com/gohugoio/hugo/helpers"
"github.com/spf13/cobra"
jww "github.com/spf13/jwalterweatherman"
"github.com/spf13/nitro"
)
type commandsBuilder struct {
hugoBuilderCommon
commands []cmder
}
func newCommandsBuilder() *commandsBuilder {
return &commandsBuilder{}
}
func (b *commandsBuilder) addCommands(commands ...cmder) *commandsBuilder {
b.commands = append(b.commands, commands...)
return b
}
func (b *commandsBuilder) addAll() *commandsBuilder {
b.addCommands(
b.newServerCmd(),
newVersionCmd(),
newEnvCmd(),
newConfigCmd(),
newCheckCmd(),
b.newBenchmarkCmd(),
newConvertCmd(),
newNewCmd(),
newListCmd(),
newImportCmd(),
newGenCmd(),
createReleaser(),
)
return b
}
func (b *commandsBuilder) build() *hugoCmd {
h := b.newHugoCmd()
addCommands(h.getCommand(), b.commands...)
return h
}
func addCommands(root *cobra.Command, commands ...cmder) {
for _, command := range commands {
cmd := command.getCommand()
if cmd == nil {
continue
}
root.AddCommand(cmd)
}
}
type baseCmd struct {
cmd *cobra.Command
}
var _ commandsBuilderGetter = (*baseBuilderCmd)(nil)
// Used in tests.
type commandsBuilderGetter interface {
getCmmandsBuilder() *commandsBuilder
}
type baseBuilderCmd struct {
*baseCmd
*commandsBuilder
}
func (b *baseBuilderCmd) getCmmandsBuilder() *commandsBuilder {
return b.commandsBuilder
}
func (c *baseCmd) getCommand() *cobra.Command {
return c.cmd
}
func newBaseCmd(cmd *cobra.Command) *baseCmd {
return &baseCmd{cmd: cmd}
}
func (b *commandsBuilder) newBuilderCmd(cmd *cobra.Command) *baseBuilderCmd {
bcmd := &baseBuilderCmd{commandsBuilder: b, baseCmd: &baseCmd{cmd: cmd}}
bcmd.hugoBuilderCommon.handleFlags(cmd)
return bcmd
}
func (c *baseCmd) flagsToConfig(cfg config.Provider) {
initializeFlags(c.cmd, cfg)
}
type hugoCmd struct {
*baseBuilderCmd
// Need to get the sites once built.
c *commandeer
}
var _ cmder = (*nilCommand)(nil)
type nilCommand struct {
}
func (c *nilCommand) getCommand() *cobra.Command {
return nil
}
func (c *nilCommand) flagsToConfig(cfg config.Provider) {
}
func (b *commandsBuilder) newHugoCmd() *hugoCmd {
cc := &hugoCmd{}
cc.baseBuilderCmd = b.newBuilderCmd(&cobra.Command{
Use: "hugo",
Short: "hugo builds your site",
Long: `hugo is the main command, used to build your Hugo site.
Hugo is a Fast and Flexible Static Site Generator
built with love by spf13 and friends in Go.
Complete documentation is available at http://gohugo.io/.`,
RunE: func(cmd *cobra.Command, args []string) error {
cfgInit := func(c *commandeer) error {
if cc.buildWatch {
c.Set("disableLiveReload", true)
}
return nil
}
c, err := initializeConfig(true, cc.buildWatch, &cc.hugoBuilderCommon, cc, cfgInit)
if err != nil {
return err
}
cc.c = c
return c.build()
},
})
cc.cmd.PersistentFlags().StringVar(&cc.cfgFile, "config", "", "config file (default is path/config.yaml|json|toml)")
cc.cmd.PersistentFlags().BoolVar(&cc.quiet, "quiet", false, "build in quiet mode")
// Set bash-completion
validConfigFilenames := []string{"json", "js", "yaml", "yml", "toml", "tml"}
_ = cc.cmd.PersistentFlags().SetAnnotation("config", cobra.BashCompFilenameExt, validConfigFilenames)
cc.cmd.PersistentFlags().BoolVarP(&cc.verbose, "verbose", "v", false, "verbose output")
cc.cmd.PersistentFlags().BoolVarP(&cc.debug, "debug", "", false, "debug output")
cc.cmd.PersistentFlags().BoolVar(&cc.logging, "log", false, "enable Logging")
cc.cmd.PersistentFlags().StringVar(&cc.logFile, "logFile", "", "log File path (if set, logging enabled automatically)")
cc.cmd.PersistentFlags().BoolVar(&cc.verboseLog, "verboseLog", false, "verbose logging")
cc.cmd.Flags().BoolVarP(&cc.buildWatch, "watch", "w", false, "watch filesystem for changes and recreate as needed")
cc.cmd.Flags().Bool("renderToMemory", false, "render to memory (only useful for benchmark testing)")
// Set bash-completion
_ = cc.cmd.PersistentFlags().SetAnnotation("logFile", cobra.BashCompFilenameExt, []string{})
cc.cmd.SetGlobalNormalizationFunc(helpers.NormalizeHugoFlags)
cc.cmd.SilenceUsage = true
return cc
}
type hugoBuilderCommon struct {
source string
baseURL string
buildWatch bool
gc bool
// TODO(bep) var vs string
logging bool
verbose bool
verboseLog bool
debug bool
quiet bool
cfgFile string
logFile string
}
func (cc *hugoBuilderCommon) handleFlags(cmd *cobra.Command) {
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().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().StringP("theme", "t", "", "theme to use (located in /themes/THEMENAME/)")
cmd.Flags().StringP("themesDir", "", "", "filesystem path to themes directory")
cmd.Flags().Bool("uglyURLs", false, "(deprecated) if true, use /filename.html instead of /filename/")
cmd.Flags().Bool("canonifyURLs", false, "(deprecated) if true, all relative URLs will be canonicalized using baseURL")
cmd.Flags().StringVarP(&cc.baseURL, "baseURL", "b", "", "hostname (and path) to the root, e.g. http://spf13.com/")
cmd.Flags().Bool("enableGitInfo", false, "add Git revision, date and author info to the pages")
cmd.Flags().BoolVar(&cc.gc, "gc", false, "enable to run some cleanup tasks (remove unused cache files) after the build")
cmd.Flags().BoolVar(&nitro.AnalysisOn, "stepAnalysis", false, "display memory and timing of different steps of the program")
cmd.Flags().Bool("templateMetrics", false, "display metrics about template executions")
cmd.Flags().Bool("templateMetricsHints", false, "calculate some improvement hints when combined with --templateMetrics")
cmd.Flags().Bool("pluralizeListTitles", true, "(deprecated) pluralize titles in lists using inflect")
cmd.Flags().Bool("preserveTaxonomyNames", false, `(deprecated) preserve taxonomy names as written ("Gérard Depardieu" vs "gerard-depardieu")`)
cmd.Flags().BoolP("forceSyncStatic", "", false, "copy all files when static is changed.")
cmd.Flags().BoolP("noTimes", "", false, "don't sync modification time of files")
cmd.Flags().BoolP("noChmod", "", false, "don't sync permission mode of files")
cmd.Flags().BoolP("i18n-warnings", "", false, "print missing translations")
cmd.Flags().StringSlice("disableKinds", []string{}, "disable different kind of pages (home, RSS etc.)")
// Set bash-completion.
// Each flag must first be defined before using the SetAnnotation() call.
_ = cmd.Flags().SetAnnotation("source", cobra.BashCompSubdirsInDir, []string{})
_ = cmd.Flags().SetAnnotation("cacheDir", cobra.BashCompSubdirsInDir, []string{})
_ = cmd.Flags().SetAnnotation("destination", cobra.BashCompSubdirsInDir, []string{})
_ = cmd.Flags().SetAnnotation("theme", cobra.BashCompSubdirsInDir, []string{"themes"})
}
func checkErr(logger *jww.Notepad, err error, s ...string) {
if err == nil {
return
}
if len(s) == 0 {
logger.CRITICAL.Println(err)
return
}
for _, message := range s {
logger.ERROR.Println(message)
}
logger.ERROR.Println(err)
}
func stopOnErr(logger *jww.Notepad, err error, s ...string) {
if err == nil {
return
}
defer os.Exit(-1)
if len(s) == 0 {
newMessage := err.Error()
// Printing an empty string results in a error with
// no message, no bueno.
if newMessage != "" {
logger.CRITICAL.Println(newMessage)
}
}
for _, message := range s {
if message != "" {
logger.CRITICAL.Println(message)
}
}
}
+253
View File
@@ -0,0 +1,253 @@
// Copyright 2018 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package commands
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"testing"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/stretchr/testify/require"
)
func TestExecute(t *testing.T) {
assert := require.New(t)
dir, err := createSimpleTestSite(t)
assert.NoError(err)
defer func() {
os.RemoveAll(dir)
}()
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)
}
func TestCommandsPersistentFlags(t *testing.T) {
assert := require.New(t)
noOpRunE := func(cmd *cobra.Command, args []string) error {
return nil
}
tests := []struct {
args []string
check func(command []cmder)
}{{[]string{"server",
"--config=myconfig.toml",
"--contentDir=mycontent",
"--disableKinds=page,home",
"--layoutDir=mylayouts",
"--theme=mytheme",
"--gc",
"--themesDir=mythemes",
"--cleanDestinationDir",
"--navigateToChanged",
"--disableLiveReload",
"--noHTTPCache",
"--i18n-warnings",
"--destination=/tmp/mydestination",
"-b=https://example.com/b/",
"--port=1366",
"--renderToDisk",
"--source=mysource",
"--uglyURLs"}, func(commands []cmder) {
var sc *serverCmd
for _, command := range commands {
if b, ok := command.(commandsBuilderGetter); ok {
v := b.getCmmandsBuilder().hugoBuilderCommon
assert.Equal("myconfig.toml", v.cfgFile)
assert.Equal("mysource", v.source)
assert.Equal("https://example.com/b/", v.baseURL)
}
if srvCmd, ok := command.(*serverCmd); ok {
sc = srvCmd
}
}
assert.NotNil(sc)
assert.True(sc.navigateToChanged)
assert.True(sc.disableLiveReload)
assert.True(sc.noHTTPCache)
assert.True(sc.renderToDisk)
assert.Equal(1366, sc.serverPort)
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("mytheme", cfg.GetString("theme"))
assert.Equal("mythemes", cfg.GetString("themesDir"))
assert.Equal("https://example.com/b/", cfg.GetString("baseURL"))
assert.Equal([]string{"page", "home"}, cfg.Get("disableKinds"))
assert.True(cfg.GetBool("uglyURLs"))
assert.True(cfg.GetBool("gc"))
// The flag is named i18n-warnings
assert.True(cfg.GetBool("logI18nWarnings"))
}}}
for _, test := range tests {
b := newCommandsBuilder()
root := b.addAll().build()
for _, c := range b.commands {
if c.getCommand() == nil {
continue
}
// We are only intereseted in the flag handling here.
c.getCommand().RunE = noOpRunE
}
rootCmd := root.getCommand()
rootCmd.SetArgs(test.args)
assert.NoError(rootCmd.Execute())
test.check(b.commands)
}
}
func TestCommandsExecute(t *testing.T) {
assert := require.New(t)
dir, err := createSimpleTestSite(t)
assert.NoError(err)
dirOut, err := ioutil.TempDir("", "hugo-cli-out")
assert.NoError(err)
defer func() {
os.RemoveAll(dir)
os.RemoveAll(dirOut)
}()
sourceFlag := fmt.Sprintf("-s=%s", dir)
tests := []struct {
commands []string
flags []string
expectErrToContain string
}{
// TODO(bep) permission issue on my OSX? "operation not permitted" {[]string{"check", "ulimit"}, nil, false},
{[]string{"env"}, nil, ""},
{[]string{"version"}, nil, ""},
// no args = hugo build
{nil, []string{sourceFlag}, ""},
{nil, []string{sourceFlag, "--renderToMemory"}, ""},
{[]string{"config"}, []string{sourceFlag}, ""},
{[]string{"benchmark"}, []string{sourceFlag, "-n=1"}, ""},
{[]string{"convert", "toTOML"}, []string{sourceFlag, "-o=" + filepath.Join(dirOut, "toml")}, ""},
{[]string{"convert", "toYAML"}, []string{sourceFlag, "-o=" + filepath.Join(dirOut, "yaml")}, ""},
{[]string{"convert", "toJSON"}, []string{sourceFlag, "-o=" + filepath.Join(dirOut, "json")}, ""},
{[]string{"gen", "autocomplete"}, []string{"--completionfile=" + filepath.Join(dirOut, "autocomplete.txt")}, ""},
{[]string{"gen", "chromastyles"}, []string{"--style=manni"}, ""},
{[]string{"gen", "doc"}, []string{"--dir=" + filepath.Join(dirOut, "doc")}, ""},
{[]string{"gen", "man"}, []string{"--dir=" + filepath.Join(dirOut, "man")}, ""},
{[]string{"list", "drafts"}, []string{sourceFlag}, ""},
{[]string{"list", "expired"}, []string{sourceFlag}, ""},
{[]string{"list", "future"}, []string{sourceFlag}, ""},
{[]string{"new", "new-page.md"}, []string{sourceFlag}, ""},
{[]string{"new", "site", filepath.Join(dirOut, "new-site")}, nil, ""},
{[]string{"unknowncommand"}, nil, "unknown command"},
// TODO(bep) cli refactor fix https://github.com/gohugoio/hugo/issues/4450
//{[]string{"new", "theme", filepath.Join(dirOut, "new-theme")}, nil,false},
}
for _, test := range tests {
hugoCmd := newCommandsBuilder().addAll().build().getCommand()
test.flags = append(test.flags, "--quiet")
hugoCmd.SetArgs(append(test.commands, test.flags...))
// TODO(bep) capture output and add some simple asserts
// TODO(bep) misspelled subcommands does not return an error. We should investigate this
// but before that, check for "Error: unknown command".
_, err := hugoCmd.ExecuteC()
if test.expectErrToContain != "" {
assert.Error(err, fmt.Sprintf("%v", test.commands))
assert.Contains(err.Error(), test.expectErrToContain)
} else {
assert.NoError(err, fmt.Sprintf("%v", test.commands))
}
}
}
func createSimpleTestSite(t *testing.T) (string, error) {
d, e := ioutil.TempDir("", "hugo-cli")
if e != nil {
return "", e
}
// Just the basic. These are for CLI tests, not site testing.
writeFile(t, filepath.Join(d, "config.toml"), `
baseURL = "https://example.org"
title = "Hugo Commands"
`)
writeFile(t, filepath.Join(d, "content", "p1.md"), `
---
title: "P1"
weight: 1
---
Content
`)
writeFile(t, filepath.Join(d, "layouts", "_default", "single.html"), `
Single: {{ .Title }}
`)
writeFile(t, filepath.Join(d, "layouts", "_default", "list.html"), `
List: {{ .Title }}
`)
return d, nil
}
func writeFile(t *testing.T, filename, content string) {
must(t, os.MkdirAll(filepath.Dir(filename), os.FileMode(0755)))
must(t, ioutil.WriteFile(filename, []byte(content), os.FileMode(0755)))
}
func must(t *testing.T, err error) {
if err != nil {
t.Fatal(err)
}
}
+19 -8
View File
@@ -22,18 +22,29 @@ import (
"github.com/spf13/viper"
)
var configCmd = &cobra.Command{
Use: "config",
Short: "Print the site configuration",
Long: `Print the site configuration, both default and custom settings.`,
var _ cmder = (*configCmd)(nil)
type configCmd struct {
hugoBuilderCommon
*baseCmd
}
func init() {
configCmd.RunE = printConfig
func newConfigCmd() *configCmd {
cc := &configCmd{}
cc.baseCmd = newBaseCmd(&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")
return cc
}
func printConfig(cmd *cobra.Command, args []string) error {
cfg, err := InitializeConfig(false, nil, configCmd)
func (c *configCmd) printConfig(cmd *cobra.Command, args []string) error {
cfg, err := initializeConfig(true, false, &c.hugoBuilderCommon, c, nil)
if err != nil {
return err
+62 -51
View File
@@ -28,64 +28,75 @@ import (
"github.com/spf13/cobra"
)
var outputDir string
var unsafe bool
var (
_ cmder = (*convertCmd)(nil)
)
var convertCmd = &cobra.Command{
Use: "convert",
Short: "Convert your content to different formats",
Long: `Convert your content (e.g. front matter) to different formats.
type convertCmd struct {
hugoBuilderCommon
outputDir string
unsafe bool
*baseCmd
}
func newConvertCmd() *convertCmd {
cc := &convertCmd{}
cc.baseCmd = newBaseCmd(&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,
}
RunE: nil,
})
var toJSONCmd = &cobra.Command{
Use: "toJSON",
Short: "Convert front matter to JSON",
Long: `toJSON converts all front matter in the content directory
cc.cmd.AddCommand(
&cobra.Command{
Use: "toJSON",
Short: "Convert front matter to JSON",
Long: `toJSON converts all front matter in the content directory
to use JSON for the front matter.`,
RunE: func(cmd *cobra.Command, args []string) error {
return convertContents(rune([]byte(parser.JSONLead)[0]))
},
}
var toTOMLCmd = &cobra.Command{
Use: "toTOML",
Short: "Convert front matter to TOML",
Long: `toTOML converts all front matter in the content directory
RunE: func(cmd *cobra.Command, args []string) error {
return cc.convertContents(rune([]byte(parser.JSONLead)[0]))
},
},
&cobra.Command{
Use: "toTOML",
Short: "Convert front matter to TOML",
Long: `toTOML converts all front matter in the content directory
to use TOML for the front matter.`,
RunE: func(cmd *cobra.Command, args []string) error {
return convertContents(rune([]byte(parser.TOMLLead)[0]))
},
}
var toYAMLCmd = &cobra.Command{
Use: "toYAML",
Short: "Convert front matter to YAML",
Long: `toYAML converts all front matter in the content directory
RunE: func(cmd *cobra.Command, args []string) error {
return cc.convertContents(rune([]byte(parser.TOMLLead)[0]))
},
},
&cobra.Command{
Use: "toYAML",
Short: "Convert front matter to YAML",
Long: `toYAML converts all front matter in the content directory
to use YAML for the front matter.`,
RunE: func(cmd *cobra.Command, args []string) error {
return convertContents(rune([]byte(parser.YAMLLead)[0]))
},
RunE: func(cmd *cobra.Command, args []string) error {
return cc.convertContents(rune([]byte(parser.YAMLLead)[0]))
},
},
)
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{})
return cc
}
func init() {
convertCmd.AddCommand(toJSONCmd)
convertCmd.AddCommand(toTOMLCmd)
convertCmd.AddCommand(toYAMLCmd)
convertCmd.PersistentFlags().StringVarP(&outputDir, "output", "o", "", "filesystem path to write files to")
convertCmd.PersistentFlags().StringVarP(&source, "source", "s", "", "filesystem path to read files relative from")
convertCmd.PersistentFlags().BoolVar(&unsafe, "unsafe", false, "enable less safe operations, please backup first")
convertCmd.PersistentFlags().SetAnnotation("source", cobra.BashCompSubdirsInDir, []string{})
}
func convertContents(mark rune) error {
if outputDir == "" && !unsafe {
func (cc *convertCmd) convertContents(mark rune) error {
if cc.outputDir == "" && !cc.unsafe {
return newUserError("Unsafe operation not allowed, use --unsafe or set a different output path")
}
c, err := InitializeConfig(false, nil)
c, err := initializeConfig(true, false, &cc.hugoBuilderCommon, cc, nil)
if err != nil {
return err
}
@@ -103,17 +114,17 @@ func convertContents(mark rune) error {
site.Log.FEEDBACK.Println("processing", len(site.AllPages), "content files")
for _, p := range site.AllPages {
if err := convertAndSavePage(p, site, mark); err != nil {
if err := cc.convertAndSavePage(p, site, mark); err != nil {
return err
}
}
return nil
}
func convertAndSavePage(p *hugolib.Page, site *hugolib.Site, mark rune) error {
func (cc *convertCmd) convertAndSavePage(p *hugolib.Page, site *hugolib.Site, mark rune) error {
// The resources are not in .Site.AllPages.
for _, r := range p.Resources.ByType("page") {
if err := convertAndSavePage(r.(*hugolib.Page), site, mark); err != nil {
if err := cc.convertAndSavePage(r.(*hugolib.Page), site, mark); err != nil {
return err
}
}
@@ -171,8 +182,8 @@ func convertAndSavePage(p *hugolib.Page, site *hugolib.Site, mark rune) error {
}
newFilename := p.Filename()
if outputDir != "" {
newFilename = filepath.Join(outputDir, p.Dir(), newPage.LogicalName())
if cc.outputDir != "" {
newFilename = filepath.Join(cc.outputDir, p.Dir(), newPage.LogicalName())
}
if err = newPage.SaveSourceAs(newFilename); err != nil {
+20 -11
View File
@@ -20,16 +20,25 @@ import (
jww "github.com/spf13/jwalterweatherman"
)
var envCmd = &cobra.Command{
Use: "env",
Short: "Print Hugo version and environment info",
Long: `Print Hugo version and environment info. This is useful in Hugo bug reports.`,
RunE: func(cmd *cobra.Command, args []string) error {
printHugoVersion()
jww.FEEDBACK.Printf("GOOS=%q\n", runtime.GOOS)
jww.FEEDBACK.Printf("GOARCH=%q\n", runtime.GOARCH)
jww.FEEDBACK.Printf("GOVERSION=%q\n", runtime.Version())
var _ cmder = (*envCmd)(nil)
return nil
},
type envCmd struct {
*baseCmd
}
func newEnvCmd() *envCmd {
return &envCmd{baseCmd: newBaseCmd(&cobra.Command{
Use: "env",
Short: "Print Hugo version and environment info",
Long: `Print Hugo version and environment info. This is useful in Hugo bug reports.`,
RunE: func(cmd *cobra.Command, args []string) error {
printHugoVersion()
jww.FEEDBACK.Printf("GOOS=%q\n", runtime.GOOS)
jww.FEEDBACK.Printf("GOARCH=%q\n", runtime.GOARCH)
jww.FEEDBACK.Printf("GOVERSION=%q\n", runtime.Version())
return nil
},
}),
}
}
+21 -3
View File
@@ -17,7 +17,25 @@ import (
"github.com/spf13/cobra"
)
var genCmd = &cobra.Command{
Use: "gen",
Short: "A collection of several useful generators.",
var _ cmder = (*genCmd)(nil)
type genCmd struct {
*baseCmd
}
func newGenCmd() *genCmd {
cc := &genCmd{}
cc.baseCmd = newBaseCmd(&cobra.Command{
Use: "gen",
Short: "A collection of several useful generators.",
})
cc.cmd.AddCommand(
newGenautocompleteCmd().getCommand(),
newGenDocCmd().getCommand(),
newGenManCmd().getCommand(),
createGenDocsHelper().getCommand(),
createGenChromaStyles().getCommand())
return cc
}
+33 -23
View File
@@ -18,15 +18,24 @@ import (
jww "github.com/spf13/jwalterweatherman"
)
var autocompleteTarget string
var _ cmder = (*genautocompleteCmd)(nil)
// bash for now (zsh and others will come)
var autocompleteType string
type genautocompleteCmd struct {
autocompleteTarget string
var genautocompleteCmd = &cobra.Command{
Use: "autocomplete",
Short: "Generate shell autocompletion script for Hugo",
Long: `Generates a shell autocompletion script for Hugo.
// bash for now (zsh and others will come)
autocompleteType string
*baseCmd
}
func newGenautocompleteCmd() *genautocompleteCmd {
cc := &genautocompleteCmd{}
cc.baseCmd = newBaseCmd(&cobra.Command{
Use: "autocomplete",
Short: "Generate shell autocompletion script for Hugo",
Long: `Generates a shell autocompletion script for Hugo.
NOTE: The current version supports Bash only.
This should work for *nix systems with Bash installed.
@@ -44,27 +53,28 @@ or just source them in directly:
$ . /etc/bash_completion`,
RunE: func(cmd *cobra.Command, args []string) error {
if autocompleteType != "bash" {
return newUserError("Only Bash is supported for now")
}
RunE: func(cmd *cobra.Command, args []string) error {
if cc.autocompleteType != "bash" {
return newUserError("Only Bash is supported for now")
}
err := cmd.Root().GenBashCompletionFile(autocompleteTarget)
err := cmd.Root().GenBashCompletionFile(cc.autocompleteTarget)
if err != nil {
return err
}
if err != nil {
return err
}
jww.FEEDBACK.Println("Bash completion file for Hugo saved to", autocompleteTarget)
jww.FEEDBACK.Println("Bash completion file for Hugo saved to", cc.autocompleteTarget)
return nil
},
}
return nil
},
})
func init() {
genautocompleteCmd.PersistentFlags().StringVarP(&autocompleteTarget, "completionfile", "", "/etc/bash_completion.d/hugo.sh", "autocompletion file")
genautocompleteCmd.PersistentFlags().StringVarP(&autocompleteType, "type", "", "bash", "autocompletion type (currently only bash supported)")
cc.cmd.PersistentFlags().StringVarP(&cc.autocompleteTarget, "completionfile", "", "/etc/bash_completion.d/hugo.sh", "autocompletion file")
cc.cmd.PersistentFlags().StringVarP(&cc.autocompleteType, "type", "", "bash", "autocompletion type (currently only bash supported)")
// For bash-completion
genautocompleteCmd.PersistentFlags().SetAnnotation("completionfile", cobra.BashCompFilenameExt, []string{})
cc.cmd.PersistentFlags().SetAnnotation("completionfile", cobra.BashCompFilenameExt, []string{})
return cc
}
+7 -3
View File
@@ -22,23 +22,27 @@ import (
"github.com/spf13/cobra"
)
var (
_ cmder = (*genChromaStyles)(nil)
)
type genChromaStyles struct {
style string
highlightStyle string
linesStyle string
cmd *cobra.Command
*baseCmd
}
// TODO(bep) highlight
func createGenChromaStyles() *genChromaStyles {
g := &genChromaStyles{
cmd: &cobra.Command{
baseCmd: newBaseCmd(&cobra.Command{
Use: "chromastyles",
Short: "Generate CSS stylesheet for the Chroma code highlighter",
Long: `Generate CSS stylesheet for the Chroma code highlighter for a given style. This stylesheet is needed if pygmentsUseClasses is enabled in config.
See https://help.farbox.com/pygments.html for preview of available styles`,
},
}),
}
g.cmd.RunE = func(cmd *cobra.Command, args []string) error {
+45 -35
View File
@@ -27,7 +27,15 @@ import (
jww "github.com/spf13/jwalterweatherman"
)
const gendocFrontmatterTemplate = `---
var _ cmder = (*genDocCmd)(nil)
type genDocCmd struct {
gendocdir string
*baseCmd
}
func newGenDocCmd() *genDocCmd {
const gendocFrontmatterTemplate = `---
date: %s
title: "%s"
slug: %s
@@ -35,11 +43,12 @@ url: %s
---
`
var gendocdir string
var gendocCmd = &cobra.Command{
Use: "doc",
Short: "Generate Markdown documentation for the Hugo CLI.",
Long: `Generate Markdown documentation for the Hugo CLI.
cc := &genDocCmd{}
cc.baseCmd = newBaseCmd(&cobra.Command{
Use: "doc",
Short: "Generate Markdown documentation for the Hugo CLI.",
Long: `Generate Markdown documentation for the Hugo CLI.
This command is, mostly, used to create up-to-date documentation
of Hugo's command-line interface for http://gohugo.io/.
@@ -47,40 +56,41 @@ of Hugo's command-line interface for http://gohugo.io/.
It creates one Markdown file per command with front matter suitable
for rendering in Hugo.`,
RunE: func(cmd *cobra.Command, args []string) error {
if !strings.HasSuffix(gendocdir, helpers.FilePathSeparator) {
gendocdir += helpers.FilePathSeparator
}
if found, _ := helpers.Exists(gendocdir, hugofs.Os); !found {
jww.FEEDBACK.Println("Directory", gendocdir, "does not exist, creating...")
if err := hugofs.Os.MkdirAll(gendocdir, 0777); err != nil {
return err
RunE: func(cmd *cobra.Command, args []string) error {
if !strings.HasSuffix(cc.gendocdir, helpers.FilePathSeparator) {
cc.gendocdir += helpers.FilePathSeparator
}
if found, _ := helpers.Exists(cc.gendocdir, hugofs.Os); !found {
jww.FEEDBACK.Println("Directory", cc.gendocdir, "does not exist, creating...")
if err := hugofs.Os.MkdirAll(cc.gendocdir, 0777); err != nil {
return err
}
}
now := time.Now().Format("2006-01-02")
prepender := func(filename string) string {
name := filepath.Base(filename)
base := strings.TrimSuffix(name, path.Ext(name))
url := "/commands/" + strings.ToLower(base) + "/"
return fmt.Sprintf(gendocFrontmatterTemplate, now, strings.Replace(base, "_", " ", -1), base, url)
}
}
now := time.Now().Format(time.RFC3339)
prepender := func(filename string) string {
name := filepath.Base(filename)
base := strings.TrimSuffix(name, path.Ext(name))
url := "/commands/" + strings.ToLower(base) + "/"
return fmt.Sprintf(gendocFrontmatterTemplate, now, strings.Replace(base, "_", " ", -1), base, url)
}
linkHandler := func(name string) string {
base := strings.TrimSuffix(name, path.Ext(name))
return "/commands/" + strings.ToLower(base) + "/"
}
linkHandler := func(name string) string {
base := strings.TrimSuffix(name, path.Ext(name))
return "/commands/" + strings.ToLower(base) + "/"
}
jww.FEEDBACK.Println("Generating Hugo command-line documentation in", gendocdir, "...")
doc.GenMarkdownTreeCustom(cmd.Root(), gendocdir, prepender, linkHandler)
jww.FEEDBACK.Println("Done.")
jww.FEEDBACK.Println("Generating Hugo command-line documentation in", cc.gendocdir, "...")
doc.GenMarkdownTreeCustom(cmd.Root(), cc.gendocdir, prepender, linkHandler)
jww.FEEDBACK.Println("Done.")
return nil
},
}
return nil
},
})
func init() {
gendocCmd.PersistentFlags().StringVar(&gendocdir, "dir", "/tmp/hugodoc/", "the directory to write the doc.")
cc.cmd.PersistentFlags().StringVar(&cc.gendocdir, "dir", "/tmp/hugodoc/", "the directory to write the doc.")
// For bash-completion
gendocCmd.PersistentFlags().SetAnnotation("dir", cobra.BashCompSubdirsInDir, []string{})
cc.cmd.PersistentFlags().SetAnnotation("dir", cobra.BashCompSubdirsInDir, []string{})
return cc
}
+7 -3
View File
@@ -23,18 +23,22 @@ import (
"github.com/spf13/cobra"
)
var (
_ cmder = (*genDocsHelper)(nil)
)
type genDocsHelper struct {
target string
cmd *cobra.Command
*baseCmd
}
func createGenDocsHelper() *genDocsHelper {
g := &genDocsHelper{
cmd: &cobra.Command{
baseCmd: newBaseCmd(&cobra.Command{
Use: "docshelper",
Short: "Generate some data files for the Hugo docs.",
Hidden: true,
},
}),
}
g.cmd.RunE = func(cmd *cobra.Command, args []string) error {
+39 -29
View File
@@ -24,43 +24,53 @@ import (
jww "github.com/spf13/jwalterweatherman"
)
var genmandir string
var genmanCmd = &cobra.Command{
Use: "man",
Short: "Generate man pages for the Hugo CLI",
Long: `This command automatically generates up-to-date man pages of Hugo's
var _ cmder = (*genManCmd)(nil)
type genManCmd struct {
genmandir string
*baseCmd
}
func newGenManCmd() *genManCmd {
cc := &genManCmd{}
cc.baseCmd = newBaseCmd(&cobra.Command{
Use: "man",
Short: "Generate man pages for the Hugo CLI",
Long: `This command automatically generates up-to-date man pages of Hugo's
command-line interface. By default, it creates the man page files
in the "man" directory under the current directory.`,
RunE: func(cmd *cobra.Command, args []string) error {
header := &doc.GenManHeader{
Section: "1",
Manual: "Hugo Manual",
Source: fmt.Sprintf("Hugo %s", helpers.CurrentHugoVersion),
}
if !strings.HasSuffix(genmandir, helpers.FilePathSeparator) {
genmandir += helpers.FilePathSeparator
}
if found, _ := helpers.Exists(genmandir, hugofs.Os); !found {
jww.FEEDBACK.Println("Directory", genmandir, "does not exist, creating...")
if err := hugofs.Os.MkdirAll(genmandir, 0777); err != nil {
return err
RunE: func(cmd *cobra.Command, args []string) error {
header := &doc.GenManHeader{
Section: "1",
Manual: "Hugo Manual",
Source: fmt.Sprintf("Hugo %s", helpers.CurrentHugoVersion),
}
}
cmd.Root().DisableAutoGenTag = true
if !strings.HasSuffix(cc.genmandir, helpers.FilePathSeparator) {
cc.genmandir += helpers.FilePathSeparator
}
if found, _ := helpers.Exists(cc.genmandir, hugofs.Os); !found {
jww.FEEDBACK.Println("Directory", cc.genmandir, "does not exist, creating...")
if err := hugofs.Os.MkdirAll(cc.genmandir, 0777); err != nil {
return err
}
}
cmd.Root().DisableAutoGenTag = true
jww.FEEDBACK.Println("Generating Hugo man pages in", genmandir, "...")
doc.GenManTree(cmd.Root(), header, genmandir)
jww.FEEDBACK.Println("Generating Hugo man pages in", cc.genmandir, "...")
doc.GenManTree(cmd.Root(), header, cc.genmandir)
jww.FEEDBACK.Println("Done.")
jww.FEEDBACK.Println("Done.")
return nil
},
}
return nil
},
})
func init() {
genmanCmd.PersistentFlags().StringVar(&genmandir, "dir", "man/", "the directory to write the man pages.")
cc.cmd.PersistentFlags().StringVar(&cc.genmandir, "dir", "man/", "the directory to write the man pages.")
// For bash-completion
genmanCmd.PersistentFlags().SetAnnotation("dir", cobra.BashCompSubdirsInDir, []string{})
cc.cmd.PersistentFlags().SetAnnotation("dir", cobra.BashCompSubdirsInDir, []string{})
return cc
}
+72
View File
@@ -0,0 +1,72 @@
// Copyright 2018 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package commands defines and implements command-line commands and flags
// used by Hugo. Commands and flags are implemented using Cobra.
package commands
import (
"fmt"
"regexp"
"github.com/gohugoio/hugo/config"
"github.com/spf13/cobra"
)
type flagsToConfigHandler interface {
flagsToConfig(cfg config.Provider)
}
type cmder interface {
flagsToConfigHandler
getCommand() *cobra.Command
}
// commandError is an error used to signal different error situations in command handling.
type commandError struct {
s string
userError bool
}
func (c commandError) Error() string {
return c.s
}
func (c commandError) isUserError() bool {
return c.userError
}
func newUserError(a ...interface{}) commandError {
return commandError{s: fmt.Sprintln(a...), userError: true}
}
func newSystemError(a ...interface{}) commandError {
return commandError{s: fmt.Sprintln(a...), userError: false}
}
func newSystemErrorF(format string, a ...interface{}) commandError {
return commandError{s: fmt.Sprintf(format, a...), userError: false}
}
// Catch some of the obvious user errors from Cobra.
// We don't want to show the usage message for every error.
// The below may be to generic. Time will show.
var userErrorRegexp = regexp.MustCompile("argument|flag|shorthand")
func isUserError(err error) bool {
if cErr, ok := err.(commandError); ok && cErr.isUserError() {
return true
}
return userErrorRegexp.MatchString(err.Error())
}
+23
View File
@@ -0,0 +1,23 @@
// Copyright 2018 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// +build !windows
package commands
const (
ansiEsc = "\u001B"
clearLine = "\r\033[K"
hideCursor = ansiEsc + "[?25l"
showCursor = ansiEsc + "[?25h"
)
+23
View File
@@ -0,0 +1,23 @@
// Copyright 2018 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// +build windows
package commands
const (
ansiEsc = ""
clearLine = ""
hideCursor = ""
showCursor = ""
)
+295 -563
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -23,5 +23,5 @@ func init() {
You need to open cmd.exe and run Hugo from there.
Visit http://gohugo.io/ for more information.`
Visit https://gohugo.io/ for more information.`
}
+38 -29
View File
@@ -35,33 +35,42 @@ import (
jww "github.com/spf13/jwalterweatherman"
)
func init() {
importCmd.AddCommand(importJekyllCmd)
var _ cmder = (*importCmd)(nil)
type importCmd struct {
*baseCmd
}
var importCmd = &cobra.Command{
Use: "import",
Short: "Import your site from others.",
Long: `Import your site from other web site generators like Jekyll.
func newImportCmd() *importCmd {
cc := &importCmd{}
cc.baseCmd = newBaseCmd(&cobra.Command{
Use: "import",
Short: "Import your site from others.",
Long: `Import your site from other web site generators like Jekyll.
Import requires a subcommand, e.g. ` + "`hugo import jekyll jekyll_root_path target_path`.",
RunE: nil,
}
RunE: nil,
})
var importJekyllCmd = &cobra.Command{
Use: "jekyll",
Short: "hugo import from Jekyll",
Long: `hugo import from Jekyll.
importJekyllCmd := &cobra.Command{
Use: "jekyll",
Short: "hugo import from Jekyll",
Long: `hugo import from Jekyll.
Import from Jekyll requires two paths, e.g. ` + "`hugo import jekyll jekyll_root_path target_path`.",
RunE: importFromJekyll,
}
RunE: cc.importFromJekyll,
}
func init() {
importJekyllCmd.Flags().Bool("force", false, "allow import into non-empty target directory")
cc.cmd.AddCommand(importJekyllCmd)
return cc
}
func importFromJekyll(cmd *cobra.Command, args []string) error {
func (i *importCmd) importFromJekyll(cmd *cobra.Command, args []string) error {
if len(args) < 2 {
return newUserError(`Import from Jekyll requires two paths, e.g. ` + "`hugo import jekyll jekyll_root_path target_path`.")
@@ -86,12 +95,12 @@ func importFromJekyll(cmd *cobra.Command, args []string) error {
forceImport, _ := cmd.Flags().GetBool("force")
fs := afero.NewOsFs()
jekyllPostDirs, hasAnyPost := getJekyllDirInfo(fs, jekyllRoot)
jekyllPostDirs, hasAnyPost := i.getJekyllDirInfo(fs, jekyllRoot)
if !hasAnyPost {
return errors.New("Your Jekyll root contains neither posts nor drafts, aborting.")
}
site, err := createSiteFromJekyll(jekyllRoot, targetDir, jekyllPostDirs, forceImport)
site, err := i.createSiteFromJekyll(jekyllRoot, targetDir, jekyllPostDirs, forceImport)
if err != nil {
return newUserError(err)
@@ -147,14 +156,14 @@ func importFromJekyll(cmd *cobra.Command, args []string) error {
return nil
}
func getJekyllDirInfo(fs afero.Fs, jekyllRoot string) (map[string]bool, bool) {
func (i *importCmd) getJekyllDirInfo(fs afero.Fs, jekyllRoot string) (map[string]bool, bool) {
postDirs := make(map[string]bool)
hasAnyPost := false
if entries, err := ioutil.ReadDir(jekyllRoot); err == nil {
for _, entry := range entries {
if entry.IsDir() {
subDir := filepath.Join(jekyllRoot, entry.Name())
if isPostDir, hasAnyPostInDir := retrieveJekyllPostDir(fs, subDir); isPostDir {
if isPostDir, hasAnyPostInDir := i.retrieveJekyllPostDir(fs, subDir); isPostDir {
postDirs[entry.Name()] = hasAnyPostInDir
if hasAnyPostInDir {
hasAnyPost = true
@@ -166,7 +175,7 @@ func getJekyllDirInfo(fs afero.Fs, jekyllRoot string) (map[string]bool, bool) {
return postDirs, hasAnyPost
}
func retrieveJekyllPostDir(fs afero.Fs, dir string) (bool, bool) {
func (i *importCmd) retrieveJekyllPostDir(fs afero.Fs, dir string) (bool, bool) {
if strings.HasSuffix(dir, "_posts") || strings.HasSuffix(dir, "_drafts") {
isEmpty, _ := helpers.IsEmpty(dir, fs)
return true, !isEmpty
@@ -176,7 +185,7 @@ func retrieveJekyllPostDir(fs afero.Fs, dir string) (bool, bool) {
for _, entry := range entries {
if entry.IsDir() {
subDir := filepath.Join(dir, entry.Name())
if isPostDir, hasAnyPost := retrieveJekyllPostDir(fs, subDir); isPostDir {
if isPostDir, hasAnyPost := i.retrieveJekyllPostDir(fs, subDir); isPostDir {
return isPostDir, hasAnyPost
}
}
@@ -186,7 +195,7 @@ func retrieveJekyllPostDir(fs afero.Fs, dir string) (bool, bool) {
return false, true
}
func 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) (*hugolib.Site, error) {
s, err := hugolib.NewSiteDefaultLang()
if err != nil {
return nil, err
@@ -205,7 +214,7 @@ func createSiteFromJekyll(jekyllRoot, targetDir string, jekyllPostDirs map[strin
}
}
jekyllConfig := loadJekyllConfig(fs, jekyllRoot)
jekyllConfig := i.loadJekyllConfig(fs, jekyllRoot)
mkdir(targetDir, "layouts")
mkdir(targetDir, "content")
@@ -214,14 +223,14 @@ func createSiteFromJekyll(jekyllRoot, targetDir string, jekyllPostDirs map[strin
mkdir(targetDir, "data")
mkdir(targetDir, "themes")
createConfigFromJekyll(fs, targetDir, "yaml", jekyllConfig)
i.createConfigFromJekyll(fs, targetDir, "yaml", jekyllConfig)
copyJekyllFilesAndFolders(jekyllRoot, filepath.Join(targetDir, "static"), jekyllPostDirs)
i.copyJekyllFilesAndFolders(jekyllRoot, filepath.Join(targetDir, "static"), jekyllPostDirs)
return s, nil
}
func loadJekyllConfig(fs afero.Fs, jekyllRoot string) map[string]interface{} {
func (i *importCmd) loadJekyllConfig(fs afero.Fs, jekyllRoot string) map[string]interface{} {
path := filepath.Join(jekyllRoot, "_config.yml")
exists, err := helpers.Exists(path, fs)
@@ -253,7 +262,7 @@ func loadJekyllConfig(fs afero.Fs, jekyllRoot string) map[string]interface{} {
return c
}
func createConfigFromJekyll(fs afero.Fs, inpath string, kind string, jekyllConfig map[string]interface{}) (err error) {
func (i *importCmd) createConfigFromJekyll(fs afero.Fs, inpath string, kind string, jekyllConfig map[string]interface{}) (err error) {
title := "My New Hugo Site"
baseURL := "http://example.org/"
@@ -348,7 +357,7 @@ func copyDir(source string, dest string) error {
return nil
}
func copyJekyllFilesAndFolders(jekyllRoot, dest string, jekyllPostDirs map[string]bool) (err error) {
func (i *importCmd) copyJekyllFilesAndFolders(jekyllRoot, dest string, jekyllPostDirs map[string]bool) (err error) {
fi, err := os.Stat(jekyllRoot)
if err != nil {
return err
+34 -41
View File
@@ -1,17 +1,4 @@
// Copyright 2015 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.
// Copyright 2015 The Hugo Authors. All rights reserved.
// Copyright 2018 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -33,39 +20,45 @@ import (
jww "github.com/spf13/jwalterweatherman"
)
func init() {
checkCmd.AddCommand(limit)
var _ cmder = (*limitCmd)(nil)
type limitCmd struct {
*baseCmd
}
var limit = &cobra.Command{
Use: "ulimit",
Short: "Check system ulimit settings",
Long: `Hugo will inspect the current ulimit settings on the system.
func newLimitCmd() *limitCmd {
ccmd := &cobra.Command{
Use: "ulimit",
Short: "Check system ulimit settings",
Long: `Hugo will inspect the current ulimit settings on the system.
This is primarily to ensure that Hugo can watch enough files on some OSs`,
RunE: func(cmd *cobra.Command, args []string) error {
var rLimit syscall.Rlimit
err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit)
if err != nil {
return newSystemError("Error Getting Rlimit ", err)
}
RunE: func(cmd *cobra.Command, args []string) error {
var rLimit syscall.Rlimit
err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit)
if err != nil {
return newSystemError("Error Getting Rlimit ", err)
}
jww.FEEDBACK.Println("Current rLimit:", rLimit)
jww.FEEDBACK.Println("Current rLimit:", rLimit)
jww.FEEDBACK.Println("Attempting to increase limit")
rLimit.Max = 999999
rLimit.Cur = 999999
err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rLimit)
if err != nil {
return newSystemError("Error Setting rLimit ", err)
}
err = syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit)
if err != nil {
return newSystemError("Error Getting rLimit ", err)
}
jww.FEEDBACK.Println("rLimit after change:", rLimit)
jww.FEEDBACK.Println("Attempting to increase limit")
rLimit.Max = 999999
rLimit.Cur = 999999
err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rLimit)
if err != nil {
return newSystemError("Error Setting rLimit ", err)
}
err = syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit)
if err != nil {
return newSystemError("Error Getting rLimit ", err)
}
jww.FEEDBACK.Println("rLimit after change:", rLimit)
return nil
},
return nil
},
}
return &limitCmd{baseCmd: newBaseCmd(ccmd)}
}
func tweakLimit() {
+1 -13
View File
@@ -1,4 +1,4 @@
// Copyright 2015 The Hugo Authors. All rights reserved.
// Copyright 2018 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -12,18 +12,6 @@
// limitations under the License.
// +build !darwin
// Copyright 2015 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
+105 -97
View File
@@ -21,129 +21,137 @@ import (
jww "github.com/spf13/jwalterweatherman"
)
func init() {
listCmd.AddCommand(listDraftsCmd)
listCmd.AddCommand(listFutureCmd)
listCmd.AddCommand(listExpiredCmd)
listCmd.PersistentFlags().StringVarP(&source, "source", "s", "", "filesystem path to read files relative from")
listCmd.PersistentFlags().SetAnnotation("source", cobra.BashCompSubdirsInDir, []string{})
var _ cmder = (*listCmd)(nil)
type listCmd struct {
hugoBuilderCommon
*baseCmd
}
var listCmd = &cobra.Command{
Use: "list",
Short: "Listing out various types of content",
Long: `Listing out various types of content.
func newListCmd() *listCmd {
cc := &listCmd{}
cc.baseCmd = newBaseCmd(&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,
}
RunE: nil,
})
var listDraftsCmd = &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(false, cfgInit)
if err != nil {
return err
}
cc.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 := hugolib.NewHugoSites(*c.DepsCfg)
if err != nil {
return newSystemError("Error creating sites", err)
}
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)
}
if err := sites.Build(hugolib.BuildCfg{SkipRender: true}); err != nil {
return newSystemError("Error Processing Source Content", err)
}
for _, p := range sites.Pages() {
if p.IsDraft() {
jww.FEEDBACK.Println(filepath.Join(p.File.Dir(), p.File.LogicalName()))
}
for _, p := range sites.Pages() {
if p.IsDraft() {
jww.FEEDBACK.Println(filepath.Join(p.File.Dir(), p.File.LogicalName()))
}
}
}
return nil
return nil
},
}
var listFutureCmd = &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
},
},
&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.`,
RunE: func(cmd *cobra.Command, args []string) error {
cfgInit := func(c *commandeer) error {
c.Set("buildFuture", true)
return nil
}
c, err := InitializeConfig(false, cfgInit)
if err != nil {
return err
}
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 := hugolib.NewHugoSites(*c.DepsCfg)
if err != nil {
return newSystemError("Error creating sites", err)
}
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)
}
if err := sites.Build(hugolib.BuildCfg{SkipRender: true}); err != nil {
return newSystemError("Error Processing Source Content", err)
}
for _, p := range sites.Pages() {
if p.IsFuture() {
jww.FEEDBACK.Println(filepath.Join(p.File.Dir(), p.File.LogicalName()))
}
for _, p := range sites.Pages() {
if p.IsFuture() {
jww.FEEDBACK.Println(filepath.Join(p.File.Dir(), p.File.LogicalName()))
}
}
}
return nil
return nil
},
}
var listExpiredCmd = &cobra.Command{
Use: "expired",
Short: "List all posts already expired",
Long: `List all of the posts in your content directory which has already
},
},
&cobra.Command{
Use: "expired",
Short: "List all posts 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(false, cfgInit)
if err != nil {
return err
}
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 := hugolib.NewHugoSites(*c.DepsCfg)
if err != nil {
return newSystemError("Error creating sites", err)
}
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)
}
if err := sites.Build(hugolib.BuildCfg{SkipRender: true}); err != nil {
return newSystemError("Error Processing Source Content", err)
}
for _, p := range sites.Pages() {
if p.IsExpired() {
jww.FEEDBACK.Println(filepath.Join(p.File.Dir(), p.File.LogicalName()))
}
for _, p := range sites.Pages() {
if p.IsExpired() {
jww.FEEDBACK.Println(filepath.Join(p.File.Dir(), p.File.LogicalName()))
}
}
}
return nil
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{})
return cc
}
+34 -272
View File
@@ -1,4 +1,4 @@
// Copyright 2016 The Hugo Authors. All rights reserved.
// Copyright 2018 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -15,85 +15,63 @@ package commands
import (
"bytes"
"errors"
"fmt"
"os"
"path/filepath"
"strings"
"time"
"github.com/gohugoio/hugo/create"
"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/cobra"
jww "github.com/spf13/jwalterweatherman"
"github.com/spf13/viper"
)
var (
configFormat string
var _ cmder = (*newCmd)(nil)
type newCmd struct {
hugoBuilderCommon
contentEditor string
contentType string
)
func init() {
newSiteCmd.Flags().StringVarP(&configFormat, "format", "f", "toml", "config & frontmatter format")
newSiteCmd.Flags().Bool("force", false, "init inside non-empty directory")
newCmd.Flags().StringVarP(&contentType, "kind", "k", "", "content type to create")
newCmd.PersistentFlags().StringVarP(&source, "source", "s", "", "filesystem path to read files relative from")
newCmd.PersistentFlags().SetAnnotation("source", cobra.BashCompSubdirsInDir, []string{})
newCmd.Flags().StringVar(&contentEditor, "editor", "", "edit new content with this editor, if provided")
newCmd.AddCommand(newSiteCmd)
newCmd.AddCommand(newThemeCmd)
*baseCmd
}
var newCmd = &cobra.Command{
Use: "new [path]",
Short: "Create new content for your site",
Long: `Create a new content file and automatically set the date and title.
func newNewCmd() *newCmd {
cc := &newCmd{}
cc.baseCmd = newBaseCmd(&cobra.Command{
Use: "new [path]",
Short: "Create new content for your site",
Long: `Create a new content file and automatically set the date and title.
It will guess which kind of file to create based on the path provided.
You can also specify the kind with ` + "`-k KIND`" + `.
If archetypes are provided in your theme or site, they will be used.`,
RunE: NewContent,
RunE: cc.newContent,
})
cc.cmd.Flags().StringVarP(&cc.contentType, "kind", "k", "", "content type to create")
cc.cmd.PersistentFlags().StringVarP(&cc.source, "source", "s", "", "filesystem path to read files relative from")
cc.cmd.PersistentFlags().SetAnnotation("source", cobra.BashCompSubdirsInDir, []string{})
cc.cmd.Flags().StringVar(&cc.contentEditor, "editor", "", "edit new content with this editor, if provided")
cc.cmd.AddCommand(newNewSiteCmd().getCommand())
cc.cmd.AddCommand(newNewThemeCmd().getCommand())
return cc
}
var newSiteCmd = &cobra.Command{
Use: "site [path]",
Short: "Create a new site (skeleton)",
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: NewSite,
}
var newThemeCmd = &cobra.Command{
Use: "theme [name]",
Short: "Create a new theme",
Long: `Create a new theme (skeleton) called [name] in the current directory.
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: NewTheme,
}
// NewContent adds new content to a Hugo site.
func NewContent(cmd *cobra.Command, args []string) error {
func (n *newCmd) newContent(cmd *cobra.Command, args []string) error {
cfgInit := func(c *commandeer) error {
if cmd.Flags().Changed("editor") {
c.Set("newContentEditor", contentEditor)
c.Set("newContentEditor", n.contentEditor)
}
return nil
}
c, err := InitializeConfig(false, cfgInit)
c, err := initializeConfig(true, false, &n.hugoBuilderCommon, n, cfgInit)
if err != nil {
return err
@@ -109,8 +87,8 @@ func NewContent(cmd *cobra.Command, args []string) error {
createPath, kind = newContentPathSection(createPath)
if contentType != "" {
kind = contentType
if n.contentType != "" {
kind = n.contentType
}
cfg := c.DepsCfg
@@ -126,19 +104,16 @@ func NewContent(cmd *cobra.Command, args []string) error {
return hugolib.NewSite(*cfg)
}
var s *hugolib.Site
if err := c.initSites(); err != nil {
if err := c.hugo.Build(hugolib.BuildCfg{SkipRender: true}); err != nil {
return nil, err
}
if err := Hugo.Build(hugolib.BuildCfg{SkipRender: true}); err != nil {
return nil, err
}
s = c.hugo.Sites[0]
s = Hugo.Sites[0]
if len(Hugo.Sites) > 1 {
if len(c.hugo.Sites) > 1 {
// Find the best match.
for _, ss := range Hugo.Sites {
for _, ss := range c.hugo.Sites {
if strings.Contains(createPath, "."+ss.Language.Lang) {
s = ss
break
@@ -151,169 +126,6 @@ func NewContent(cmd *cobra.Command, args []string) error {
return create.NewContent(ps, siteFactory, kind, createPath)
}
func doNewSite(fs *hugofs.Fs, basepath string, force bool) error {
archeTypePath := filepath.Join(basepath, "archetypes")
dirs := []string{
filepath.Join(basepath, "layouts"),
filepath.Join(basepath, "content"),
archeTypePath,
filepath.Join(basepath, "static"),
filepath.Join(basepath, "data"),
filepath.Join(basepath, "themes"),
}
if exists, _ := helpers.Exists(basepath, fs.Source); exists {
if isDir, _ := helpers.IsDir(basepath, fs.Source); !isDir {
return errors.New(basepath + " already exists but not a directory")
}
isEmpty, _ := helpers.IsEmpty(basepath, fs.Source)
switch {
case !isEmpty && !force:
return errors.New(basepath + " already exists and is not empty")
case !isEmpty && force:
all := append(dirs, filepath.Join(basepath, "config."+configFormat))
for _, path := range all {
if exists, _ := helpers.Exists(path, fs.Source); exists {
return errors.New(path + " already exists")
}
}
}
}
for _, dir := range dirs {
if err := fs.Source.MkdirAll(dir, 0777); err != nil {
return fmt.Errorf("Failed to create dir: %s", err)
}
}
createConfig(fs, basepath, configFormat)
// Create a defaul archetype file.
helpers.SafeWriteToDisk(filepath.Join(archeTypePath, "default.md"),
strings.NewReader(create.ArchetypeTemplateTemplate), fs.Source)
jww.FEEDBACK.Printf("Congratulations! Your new Hugo site is created in %s.\n\n", basepath)
jww.FEEDBACK.Println(nextStepsText())
return nil
}
func nextStepsText() string {
var nextStepsText bytes.Buffer
nextStepsText.WriteString(`Just a few more steps and you're ready to go:
1. Download a theme into the same-named folder.
Choose a theme from https://themes.gohugo.io/, or
create your own with the "hugo new theme <THEMENAME>" command.
2. Perhaps you want to add some content. You can add single files
with "hugo new `)
nextStepsText.WriteString(filepath.Join("<SECTIONNAME>", "<FILENAME>.<FORMAT>"))
nextStepsText.WriteString(`".
3. Start the built-in live server via "hugo server".
Visit https://gohugo.io/ for quickstart guide and full documentation.`)
return nextStepsText.String()
}
// NewSite creates a new Hugo site and initializes a structured Hugo directory.
func NewSite(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return newUserError("path needs to be provided")
}
createpath, err := filepath.Abs(filepath.Clean(args[0]))
if err != nil {
return newUserError(err)
}
forceNew, _ := cmd.Flags().GetBool("force")
return doNewSite(hugofs.NewDefault(viper.New()), createpath, forceNew)
}
// NewTheme creates a new Hugo theme.
func NewTheme(cmd *cobra.Command, args []string) error {
c, err := InitializeConfig(false, nil)
if err != nil {
return err
}
if len(args) < 1 {
return newUserError("theme name needs to be provided")
}
createpath := c.PathSpec().AbsPathify(filepath.Join(c.Cfg.GetString("themesDir"), args[0]))
jww.INFO.Println("creating theme at", createpath)
cfg := c.DepsCfg
if x, _ := helpers.Exists(createpath, cfg.Fs.Source); x {
return newUserError(createpath, "already exists")
}
mkdir(createpath, "layouts", "_default")
mkdir(createpath, "layouts", "partials")
touchFile(cfg.Fs.Source, createpath, "layouts", "index.html")
touchFile(cfg.Fs.Source, createpath, "layouts", "404.html")
touchFile(cfg.Fs.Source, createpath, "layouts", "_default", "list.html")
touchFile(cfg.Fs.Source, createpath, "layouts", "_default", "single.html")
touchFile(cfg.Fs.Source, createpath, "layouts", "partials", "header.html")
touchFile(cfg.Fs.Source, createpath, "layouts", "partials", "footer.html")
mkdir(createpath, "archetypes")
archDefault := []byte("+++\n+++\n")
err = helpers.WriteToDisk(filepath.Join(createpath, "archetypes", "default.md"), bytes.NewReader(archDefault), cfg.Fs.Source)
if err != nil {
return err
}
mkdir(createpath, "static", "js")
mkdir(createpath, "static", "css")
by := []byte(`The MIT License (MIT)
Copyright (c) ` + time.Now().Format("2006") + ` YOUR_NAME_HERE
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
`)
err = helpers.WriteToDisk(filepath.Join(createpath, "LICENSE.md"), bytes.NewReader(by), cfg.Fs.Source)
if err != nil {
return err
}
createThemeMD(cfg.Fs, createpath)
return nil
}
func mkdir(x ...string) {
p := filepath.Join(x...)
@@ -332,39 +144,6 @@ func touchFile(fs afero.Fs, x ...string) {
}
}
func createThemeMD(fs *hugofs.Fs, inpath string) (err error) {
by := []byte(`# theme.toml template for a Hugo theme
# See https://github.com/gohugoio/hugoThemes#themetoml for an example
name = "` + strings.Title(helpers.MakeTitle(filepath.Base(inpath))) + `"
license = "MIT"
licenselink = "https://github.com/yourname/yourtheme/blob/master/LICENSE.md"
description = ""
homepage = "http://example.com/"
tags = []
features = []
min_version = "0.37"
[author]
name = ""
homepage = ""
# If porting an existing theme
[original]
name = ""
homepage = ""
repo = ""
`)
err = helpers.WriteToDisk(filepath.Join(inpath, "theme.toml"), bytes.NewReader(by), fs.Source)
if err != nil {
return
}
return nil
}
func newContentPathSection(path string) (string, string) {
// Forward slashes is used in all examples. Convert if needed.
// Issue #1133
@@ -381,20 +160,3 @@ func newContentPathSection(path string) (string, string) {
return createpath, section
}
func createConfig(fs *hugofs.Fs, inpath string, kind string) (err error) {
in := map[string]string{
"baseURL": "http://example.org/",
"title": "My New Hugo Site",
"languageCode": "en-us",
}
kind = parser.FormatSanitize(kind)
var buf bytes.Buffer
err = parser.InterfaceToConfig(in, parser.FormatToLeadRune(kind), &buf)
if err != nil {
return err
}
return helpers.WriteToDisk(filepath.Join(inpath, "config."+kind), &buf, fs.Source)
}
@@ -1,4 +1,4 @@
// Copyright 2016 The Hugo Authors. All rights reserved.
// Copyright 2018 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -48,10 +48,11 @@ func checkNewSiteInited(fs *hugofs.Fs, basepath string, t *testing.T) {
}
func TestDoNewSite(t *testing.T) {
n := newNewSiteCmd()
basepath := filepath.Join("base", "blog")
_, fs := newTestCfg()
require.NoError(t, doNewSite(fs, basepath, false))
require.NoError(t, n.doNewSite(fs, basepath, false))
checkNewSiteInited(fs, basepath, t)
}
@@ -59,31 +60,34 @@ func TestDoNewSite(t *testing.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, 777))
require.NoError(t, doNewSite(fs, basepath, false))
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, 777))
_, 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, doNewSite(fs, basepath, false))
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, 777))
require.NoError(t, doNewSite(fs, basepath, true))
require.NoError(t, n.doNewSite(fs, basepath, true))
checkNewSiteInited(fs, basepath, t)
}
@@ -91,23 +95,25 @@ func TestDoNewSite_force_empty_dir(t *testing.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, 777))
require.Error(t, doNewSite(fs, basepath, true))
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, 777))
_, err := fs.Source.Create(configPath)
require.NoError(t, err)
require.Error(t, doNewSite(fs, basepath, true))
require.Error(t, n.doNewSite(fs, basepath, true))
}
func newTestCfg() (*viper.Viper, *hugofs.Fs) {
+163
View File
@@ -0,0 +1,163 @@
// Copyright 2018 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package commands
import (
"bytes"
"errors"
"fmt"
"path/filepath"
"strings"
"github.com/gohugoio/hugo/create"
"github.com/gohugoio/hugo/helpers"
"github.com/gohugoio/hugo/hugofs"
"github.com/gohugoio/hugo/parser"
"github.com/spf13/cobra"
jww "github.com/spf13/jwalterweatherman"
"github.com/spf13/viper"
)
var _ cmder = (*newSiteCmd)(nil)
type newSiteCmd struct {
configFormat string
*baseCmd
}
func newNewSiteCmd() *newSiteCmd {
ccmd := &newSiteCmd{}
cmd := &cobra.Command{
Use: "site [path]",
Short: "Create a new site (skeleton)",
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,
}
cmd.Flags().StringVarP(&ccmd.configFormat, "format", "f", "toml", "config & frontmatter format")
cmd.Flags().Bool("force", false, "init inside non-empty directory")
ccmd.baseCmd = newBaseCmd(cmd)
return ccmd
}
func (n *newSiteCmd) doNewSite(fs *hugofs.Fs, basepath string, force bool) error {
archeTypePath := filepath.Join(basepath, "archetypes")
dirs := []string{
filepath.Join(basepath, "layouts"),
filepath.Join(basepath, "content"),
archeTypePath,
filepath.Join(basepath, "static"),
filepath.Join(basepath, "data"),
filepath.Join(basepath, "themes"),
}
if exists, _ := helpers.Exists(basepath, fs.Source); exists {
if isDir, _ := helpers.IsDir(basepath, fs.Source); !isDir {
return errors.New(basepath + " already exists but not a directory")
}
isEmpty, _ := helpers.IsEmpty(basepath, fs.Source)
switch {
case !isEmpty && !force:
return errors.New(basepath + " already exists and is not empty")
case !isEmpty && force:
all := append(dirs, filepath.Join(basepath, "config."+n.configFormat))
for _, path := range all {
if exists, _ := helpers.Exists(path, fs.Source); exists {
return errors.New(path + " already exists")
}
}
}
}
for _, dir := range dirs {
if err := fs.Source.MkdirAll(dir, 0777); err != nil {
return fmt.Errorf("Failed to create dir: %s", err)
}
}
createConfig(fs, basepath, n.configFormat)
// Create a default archetype file.
helpers.SafeWriteToDisk(filepath.Join(archeTypePath, "default.md"),
strings.NewReader(create.ArchetypeTemplateTemplate), fs.Source)
jww.FEEDBACK.Printf("Congratulations! Your new Hugo site is created in %s.\n\n", basepath)
jww.FEEDBACK.Println(nextStepsText())
return nil
}
// newSite creates a new Hugo site and initializes a structured Hugo directory.
func (n *newSiteCmd) newSite(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return newUserError("path needs to be provided")
}
createpath, err := filepath.Abs(filepath.Clean(args[0]))
if err != nil {
return newUserError(err)
}
forceNew, _ := cmd.Flags().GetBool("force")
return n.doNewSite(hugofs.NewDefault(viper.New()), createpath, forceNew)
}
func createConfig(fs *hugofs.Fs, inpath string, kind string) (err error) {
in := map[string]string{
"baseURL": "http://example.org/",
"title": "My New Hugo Site",
"languageCode": "en-us",
}
kind = parser.FormatSanitize(kind)
var buf bytes.Buffer
err = parser.InterfaceToConfig(in, parser.FormatToLeadRune(kind), &buf)
if err != nil {
return err
}
return helpers.WriteToDisk(filepath.Join(inpath, "config."+kind), &buf, fs.Source)
}
func nextStepsText() string {
var nextStepsText bytes.Buffer
nextStepsText.WriteString(`Just a few more steps and you're ready to go:
1. Download a theme into the same-named folder.
Choose a theme from https://themes.gohugo.io/, or
create your own with the "hugo new theme <THEMENAME>" command.
2. Perhaps you want to add some content. You can add single files
with "hugo new `)
nextStepsText.WriteString(filepath.Join("<SECTIONNAME>", "<FILENAME>.<FORMAT>"))
nextStepsText.WriteString(`".
3. Start the built-in live server via "hugo server".
Visit https://gohugo.io/ for quickstart guide and full documentation.`)
return nextStepsText.String()
}
+179
View File
@@ -0,0 +1,179 @@
// Copyright 2018 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package commands
import (
"bytes"
"errors"
"path/filepath"
"strings"
"time"
"github.com/gohugoio/hugo/helpers"
"github.com/gohugoio/hugo/hugofs"
"github.com/spf13/cobra"
jww "github.com/spf13/jwalterweatherman"
)
var _ cmder = (*newThemeCmd)(nil)
type newThemeCmd struct {
*baseCmd
hugoBuilderCommon
}
func newNewThemeCmd() *newThemeCmd {
ccmd := &newThemeCmd{baseCmd: newBaseCmd(nil)}
cmd := &cobra.Command{
Use: "theme [name]",
Short: "Create a new theme",
Long: `Create a new theme (skeleton) called [name] in the current directory.
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,
}
ccmd.cmd = cmd
return ccmd
}
// newTheme creates a new Hugo theme template
func (n *newThemeCmd) newTheme(cmd *cobra.Command, args []string) error {
c, err := initializeConfig(false, false, &n.hugoBuilderCommon, n, nil)
if err != nil {
return err
}
if len(args) < 1 {
return newUserError("theme name needs to be provided")
}
createpath := c.hugo.PathSpec.AbsPathify(filepath.Join(c.Cfg.GetString("themesDir"), args[0]))
jww.FEEDBACK.Println("Creating theme at", createpath)
cfg := c.DepsCfg
if x, _ := helpers.Exists(createpath, cfg.Fs.Source); x {
return errors.New(createpath + " already exists")
}
mkdir(createpath, "layouts", "_default")
mkdir(createpath, "layouts", "partials")
touchFile(cfg.Fs.Source, createpath, "layouts", "index.html")
touchFile(cfg.Fs.Source, createpath, "layouts", "404.html")
touchFile(cfg.Fs.Source, createpath, "layouts", "_default", "list.html")
touchFile(cfg.Fs.Source, createpath, "layouts", "_default", "single.html")
baseofDefault := []byte(`<!DOCTYPE html>
<html>
{{- partial "head.html" . -}}
<body>
{{- partial "header.html" . -}}
<div id="content">
{{- block "main" . }}{{- end }}
</div>
{{- partial "footer.html" . -}}
</body>
</html>
`)
err = helpers.WriteToDisk(filepath.Join(createpath, "layouts", "_default", "baseof.html"), bytes.NewReader(baseofDefault), cfg.Fs.Source)
if err != nil {
return err
}
touchFile(cfg.Fs.Source, createpath, "layouts", "partials", "head.html")
touchFile(cfg.Fs.Source, createpath, "layouts", "partials", "header.html")
touchFile(cfg.Fs.Source, createpath, "layouts", "partials", "footer.html")
mkdir(createpath, "archetypes")
archDefault := []byte("+++\n+++\n")
err = helpers.WriteToDisk(filepath.Join(createpath, "archetypes", "default.md"), bytes.NewReader(archDefault), cfg.Fs.Source)
if err != nil {
return err
}
mkdir(createpath, "static", "js")
mkdir(createpath, "static", "css")
by := []byte(`The MIT License (MIT)
Copyright (c) ` + time.Now().Format("2006") + ` YOUR_NAME_HERE
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
`)
err = helpers.WriteToDisk(filepath.Join(createpath, "LICENSE"), bytes.NewReader(by), cfg.Fs.Source)
if err != nil {
return err
}
n.createThemeMD(cfg.Fs, createpath)
return nil
}
func (n *newThemeCmd) createThemeMD(fs *hugofs.Fs, inpath string) (err error) {
by := []byte(`# theme.toml template for a Hugo theme
# See https://github.com/gohugoio/hugoThemes#themetoml for an example
name = "` + strings.Title(helpers.MakeTitle(filepath.Base(inpath))) + `"
license = "MIT"
licenselink = "https://github.com/yourname/yourtheme/blob/master/LICENSE"
description = ""
homepage = "http://example.com/"
tags = []
features = []
min_version = "0.41"
[author]
name = ""
homepage = ""
# If porting an existing theme
[original]
name = ""
homepage = ""
repo = ""
`)
err = helpers.WriteToDisk(filepath.Join(inpath, "theme.toml"), bytes.NewReader(by), fs.Source)
if err != nil {
return
}
return nil
}
+11 -4
View File
@@ -18,13 +18,12 @@ package commands
import (
"errors"
"github.com/gohugoio/hugo/config"
"github.com/gohugoio/hugo/releaser"
"github.com/spf13/cobra"
)
func init() {
HugoCmd.AddCommand(createReleaser().cmd)
}
var _ cmder = (*releaseCommandeer)(nil)
type releaseCommandeer struct {
cmd *cobra.Command
@@ -35,7 +34,7 @@ type releaseCommandeer struct {
try bool
}
func createReleaser() *releaseCommandeer {
func createReleaser() cmder {
// Note: This is a command only meant for internal use and must be run
// via "go run -tags release main.go release" on the actual code base that is in the release.
r := &releaseCommandeer{
@@ -57,6 +56,14 @@ func createReleaser() *releaseCommandeer {
return r
}
func (c *releaseCommandeer) getCommand() *cobra.Command {
return c.cmd
}
func (c *releaseCommandeer) flagsToConfig(cfg config.Provider) {
}
func (r *releaseCommandeer) release() error {
if r.version == "" {
return errors.New("must set the --rel flag to the relevant version number")
+20
View File
@@ -0,0 +1,20 @@
// +build !release
// Copyright 2018 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package commands
func createReleaser() cmder {
return &nilCommand{}
}
+122 -91
View File
@@ -1,4 +1,4 @@
// Copyright 2016 The Hugo Authors. All rights reserved.
// Copyright 2018 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -24,6 +24,7 @@ import (
"runtime"
"strconv"
"strings"
"sync"
"syscall"
"time"
@@ -37,7 +38,10 @@ import (
jww "github.com/spf13/jwalterweatherman"
)
var (
type serverCmd struct {
// Can be used to stop the server. Useful in tests
stop <-chan bool
disableLiveReload bool
navigateToChanged bool
renderToDisk bool
@@ -49,13 +53,22 @@ var (
noHTTPCache bool
disableFastRender bool
)
var serverCmd = &cobra.Command{
Use: "server",
Aliases: []string{"serve"},
Short: "A high performance webserver",
Long: `Hugo provides its own webserver which builds and serves the site.
*baseBuilderCmd
}
func (b *commandsBuilder) newServerCmd() *serverCmd {
return b.newServerCmdSignaled(nil)
}
func (b *commandsBuilder) newServerCmdSignaled(stop <-chan bool) *serverCmd {
cc := &serverCmd{stop: stop}
cc.baseBuilderCmd = b.newBuilderCmd(&cobra.Command{
Use: "server",
Aliases: []string{"serve"},
Short: "A high performance webserver",
Long: `Hugo provides its own webserver which builds and serves the site.
While hugo server is high performance, it is a webserver with limited options.
Many run it in production, but the standard behavior is for people to use it
in development and use a more full featured server such as Nginx or Caddy.
@@ -67,7 +80,24 @@ By default hugo will also watch your files for any changes you make and
automatically rebuild the site. It will then live reload any open browser pages
and push the latest content to them. As most Hugo sites are built in a fraction
of a second, you will be able to save and see your changes nearly instantly.`,
//RunE: server,
RunE: cc.server,
})
cc.cmd.Flags().IntVarP(&cc.serverPort, "port", "p", 1313, "port on which the server will listen")
cc.cmd.Flags().IntVar(&cc.liveReloadPort, "liveReloadPort", -1, "port for live reloading (i.e. 443 in HTTPS proxy situations)")
cc.cmd.Flags().StringVarP(&cc.serverInterface, "bind", "", "127.0.0.1", "interface to which the server will bind")
cc.cmd.Flags().BoolVarP(&cc.serverWatch, "watch", "w", true, "watch filesystem for changes and recreate as needed")
cc.cmd.Flags().BoolVar(&cc.noHTTPCache, "noHTTPCache", false, "prevent HTTP caching")
cc.cmd.Flags().BoolVarP(&cc.serverAppend, "appendPort", "", true, "append port to baseURL")
cc.cmd.Flags().BoolVar(&cc.disableLiveReload, "disableLiveReload", false, "watch without enabling live browser reload on rebuild")
cc.cmd.Flags().BoolVar(&cc.navigateToChanged, "navigateToChanged", false, "navigate to changed content file on live browser reload")
cc.cmd.Flags().BoolVar(&cc.renderToDisk, "renderToDisk", false, "render to Destination path (default is render to memory & serve from there)")
cc.cmd.Flags().BoolVar(&cc.disableFastRender, "disableFastRender", false, "enables full re-renders on changes")
cc.cmd.Flags().String("memstats", "", "log memory usage to this file")
cc.cmd.Flags().String("meminterval", "100ms", "interval to poll memory usage (requires --memstats), valid time units are \"ns\", \"us\" (or \"µs\"), \"ms\", \"s\", \"m\", \"h\".")
return cc
}
type filesOnlyFs struct {
@@ -90,85 +120,79 @@ func (f noDirFile) Readdir(count int) ([]os.FileInfo, error) {
return nil, nil
}
func init() {
initHugoBuilderFlags(serverCmd)
var serverPorts []int
serverCmd.Flags().IntVarP(&serverPort, "port", "p", 1313, "port on which the server will listen")
serverCmd.Flags().IntVar(&liveReloadPort, "liveReloadPort", -1, "port for live reloading (i.e. 443 in HTTPS proxy situations)")
serverCmd.Flags().StringVarP(&serverInterface, "bind", "", "127.0.0.1", "interface to which the server will bind")
serverCmd.Flags().BoolVarP(&serverWatch, "watch", "w", true, "watch filesystem for changes and recreate as needed")
serverCmd.Flags().BoolVar(&noHTTPCache, "noHTTPCache", false, "prevent HTTP caching")
serverCmd.Flags().BoolVarP(&serverAppend, "appendPort", "", true, "append port to baseURL")
serverCmd.Flags().BoolVar(&disableLiveReload, "disableLiveReload", false, "watch without enabling live browser reload on rebuild")
serverCmd.Flags().BoolVar(&navigateToChanged, "navigateToChanged", false, "navigate to changed content file on live browser reload")
serverCmd.Flags().BoolVar(&renderToDisk, "renderToDisk", false, "render to Destination path (default is render to memory & serve from there)")
serverCmd.Flags().BoolVar(&disableFastRender, "disableFastRender", false, "enables full re-renders on changes")
serverCmd.Flags().String("memstats", "", "log memory usage to this file")
serverCmd.Flags().String("meminterval", "100ms", "interval to poll memory usage (requires --memstats), valid time units are \"ns\", \"us\" (or \"µs\"), \"ms\", \"s\", \"m\", \"h\".")
serverCmd.RunE = server
}
func server(cmd *cobra.Command, args []string) error {
func (s *serverCmd) server(cmd *cobra.Command, args []string) error {
// If a Destination is provided via flag write to disk
destination, _ := cmd.Flags().GetString("destination")
if destination != "" {
renderToDisk = true
s.renderToDisk = true
}
var serverCfgInit sync.Once
cfgInit := func(c *commandeer) error {
c.Set("renderToMemory", !renderToDisk)
c.Set("renderToMemory", !s.renderToDisk)
if cmd.Flags().Changed("navigateToChanged") {
c.Set("navigateToChanged", navigateToChanged)
c.Set("navigateToChanged", s.navigateToChanged)
}
if cmd.Flags().Changed("disableLiveReload") {
c.Set("disableLiveReload", disableLiveReload)
c.Set("disableLiveReload", s.disableLiveReload)
}
if cmd.Flags().Changed("disableFastRender") {
c.Set("disableFastRender", disableFastRender)
c.Set("disableFastRender", s.disableFastRender)
}
if serverWatch {
if s.serverWatch {
c.Set("watch", true)
}
serverPorts := make([]int, 1)
if c.languages.IsMultihost() {
if !serverAppend {
return newSystemError("--appendPort=false not supported when in multihost mode")
}
serverPorts = make([]int, len(c.languages))
// TODO(bep) yes, we should fix.
if !c.languagesConfigured {
return nil
}
currentServerPort := serverPort
var err error
for i := 0; i < len(serverPorts); i++ {
l, err := net.Listen("tcp", net.JoinHostPort(serverInterface, strconv.Itoa(currentServerPort)))
if err == nil {
l.Close()
serverPorts[i] = currentServerPort
} else {
if i == 0 && serverCmd.Flags().Changed("port") {
// port set explicitly by user -- he/she probably meant it!
return newSystemErrorF("Server startup failed: %s", err)
// We can only do this once.
serverCfgInit.Do(func() {
serverPorts = make([]int, 1)
if c.languages.IsMultihost() {
if !s.serverAppend {
err = newSystemError("--appendPort=false not supported when in multihost mode")
}
jww.ERROR.Println("port", serverPort, "already in use, attempting to use an available port")
sp, err := helpers.FindAvailablePort()
if err != nil {
return newSystemError("Unable to find alternative port to use:", err)
}
serverPorts[i] = sp.Port
serverPorts = make([]int, len(c.languages))
}
currentServerPort = serverPorts[i] + 1
}
currentServerPort := s.serverPort
for i := 0; i < len(serverPorts); i++ {
l, err := net.Listen("tcp", net.JoinHostPort(s.serverInterface, strconv.Itoa(currentServerPort)))
if err == nil {
l.Close()
serverPorts[i] = currentServerPort
} else {
if i == 0 && s.cmd.Flags().Changed("port") {
// port set explicitly by user -- he/she probably meant it!
err = newSystemErrorF("Server startup failed: %s", err)
}
jww.ERROR.Println("port", s.serverPort, "already in use, attempting to use an available port")
sp, err := helpers.FindAvailablePort()
if err != nil {
err = newSystemError("Unable to find alternative port to use:", err)
}
serverPorts[i] = sp.Port
}
currentServerPort = serverPorts[i] + 1
}
})
c.serverPorts = serverPorts
c.Set("port", serverPort)
if liveReloadPort != -1 {
c.Set("liveReloadPort", liveReloadPort)
c.Set("port", s.serverPort)
if s.liveReloadPort != -1 {
c.Set("liveReloadPort", s.liveReloadPort)
} else {
c.Set("liveReloadPort", serverPorts[0])
}
@@ -182,9 +206,9 @@ func server(cmd *cobra.Command, args []string) error {
serverPort = serverPorts[0]
}
baseURL, err := fixURL(language, baseURL, serverPort)
baseURL, err := s.fixURL(language, s.baseURL, serverPort)
if err != nil {
return err
return nil
}
if isMultiHost {
language.Set("baseURL", baseURL)
@@ -194,7 +218,7 @@ func server(cmd *cobra.Command, args []string) error {
}
}
return nil
return err
}
@@ -202,7 +226,7 @@ func server(cmd *cobra.Command, args []string) error {
jww.ERROR.Println("memstats error:", err)
}
c, err := InitializeConfig(true, cfgInit, serverCmd)
c, err := initializeConfig(true, true, &s.hugoBuilderCommon, s, cfgInit)
if err != nil {
return err
}
@@ -211,16 +235,12 @@ func server(cmd *cobra.Command, args []string) error {
return err
}
for _, s := range Hugo.Sites {
for _, s := range c.hugo.Sites {
s.RegisterMediaTypes()
}
if serverWatch {
c.watchConfig()
}
// Watch runs its own server as part of the routine
if serverWatch {
if s.serverWatch {
watchDirs, err := c.getDirList()
if err != nil {
@@ -246,7 +266,7 @@ func server(cmd *cobra.Command, args []string) error {
}
return c.serve()
return c.serve(s)
}
@@ -254,6 +274,7 @@ type fileServer struct {
baseURLs []string
roots []string
c *commandeer
s *serverCmd
}
func (f *fileServer) createEndpoint(i int) (*http.ServeMux, string, string, error) {
@@ -267,20 +288,20 @@ func (f *fileServer) createEndpoint(i int) (*http.ServeMux, string, string, erro
publishDir = filepath.Join(publishDir, root)
}
absPublishDir := f.c.PathSpec().AbsPathify(publishDir)
absPublishDir := f.c.hugo.PathSpec.AbsPathify(publishDir)
if i == 0 {
if renderToDisk {
if f.s.renderToDisk {
jww.FEEDBACK.Println("Serving pages from " + absPublishDir)
} else {
jww.FEEDBACK.Println("Serving pages from memory")
}
}
httpFs := afero.NewHttpFs(f.c.Fs.Destination)
httpFs := afero.NewHttpFs(f.c.destinationFs)
fs := filesOnlyFs{httpFs.Dir(absPublishDir)}
doLiveReload := !buildWatch && !f.c.Cfg.GetBool("disableLiveReload")
doLiveReload := !f.s.buildWatch && !f.c.Cfg.GetBool("disableLiveReload")
fastRenderMode := doLiveReload && !f.c.Cfg.GetBool("disableFastRender")
if i == 0 && fastRenderMode {
@@ -295,7 +316,7 @@ func (f *fileServer) createEndpoint(i int) (*http.ServeMux, string, string, erro
decorate := func(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if noHTTPCache {
if f.s.noHTTPCache {
w.Header().Set("Cache-Control", "no-store, no-cache, must-revalidate, max-age=0")
w.Header().Set("Pragma", "no-cache")
}
@@ -319,14 +340,14 @@ func (f *fileServer) createEndpoint(i int) (*http.ServeMux, string, string, erro
mu.Handle(u.Path, http.StripPrefix(u.Path, fileserver))
}
endpoint := net.JoinHostPort(serverInterface, strconv.Itoa(port))
endpoint := net.JoinHostPort(f.s.serverInterface, strconv.Itoa(port))
return mu, u.String(), endpoint, nil
}
func (c *commandeer) serve() error {
func (c *commandeer) serve(s *serverCmd) error {
isMultiHost := Hugo.IsMultihost()
isMultiHost := c.hugo.IsMultihost()
var (
baseURLs []string
@@ -334,12 +355,12 @@ func (c *commandeer) serve() error {
)
if isMultiHost {
for _, s := range Hugo.Sites {
for _, s := range c.hugo.Sites {
baseURLs = append(baseURLs, s.BaseURL.String())
roots = append(roots, s.Language.Lang)
}
} else {
s := Hugo.Sites[0]
s := c.hugo.Sites[0]
baseURLs = []string{s.BaseURL.String()}
roots = []string{""}
}
@@ -348,6 +369,7 @@ func (c *commandeer) serve() error {
baseURLs: baseURLs,
roots: roots,
c: c,
s: s,
}
doLiveReload := !c.Cfg.GetBool("disableLiveReload")
@@ -366,7 +388,7 @@ func (c *commandeer) serve() error {
mu.HandleFunc("/livereload.js", livereload.ServeJS)
mu.HandleFunc("/livereload", livereload.Handler)
}
jww.FEEDBACK.Printf("Web Server is available at %s (bind address %s)\n", serverURL, serverInterface)
jww.FEEDBACK.Printf("Web Server is available at %s (bind address %s)\n", serverURL, s.serverInterface)
go func() {
err = http.ListenAndServe(endpoint, mu)
if err != nil {
@@ -378,14 +400,21 @@ func (c *commandeer) serve() error {
jww.FEEDBACK.Println("Press Ctrl+C to stop")
<-sigs
if s.stop != nil {
select {
case <-sigs:
case <-s.stop:
}
} else {
<-sigs
}
return nil
}
// fixURL massages the baseURL into a form needed for serving
// all pages correctly.
func fixURL(cfg config.Provider, s string, port int) (string, error) {
func (sc *serverCmd) fixURL(cfg config.Provider, s string, port int) (string, error) {
useLocalhost := false
if s == "" {
s = cfg.GetString("baseURL")
@@ -420,7 +449,7 @@ func fixURL(cfg config.Provider, s string, port int) (string, error) {
u.Host = "localhost"
}
if serverAppend {
if sc.serverAppend {
if strings.Contains(u.Host, ":") {
u.Host, _, err = net.SplitHostPort(u.Host)
if err != nil {
@@ -434,9 +463,11 @@ func fixURL(cfg config.Provider, s string, port int) (string, error) {
}
func memStats() error {
memstats := serverCmd.Flags().Lookup("memstats").Value.String()
b := newCommandsBuilder()
sc := b.newServerCmd().getCommand()
memstats := sc.Flags().Lookup("memstats").Value.String()
if memstats != "" {
interval, err := time.ParseDuration(serverCmd.Flags().Lookup("meminterval").Value.String())
interval, err := time.ParseDuration(sc.Flags().Lookup("meminterval").Value.String())
if err != nil {
interval, _ = time.ParseDuration("100ms")
}
+64 -4
View File
@@ -14,11 +14,65 @@
package commands
import (
"fmt"
"net/http"
"os"
"runtime"
"testing"
"time"
"github.com/gohugoio/hugo/helpers"
"github.com/spf13/viper"
"github.com/stretchr/testify/require"
)
func TestServer(t *testing.T) {
if isWindowsCI() {
// 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)
assert.NoError(err)
// Let us hope that this port is available on all systems ...
port := 1331
defer func() {
os.RemoveAll(dir)
}()
stop := make(chan bool)
b := newCommandsBuilder()
scmd := b.newServerCmdSignaled(stop)
cmd := scmd.getCommand()
cmd.SetArgs([]string{"-s=" + dir, fmt.Sprintf("-p=%d", port)})
go func() {
_, err = cmd.ExecuteC()
assert.NoError(err)
}()
// There is no way to know exactly when the server is ready for connections.
// We could improve by something like https://golang.org/pkg/net/http/httptest/#Server
// But for now, let us sleep and pray!
time.Sleep(2 * time.Second)
resp, err := http.Get("http://localhost:1331/")
assert.NoError(err)
defer resp.Body.Close()
homeContent := helpers.ReaderToString(resp.Body)
assert.Contains(homeContent, "List: Hugo Commands")
// Stop the server.
stop <- true
}
func TestFixURL(t *testing.T) {
type data struct {
TestName string
@@ -42,12 +96,14 @@ func TestFixURL(t *testing.T) {
}
for i, test := range tests {
b := newCommandsBuilder()
s := b.newServerCmd()
v := viper.New()
baseURL = test.CLIBaseURL
baseURL := test.CLIBaseURL
v.Set("baseURL", test.CfgBaseURL)
serverAppend = test.AppendPort
serverPort = test.Port
result, err := fixURL(v, baseURL, serverPort)
s.serverAppend = test.AppendPort
s.serverPort = test.Port
result, err := s.fixURL(v, baseURL, s.serverPort)
if err != nil {
t.Errorf("Test #%d %s: unexpected error %s", i, test.TestName, err)
}
@@ -56,3 +112,7 @@ func TestFixURL(t *testing.T) {
}
}
}
func isWindowsCI() bool {
return runtime.GOOS == "windows" && os.Getenv("CI") != ""
}
+15 -26
View File
@@ -17,53 +17,43 @@ import (
"os"
"path/filepath"
"github.com/gohugoio/hugo/hugolib/filesystems"
"github.com/fsnotify/fsnotify"
"github.com/gohugoio/hugo/helpers"
src "github.com/gohugoio/hugo/source"
"github.com/spf13/fsync"
)
type staticSyncer struct {
c *commandeer
d *src.Dirs
}
func newStaticSyncer(c *commandeer) (*staticSyncer, error) {
dirs, err := src.NewDirs(c.Fs, c.Cfg, c.DepsCfg.Logger)
if err != nil {
return nil, err
}
return &staticSyncer{c: c, d: dirs}, nil
return &staticSyncer{c: c}, nil
}
func (s *staticSyncer) isStatic(path string) bool {
return s.d.IsStatic(path)
func (s *staticSyncer) isStatic(filename string) bool {
return s.c.hugo.BaseFs.SourceFilesystems.IsStatic(filename)
}
func (s *staticSyncer) syncsStaticEvents(staticEvents []fsnotify.Event) error {
c := s.c
syncFn := func(dirs *src.Dirs, publishDir string) (uint64, error) {
staticSourceFs, err := dirs.CreateStaticFs()
if err != nil {
return 0, err
syncFn := func(sourceFs *filesystems.SourceFilesystem) (uint64, error) {
publishDir := c.hugo.PathSpec.PublishDir
// If root, remove the second '/'
if publishDir == "//" {
publishDir = helpers.FilePathSeparator
}
if dirs.Language != nil {
// Multihost setup
publishDir = filepath.Join(publishDir, dirs.Language.Lang)
}
if staticSourceFs == nil {
c.Logger.WARN.Println("No static directories found to sync")
return 0, nil
if sourceFs.PublishFolder != "" {
publishDir = filepath.Join(publishDir, sourceFs.PublishFolder)
}
syncer := fsync.NewSyncer()
syncer.NoTimes = c.Cfg.GetBool("noTimes")
syncer.NoChmod = c.Cfg.GetBool("noChmod")
syncer.SrcFs = staticSourceFs
syncer.SrcFs = sourceFs.Fs
syncer.DestFs = c.Fs.Destination
// prevent spamming the log on changes
@@ -88,8 +78,7 @@ func (s *staticSyncer) syncsStaticEvents(staticEvents []fsnotify.Event) error {
fromPath := ev.Name
// If we are here we already know the event took place in a static dir
relPath := dirs.MakeStaticPathRelative(fromPath)
relPath := sourceFs.MakePathRelative(fromPath)
if relPath == "" {
// Not member of this virtual host.
continue
@@ -105,7 +94,7 @@ func (s *staticSyncer) syncsStaticEvents(staticEvents []fsnotify.Event) error {
// the source of that static file. In this case Hugo will incorrectly remove that file
// from the published directory.
if ev.Op&fsnotify.Rename == fsnotify.Rename || ev.Op&fsnotify.Remove == fsnotify.Remove {
if _, err := staticSourceFs.Stat(relPath); os.IsNotExist(err) {
if _, err := sourceFs.Fs.Stat(relPath); os.IsNotExist(err) {
// If file doesn't exist in any static dir, remove it
toRemove := filepath.Join(publishDir, relPath)
+38 -12
View File
@@ -19,24 +19,50 @@ import (
"github.com/gohugoio/hugo/helpers"
"github.com/gohugoio/hugo/hugolib"
"github.com/gohugoio/hugo/resource/tocss/scss"
"github.com/spf13/cobra"
jww "github.com/spf13/jwalterweatherman"
)
var versionCmd = &cobra.Command{
Use: "version",
Short: "Print the version number of Hugo",
Long: `All software has versions. This is Hugo's.`,
RunE: func(cmd *cobra.Command, args []string) error {
printHugoVersion()
return nil
},
var _ cmder = (*versionCmd)(nil)
type versionCmd struct {
*baseCmd
}
func newVersionCmd() *versionCmd {
return &versionCmd{
newBaseCmd(&cobra.Command{
Use: "version",
Short: "Print the version number of Hugo",
Long: `All software has versions. This is Hugo's.`,
RunE: func(cmd *cobra.Command, args []string) error {
printHugoVersion()
return nil
},
}),
}
}
func printHugoVersion() {
if hugolib.CommitHash == "" {
jww.FEEDBACK.Printf("Hugo Static Site Generator v%s %s/%s BuildDate: %s\n", helpers.CurrentHugoVersion, runtime.GOOS, runtime.GOARCH, hugolib.BuildDate)
} else {
jww.FEEDBACK.Printf("Hugo Static Site Generator v%s-%s %s/%s BuildDate: %s\n", helpers.CurrentHugoVersion, strings.ToUpper(hugolib.CommitHash), runtime.GOOS, runtime.GOARCH, hugolib.BuildDate)
program := "Hugo Static Site Generator"
version := "v" + helpers.CurrentHugoVersion.String()
if hugolib.CommitHash != "" {
version += "-" + strings.ToUpper(hugolib.CommitHash)
}
if scss.Supports() {
version += "/extended"
}
osArch := runtime.GOOS + "/" + runtime.GOARCH
var buildDate string
if hugolib.BuildDate != "" {
buildDate = hugolib.BuildDate
} else {
buildDate = "unknown"
}
jww.FEEDBACK.Println(program, version, osArch, "BuildDate:", buildDate)
}
+23
View File
@@ -0,0 +1,23 @@
// Copyright 2018 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package errors contains common Hugo errors and error related utilities.
package errors
import (
"errors"
)
// We will, at least to begin with, make some Hugo features (SCSS with libsass) optional,
// and this error is used to signal those situations.
var FeatureNotAvailableErr = errors.New("this feature is not available in your current Hugo version")
+37
View File
@@ -0,0 +1,37 @@
// Copyright 2018 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package loggers
import (
"io/ioutil"
"log"
"os"
jww "github.com/spf13/jwalterweatherman"
)
// NewDebugLogger is a convenience function to create a debug logger.
func NewDebugLogger() *jww.Notepad {
return jww.NewNotepad(jww.LevelDebug, jww.LevelError, os.Stdout, ioutil.Discard, "", log.Ldate|log.Ltime)
}
// NewWarningLogger is a convenience function to create a warning logger.
func NewWarningLogger() *jww.Notepad {
return jww.NewNotepad(jww.LevelWarn, jww.LevelError, os.Stdout, ioutil.Discard, "", log.Ldate|log.Ltime)
}
// NewErrorLogger is a convenience function to create an error logger.
func NewErrorLogger() *jww.Notepad {
return jww.NewNotepad(jww.LevelError, jww.LevelError, os.Stdout, ioutil.Discard, "", log.Ldate|log.Ltime)
}
+44
View File
@@ -0,0 +1,44 @@
// Copyright 2018 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package maps
import (
"strings"
"github.com/spf13/cast"
)
// ToLower makes all the keys in the given map lower cased and will do so
// recursively.
// Notes:
// * This will modify the map given.
// * Any nested map[interface{}]interface{} will be converted to map[string]interface{}.
func ToLower(m map[string]interface{}) {
for k, v := range m {
switch v.(type) {
case map[interface{}]interface{}:
v = cast.ToStringMap(v)
ToLower(v.(map[string]interface{}))
case map[string]interface{}:
ToLower(v.(map[string]interface{}))
}
lKey := strings.ToLower(k)
if k != lKey {
delete(m, k)
m[lKey] = v
}
}
}
+72
View File
@@ -0,0 +1,72 @@
// Copyright 2018 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package maps
import (
"reflect"
"testing"
)
func TestToLower(t *testing.T) {
tests := []struct {
input map[string]interface{}
expected map[string]interface{}
}{
{
map[string]interface{}{
"abC": 32,
},
map[string]interface{}{
"abc": 32,
},
},
{
map[string]interface{}{
"abC": 32,
"deF": map[interface{}]interface{}{
23: "A value",
24: map[string]interface{}{
"AbCDe": "A value",
"eFgHi": "Another value",
},
},
"gHi": map[string]interface{}{
"J": 25,
},
},
map[string]interface{}{
"abc": 32,
"def": map[string]interface{}{
"23": "A value",
"24": map[string]interface{}{
"abcde": "A value",
"efghi": "Another value",
},
},
"ghi": map[string]interface{}{
"j": 25,
},
},
},
}
for i, test := range tests {
// ToLower modifies input.
ToLower(test.input)
if !reflect.DeepEqual(test.expected, test.input) {
t.Errorf("[%d] Expected\n%#v, got\n%#v\n", i, test.expected, test.input)
}
}
}
+12 -4
View File
@@ -1,4 +1,4 @@
// Copyright 2015 The Hugo Authors. All rights reserved.
// Copyright 2018 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -11,14 +11,14 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package hugolib
package maps
import (
"reflect"
"sort"
"sync"
"github.com/gohugoio/hugo/tpl/math"
"github.com/gohugoio/hugo/common/math"
)
// Scratch is a writable context used for stateful operations in Page/Node rendering.
@@ -73,6 +73,14 @@ func (c *Scratch) Set(key string, value interface{}) string {
return ""
}
// Reset deletes the given key
func (c *Scratch) Delete(key string) string {
c.mu.Lock()
delete(c.values, key)
c.mu.Unlock()
return ""
}
// Get returns a value previously set by Add or Set
func (c *Scratch) Get(key string) interface{} {
c.mu.RLock()
@@ -122,6 +130,6 @@ func (c *Scratch) GetSortedMapValues(key string) interface{} {
return sortedArray
}
func newScratch() *Scratch {
func NewScratch() *Scratch {
return &Scratch{values: make(map[string]interface{})}
}
@@ -1,4 +1,4 @@
// Copyright 2015 The Hugo Authors. All rights reserved.
// Copyright 2018 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -11,7 +11,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package hugolib
package maps
import (
"reflect"
@@ -23,7 +23,7 @@ import (
func TestScratchAdd(t *testing.T) {
t.Parallel()
scratch := newScratch()
scratch := NewScratch()
scratch.Add("int1", 10)
scratch.Add("int1", 20)
scratch.Add("int2", 20)
@@ -53,7 +53,7 @@ func TestScratchAdd(t *testing.T) {
func TestScratchAddSlice(t *testing.T) {
t.Parallel()
scratch := newScratch()
scratch := NewScratch()
_, err := scratch.Add("intSlice", []int{1, 2})
assert.Nil(t, err)
@@ -82,15 +82,24 @@ func TestScratchAddSlice(t *testing.T) {
func TestScratchSet(t *testing.T) {
t.Parallel()
scratch := newScratch()
scratch := NewScratch()
scratch.Set("key", "val")
assert.Equal(t, "val", scratch.Get("key"))
}
func TestScratchDelete(t *testing.T) {
t.Parallel()
scratch := NewScratch()
scratch.Set("key", "val")
scratch.Delete("key")
scratch.Add("key", "Lucy Parsons")
assert.Equal(t, "Lucy Parsons", scratch.Get("key"))
}
// Issue #2005
func TestScratchInParallel(t *testing.T) {
var wg sync.WaitGroup
scratch := newScratch()
scratch := NewScratch()
key := "counter"
scratch.Set(key, int64(1))
for i := 1; i <= 10; i++ {
@@ -124,7 +133,7 @@ func TestScratchInParallel(t *testing.T) {
func TestScratchGet(t *testing.T) {
t.Parallel()
scratch := newScratch()
scratch := NewScratch()
nothing := scratch.Get("nothing")
if nothing != nil {
t.Errorf("Should not return anything, but got %v", nothing)
@@ -133,7 +142,7 @@ func TestScratchGet(t *testing.T) {
func TestScratchSetInMap(t *testing.T) {
t.Parallel()
scratch := newScratch()
scratch := NewScratch()
scratch.SetInMap("key", "lux", "Lux")
scratch.SetInMap("key", "abc", "Abc")
scratch.SetInMap("key", "zyx", "Zyx")
@@ -144,7 +153,7 @@ func TestScratchSetInMap(t *testing.T) {
func TestScratchGetSortedMapValues(t *testing.T) {
t.Parallel()
scratch := newScratch()
scratch := NewScratch()
nothing := scratch.GetSortedMapValues("nothing")
if nothing != nil {
t.Errorf("Should not return anything, but got %v", nothing)
@@ -152,7 +161,7 @@ func TestScratchGetSortedMapValues(t *testing.T) {
}
func BenchmarkScratchGet(b *testing.B) {
scratch := newScratch()
scratch := NewScratch()
scratch.Add("A", 1)
b.ResetTimer()
for i := 0; i < b.N; i++ {
+135
View File
@@ -0,0 +1,135 @@
// Copyright 2018 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package math
import (
"errors"
"reflect"
)
// DoArithmetic performs arithmetic operations (+,-,*,/) using reflection to
// determine the type of the two terms.
func DoArithmetic(a, b interface{}, op rune) (interface{}, error) {
av := reflect.ValueOf(a)
bv := reflect.ValueOf(b)
var ai, bi int64
var af, bf float64
var au, bu uint64
switch av.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
ai = av.Int()
switch bv.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
bi = bv.Int()
case reflect.Float32, reflect.Float64:
af = float64(ai) // may overflow
ai = 0
bf = bv.Float()
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
bu = bv.Uint()
if ai >= 0 {
au = uint64(ai)
ai = 0
} else {
bi = int64(bu) // may overflow
bu = 0
}
default:
return nil, errors.New("Can't apply the operator to the values")
}
case reflect.Float32, reflect.Float64:
af = av.Float()
switch bv.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
bf = float64(bv.Int()) // may overflow
case reflect.Float32, reflect.Float64:
bf = bv.Float()
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
bf = float64(bv.Uint()) // may overflow
default:
return nil, errors.New("Can't apply the operator to the values")
}
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
au = av.Uint()
switch bv.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
bi = bv.Int()
if bi >= 0 {
bu = uint64(bi)
bi = 0
} else {
ai = int64(au) // may overflow
au = 0
}
case reflect.Float32, reflect.Float64:
af = float64(au) // may overflow
au = 0
bf = bv.Float()
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
bu = bv.Uint()
default:
return nil, errors.New("Can't apply the operator to the values")
}
case reflect.String:
as := av.String()
if bv.Kind() == reflect.String && op == '+' {
bs := bv.String()
return as + bs, nil
}
return nil, errors.New("Can't apply the operator to the values")
default:
return nil, errors.New("Can't apply the operator to the values")
}
switch op {
case '+':
if ai != 0 || bi != 0 {
return ai + bi, nil
} else if af != 0 || bf != 0 {
return af + bf, nil
} else if au != 0 || bu != 0 {
return au + bu, nil
}
return 0, nil
case '-':
if ai != 0 || bi != 0 {
return ai - bi, nil
} else if af != 0 || bf != 0 {
return af - bf, nil
} else if au != 0 || bu != 0 {
return au - bu, nil
}
return 0, nil
case '*':
if ai != 0 || bi != 0 {
return ai * bi, nil
} else if af != 0 || bf != 0 {
return af * bf, nil
} else if au != 0 || bu != 0 {
return au * bu, nil
}
return 0, nil
case '/':
if bi != 0 {
return ai / bi, nil
} else if bf != 0 {
return af / bf, nil
} else if bu != 0 {
return au / bu, nil
}
return nil, errors.New("Can't divide the value by 0")
default:
return nil, errors.New("There is no such an operation")
}
}
+109
View File
@@ -0,0 +1,109 @@
// Copyright 2018 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package math
import (
"fmt"
"testing"
"github.com/alecthomas/assert"
"github.com/stretchr/testify/require"
)
func TestDoArithmetic(t *testing.T) {
t.Parallel()
for i, test := range []struct {
a interface{}
b interface{}
op rune
expect interface{}
}{
{3, 2, '+', int64(5)},
{3, 2, '-', int64(1)},
{3, 2, '*', int64(6)},
{3, 2, '/', int64(1)},
{3.0, 2, '+', float64(5)},
{3.0, 2, '-', float64(1)},
{3.0, 2, '*', float64(6)},
{3.0, 2, '/', float64(1.5)},
{3, 2.0, '+', float64(5)},
{3, 2.0, '-', float64(1)},
{3, 2.0, '*', float64(6)},
{3, 2.0, '/', float64(1.5)},
{3.0, 2.0, '+', float64(5)},
{3.0, 2.0, '-', float64(1)},
{3.0, 2.0, '*', float64(6)},
{3.0, 2.0, '/', float64(1.5)},
{uint(3), uint(2), '+', uint64(5)},
{uint(3), uint(2), '-', uint64(1)},
{uint(3), uint(2), '*', uint64(6)},
{uint(3), uint(2), '/', uint64(1)},
{uint(3), 2, '+', uint64(5)},
{uint(3), 2, '-', uint64(1)},
{uint(3), 2, '*', uint64(6)},
{uint(3), 2, '/', uint64(1)},
{3, uint(2), '+', uint64(5)},
{3, uint(2), '-', uint64(1)},
{3, uint(2), '*', uint64(6)},
{3, uint(2), '/', uint64(1)},
{uint(3), -2, '+', int64(1)},
{uint(3), -2, '-', int64(5)},
{uint(3), -2, '*', int64(-6)},
{uint(3), -2, '/', int64(-1)},
{-3, uint(2), '+', int64(-1)},
{-3, uint(2), '-', int64(-5)},
{-3, uint(2), '*', int64(-6)},
{-3, uint(2), '/', int64(-1)},
{uint(3), 2.0, '+', float64(5)},
{uint(3), 2.0, '-', float64(1)},
{uint(3), 2.0, '*', float64(6)},
{uint(3), 2.0, '/', float64(1.5)},
{3.0, uint(2), '+', float64(5)},
{3.0, uint(2), '-', float64(1)},
{3.0, uint(2), '*', float64(6)},
{3.0, uint(2), '/', float64(1.5)},
{0, 0, '+', 0},
{0, 0, '-', 0},
{0, 0, '*', 0},
{"foo", "bar", '+', "foobar"},
{3, 0, '/', false},
{3.0, 0, '/', false},
{3, 0.0, '/', false},
{uint(3), uint(0), '/', false},
{3, uint(0), '/', false},
{-3, uint(0), '/', false},
{uint(3), 0, '/', false},
{3.0, uint(0), '/', false},
{uint(3), 0.0, '/', false},
{3, "foo", '+', false},
{3.0, "foo", '+', false},
{uint(3), "foo", '+', false},
{"foo", 3, '+', false},
{"foo", "bar", '-', false},
{3, 2, '%', false},
} {
errMsg := fmt.Sprintf("[%d] %v", i, test)
result, err := DoArithmetic(test.a, test.b, test.op)
if b, ok := test.expect.(bool); ok && !b {
require.Error(t, err, errMsg)
continue
}
require.NoError(t, err, errMsg)
assert.Equal(t, test.expect, result, errMsg)
}
}
+6
View File
@@ -20,6 +20,12 @@ import (
"github.com/spf13/cast"
)
// KeyValueStr is a string tuple.
type KeyValueStr struct {
Key string
Value string
}
// KeyValues holds an key and a slice of values.
type KeyValues struct {
Key interface{}
+30
View File
@@ -13,6 +13,14 @@
package config
import (
"strings"
"github.com/spf13/cast"
"github.com/spf13/viper"
)
// Provider provides the configuration settings for Hugo.
type Provider interface {
GetString(key string) string
@@ -25,3 +33,25 @@ type Provider interface {
Set(key string, value interface{})
IsSet(key string) bool
}
// FromConfigString creates a config from the given YAML, JSON or TOML config. This is useful in tests.
func FromConfigString(config, configType string) (Provider, error) {
v := viper.New()
v.SetConfigType(configType)
if err := v.ReadConfig(strings.NewReader(config)); err != nil {
return nil, err
}
return v, nil
}
// GetStringSlicePreserveString returns a string slice from the given config and key.
// It differs from the GetStringSlice method in that if the config value is a string,
// we do not attempt to split it into fields.
func GetStringSlicePreserveString(cfg Provider, key string) []string {
sd := cfg.Get(key)
if sds, ok := sd.(string); ok {
return []string{sds}
} else {
return cast.ToStringSlice(sd)
}
}
+36
View File
@@ -0,0 +1,36 @@
// Copyright 2018 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package config
import (
"testing"
"github.com/spf13/viper"
"github.com/stretchr/testify/require"
)
func TestGetStringSlicePreserveString(t *testing.T) {
assert := require.New(t)
cfg := viper.New()
s := "This is a string"
sSlice := []string{"This", "is", "a", "slice"}
cfg.Set("s1", s)
cfg.Set("s2", sSlice)
assert.Equal([]string{s}, GetStringSlicePreserveString(cfg, "s1"))
assert.Equal(sSlice, GetStringSlicePreserveString(cfg, "s2"))
assert.Nil(GetStringSlicePreserveString(cfg, "s3"))
}
+109
View File
@@ -0,0 +1,109 @@
// Copyright 2018 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package privacy
import (
"github.com/gohugoio/hugo/config"
"github.com/mitchellh/mapstructure"
)
const privacyConfigKey = "privacy"
// Service is the common values for a service in a policy definition.
type Service struct {
Disable bool
}
// Config is a privacy configuration for all the relevant services in Hugo.
type Config struct {
Disqus Disqus
GoogleAnalytics GoogleAnalytics
Instagram Instagram
Twitter Twitter
Vimeo Vimeo
YouTube YouTube
}
// Disqus holds the privacy configuration settings related to the Disqus template.
type Disqus struct {
Service `mapstructure:",squash"`
}
// GoogleAnalytics holds the privacy configuration settings related to the Google Analytics template.
type GoogleAnalytics struct {
Service `mapstructure:",squash"`
// Enabling this will disable the use of Cookies and use Session Storage to Store the GA Client ID.
UseSessionStorage bool
// Enabling this will make the GA templates respect the
// "Do Not Track" HTTP header. See https://www.paulfurley.com/google-analytics-dnt/.
RespectDoNotTrack bool
// Enabling this will make it so the users' IP addresses are anonymized within Google Analytics.
AnonymizeIP bool
}
// Instagram holds the privacy configuration settings related to the Instagram shortcode.
type Instagram struct {
Service `mapstructure:",squash"`
// If simple mode is enabled, a static and no-JS version of the Instagram
// image card will be built.
Simple bool
}
// Twitter holds the privacy configuration settingsrelated to the Twitter shortcode.
type Twitter struct {
Service `mapstructure:",squash"`
// When set to true, the Tweet and its embedded page on your site are not used
// for purposes that include personalized suggestions and personalized ads.
EnableDNT bool
// If simple mode is enabled, a static and no-JS version of the Tweet will be built.
Simple bool
}
// Vimeo holds the privacy configuration settingsrelated to the Vimeo shortcode.
type Vimeo struct {
Service `mapstructure:",squash"`
// If simple mode is enabled, only a thumbnail is fetched from i.vimeocdn.com and
// shown with a play button overlaid. If a user clicks the button, he/she will
// be taken to the video page on vimeo.com in a new browser tab.
Simple bool
}
// YouTube holds the privacy configuration settingsrelated to the YouTube shortcode.
type YouTube struct {
Service `mapstructure:",squash"`
// When you turn on privacy-enhanced mode,
// YouTube wont store information about visitors on your website
// unless the user plays the embedded video.
PrivacyEnhanced bool
}
func DecodeConfig(cfg config.Provider) (pc Config, err error) {
if !cfg.IsSet(privacyConfigKey) {
return
}
m := cfg.GetStringMap(privacyConfigKey)
err = mapstructure.WeakDecode(m, &pc)
return
}
+104
View File
@@ -0,0 +1,104 @@
// Copyright 2018 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package privacy
import (
"testing"
"github.com/gohugoio/hugo/config"
"github.com/spf13/viper"
"github.com/stretchr/testify/require"
)
func TestDecodeConfigFromTOML(t *testing.T) {
assert := require.New(t)
tomlConfig := `
someOtherValue = "foo"
[privacy]
[privacy.disqus]
disable = true
[privacy.googleAnalytics]
disable = true
respectDoNotTrack = true
anonymizeIP = true
useSessionStorage = true
[privacy.instagram]
disable = true
simple = true
[privacy.twitter]
disable = true
enableDNT = true
simple = true
[privacy.vimeo]
disable = true
simple = true
[privacy.youtube]
disable = true
privacyEnhanced = true
simple = true
`
cfg, err := config.FromConfigString(tomlConfig, "toml")
assert.NoError(err)
pc, err := DecodeConfig(cfg)
assert.NoError(err)
assert.NotNil(pc)
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)
tomlConfig := `
someOtherValue = "foo"
[Privacy]
[Privacy.YouTube]
PrivacyENhanced = true
`
cfg, err := config.FromConfigString(tomlConfig, "toml")
assert.NoError(err)
pc, err := DecodeConfig(cfg)
assert.NoError(err)
assert.NotNil(pc)
assert.True(pc.YouTube.PrivacyEnhanced)
}
func TestDecodeConfigDefault(t *testing.T) {
assert := require.New(t)
pc, err := DecodeConfig(viper.New())
assert.NoError(err)
assert.NotNil(pc)
assert.False(pc.YouTube.PrivacyEnhanced)
}
+79
View File
@@ -0,0 +1,79 @@
// Copyright 2018 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package services
import (
"github.com/gohugoio/hugo/config"
"github.com/mitchellh/mapstructure"
)
const (
servicesConfigKey = "services"
disqusShortnameKey = "disqusshortname"
googleAnalyticsKey = "googleanalytics"
)
// Config is a privacy configuration for all the relevant services in Hugo.
type Config struct {
Disqus Disqus
GoogleAnalytics GoogleAnalytics
Instagram Instagram
Twitter Twitter
}
// Disqus holds the functional configuration settings related to the Disqus template.
type Disqus struct {
// A Shortname is the unique identifier assigned to a Disqus site.
Shortname string
}
// GoogleAnalytics holds the functional configuration settings related to the Google Analytics template.
type GoogleAnalytics struct {
// The GA tracking ID.
ID string
}
// Instagram holds the functional configuration settings related to the Instagram shortcodes.
type Instagram struct {
// The Simple variant of the Instagram is decorated with Bootstrap 4 card classes.
// This means that if you use Bootstrap 4 or want to provide your own CSS, you want
// to disable the inline CSS provided by Hugo.
DisableInlineCSS bool
}
// Twitter holds the functional configuration settings related to the Twitter shortcodes.
type Twitter struct {
// The Simple variant of Twitter is decorated with a basic set of inline styles.
// This means that if you want to provide your own CSS, you want
// to disable the inline CSS provided by Hugo.
DisableInlineCSS bool
}
func DecodeConfig(cfg config.Provider) (c Config, err error) {
m := cfg.GetStringMap(servicesConfigKey)
err = mapstructure.WeakDecode(m, &c)
// Keep backwards compatibility.
if c.GoogleAnalytics.ID == "" {
// Try the global config
c.GoogleAnalytics.ID = cfg.GetString(googleAnalyticsKey)
}
if c.Disqus.Shortname == "" {
c.Disqus.Shortname = cfg.GetString(disqusShortnameKey)
}
return
}
+69
View File
@@ -0,0 +1,69 @@
// Copyright 2018 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package services
import (
"testing"
"github.com/gohugoio/hugo/config"
"github.com/spf13/viper"
"github.com/stretchr/testify/require"
)
func TestDecodeConfigFromTOML(t *testing.T) {
assert := require.New(t)
tomlConfig := `
someOtherValue = "foo"
[services]
[services.disqus]
shortname = "DS"
[services.googleAnalytics]
id = "ga_id"
[services.instagram]
disableInlineCSS = true
[services.twitter]
disableInlineCSS = true
`
cfg, err := config.FromConfigString(tomlConfig, "toml")
assert.NoError(err)
config, err := DecodeConfig(cfg)
assert.NoError(err)
assert.NotNil(config)
assert.Equal("DS", config.Disqus.Shortname)
assert.Equal("ga_id", config.GoogleAnalytics.ID)
assert.True(config.Instagram.DisableInlineCSS)
}
// Support old root-level GA settings etc.
func TestUseSettingsFromRootIfSet(t *testing.T) {
assert := require.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)
assert.Equal("root_short", config.Disqus.Shortname)
assert.Equal("ga_root", config.GoogleAnalytics.ID)
}
+35 -33
View File
@@ -16,6 +16,7 @@ package create
import (
"bytes"
"fmt"
"os"
"os/exec"
"path/filepath"
@@ -31,6 +32,7 @@ func NewContent(
ps *helpers.PathSpec,
siteFactory func(filename string, siteUsed bool) (*hugolib.Site, error), kind, targetPath string) error {
ext := helpers.Ext(targetPath)
fs := ps.BaseFs.SourceFilesystems.Archetypes.Fs
jww.INFO.Printf("attempting to create %q of %q of ext %q", targetPath, kind, ext)
@@ -40,9 +42,9 @@ func NewContent(
siteUsed := false
if archetypeFilename != "" {
f, err := ps.Fs.Source.Open(archetypeFilename)
f, err := fs.Open(archetypeFilename)
if err != nil {
return err
return fmt.Errorf("failed to open archetype file: %s", err)
}
defer f.Close()
@@ -63,7 +65,22 @@ func NewContent(
return err
}
contentPath := s.PathSpec.AbsPathify(filepath.Join(s.Cfg.GetString("contentDir"), targetPath))
// The site may have multiple content dirs, and we currently do not know which contentDir the
// user wants to create this content in. We should improve on this, but we start by testing if the
// provided path points to an existing dir. If so, use it as is.
var contentPath string
var exists bool
targetDir := filepath.Dir(targetPath)
if targetDir != "" && targetDir != "." {
exists, _ = helpers.Exists(targetDir, fs)
}
if exists {
contentPath = targetPath
} else {
contentPath = s.PathSpec.AbsPathify(filepath.Join(s.Cfg.GetString("contentDir"), targetPath))
}
if err := helpers.SafeWriteToDisk(contentPath, bytes.NewReader(content), s.Fs.Source); err != nil {
return err
@@ -86,42 +103,27 @@ func NewContent(
return nil
}
// FindArchetype takes a given kind/archetype of content and returns an output
// path for that archetype. If no archetype is found, an empty string is
// returned.
// FindArchetype takes a given kind/archetype of content and returns the path
// to the archetype in the archetype filesystem, blank if none found.
func findArchetype(ps *helpers.PathSpec, kind, ext string) (outpath string) {
search := []string{ps.AbsPathify(ps.Cfg.GetString("archetypeDir"))}
fs := ps.BaseFs.Archetypes.Fs
if ps.Cfg.GetString("theme") != "" {
themeDir := filepath.Join(ps.AbsPathify(ps.Cfg.GetString("themesDir")+"/"+ps.Cfg.GetString("theme")), "/archetypes/")
if _, err := ps.Fs.Source.Stat(themeDir); os.IsNotExist(err) {
jww.ERROR.Printf("Unable to find archetypes directory for theme %q at %q", ps.Cfg.GetString("theme"), themeDir)
// If the new content isn't in a subdirectory, kind == "".
// Therefore it should be excluded otherwise `is a directory`
// error will occur. github.com/gohugoio/hugo/issues/411
var pathsToCheck = []string{"default"}
if ext != "" {
if kind != "" {
pathsToCheck = append([]string{kind + ext, "default" + ext}, pathsToCheck...)
} else {
search = append(search, themeDir)
pathsToCheck = append([]string{"default" + ext}, pathsToCheck...)
}
}
for _, x := range search {
// If the new content isn't in a subdirectory, kind == "".
// Therefore it should be excluded otherwise `is a directory`
// error will occur. github.com/gohugoio/hugo/issues/411
var pathsToCheck = []string{"default"}
if ext != "" {
if kind != "" {
pathsToCheck = append([]string{kind + ext, "default" + ext}, pathsToCheck...)
} else {
pathsToCheck = append([]string{"default" + ext}, pathsToCheck...)
}
}
for _, p := range pathsToCheck {
curpath := filepath.Join(x, p)
jww.DEBUG.Println("checking", curpath, "for archetypes")
if exists, _ := helpers.Exists(curpath, ps.Fs.Source); exists {
jww.INFO.Println("curpath: " + curpath)
return curpath
}
for _, p := range pathsToCheck {
if exists, _ := helpers.Exists(p, fs); exists {
return p
}
}
+12 -15
View File
@@ -42,7 +42,7 @@ type ArchetypeFileData struct {
// used in the archetype template. Also, if this is a multilingual setup,
// this site is the site that best matches the target content file, based
// on the presence of language code in the filename.
Site *hugolib.Site
Site *hugolib.SiteInfo
// Name will in most cases be the same as TranslationBaseName, e.g. "my-post".
// But if that value is "index" (bundles), the Name is instead the owning folder.
@@ -88,10 +88,16 @@ func executeArcheTypeAsTemplate(s *hugolib.Site, kind, targetPath, archetypeFile
err error
)
sp := source.NewSourceSpec(s.Deps.Cfg, s.Deps.Fs)
ps, err := helpers.NewPathSpec(s.Deps.Fs, s.Deps.Cfg)
if err != nil {
return nil, err
}
sp := source.NewSourceSpec(ps, ps.Fs.Source)
f := sp.NewFileInfo("", targetPath, false, nil)
name := f.TranslationBaseName()
if name == "index" || name == "_index" {
// Page bundles; the directory name will hopefully have a better name.
dir := strings.TrimSuffix(f.Dir(), helpers.FilePathSeparator)
@@ -103,16 +109,16 @@ func executeArcheTypeAsTemplate(s *hugolib.Site, kind, targetPath, archetypeFile
Date: time.Now().Format(time.RFC3339),
Name: name,
File: f,
Site: s,
Site: &s.Info,
}
if archetypeFilename == "" {
// TODO(bep) archetype revive the issue about wrong tpl funcs arg order
archetypeTemplate = []byte(ArchetypeTemplateTemplate)
} else {
archetypeTemplate, err = afero.ReadFile(s.Fs.Source, archetypeFilename)
archetypeTemplate, err = afero.ReadFile(s.BaseFs.Archetypes.Fs, archetypeFilename)
if err != nil {
return nil, fmt.Errorf("Failed to read archetype file %q: %s", archetypeFilename, err)
return nil, fmt.Errorf("failed to read archetype file %s", err)
}
}
@@ -128,7 +134,7 @@ func executeArcheTypeAsTemplate(s *hugolib.Site, kind, targetPath, archetypeFile
return nil, fmt.Errorf("Failed to parse archetype file %q: %s", archetypeFilename, err)
}
templ := templateHandler.Lookup(templateName)
templ, _ := templateHandler.Lookup(templateName)
var buff bytes.Buffer
if err := templ.Execute(&buff, data); err != nil {
@@ -137,15 +143,6 @@ func executeArcheTypeAsTemplate(s *hugolib.Site, kind, targetPath, archetypeFile
archetypeContent = []byte(archetypeShortcodeReplacementsPost.Replace(buff.String()))
if !bytes.Contains(archetypeContent, []byte("date")) || !bytes.Contains(archetypeContent, []byte("title")) {
// TODO(bep) remove some time in the future.
s.Log.FEEDBACK.Println(fmt.Sprintf(`WARNING: date and/or title missing from archetype file %q.
From Hugo 0.24 this must be provided in the archetype file itself, if needed. Example:
%s
`, archetypeFilename, ArchetypeTemplateTemplate))
}
return archetypeContent, nil
}
+13 -5
View File
@@ -58,24 +58,22 @@ func TestNewContent(t *testing.T) {
for _, c := range cases {
cfg, fs := newTestCfg()
ps, err := helpers.NewPathSpec(fs, cfg)
require.NoError(t, err)
require.NoError(t, initFs(fs))
h, err := hugolib.NewHugoSites(deps.DepsCfg{Cfg: cfg, Fs: fs})
require.NoError(t, err)
require.NoError(t, initFs(fs))
siteFactory := func(filename string, siteUsed bool) (*hugolib.Site, error) {
return h.Sites[0], nil
}
require.NoError(t, create.NewContent(ps, siteFactory, c.kind, c.path))
require.NoError(t, create.NewContent(h.PathSpec, siteFactory, c.kind, c.path))
fname := filepath.Join("content", filepath.FromSlash(c.path))
content := readFileFromFs(t, fs.Source, fname)
for i, v := range c.expected {
found := strings.Contains(content, v)
if !found {
t.Errorf("[%d] %q missing from output:\n%q", i, v, content)
t.Fatalf("[%d] %q missing from output:\n%q", i, v, content)
}
}
}
@@ -89,6 +87,9 @@ func initViper(v *viper.Viper) {
v.Set("layoutDir", "layouts")
v.Set("i18nDir", "i18n")
v.Set("theme", "sample")
v.Set("archetypeDir", "archetypes")
v.Set("resourceDir", "resources")
v.Set("publishDir", "public")
}
func initFs(fs *hugofs.Fs) error {
@@ -187,6 +188,13 @@ func readFileFromFs(t *testing.T, fs afero.Fs, filename string) string {
func newTestCfg() (*viper.Viper, *hugofs.Fs) {
v := viper.New()
v.Set("contentDir", "content")
v.Set("dataDir", "data")
v.Set("i18nDir", "i18n")
v.Set("layoutDir", "layouts")
v.Set("archetypeDir", "archetypes")
v.Set("assetDir", "assets")
fs := hugofs.NewMem(v)
v.SetFs(fs.Source)
+81 -9
View File
@@ -1,15 +1,19 @@
package deps
import (
"io/ioutil"
"log"
"os"
"sync"
"time"
"github.com/gohugoio/hugo/common/loggers"
"github.com/gohugoio/hugo/config"
"github.com/gohugoio/hugo/helpers"
"github.com/gohugoio/hugo/hugofs"
"github.com/gohugoio/hugo/langs"
"github.com/gohugoio/hugo/media"
"github.com/gohugoio/hugo/metrics"
"github.com/gohugoio/hugo/output"
"github.com/gohugoio/hugo/resource"
"github.com/gohugoio/hugo/source"
"github.com/gohugoio/hugo/tpl"
jww "github.com/spf13/jwalterweatherman"
@@ -19,12 +23,19 @@ import (
// There will be normally only one instance of deps in play
// at a given time, i.e. one per Site built.
type Deps struct {
// The logger to use.
Log *jww.Notepad `json:"-"`
// Used to log errors that may repeat itself many times.
DistinctErrorLog *helpers.DistinctLogger
// The templates to use. This will usually implement the full tpl.TemplateHandler.
Tmpl tpl.TemplateFinder `json:"-"`
// We use this to parse and execute ad-hoc text templates.
TextTmpl tpl.TemplateParseFinder `json:"-"`
// The file systems to use.
Fs *hugofs.Fs `json:"-"`
@@ -37,13 +48,16 @@ type Deps struct {
// The SourceSpec to use
SourceSpec *source.SourceSpec `json:"-"`
// The Resource Spec to use
ResourceSpec *resource.Spec
// The configuration to use
Cfg config.Provider `json:"-"`
// The translation func to use
Translate func(translationID string, args ...interface{}) string `json:"-"`
Language *helpers.Language
Language *langs.Language
// All the output formats available for the current site.
OutputFormatsConfig output.Formats
@@ -54,6 +68,33 @@ type Deps struct {
translationProvider ResourceProvider
Metrics metrics.Provider
// Timeout is configurable in site config.
Timeout time.Duration
// BuildStartListeners will be notified before a build starts.
BuildStartListeners *Listeners
}
type Listeners struct {
sync.Mutex
// A list of funcs to be notified about an event.
listeners []func()
}
func (b *Listeners) Add(f func()) {
b.Lock()
defer b.Unlock()
b.listeners = append(b.listeners, f)
}
func (b *Listeners) Notify() {
b.Lock()
defer b.Unlock()
for _, notify := range b.listeners {
notify()
}
}
// ResourceProvider is used to create and refresh, and clone resources needed.
@@ -107,7 +148,7 @@ func New(cfg DepsCfg) (*Deps, error) {
}
if logger == nil {
logger = jww.NewNotepad(jww.LevelError, jww.LevelError, os.Stdout, ioutil.Discard, "", log.Ldate|log.Ltime)
logger = loggers.NewErrorLogger()
}
if fs == nil {
@@ -121,24 +162,40 @@ func New(cfg DepsCfg) (*Deps, error) {
return nil, err
}
resourceSpec, err := resource.NewSpec(ps, logger, cfg.MediaTypes)
if err != nil {
return nil, err
}
contentSpec, err := helpers.NewContentSpec(cfg.Language)
if err != nil {
return nil, err
}
sp := source.NewSourceSpec(cfg.Language, fs)
sp := source.NewSourceSpec(ps, fs.Source)
timeoutms := cfg.Language.GetInt("timeout")
if timeoutms <= 0 {
timeoutms = 3000
}
distinctErrorLogger := helpers.NewDistinctLogger(logger.ERROR)
d := &Deps{
Fs: fs,
Log: logger,
DistinctErrorLog: distinctErrorLogger,
templateProvider: cfg.TemplateProvider,
translationProvider: cfg.TranslationProvider,
WithTemplate: cfg.WithTemplate,
PathSpec: ps,
ContentSpec: contentSpec,
SourceSpec: sp,
ResourceSpec: resourceSpec,
Cfg: cfg.Language,
Language: cfg.Language,
BuildStartListeners: &Listeners{},
Timeout: time.Duration(timeoutms) * time.Millisecond,
}
if cfg.Cfg.GetBool("templateMetrics") {
@@ -150,10 +207,11 @@ func New(cfg DepsCfg) (*Deps, error) {
// ForLanguage creates a copy of the Deps with the language dependent
// parts switched out.
func (d Deps) ForLanguage(l *helpers.Language) (*Deps, error) {
func (d Deps) ForLanguage(cfg DepsCfg) (*Deps, error) {
l := cfg.Language
var err error
d.PathSpec, err = helpers.NewPathSpec(d.Fs, l)
d.PathSpec, err = helpers.NewPathSpecWithBaseBaseFsProvided(d.Fs, l, d.BaseFs)
if err != nil {
return nil, err
}
@@ -163,6 +221,15 @@ func (d Deps) ForLanguage(l *helpers.Language) (*Deps, error) {
return nil, err
}
// The resource cache is global so reuse.
// TODO(bep) clean up these inits.
resourceCache := d.ResourceSpec.ResourceCache
d.ResourceSpec, err = resource.NewSpec(d.PathSpec, d.Log, cfg.MediaTypes)
if err != nil {
return nil, err
}
d.ResourceSpec.ResourceCache = resourceCache
d.Cfg = l
d.Language = l
@@ -174,6 +241,8 @@ func (d Deps) ForLanguage(l *helpers.Language) (*Deps, error) {
return nil, err
}
d.BuildStartListeners = &Listeners{}
return &d, nil
}
@@ -190,11 +259,14 @@ type DepsCfg struct {
Fs *hugofs.Fs
// The language to use.
Language *helpers.Language
Language *langs.Language
// The configuration to use.
Cfg config.Provider
// The media types configured.
MediaTypes media.Types
// Template handling.
TemplateProvider ResourceProvider
WithTemplate func(templ tpl.TemplateHandler) error
View File
+7 -1
View File
@@ -1,6 +1,6 @@
# Hugo Docs
Documentation site for [Hugo](https://github.com/gohugoio/hugo), the very fast and flexible static site generator built with love in GoLang.
Documentation site for [Hugo](https://github.com/gohugoio/hugo), the very fast and flexible static site generator built with love in Go.
## Contributing
@@ -10,6 +10,12 @@ Note that this repository contains solely the documentation for Hugo. For contri
*Pull requests shall **only** contain changes to the actual documentation. However, changes on the code base of Hugo **and** the documentation shall be a single, atomic pull request in the [hugo](https://github.com/gohugoio/hugo) repository.*
Spelling fixes are most welcomed, and if you want to contribute longer sections to the documentation, it would be great if you had these in mind when writing:
* Short is good. People go to the library to read novels. If there is more than one way to _do a thing_ in Hugo, describe the current _best practice_ (avoid "… but you can also do …" and "… in older versions of Hugo you had to …".
* For examples, try to find short snippets that teaches people about the concept. If the example is also useful as-is (copy and paste), then great, but don't list long and similar examples just so people can use them on their sites.
* Hugo has users from all over the world, so an easy to understand and [simple English](https://simple.wikipedia.org/wiki/Basic_English) is good.
## Branches
* The `master` branch is where the site is automatically built from, and is the place to put changes relevant to the current Hugo version.
+143 -5
View File
@@ -16,7 +16,6 @@ pluralizeListTitles = false
# We do redirects via Netlify's _redirects file, generated by Hugo (see "outputs" below).
disableAliases = true
# Highlighting config (Pygments)
# It is (currently) not in use, but you can do ```go in a content file if you want to.
pygmentsCodeFences = true
@@ -27,7 +26,7 @@ pygmentsUseClasses = true
pygmentsUseClassic = false
# See https://help.farbox.com/pygments.html
pygmentsStyle = "friendly"
pygmentsStyle = "trac"
[outputs]
home = [ "HTML", "RSS", "REDIR", "HEADERS" ]
@@ -35,7 +34,6 @@ section = [ "HTML", "RSS"]
[mediaTypes]
[mediaTypes."text/netlify"]
suffix = ""
delimiter = ""
[outputFormats]
@@ -71,7 +69,7 @@ twitter = "GoHugoIO"
[params]
description = "The worlds fastest framework for building websites"
## Used for views in rendered HTML (i.e., rather than using the .Hugo variable)
release = "0.37"
release = "0.46"
## Setting this to true will add a "noindex" to *EVERY* page on the site
removefromexternalsearch = false
## Gh repo for site footer (include trailing slash)
@@ -168,7 +166,11 @@ anchor = "smart"
weight = 35
identifier = "variables"
url = "/variables/"
[[menu.docs]]
name = "Hugo Pipes"
weight = 36
identifier = "pipes"
url = "/hugo-pipes/"
[[menu.docs]]
name = "CLI"
weight = 40
@@ -272,3 +274,139 @@ anchor = "smart"
identifier = "github"
post = "external"
url = "https://github.com/gohugoio/hugo"
### LANGUAGES ###
[languages]
[languages.en]
contentDir = "content/en"
languageName = "English"
weight = 1
[languages.zh]
contentDir = "content/zh"
languageName = "中文"
weight = 2
### LANGUAGE-SPECIFIC MENUS ###
# Chinese menus
[[languages.zh.menu.docs]]
name = "关于 Hugo"
weight = 1
identifier = "about"
url = "/zh/about/"
[[languages.zh.menu.docs]]
name = "入门"
weight = 5
identifier = "getting-started"
url = "/zh/getting-started/"
[[languages.zh.menu.docs]]
name = "主题"
weight = 15
identifier = "themes"
post = "break"
url = "/zh/themes/"
# Core languages.zh.menus
[[languages.zh.menu.docs]]
name = "内容管理"
weight = 20
identifier = "content-management"
post = "expanded"
url = "/zh/content-management/"
[[languages.zh.menu.docs]]
name = "模板"
weight = 25
identifier = "templates"
url = "/zh/templates/"
[[languages.zh.menu.docs]]
name = "函数"
weight = 30
identifier = "functions"
url = "/zh/functions/"
[[languages.zh.menu.docs]]
name = "变量"
weight = 35
identifier = "variables"
url = "/zh/variables/"
[[languages.zh.menu.docs]]
name = "CLI"
weight = 40
post = "break"
identifier = "commands"
url = "/commands/"
# LOW LEVEL ITEMS
[[languages.zh.menu.docs]]
name = "故障排除"
weight = 60
identifier = "troubleshooting"
url = "/zh/troubleshooting/"
[[languages.zh.menu.docs]]
name = "工具"
weight = 70
identifier = "tools"
url = "/zh/tools/"
[[languages.zh.menu.docs]]
name = "托管与部署"
weight = 80
identifier = "hosting-and-deployment"
url = "/zh/hosting-and-deployment/"
[[languages.zh.menu.docs]]
name = "贡献"
weight = 100
post = "break"
identifier = "contribute"
url = "/zh/contribute/"
[[languages.zh.menu.global]]
name = "新闻"
weight = 1
identifier = "news"
url = "/zh/news/"
[[languages.zh.menu.global]]
name = "文档"
weight = 5
identifier = "docs"
url = "/zh/documentation/"
[[languages.zh.menu.global]]
name = "主题"
weight = 10
identifier = "themes"
url = "https://themes.gohugo.io/"
[[languages.zh.menu.global]]
name = "作品展示"
weight = 20
identifier = "showcase"
url = "/zh/showcase/"
# Anything with a weight > 100 gets an external icon
[[languages.zh.menu.global]]
name = "社区"
weight = 150
icon = true
identifier = "community"
post = "external"
url = "https://discourse.gohugo.io/"
[[languages.zh.menu.global]]
name = "GitHub"
weight = 200
identifier = "github"
post = "external"
url = "https://github.com/gohugoio/hugo"
@@ -1,192 +0,0 @@
---
title: Archetypes
linktitle: Archetypes
description: Archetypes allow you to create new instances of content types and set default parameters from the command line.
date: 2017-02-01
publishdate: 2017-02-01
lastmod: 2017-02-01
keywords: [archetypes,generators,metadata,front matter]
categories: ["content management"]
menu:
docs:
parent: "content-management"
weight: 70
quicklinks:
weight: 70 #rem
draft: false
aliases: [/content/archetypes/]
toc: true
---
{{% note %}}
This section is outdated, see https://github.com/gohugoio/hugoDocs/issues/11
{{% /note %}}
{{% todo %}}
See above
{{% /todo %}}
## What are Archetypes?
**Archetypes** are content files in the [archetypes directory][] of your project that contain preconfigured [front matter][] for your website's [content types][]. Archetypes facilitate consistent metadata across your website content and allow content authors to quickly generate instances of a content type via the `hugo new` command.
{{< youtube bcme8AzVh6o >}}
The `hugo new` generator for archetypes assumes your working directory is the content folder at the root of your project. Hugo is able to infer the appropriate archetype by assuming the content type from the content section passed to the CLI command:
```
hugo new <content-section>/<file-name.md>
```
We can use this pattern to create a new `.md` file in the `posts` section:
{{< code file="archetype-example.sh" >}}
hugo new posts/my-first-post.md
{{< /code >}}
{{% note "Override Content Type in a New File" %}}
To override the content type Hugo infers from `[content-section]`, add the `--kind` flag to the end of the `hugo new` command.
{{% /note %}}
Running this command in a new site that does not have default or custom archetypes will create the following file:
{{< output file="content/posts/my-first-post.md" >}}
+++
date = "2017-02-01T19:20:04-07:00"
title = "my first post"
draft = true
+++
{{< /output >}}
{{% note %}}
In this example, if you do not already have a `content/posts` directory, Hugo will create both `content/posts/` and `content/posts/my-first-post.md` for you.
{{% /note %}}
The auto-populated fields are worth examining:
* `title` is generated from the new content's filename (i.e. in this case, `my-first-post` becomes `"my first post"`)
* `date` and `title` are the variables that ship with Hugo and are therefore included in *all* content files created with the Hugo CLI. `date` is generated in [RFC 3339 format][] by way of Go's [`now()`][] function, which returns the current time.
* The third variable, `draft = true`, is *not* inherited by your default or custom archetypes but is included in Hugo's automatically scaffolded `default.md` archetype for convenience.
Three variables per content file are often not enough for effective content management of larger websites. Luckily, Hugo provides a simple mechanism for extending the number of variables through custom archetypes, as well as default archetypes to keep content creation DRY.
## Lookup Order for Archetypes
Similar to the [lookup order for templates][lookup] in your `layouts` directory, Hugo looks for a section- or type-specific archetype, then a default archetype, and finally an internal archetype that ships with Hugo. For example, Hugo will look for an archetype for `content/posts/my-first-post.md` in the following order:
1. `archetypes/posts.md`
2. `archetypes/default.md`
3. `themes/<THEME>/archetypes/posts.md`
4. `themes/<THEME>/archetypes/default.md` (Auto-generated with `hugo new site`)
{{% note "Using a Theme Archetype" %}}
If you wish to use archetypes that ship with a theme, the `theme` field must be specified in your [configuration file](/getting-started/configuration/).
{{% /note %}}
## Choose Your Archetype's Front Matter Format
By default, `hugo new` content files include front matter in the TOML format regardless of the format used in `archetypes/*.md`.
You can specify a different default format in your site [configuration file][] file using the `metaDataFormat` directive. Possible values are `toml`, `yaml`, and `json`.
## Default Archetypes
Default archetypes are convenient if your content's front matter stays consistent across multiple [content sections][sections].
### Create the Default Archetype
When you create a new Hugo project using `hugo new site`, you'll notice that Hugo has already scaffolded a file at `archetypes/default.md`.
The following examples are from a site that's using `tags` and `categories` as [taxonomies][]. If we assume that all content files will require these two key-values, we can create a `default.md` archetype that *extends* Hugo's base archetype. In this example, we are including "golang" and "hugo" as tags and "web development" as a category.
{{< code file="archetypes/default.md" >}}
+++
tags = ["golang", "hugo"]
categories = ["web development"]
+++
{{< /code >}}
{{% warning "EOL Characters in Text Editors"%}}
If you get an `EOF error` when using `hugo new`, add a carriage return after the closing `+++` or `---` for your TOML or YAML front matter, respectively. (See the [troubleshooting article on EOF errors](/troubleshooting/eof-error/) for more information.)
{{% /warning %}}
### Use the Default Archetype
With an `archetypes/default.md` in place, we can use the CLI to create a new post in the `posts` content section:
{{< code file="new-post-from-default.sh" >}}
$ hugo new posts/my-new-post.md
{{< /code >}}
Hugo then creates a new markdown file with the following front matter:
{{< output file="content/posts/my-new-post.md" >}}
+++
categories = ["web development"]
date = "2017-02-01T19:20:04-07:00"
tags = ["golang", "hugo"]
title = "my new post"
+++
{{< /output >}}
We see that the `title` and `date` key-values have been added in addition to the `tags` and `categories` key-values from `archetypes/default.md`.
{{% note "Ordering of Front Matter" %}}
You may notice that content files created with `hugo new` do not respect the order of the key-values specified in your archetype files. This is a [known issue](https://github.com/gohugoio/hugo/issues/452).
{{% /note %}}
## Custom Archetypes
Suppose your site's `posts` section requires more sophisticated front matter than what has been specified in `archetypes/default.md`. You can create a custom archetype for your posts at `archetypes/posts.md` that includes the full set of front matter to be added to the two default archetypes fields.
### Create a Custom Archetype
{{< code file="archetypes/posts.md">}}
+++
description = ""
tags = ""
categories = ""
+++
{{< /code >}}
### Use a Custom Archetype
With an `archetypes/posts.md` in place, you can use the Hugo CLI to create a new post with your preconfigured front matter in the `posts` content section:
{{< code file="new-post-from-custom.sh" >}}
$ hugo new posts/post-from-custom.md
{{< /code >}}
This time, Hugo recognizes our custom `archetypes/posts.md` archetype and uses it instead of `archetypes/default.md`. The generated file will now include the full list of front matter parameters, as well as the base archetype's `title` and `date`:
{{< output file="content/posts/post-from-custom-archetype.md" >}}
+++
categories = ""
date = 2017-02-13T17:24:43-08:00
description = ""
tags = ""
title = "post from custom archetype"
+++
{{< /output >}}
### Hugo Docs Custom Archetype
As an example of archetypes in practice, the following is the `functions` archetype from the Hugo docs:
{{< code file="archetypes/functions.md" >}}
{{< readfile file="/archetypes/functions.md" >}}
{{< /code >}}
{{% note %}}
The preceding archetype is kept up to date with every Hugo build by using Hugo's [`readFile` function](/functions/readfile/). For similar examples, see [Local File Templates](/templates/files/).
{{% /note %}}
[archetypes directory]: /getting-started/directory-structure/
[`now()`]: http://golang.org/pkg/time/#Now
[configuration file]: /getting-started/configuration/
[sections]: /content-management/sections/
[content types]: /content-management/types/
[front matter]: /content-management/front-matter/
[RFC 3339 format]: https://www.ietf.org/rfc/rfc3339.txt
[taxonomies]: /content-management/taxonomies/
[lookup]: /templates/lookup/
[templates]: /templates/
@@ -1,116 +0,0 @@
---
title: Links and Cross References
description: Hugo makes it easy to link documents together.
date: 2017-02-01
publishdate: 2017-02-01
lastmod: 2017-03-31
categories: [content management]
keywords: ["cross references","references", "anchors", "urls"]
menu:
docs:
parent: "content-management"
weight: 100
weight: 100 #rem
aliases: [/extras/crossreferences/]
toc: true
---
The `ref` and `relref` shortcodes link documents together, both of which are [built-in Hugo shortcodes][]. These shortcodes are also used to provide links to headings inside of your content, whether across documents or within a document. The only difference between `ref` and `relref` is whether the resulting URL is absolute (`http://1.com/about/`) or relative (`/about/`), respectively.
## Use `ref` and `relref`
```
{{</* ref "document.md" */>}}
{{</* ref "#anchor" */>}}
{{</* ref "document.md#anchor" */>}}
{{</* relref "document.md" */>}}
{{</* relref "#anchor" */>}}
{{</* relref "document.md#anchor" */>}}
```
The single parameter to `ref` is a string with a content `documentname` (e.g., `about.md`) with or without an appended in-document `anchor` (`#who`) without spaces.
### Document Names
The `documentname` is the name of a document, including the format extension; this may be just the filename, or the relative path from the `content/` directory. With a document `content/blog/post.md`, either format will produce the same result:
```
{{</* relref "blog/post.md" */>}} => `/blog/post/`
{{</* relref "post.md" */>}} => `/blog/post/`
```
If you have the same filename used across multiple sections, you should only use the relative path format; otherwise, the behavior will be `undefined`. This is best illustrated with an example `content` directory:
```
.
└── content
├── events
│   └── my-birthday.md
├── galleries
│   └── my-birthday.md
├── meta
│   └── my-article.md
└── posts
└── my-birthday.md
```
To be sure to get the correct reference in this case, use the full path:
{{< code file="content/meta/my-article.md" copy="false" >}}
{{</* relref "events/my-birthday.md" */>}} => /events/my-birthday/
{{< /code >}}
### With Multiple Output Formats
If the page exists in multiple [output formats][], `ref` or `relref` can be used with a output format name:
```
[Neat]({{</* ref "blog/neat.md" "amp" */>}})
```
### Anchors
When an `anchor` is provided by itself, the current pages unique identifier will be appended; when an `anchor` is provided appended to `documentname`, the found page's unique identifier will be appended:
```
{{</* relref "#anchors" */>}} => #anchors:9decaf7
{{</* relref "about-hugo/hugo-features.md#content" */>}} => /blog/post/#who:badcafe
```
The above examples render as follows for this very page as well as a reference to the "Content" heading in the Hugo docs features pageyoursite
```
{{</* relref "#who" */>}} => #who:9decaf7
{{</* relref "blog/post.md#who" */>}} => /blog/post/#who:badcafe
```
More information about document unique identifiers and headings can be found [below]({{< ref "#hugo-heading-anchors" >}}).
### Examples
* `{{</* ref "blog/post.md" */>}}` => `https://example.com/blog/post/`
* `{{</* ref "post.md#tldr" */>}}` => `https://example.com/blog/post/#tldr:caffebad`
* `{{</* relref "post.md" */>}}` => `/blog/post/`
* `{{</* relref "blog/post.md#tldr" */>}}` => `/blog/post/#tldr:caffebad`
* `{{</* ref "#tldr" */>}}` => `#tldr:badcaffe`
* `{{</* relref "#tldr" */>}}` => `#tldr:badcaffe`
## Hugo Heading Anchors
When using Markdown document types, Hugo generates heading anchors automatically. The generated anchor for this section is `hugo-heading-anchors`. Because the heading anchors are generated automatically, Hugo takes some effort to ensure that heading anchors are unique both inside a document and across the entire site.
Ensuring heading uniqueness across the site is accomplished with a unique identifier for each document based on its path. Unless a document is renamed or moved between sections *in the filesystem*, the unique identifier for the document will not change: `blog/post.md` will always have a unique identifier of `81df004c333b392d34a49fd3a91ba720`.
`ref` and `relref` were added so you can make these reference links without having to know the documents unique identifier. (The links in document tables of contents are automatically up-to-date with this value.)
```
{{</* relref "content-management/cross-references.md#hugo-heading-anchors" */>}}
/content-management/cross-references/#hugo-heading-anchors:77cd9ea530577debf4ce0f28c8dca242
```
[built-in Hugo shortcodes]: /content-management/shortcodes/#using-the-built-in-shortcodes
[lists]: /templates/lists/
[output formats]: /templates/output-formats/
[shortcode]: /content-management/shortcodes/
@@ -1,182 +0,0 @@
---
title : "Page Bundles"
description : "Content organization using Page Bundles"
date : 2018-01-24T13:09:00-05:00
lastmod : 2018-01-28T22:26:40-05:00
linktitle : "Page Bundles"
keywords : ["page", "bundle", "leaf", "branch"]
categories : ["content management"]
draft : true
toc : true
menu :
docs:
identifier : "page-bundles"
parent : "content-management"
weight : 11
---
Page Bundles are a way to organize the content files. It's useful for
cases where a page or section's content needs to be split into
multiple content pages for convenience or has associated attachments
like documents or images.
A Page Bundle can be one of two types:
- Leaf Bundle
- Branch Bundle
| | Leaf Bundle | Branch Bundle |
|-----------------|--------------------------------------------------------|---------------------------------------------------------|
| Usage | Collection of content and attachments for single pages | Collection of content and attachments for section pages |
| Index file name | `index.md` [^fn:1] | `_index.md` [^fn:1] |
| Layout type | `single` | `list` |
| Nesting | Doesn't allow nesting of more bundles under it | Allows nesting of leaf/branch bundles under it |
| Example | `content/posts/my-post/index.md` | `content/posts/_index.md` |
## Leaf Bundles {#leaf-bundles}
A _Leaf Bundle_ is a directory at any hierarchy within the `content/`
directory, that contains at least an **`index.md`** file.
{{% note %}}
Here `md` (markdown) is used just as an example. You can use any file
type as a content resource as long as it is a MIME type recognized by
Hugo (`json` files will, as one example, work fine). If you want to
get exotic, you can define your own media type.
{{% /note %}}
### Examples of Leaf Bundle organization {#examples-of-leaf-bundle-organization}
```text
content/
├── about
│ ├── index.md
├── posts
│ ├── my-post
│ │ ├── content1.md
│ │ ├── content2.md
│ │ ├── image1.jpg
│ │ ├── image2.png
│ │ └── index.md
│ └── my-another-post
   └── index.md
└── another-section
├── ..
   └── not-a-leaf-bundle
├── ..
   └── another-leaf-bundle
   └── index.md
```
In the above example `content/` directory, there are four leaf
bundles:
about
: This leaf bundle is at the root level (directly under
`content` directory) and has only the `index.md`.
my-post
: This leaf bundle has the `index.md`, two other content
Markdown files and two image files.
my-another-post
: This leaf bundle has only the `index.md`.
another-leaf-bundle
: This leaf bundle is nested under couple of
directories. This bundle also has only the `index.md`.
{{% note %}}
The hierarchy depth at which a leaf bundle is created does not matter,
as long as it is not inside another **leaf** bundle.
{{% /note %}}
### Headless Bundle {#headless-bundle}
A headless bundle is a bundle that is configured to not get published
anywhere:
- It will have no `Permalink` and no rendered HTML in `public/`.
- It will not be part of `.Site.RegularPages`, etc.
But you can get it by `.Site.GetPage`. Here is an example:
```html
{{ $headless := .Site.GetPage "page" "some-headless-bundle" }}
{{ $reusablePages := $headless.Resources.Match "author*" }}
<h2>Authors</h2>
{{ range $reusablePages }}
<h3>{{ .Title }}</h3>
{{ .Content }}
{{ end }}
```
A leaf bundle can be made headless by adding below in the Front Matter
(in the `index.md`):
```toml
headless = true
```
{{% note %}}
Only leaf bundles can be made headless.
{{% /note %}}
There are many use cases of such headless page bundles:
- Shared media galleries
- Reusable page content "snippets"
## Branch Bundles {#branch-bundles}
A _Branch Bundle_ is any directory at any hierarchy within the
`content/` directory, that contains at least an **`_index.md`** file.
This `_index.md` can also be directly under the `content/` directory.
{{% note %}}
Here `md` (markdown) is used just as an example. You can use any file
type as a content resource as long as it is a MIME type recognized by
Hugo (`json` files will, as one example, work fine). If you want to
get exotic, you can define your own media type.
{{% /note %}}
### Examples of Branch Bundle organization {#examples-of-branch-bundle-organization}
```text
content/
├── branch-bundle-1
│   ├── branch-content1.md
│   ├── branch-content2.md
│   ├── image1.jpg
│   ├── image2.png
│   └── _index.md
└── branch-bundle-2
├── _index.md
└── a-leaf-bundle
└── index.md
```
In the above example `content/` directory, there are two branch
bundles (and a leaf bundle):
`branch-bundle-1`
: This branch bundle has the `_index.md`, two
other content Markdown files and two image files.
`branch-bundle-2`
: This branch bundle has the `_index.md` and a
nested leaf bundle.
{{% note %}}
The hierarchy depth at which a branch bundle is created does not
matter.
{{% /note %}}
[^fn:1]: The `.md` extension is just an example. The extension can be `.html`, `.json` or any of any valid MIME type.
@@ -1,48 +0,0 @@
---
title: Static Files
description: "The `static` folder is where you place all your **static files**."
date: 2017-11-18
categories: [content management]
keywords: [source, directories]
menu:
docs:
parent: "content-management"
weight: 130
weight: 130 #rem
aliases: [/static-files]
toc: true
---
The `static` folder is where you place all your **static files**, e.g. stylesheets, JavaScript, images etc.
You can set the name of the static folder to use in your configuration file, for example `config.toml`. From **Hugo 0.31** you can configure as many static directories as you need. All the files in all the static directories will form a union filesystem.
Example:
```toml
staticDir = ["static1", "static2"]
[languages]
[languages.no]
staticDir = ["staticDir_override", "static_no"]
baseURL = "https://example.no"
languageName = "Norsk"
weight = 1
title = "På norsk"
[languages.en]
staticDir2 = "static_en"
baseURL = "https://example.com"
languageName = "English"
weight = 2
title = "In English"
```
In the above, with no theme used:
* The English site will get its static files as a union of "static1", "static2" and "static_en". On file duplicates, the right-most version will win.
* The Norwegian site will get its static files as a union of "staticDir_override" and "static_no".
**Note:** The `2` `static2` (can be a number between 0 and 10) is added to tell Hugo that you want to **add** this directory to the global set of static directories. Using `staticDir` on the language level would replace the global value.
**Note:** The example above is a [multihost setup](/content-management/multilingual/#configure-multilingual-multihost). In a regular setup, all the static directories will be available to all sites.
@@ -33,7 +33,7 @@ features:
copy: Hugo allows you to output your content in multiple formats, including JSON or AMP, and makes it easy to create your own.
sections:
- heading: "100s of Themes"
cta: Check out the Hugo's themes.
cta: Check out the Hugo themes.
link: http://themes.gohugo.io/
color_classes: bg-accent-color white
image: /images/homepage-screenshot-hugo-themes.jpg
@@ -29,14 +29,14 @@ This has many benefits. The most noticeable is performance. HTTP servers are *ve
* ["An Introduction to Static Site Generators", David Walsh][]
* ["Hugo vs. Wordpress page load speed comparison: Hugo leaves WordPress in its dust", GettingThingsTech][hugovwordpress]
* ["Static Site Generators", O-Reilly][]
* ["Static Site Generators", O'Reilly][]
* [StaticGen: Top Open-Source Static Site Generators (GitHub Stars)][]
* ["Top 10 Static Website Generators", Netlify blog][]
* ["The Resurgence of Static", dotCMS][dotcms]
["An Introduction to Static Site Generators", David Walsh]: https://davidwalsh.name/introduction-static-site-generators
["Static Site Generators", O-Reilly]: /documents/oreilly-static-site-generators.pdf
["Static Site Generators", O'Reilly]: http://www.oreilly.com/web-platform/free/files/static-site-generators.pdf
["Top 10 Static Website Generators", Netlify blog]: https://www.netlify.com/blog/2016/05/02/top-ten-static-website-generators/
[hugovwordpress]: https://gettingthingstech.com/hugo-vs.-wordpress-page-load-speed-comparison-hugo-leaves-wordpress-in-its-dust/
[StaticGen: Top Open-Source Static Site Generators (GitHub Stars)]: https://www.staticgen.com/
@@ -53,12 +53,13 @@ toc: true
* Integrated [Google Analytics][] support
* Automatic [RSS][] creation
* Support for [Go][], [Amber], and [Ace][] HTML templates
* [Syntax highlighting][] powered by [Pygments][]
* [Syntax highlighting][] powered by [Chroma][] (partly compatible with Pygments)
[Ace]: /templates/alternatives/
[aliases]: /content-management/urls/#aliases
[Amber]: https://github.com/eknkc/amber
[Chroma]: https://github.com/alecthomas/chroma
[content summaries]: /content-management/summaries/
[content types]: /content-management/types/
[Disqus]: https://disqus.com/
@@ -77,7 +78,6 @@ toc: true
[Permalink]: /content-management/urls/#permalinks
[Powerful theming]: /themes/
[Pretty URLs]: /content-management/urls/
[Pygments]: http://pygments.org/
[RSS]: /templates/rss/
[Shortcodes]: /content-management/shortcodes/
[sort content]: /templates/
+134
View File
@@ -0,0 +1,134 @@
---
title: Hugo and the General Data Protection Regulation (GDPR)
linktitle: Hugo and GDPR
description: About how to configure your Hugo site to meet the new regulations.
date: 2018-05-25
layout: single
keywords: ["GDPR", "Privacy", "Data Protection"]
menu:
docs:
parent: "about"
weight: 5
weight: 5
sections_weight: 5
draft: false
aliases: [/privacy/,/gdpr/]
toc: true
---
General Data Protection Regulation ([GDPR](https://en.wikipedia.org/wiki/General_Data_Protection_Regulation)) is a regulation in EU law on data protection and privacy for all individuals within the European Union and the European Economic Area. It became enforceable on 25 May 2018.
**Hugo is a static site generator. By using Hugo you are already standing on very solid ground. Static HTML files on disk are much easier to reason about compared to server and database driven web sites.**
But even static websites can integrate with external services, so from version `0.41`, Hugo provides a **Privacy Config** that covers the relevant built-in templates.
Note that:
* These settings have their defaults setting set to _off_, i.e. how it worked before Hugo `0.41`. You must do your own evaluation of your site and apply the appropriate settings.
* We will continue this work and improve this further in future Hugo versions.
## All Privacy Settings
Below are all privacy settings and their default value. These settings need to be put in your site config (e.g. `config.toml`).
{{< code-toggle file="config">}}
[privacy]
[privacy.disqus]
disable = false
[privacy.googleAnalytics]
disable = false
respectDoNotTrack = false
anonymizeIP = false
useSessionStorage = false
[privacy.instagram]
disable = false
simple = false
[privacy.twitter]
disable = false
enableDNT = false
simple = false
[privacy.vimeo]
disable = false
simple = false
[privacy.youtube]
disable = false
privacyEnhanced = false
{{< /code-toggle >}}
## Disable All Services
An example Privacy Config that disables all the relevant services in Hugo. With this configuration, the other settings will not matter.
{{< code-toggle file="config">}}
[privacy]
[privacy.disqus]
disable = true
[privacy.googleAnalytics]
disable = true
[privacy.instagram]
disable = true
[privacy.twitter]
disable = true
[privacy.vimeo]
disable = true
[privacy.youtube]
disable = true
{{< /code-toggle >}}
## The Privacy Settings Explained
### GoogleAnalytics
anonymizeIP
: Enabling this will make it so the users' IP addresses are anonymized within Google Analytics.
respectDoNotTrack
: Enabling this will make the GA templates respect the "Do Not Track" HTTP header.
useSessionStorage
: Enabling this will disable the use of Cookies and use Session Storage to Store the GA Client ID.
### Instagram
simple
: If simple mode is enabled, a static and no-JS version of the Instagram image card will be built. Note that this only supports image cards and the image itself will be fetched from Instagram's servers.
**Note:** If you use the _simple mode_ for Instagram and a site styled with Bootstrap 4, you may want to disable the inlines styles provided by Hugo:
{{< code-toggle file="config">}}
[services]
[services.instagram]
disableInlineCSS = true
{{< /code-toggle >}}
### Twitter
enableDNT
: Enabling this for the twitter/tweet shortcode, the tweet and its embedded page on your site are not used for purposes that include personalized suggestions and personalized ads.
simple
: If simple mode is enabled, a static and no-JS version of a tweet will be built.
**Note:** If you use the _simple mode_ for Twitter, you may want to disable the inlines styles provided by Hugo:
{{< code-toggle file="config">}}
[services]
[services.twitter]
disableInlineCSS = true
{{< /code-toggle >}}
### YouTube
privacyEnhanced
: When you turn on privacy-enhanced mode, YouTube wont store information about visitors on your website unless the user plays the embedded video.
### Vimeo
simple
: If simple mode is enabled, the video thumbnail is fetched from Vimeo's servers and it is overlayed with a play button. If the user clicks to play the video, it will open in a new tab directly on Vimeo's website.
@@ -24,7 +24,7 @@ This documentation belongs in other places in this documentation site, but is pu
Also see this demo project from [bep](https://github.com/bep/), the clever Norwegian behind these new features:
* http://hugotest.bep.is/
* https://temp.bep.is/hugotest/
* https://github.com/bep/hugotest (source)
## Page Resources
@@ -61,7 +61,7 @@ Note that changes to any resource inside the `content` folder will trigger a rel
#### List all Resources
```html
```go-html-template
{{ range .Resources }}
<li><a href="{{ .RelPermalink }}">{{ .ResourceType | title }}</a></li>
{{ end }}
@@ -73,7 +73,7 @@ For an absolute URL, use `.Permalink`.
#### List All Resources by Type
```html
```go-html-template
{{ with .Resources.ByType "image" }}
{{ end }}
@@ -83,7 +83,7 @@ Type here is `page` for pages, else the main type in the MIME type, so `image`,
#### Get a Specific Resource
```html
```go-html-template
{{ $logo := .Resources.GetByPrefix "logo" }}
{{ with $logo }}
{{ end }}
@@ -91,7 +91,7 @@ Type here is `page` for pages, else the main type in the MIME type, so `image`,
#### Include Page Resource Content
```html
```go-html-template
{{ with .Resources.ByType "page" }}
{{ range . }}
<h3>{{ .Title }}</h3>
@@ -146,7 +146,7 @@ This is the shortcode used in the examples above:
And it is used like this:
```html
```go-html-template
{{</* imgproc sunset Resize "300x" */>}}
```

Before

Width:  |  Height:  |  Size: 88 KiB

After

Width:  |  Height:  |  Size: 88 KiB

@@ -43,27 +43,23 @@ Hugo is for people building a blog, a company site, a portfolio site, documentat
[@spf13]: https://twitter.com/@spf13
[Aerobatic]: https://www.aerobatic.com/
[Amazon S3]: http://aws.amazon.com/s3/
[Azure]: https://blogs.msdn.microsoft.com/acoat/2016/01/28/publish-a-static-web-site-using-azure-web-apps/
[CloudFront]: http://aws.amazon.com/cloudfront/ "Amazon CloudFront"
[contributing to it]: https://github.com/gohugoio/hugo
[DreamHost]: http://www.dreamhost.com/
[Amazon S3]: https://aws.amazon.com/s3/
[Azure]: https://docs.microsoft.com/en-us/azure/storage/blobs/storage-blob-static-website
[CloudFront]: https://aws.amazon.com/cloudfront/ "Amazon CloudFront"
[DreamHost]: https://www.dreamhost.com/
[Firebase]: https://firebase.google.com/docs/hosting/ "Firebase static hosting"
[GitHub Pages]: https://pages.github.com/
[GitLab Pages]: https://about.gitlab.com/features/pages/
[Go language]: https://golang.org/
[GoDaddy]: https://www.godaddy.com/ "Godaddy.com Hosting"
[Google Cloud Storage]: http://cloud.google.com/storage/
[Google Cloud Storage]: https://cloud.google.com/storage/
[Heroku]: https://www.heroku.com/
[Jekyll]: http://jekyllrb.com/
[Jekyll]: https://jekyllrb.com/
[Middleman]: https://middlemanapp.com/
[Middleman]: https://middlemanapp.com/
[Nanoc]: http://nanoc.ws/
[Nanoc]: https://nanoc.ws/
[Netlify]: https://netlify.com
[Rackspace]: https://www.rackspace.com/cloud/files
[Surge]: https://surge.sh
[contributing to it]: https://github.com/gohugoio/hugo
[rackspace]: https://www.rackspace.com/cloud/files
[static site generator]: /about/benefits/
[Rackspace]: https://www.rackspace.com/cloud/files
[static site generator]: /about/benefits/
[Surge]: https://surge.sh
@@ -1,5 +1,5 @@
---
date: 2018-01-31T11:40:21+01:00
date: 2018-04-16
title: "hugo"
slug: hugo
url: /commands/hugo/
@@ -77,4 +77,4 @@ hugo [flags]
* [hugo server](/commands/hugo_server/) - A high performance webserver
* [hugo version](/commands/hugo_version/) - Print the version number of Hugo
###### Auto generated by spf13/cobra on 31-Jan-2018
###### Auto generated by spf13/cobra on 16-Apr-2018
@@ -1,5 +1,5 @@
---
date: 2018-01-31T11:40:21+01:00
date: 2018-04-16
title: "hugo benchmark"
slug: hugo_benchmark
url: /commands/hugo_benchmark/
@@ -70,4 +70,4 @@ hugo benchmark [flags]
* [hugo](/commands/hugo/) - hugo builds your site
###### Auto generated by spf13/cobra on 31-Jan-2018
###### Auto generated by spf13/cobra on 16-Apr-2018
@@ -1,5 +1,5 @@
---
date: 2018-01-31T11:40:21+01:00
date: 2018-04-16
title: "hugo check"
slug: hugo_check
url: /commands/hugo_check/
@@ -35,4 +35,4 @@ Contains some verification checks
* [hugo](/commands/hugo/) - hugo builds your site
* [hugo check ulimit](/commands/hugo_check_ulimit/) - Check system ulimit settings
###### Auto generated by spf13/cobra on 31-Jan-2018
###### Auto generated by spf13/cobra on 16-Apr-2018
@@ -1,5 +1,5 @@
---
date: 2018-01-31T11:40:21+01:00
date: 2018-04-16
title: "hugo check ulimit"
slug: hugo_check_ulimit
url: /commands/hugo_check_ulimit/
@@ -39,4 +39,4 @@ hugo check ulimit [flags]
* [hugo check](/commands/hugo_check/) - Contains some verification checks
###### Auto generated by spf13/cobra on 31-Jan-2018
###### Auto generated by spf13/cobra on 16-Apr-2018
@@ -1,5 +1,5 @@
---
date: 2018-01-31T11:40:21+01:00
date: 2018-04-16
title: "hugo config"
slug: hugo_config
url: /commands/hugo_config/
@@ -19,7 +19,8 @@ hugo config [flags]
### Options
```
-h, --help help for config
-h, --help help for config
-s, --source string filesystem path to read files relative from
```
### Options inherited from parent commands
@@ -38,4 +39,4 @@ hugo config [flags]
* [hugo](/commands/hugo/) - hugo builds your site
###### Auto generated by spf13/cobra on 31-Jan-2018
###### Auto generated by spf13/cobra on 16-Apr-2018
@@ -1,5 +1,5 @@
---
date: 2018-01-31T11:40:21+01:00
date: 2018-04-16
title: "hugo convert"
slug: hugo_convert
url: /commands/hugo_convert/
@@ -42,4 +42,4 @@ See convert's subcommands toJSON, toTOML and toYAML for more information.
* [hugo convert toTOML](/commands/hugo_convert_totoml/) - Convert front matter to TOML
* [hugo convert toYAML](/commands/hugo_convert_toyaml/) - Convert front matter to YAML
###### Auto generated by spf13/cobra on 31-Jan-2018
###### Auto generated by spf13/cobra on 16-Apr-2018
@@ -1,5 +1,5 @@
---
date: 2018-01-31T11:40:21+01:00
date: 2018-04-16
title: "hugo convert toJSON"
slug: hugo_convert_toJSON
url: /commands/hugo_convert_tojson/
@@ -42,4 +42,4 @@ hugo convert toJSON [flags]
* [hugo convert](/commands/hugo_convert/) - Convert your content to different formats
###### Auto generated by spf13/cobra on 31-Jan-2018
###### Auto generated by spf13/cobra on 16-Apr-2018
@@ -1,5 +1,5 @@
---
date: 2018-01-31T11:40:21+01:00
date: 2018-04-16
title: "hugo convert toTOML"
slug: hugo_convert_toTOML
url: /commands/hugo_convert_totoml/
@@ -42,4 +42,4 @@ hugo convert toTOML [flags]
* [hugo convert](/commands/hugo_convert/) - Convert your content to different formats
###### Auto generated by spf13/cobra on 31-Jan-2018
###### Auto generated by spf13/cobra on 16-Apr-2018
@@ -1,5 +1,5 @@
---
date: 2018-01-31T11:40:21+01:00
date: 2018-04-16
title: "hugo convert toYAML"
slug: hugo_convert_toYAML
url: /commands/hugo_convert_toyaml/
@@ -42,4 +42,4 @@ hugo convert toYAML [flags]
* [hugo convert](/commands/hugo_convert/) - Convert your content to different formats
###### Auto generated by spf13/cobra on 31-Jan-2018
###### Auto generated by spf13/cobra on 16-Apr-2018
@@ -1,5 +1,5 @@
---
date: 2018-01-31T11:40:21+01:00
date: 2018-04-16
title: "hugo env"
slug: hugo_env
url: /commands/hugo_env/
@@ -38,4 +38,4 @@ hugo env [flags]
* [hugo](/commands/hugo/) - hugo builds your site
###### Auto generated by spf13/cobra on 31-Jan-2018
###### Auto generated by spf13/cobra on 16-Apr-2018
@@ -1,5 +1,5 @@
---
date: 2018-01-31T11:40:21+01:00
date: 2018-04-16
title: "hugo gen"
slug: hugo_gen
url: /commands/hugo_gen/
@@ -38,4 +38,4 @@ A collection of several useful generators.
* [hugo gen doc](/commands/hugo_gen_doc/) - Generate Markdown documentation for the Hugo CLI.
* [hugo gen man](/commands/hugo_gen_man/) - Generate man pages for the Hugo CLI
###### Auto generated by spf13/cobra on 31-Jan-2018
###### Auto generated by spf13/cobra on 16-Apr-2018
@@ -1,5 +1,5 @@
---
date: 2018-01-31T11:40:21+01:00
date: 2018-04-16
title: "hugo gen autocomplete"
slug: hugo_gen_autocomplete
url: /commands/hugo_gen_autocomplete/
@@ -56,4 +56,4 @@ hugo gen autocomplete [flags]
* [hugo gen](/commands/hugo_gen/) - A collection of several useful generators.
###### Auto generated by spf13/cobra on 31-Jan-2018
###### Auto generated by spf13/cobra on 16-Apr-2018
@@ -1,5 +1,5 @@
---
date: 2018-01-31T11:40:21+01:00
date: 2018-04-16
title: "hugo gen chromastyles"
slug: hugo_gen_chromastyles
url: /commands/hugo_gen_chromastyles/
@@ -43,4 +43,4 @@ hugo gen chromastyles [flags]
* [hugo gen](/commands/hugo_gen/) - A collection of several useful generators.
###### Auto generated by spf13/cobra on 31-Jan-2018
###### Auto generated by spf13/cobra on 16-Apr-2018
@@ -1,5 +1,5 @@
---
date: 2018-01-31T11:40:21+01:00
date: 2018-04-16
title: "hugo gen doc"
slug: hugo_gen_doc
url: /commands/hugo_gen_doc/
@@ -45,4 +45,4 @@ hugo gen doc [flags]
* [hugo gen](/commands/hugo_gen/) - A collection of several useful generators.
###### Auto generated by spf13/cobra on 31-Jan-2018
###### Auto generated by spf13/cobra on 16-Apr-2018

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