Compare commits

...

803 Commits

Author SHA1 Message Date
hugoreleaser 6608f15570 releaser: Add release notes to /docs for release of 0.62.0
[ci skip]
2019-12-23 10:23:27 +00:00
hugoreleaser b361d9a462 releaser: Bump versions for release of 0.62.0
[ci skip]
2019-12-23 10:23:27 +00:00
Bjørn Erik Pedersen 592a7d104d Release 0.62.0 2019-12-23 10:49:08 +01:00
hugoreleaser 93216fda72 releaser: Add release notes for 0.62.0
Rename to *-ready.md to continue.
[ci skip]
2019-12-23 08:57:02 +00:00
Bjørn Erik Pedersen 740b72558b Merge commit '8a4005cf2b0ef34265ff8051a6b76226685fc226' 2019-12-22 22:51:45 +01:00
Bjørn Erik Pedersen 8a4005cf2b Squashed 'docs/' changes from af4b7ac5b..54f0e8776
54f0e8776 Update image-actions.yml
94e5cad02 Update image-actions.yml
0ad20d226 Add a page about Hugo's Security Model
0dee16d11 Link to Régis Full Partials series
138782808 Update partialCached.md

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

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

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

* Text - rendered
* PlainText

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

See:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

This commit fixes that.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

This is a broad subject, but some keywords include:

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

All of the above is backed by Go Modules.

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

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

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

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

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

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

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

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

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

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

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

This commit fixes that by unwrapping such interface values.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Fixes #5882
2019-04-22 13:22:01 +02:00
hugoreleaser 1477fb33c9 releaser: Prepare repository for 0.56.0-DEV
[ci skip]
2019-04-20 14:25:57 +00:00
hugoreleaser 993b84333c releaser: Add release notes to /docs for release of 0.55.3
[ci skip]
2019-04-20 14:23:12 +00:00
hugoreleaser a9ee2ab58c releaser: Bump versions for release of 0.55.3
[ci skip]
2019-04-20 14:23:12 +00:00
Bjørn Erik Pedersen c85b726f8a Release 0.55.3 2019-04-20 16:12:42 +02:00
hugoreleaser 89cf7a3f4b releaser: Add release notes draft for 0.55.3
Rename to *-ready.md to continue. [ci skip]
2019-04-20 14:08:54 +00:00
Bjørn Erik Pedersen 75b16e30ec docs: Regenerate docs helper 2019-04-20 15:20:08 +02:00
Bjørn Erik Pedersen 0508ca1856 Merge commit 'a0c28c943c2f4714fa340b22a583b96f5013090b' 2019-04-20 15:19:38 +02:00
Bjørn Erik Pedersen a0c28c943c Squashed 'docs/' changes from 0f2bf195e..13097daf2
13097daf2 Update shortcode docs vs 0.55
9a7e19231 Update URL docs for relative URLs etc
bd58dd877 Adjust Output Formats docs
f3e9fbc00 Document output format `permalinkable`
3778ce689 Update partials.md
7b207a404 Partial: Update variable name in example
7d7b1f03c Document partials returning a value.
7ae93b7ca Merge branch 'temp552'
81910d266 releaser: Add release notes to /docs for release of 0.55.2
c166cef47 Fix typo
23adeb672 Point mmark links to its new repository
369a87339 Merge branch 'temp551'
eb6097e9f Bump to 0.55.1
766ee61a8 releaser: Add release notes to /docs for release of 0.55.1
a5a5f5d75 Start of taxonomy docs update for Hugo 0.55
fb5f75e9a Remove the space in `. RelPermalink`

git-subtree-dir: docs
git-subtree-split: 13097daf2e
2019-04-20 15:18:59 +02:00
Bjørn Erik Pedersen c7dd66bfe2 Fix links for non-HTML output formats
They were not correct for regular pages.

Fixes #5877
2019-04-20 15:01:20 +02:00
Bjørn Erik Pedersen 7aeeb60d7e hugolib: Add some OutputFormats.Get tests
See #5877
2019-04-19 10:52:31 +02:00
Bjørn Erik Pedersen ea529c847e Fix menu URL when multiple permalinkable output formats
In Hugo `0.55` we introduced the `permalinkable` config attribute on Output Format, default enabled for `AMP` and `HTML`.

This meant that a Page could have different `RelPermalink` and `Permalink` depending on the rendering format.

The menu `URL` did not reflect that fact.

Fixes #5849
2019-04-19 10:29:52 +02:00
Bjørn Erik Pedersen 6c80acbd5e hugolib: Add some integration tests for in/uniq using Pages
See #5875
See #5852
2019-04-19 09:07:21 +02:00
Bjørn Erik Pedersen 7fbfedf013 tpl/collections: Return error on invalid input in in
See #5875
2019-04-19 08:58:12 +02:00
Bjørn Erik Pedersen 06f56fc983 tpl/collections: Make Pages etc. work with the in func
Fixes #5875
2019-04-18 23:42:01 +02:00
Bjørn Erik Pedersen d7a67dcb51 tpl/collections: Make Pages etc. work in uniq
Fixes #5852
2019-04-18 16:50:13 +02:00
Bjørn Erik Pedersen 3e421bd47c commands: Replace IsDraft with Draft in list command
Fixes #5873
2019-04-18 09:25:40 +02:00
hugoreleaser 1028760331 releaser: Prepare repository for 0.56.0-DEV
[ci skip]
2019-04-17 12:22:55 +00:00
hugoreleaser 9d02034881 releaser: Add release notes to /docs for release of 0.55.2
[ci skip]
2019-04-17 12:20:37 +00:00
hugoreleaser ccfbb63d17 releaser: Bump versions for release of 0.55.2
[ci skip]
2019-04-17 12:20:37 +00:00
Bjørn Erik Pedersen fcd63a865e Release 0.55.2 2019-04-17 14:13:46 +02:00
hugoreleaser 7ace59d5bf releaser: Add release notes draft for 0.55.2
Rename to *-ready.md to continue. [ci skip]
2019-04-17 12:10:37 +00:00
Bjørn Erik Pedersen 35f41834ea hugolib: Add more tests for Permalinkable
See #5849
2019-04-17 13:26:27 +02:00
Bjørn Erik Pedersen 9b17cbb62a hugolib: Fix Pages reinitialization on rebuilds
Which had some unpredictable behaviour when using `.Pages` on home page etc. that had a content page.

Fixes #5833
2019-04-17 12:56:46 +02:00
Bjørn Erik Pedersen 2957795f52 tpl/tplimpl: Handle late transformation of templates
Fixes #5865
2019-04-16 21:24:09 +02:00
Bjørn Erik Pedersen 56550d1e44 hugolib: Fix shortcode namespace issue
Fixes #5863
2019-04-15 18:31:56 +02:00
Bjørn Erik Pedersen 7881b0965f hugolib: Fix false WARNINGs in lang prefix check
Add a slash to the check to make it less likely to match a valid value.

Fixes #5860
2019-04-15 17:12:29 +02:00
Bjørn Erik Pedersen 49d0a82641 hugolib: Fix bundle resource publishing when multiple output formats
The faulty logic published the bundled resources for the "first output" format.

This worked most of the time, but since the output formats list is sorted,
any output format only used for some of the pages (e.g. CSS) would not work properly.

Fixes #5858
2019-04-15 17:01:39 +02:00
Bjørn Erik Pedersen b799b12f4a hugolib: Fix panic for unused taxonomy content files
In Hugo 0.55 we connected the taxonomy nodes with their owning Page.

This failed if you had, say, a content file for a author that did not author anything in the site:

```
content/authors/silent-persin/_index.md
```

Fixes #5847
2019-04-15 13:36:05 +02:00
Bjørn Erik Pedersen 701486728e hugolib: Fix dates for sections with dates in front matter
Fixes #5854
2019-04-13 20:01:43 +02:00
Bjørn Erik Pedersen f2795d4d2c Fix WeightedPages in union etc.
We introduced a callback func() to get the owner Page in 0.55.0.

Sadly, funcs is  not comparable type in Go.

This commit replaces the func with a struct pointer that wraps the Page.

Fixes #5850
2019-04-13 18:52:38 +02:00
hugoreleaser e85c057f99 releaser: Prepare repository for 0.56.0-DEV
[ci skip]
2019-04-12 09:58:35 +00:00
hugoreleaser 223b3c2eec releaser: Add release notes to /docs for release of 0.55.1
[ci skip]
2019-04-12 09:56:13 +00:00
hugoreleaser 7ca15c7ddb releaser: Bump versions for release of 0.55.1
[ci skip]
2019-04-12 09:56:13 +00:00
Bjørn Erik Pedersen adb776b22b Release 0.55.1 2019-04-12 11:30:04 +02:00
hugoreleaser 5efdd14ebd releaser: Add release notes draft for 0.55.1
Rename to *-ready.md to continue. [ci skip]
2019-04-12 09:29:27 +00:00
Bjørn Erik Pedersen 8d7607aed1 hugolib: Add a test for parent's resources in shortcode
See #5833
2019-04-12 10:44:21 +02:00
Bjørn Erik Pedersen 4d425a86f5 Fix 2019-04-12 10:26:10 +02:00
Bjørn Erik Pedersen 9e9a1f92ba hugolib: Fix simple menu config
This stopped working in Hugo 0.55:

```bash
---
menu: "main"
---
```

This was also the case for using a slice of menu entries.

This still worked:

---
menu:
  main:
    weight: 30
---
2019-04-12 10:04:17 +02:00
Bjørn Erik Pedersen f7375c4972 Fix paginator refresh on server change
Fixes #5838
2019-04-12 09:18:59 +02:00
Yihui Xie 7966c0b5b7 Remove the space in . RelPermalink
The same fix as 3b86b4a9f5, applied to doc.
2019-04-10 22:45:20 +02:00
Bjørn Erik Pedersen cc98fc8ad2 Merge commit '8b73644d81a81e82851b7f7c90aa8ab5524fbe93' 2019-04-09 23:59:59 +02:00
Bjørn Erik Pedersen 8b73644d81 Squashed 'docs/' changes from acf70cdd9..0f2bf195e
0f2bf195e Adjust shortcodes for 0.55
48c577121 Fix deprecation warnings
ed95a341a Update index.md
e4bc8981f Release 0.55.0
25acacb91 Merge branch 'temp55'
b240e321a releaser: Add release notes to /docs for release of 0.55.0
86a190c92 docs: Add information about summary front matter variable
9d94f4340 integrity: Add support for sha384
dd3fe9f92 Add HUGO_NUMWORKERMULTIPLIER
968372d86 Add trace.out to .gitignore
660772713 Add the Fireship images to cache
41a3e19cb hugolib: Allow page-relative aliases
4497e4b12 Update faq.md
b0ee3dccc output: Add missing JSON tag
173dac0b7 docs: Regenerate docshelper data
e30473062 docs: Regenerate CLI docs
8cb775be2 Merge commit 'c2037f0c9a3a35b9db9c404f6b5f94ec8b690a53'
5bc64bf44 Make Page an interface
371ff6c12 Add skipHTML option to blackfriday config

git-subtree-dir: docs
git-subtree-split: 0f2bf195ef
2019-04-09 23:59:13 +02:00
Bjørn Erik Pedersen 3b86b4a9f5 resources/page: Fix .RSSLinke deprecation message
Closes #4427
2019-04-09 16:47:29 +02:00
Bjørn Erik Pedersen 27a8049da7 tpl/tplimpl: Replace deprecated .GetParam usage
Fixes #5834
2019-04-09 16:39:12 +02:00
hugoreleaser ee4274244b releaser: Prepare repository for 0.56.0-DEV
[ci skip]
2019-04-08 16:42:12 +00:00
hugoreleaser 4333cc77fe releaser: Add release notes to /docs for release of 0.55.0
[ci skip]
2019-04-08 16:39:45 +00:00
hugoreleaser 452cdcd7c8 releaser: Bump versions for release of 0.55.0
[ci skip]
2019-04-08 16:39:45 +00:00
Bjørn Erik Pedersen 05d614e13b Release 0.55.0 2019-04-08 18:34:48 +02:00
hugoreleaser 018cd0c9da releaser: Add release notes draft for 0.55.0
Rename to *-ready.md to continue. [ci skip]
2019-04-08 18:33:35 +02:00
Bjørn Erik Pedersen 612a06f067 Misc paginator adjustments
* Rewind paginator for server mode
* Add some more related tests.
* Replace the clumsy scratch constructs in internal paginator template with variables

See #5825
2019-04-08 11:02:12 +02:00
Bjørn Erik Pedersen 3db4a1cf7a Update to Go 1.12.2 and Go 1.11.7
Fixes #5819
2019-04-07 18:54:53 +02:00
Bjørn Erik Pedersen f34e6172cf hugolib: Log warning on relative front matter url with lang
Will do this for one version only, as there may be situations where this is the correct thing.

Also add some more related test cases.

Fixes #5818
2019-04-07 18:54:18 +02:00
Bjørn Erik Pedersen 708d4ceebd Adjust rlimit logic
Closes #5821
2019-04-07 00:53:55 +02:00
Jim McDonald ed65bda3b4 docs: Add information about summary front matter variable 2019-04-06 00:17:54 +02:00
Jim McDonald 3a62d54745 hugolib: Consider summary in front matter for .Summary
Add the ability to have a `summary` page variable that overrides
the auto-generated summary.  Logic for obtaining summary becomes:

  * if summary divider is present in content, use the text above it
  * if summary variables is present in page metadata, use that
  * auto-generate summary from first _x_ words of the content

Fixes #5800
2019-04-05 19:11:04 +02:00
Bjørn Erik Pedersen ebab291c0e resources/page: Regenerate JSON wrapper 2019-04-05 16:58:52 +02:00
Bjørn Erik Pedersen 75467cd785 resources/page: Add missing GitInfo to Page 2019-04-05 16:52:37 +02:00
Bjørn Erik Pedersen d1553b4b0f integrity: Add support for sha384
Fixes #5815
2019-04-05 16:35:07 +02:00
Bjørn Erik Pedersen 1d9dde82a0 hugolib: Fix default date assignment for sections
See #5784
2019-04-05 11:20:09 +02:00
Bjørn Erik Pedersen 87b16abd93 Add HUGO_NUMWORKERMULTIPLIER
And use that to calculate number of workers, if set, else fall back to number of logical CPUs.

Also tweak the relevant related settings to match the new setup.

Also remove the setting of `runtime.GOMAXPROCS` as this has been the default behaviour since Go 1.5.

Fixes #5814
2019-04-05 10:21:25 +02:00
Bjørn Erik Pedersen 415ca9673d hugolib: Fix the GOMAXPROCS env get
Fixes #5813
2019-04-05 09:57:43 +02:00
Bjørn Erik Pedersen 8559f5c29f Use YAML for the benchmark compare 2019-04-05 08:55:39 +02:00
Bjørn Erik Pedersen e2dc432fe2 hugolib: Fix benchmark for YAML front matter 2019-04-05 08:52:58 +02:00
Bjørn Erik Pedersen 950295516d hugolib: Buffer the render pages chan 2019-04-04 16:50:10 +02:00
Bjørn Erik Pedersen 032e6802d1 deps: Update to imaging v1.6.0
Closes #5812
2019-04-04 14:39:39 +02:00
Bjørn Erik Pedersen d0d661dffd hugolib: Re-work "fast render" logic in the new flow
Note that this fixes some "live reload" issues recently introduced in non-released code.

Closes #5811
See #5784
2019-04-04 13:51:22 +02:00
Bjørn Erik Pedersen 4494a01b79 metrics: Adjust the howSimilar logic vs strings
Also add a test.
2019-04-02 21:00:42 +02:00
Bjørn Erik Pedersen e91e222cd2 resources/page: Implement compare.ProbablyEqer for the core slices
Fixes #5808
2019-04-02 16:10:13 +02:00
Bjørn Erik Pedersen 5185fb065b hugolib: Allow relative URLs in front matter
Before this commit you would have to do this in multilingual setups:

```
---
title: "Custom!"
url: "/jp/custom/foo"
---
```

This commit allows for relative URLs, e.g:

```
---
title: "Custom!"
url: "custom/foo"
---
```

Which is obviously easier and more portable.

The meaning of relative may change to include more in the future (e.g. role based access).

Fixes #5704
2019-04-02 10:33:15 +02:00
Bjørn Erik Pedersen 92baa14fd3 hugolib: Allow page-relative aliases
Fixes #5757
2019-04-02 10:32:47 +02:00
Bjørn Erik Pedersen a55640de8e tpl: Allow the partial template func to return any type
This commit adds support for return values in partials.

This means that you can now do this and similar:

    {{ $v := add . 42 }}
    {{ return $v }}

Partials without a `return` statement will be rendered as before.

This works for both `partial` and `partialCached`.

Fixes #5783
2019-04-02 10:30:24 +02:00
Bjørn Erik Pedersen 9225db636e releaser: Remove version replacement in docs config
Fixes #5665
2019-04-01 09:11:36 +02:00
Bjørn Erik Pedersen f7ef7d3761 releaser: Adjust patch vs images logic
Fixes #5664
2019-04-01 09:07:19 +02:00
Bjørn Erik Pedersen f9d6feca08 hugolib: Fix alias path for AMP and similar
Fixes #5760
2019-03-30 16:46:51 +01:00
Bjørn Erik Pedersen 439ab0339d resources: Fix image publish ordering issue
Fixes #5730
2019-03-30 10:17:25 +01:00
Bjørn Erik Pedersen b6a60f718e output: Add missing JSON tag 2019-03-28 20:59:09 +01:00
Bjørn Erik Pedersen bfdc44964a docs: Regenerate docshelper data
Closes #5799
2019-03-28 09:49:54 +01:00
Bjørn Erik Pedersen cc8515f187 deps: Update Chroma
Closes #5780
2019-03-28 09:46:55 +01:00
Bjørn Erik Pedersen 8bfd3a54a4 hugolib: Add a simple test for jsonify of Site
Closes #5780
2019-03-28 09:45:25 +01:00
Bjørn Erik Pedersen bb533ca5e1 docs: Regenerate CLI docs
Fixes #5779
2019-03-26 18:46:01 +01:00
Bjørn Erik Pedersen 876e5f67b1 Merge commit 'c2037f0c9a3a35b9db9c404f6b5f94ec8b690a53' 2019-03-26 18:41:36 +01:00
Bjørn Erik Pedersen c2037f0c9a Squashed 'docs/' changes from 4f4d1f48c..acf70cdd9
acf70cdd9 Update CSS after removing Purge
74c0bb7f2 Remove purge from Webpack, temporarily
397b7284f Merge commit 'ccb1e38f3822e9b5e4fb89a296324daf3400f23b'
ccb1e38f3 Squashed 'themes/gohugoioTheme/' changes from 042112e2d..b7853ae70
bca84e914 Fix search box text being invisible in Safari
3f21d0957 FAQ: "this feature is not available in your current Hugo version"
d8b318f90 Remove Gulp from Victor Hugo description
09d9b4c24 Update contribute/development.md
4d0f6ba47 Theme Components Support on the Hugo Themes Site (#769)
f2ec3f2a6 Fix broken link 404
af82c56c5 config: Remove superflous param
8dc14f563 Update theme total on homepage (#765)
7838fd7e2 Update description of Atlas to reflect new changes
6abab23c6 update: total of hugo themes
1dba24fde Clarify: summaryLength uses words not characters
8c54f45d6 Add missing punctuation
d17000481 Remove Hugo Frontend caddy-plugin
a7094ae62 remove unneeded meta tags
f8b0f31c6 Fix typo in cross references
61781bab9 Fix: use gh shortcode correctly
357bfca43 Update files.md
d1d2406cc Updated Hugo convert to clarify for and not ..
86850f3c3 Fix typos in multilingual.md
b68d0d892 Fix typo
8cba70e28 Document disableAliases
00e440260 Remove extra whitespace
212d63e4c Update with latest Theme Submission Guidelines (#744)
c24ea638f Update frontends.md
942bc1972 Add one more video
2e1e1091d Update the rest of the videos
a7dc70f2b Add new installation video
1a78f8487 Hosting on AWS amplify
112420c46 Fix typo
f723425e4 Add fireship.io bio to showcase
574f43503 Fixed typo
88e0e0cb7 Release 0.54.0
303edf19e Merge branch 'temp54'
c38debebd releaser: Prepare repository for 0.55.0-DEV
5c6c56fa1 releaser: Add release notes to /docs for release of 0.54.0
f86e05950 releaser: Bump versions for release of 0.54.0
6a2684fe4 Add the default cache configuration
f75c0125a Merge commit 'f27faf9afd0a8db768a21954b8755f1bf1a14f1b'
e440dc6a4 Merge commit '5e078383a787e8b5ec3ba73f05ea4130840afbe2'
981bf53f8 Update _index.md
b54aea066 tpl: Fix reflect
41f8af5a6 Merge commit '978856e2ad12d2bcaf37bb9e31f806b30a4c42f4'

git-subtree-dir: docs
git-subtree-split: acf70cdd9f
2019-03-26 18:41:09 +01:00
Bjørn Erik Pedersen 9bc6187b83 hugolib: Do not fall back to site title if not set in content file
See #5784
2019-03-26 15:49:32 +01:00
Bjørn Erik Pedersen 10bb614a70 deps: Update Afero
Closes #5673
2019-03-26 13:12:58 +01:00
Bjørn Erik Pedersen bceda1b288 hugolib: Add a test for home page with no title
See #5784
2019-03-26 10:28:02 +01:00
Bjørn Erik Pedersen 4dae52af68 Avoid nilpointer on no File on Page
Fixes #5781
2019-03-26 10:20:40 +01:00
Bjørn Erik Pedersen 794d4052b8 herrors/errors: Improve the "feature not available" error 2019-03-26 10:15:57 +01:00
Bjørn Erik Pedersen a7ee9b0bb9 hugolib: Add String() to fileInfo
See #5784
2019-03-25 08:29:29 +01:00
Bjørn Erik Pedersen 91ef9655aa resources/page: Re-introduce .Page.Page
It was removed in 597e418cb0 -- it's not documented, but it's used in too many real sites on the web.

See #5784
2019-03-25 07:55:46 +01:00
Bjørn Erik Pedersen b5f39d23b8 all: Apply staticcheck recommendations 2019-03-24 16:14:51 +01:00
Bjørn Erik Pedersen 3011f36c27 hugolib: Remove unused slice 2019-03-24 16:14:51 +01:00
Bjørn Erik Pedersen d30e845485 Run gofmt -s 2019-03-23 20:15:06 +01:00
Bjørn Erik Pedersen 597e418cb0 Make Page an interface
The main motivation of this commit is to add a `page.Page` interface to replace the very file-oriented `hugolib.Page` struct.
This is all a preparation step for issue  #5074, "pages from other data sources".

But this also fixes a set of annoying limitations, especially related to custom output formats, and shortcodes.

Most notable changes:

* The inner content of shortcodes using the `{{%` as the outer-most delimiter will now be sent to the content renderer, e.g. Blackfriday.
  This means that any markdown will partake in the global ToC and footnote context etc.
* The Custom Output formats are now "fully virtualized". This removes many of the current limitations.
* The taxonomy list type now has a reference to the `Page` object.
  This improves the taxonomy template `.Title` situation and make common template constructs much simpler.

See #5074
Fixes #5763
Fixes #5758
Fixes #5090
Fixes #5204
Fixes #4695
Fixes #5607
Fixes #5707
Fixes #5719
Fixes #3113
Fixes #5706
Fixes #5767
Fixes #5723
Fixes #5769
Fixes #5770
Fixes #5771
Fixes #5759
Fixes #5776
Fixes #5777
Fixes #5778
2019-03-23 18:51:22 +01:00
Daniel Compton 44f5c1c14c List future and expired dates in CSV format
It is useful to see the date that a post will be published, or the date
that it has expired, to build tooling around it. This commit writes
posts and their publish/expired date as CSV.

Fixes #5610
2019-03-19 00:33:02 +01:00
Bjørn Erik Pedersen 984a73af9e Update to Go 1.12.1 and Go 1.11.6
Fixes #5755
2019-03-17 08:37:42 +01:00
Bjørn Erik Pedersen e54213f525 tpl/tplimpl: Fix mutex unlock 2019-03-16 09:40:27 +01:00
Bjørn Erik Pedersen 4a2a8afff2 commands: Fix doLiveReload logic
Fixes #5754
2019-03-14 21:39:00 +01:00
Bjørn Erik Pedersen 79d517d86c deps: Update Viper 2019-03-13 10:42:43 +01:00
Bjørn Erik Pedersen 34c49d788c hugolib: Adjust site benchmark
Having all the pages with shortcodes isn't realistic.
2019-03-12 20:27:50 +01:00
Bjørn Erik Pedersen b9e75afd6c Update to Go 1.12
Fixes #5716
2019-03-07 10:26:26 +01:00
Bjørn Erik Pedersen dfc72d61a5 Remove Gitter dev chat link
Almost every question we get there belong on https://discourse.gohugo.io/
2019-03-07 00:37:50 +01:00
Bjørn Erik Pedersen 02eaddc2fb tpl/tplimpl: Fix template truth logic
Before this commit, due to a bug in Go's `text/template` package, this would print different output for typed nil interface values:

```
{{ if .AuthenticatedUser }}User is authenticated!{{ else }}{{ end }}
{{ if not .AuthenticatedUser }}{{ else }}}User is authenticated!{{ end }}
```

This commit works around this by wrapping every `if` and `with` with a custom `getif` template func with truth logic that matches `not`, `and` and `or`.

Those 3 template funcs from Go's stdlib are now pulled into Hugo's source tree and adjusted to support custom zero values, e.g. types that implement `IsZero`.

This means that you can now do:

```
{{ with .Date }}{{ . }}{{ end }}
```

And it would work as expected.

Fixes #5738
2019-03-06 22:52:38 +01:00
grahamjamesaddis bdf47e8da8 Update Travis config to work for forked builds 2019-03-05 14:26:49 +01:00
arrtchiu 75904332f3 Add skipHTML option to blackfriday config 2019-03-04 11:27:18 +01:00
Elliott Sales de Andrade 60c0eb4e89 Update stretchr/testify to 1.3.0. 2019-03-02 10:24:21 +01:00
Berin Larson c154c2f7b2 Rewrite relative action URLS
Fixes #5701
2019-02-26 11:31:34 +01:00
Anthony Metzidis 075b17ee1d Support Docker args TAGS, WORKDIR, CGO; speed up repetitive builds 2019-02-22 11:53:17 -08:00
Bjørn Erik Pedersen b4148cd1d9 hugolib: Adjust test for Go 1.12 2019-02-19 21:47:38 +01:00
Anton Harniakou 908692fae5 Support nested keys/fields with missing values with the where function
Before this commit `where` would produce an error and bail building the
site. Now, `where` simply skips an element of a collection and does not
add it to the final result.

Closes #5637
Closes #5416
2019-02-06 19:53:34 +01:00
Bjørn Erik Pedersen 7e4b18c5ae commands: Update debouncer version 2019-02-02 14:05:28 +01:00
Iskander (Alex) Sharipov 483cf19d5d common/herrors: Fix args order in strings.TrimPrefix
Old code always returned "." or "" (if filepath.Ext(filename) returned ".").
Now it properly trims the prefix.

Signed-off-by: Iskander Sharipov <quasilyte@gmail.com>
2019-02-02 09:55:31 +01:00
Iskander (Alex) Sharipov 7201042946 tpl: Fix strings.HasPrefix args order 2019-02-02 01:26:05 +01:00
hugoreleaser 5383fe458c releaser: Prepare repository for 0.55.0-DEV
[ci skip]
2019-02-01 09:42:55 +00:00
hugoreleaser b1a82c61ab releaser: Add release notes to /docs for release of 0.54.0
[ci skip]
2019-02-01 09:40:32 +00:00
hugoreleaser 6fe6b9c17f releaser: Bump versions for release of 0.54.0
[ci skip]
2019-02-01 09:40:32 +00:00
Bjørn Erik Pedersen 52cec0fb2d Release 0.54.0 2019-02-01 10:34:37 +01:00
hugoreleaser 23e52ea4c8 releaser: Add release notes draft for 0.54.0
Rename to *-ready.md to continue. [ci skip]
2019-02-01 09:31:43 +00:00
Bjørn Erik Pedersen 9b619dc023 releaser: Adjust patch logic
See #5639
2019-02-01 10:09:14 +01:00
Bjørn Erik Pedersen fab41f42d3 common/hugo: Use official semver even for main releases
Closes #5639
2019-02-01 09:44:12 +01:00
Bjørn Erik Pedersen f27faf9afd Squashed 'docs/' changes from 49809a038..4f4d1f48c
4f4d1f48c Merge commit 'ccb3ee5c57a00d5d32c53c882cf9893181a6ec10'
ccb3ee5c5 Squashed 'themes/gohugoioTheme/' changes from dafc91ff1..042112e2d

git-subtree-dir: docs
git-subtree-split: 4f4d1f48cd
2019-02-01 09:08:24 +01:00
Bjørn Erik Pedersen c7c66e664a Merge commit 'f27faf9afd0a8db768a21954b8755f1bf1a14f1b' 2019-02-01 09:08:24 +01:00
Bjørn Erik Pedersen 5e078383a7 Squashed 'docs/' changes from 785e375f..49809a03
49809a03 Merge commit '20a631b4964fc0ab9137cce1e41774cbc17de044'
20a631b4 Squashed 'themes/gohugoioTheme/' changes from b8202f539..dafc91ff1
8b58f565 Re-generate CLI docs
4653a724 Add Netlify deployment badge
2d6246bc Remove some deprecated site variables
e6777153 Improve Algolia Search Display Styling
1570999f Add missing "." in front of gitlab-ci.yaml example
b922ae7d This adds documentation to the new configDir/Environment logic from .53 (#729)
7cff379f Correctly escape multi-word taxonomy terms in example
2dfeeda4 fix typo by removing stray paren
0870bd9a Fix typo in `paginate` description
91e8be85 Fixes https://github.com/gohugoio/hugo/issues/5609
c1db65ec Make the dummy URL more obvious
b4589ff0 Fix a link
b73dcb9a Consistently use "posts" as section name in examples
7a56abbc Format definitions
a9c6fd9b Minor clarification over the last commit
5c86bdc8 Add alternative instructions for Quick Start for non-git users
dafe7ee9 Add Visual Studio Code plug-ins
110ed19e Update HUGO_VERSION
2abd031a Update page.md
b332f7b9 Update page.md
f5a8c9d4 Update static-files.md
6d0c155c Add note about relative protocol URLs
a13751ac Theme Warning: Remove note about unquoted URLs
4c8f7d68 Incorporate feedback
6f2b9cf0 Update Creating Themes Warning
40d88d98 Fix ToC example to use binary true/false
4a11f3f1 Fix typo
2dbfc0a4 Fix a typo in taxonomies
d63790ef Do not mark UndocumentedFeature issues as stale
d7aff095 Regenerate docs.json
71c0826f Update transform.Unmarshal.md

git-subtree-dir: docs
git-subtree-split: 49809a038b
2019-02-01 09:01:04 +01:00
Bjørn Erik Pedersen ddc15ed41b Merge commit '5e078383a787e8b5ec3ba73f05ea4130840afbe2' 2019-02-01 09:01:04 +01:00
Bjørn Erik Pedersen ddc6d4e30f tpl/data: Adjust tests
See #5643
2019-02-01 08:54:30 +01:00
Anthony Fok 6a2bfcbec8 tpl/data: Prevent getJSON and getCSV fetch failure from aborting build
Fixes #5643
2019-02-01 08:52:29 +01:00
Bjørn Erik Pedersen 59d87044a4 commands: Add test for --configDir
See #5662
2019-02-01 08:40:53 +01:00
Bjørn Erik Pedersen 3244cb3b31 Ignore unknown config files in config dir
Swap files etc.

Fixes #5646
2019-02-01 07:47:40 +01:00
Anton Harniakou d9282cf98a Store supported config formats in a variable 2019-02-01 07:17:37 +01:00
Bjørn Erik Pedersen c52045bbb3 Fix some inline shortcode issues
Fixes #5645
Fixes #5653
2019-01-31 19:08:19 +01:00
Bjørn Erik Pedersen 8ed2a1caa9 Bump to Go 1.11.5
Fixes #5654
2019-01-31 13:23:55 +01:00
Bjørn Erik Pedersen e85961390a Update Afero
Fixes #5650
2019-01-30 09:35:55 +01:00
Anthony Fok 2a9060a85c hugolib: Expand TestPageWithEmoji to cover '+', '-' and '_' too
See #5635 and commit 3038464e
2019-01-29 13:03:42 -07:00
Anthony Fok 3038464ea6 Accept hyphen and plus sign in emoji detection
Fixes #5635
2019-01-29 05:38:36 -07:00
Elliot Murphy 526b5b1c49 Fix OpenGraph image fallback to site params
Signed-off-by: Elliot Murphy <statik@users.noreply.github.com>
2019-01-25 18:14:10 +01:00
Anton Harniakou 26f75edb7a Support numeric sort in ByParam
With this commit ByParam takes into account a type of a value under a
key. If both values are numeric then they're coerced into float64 and
then get compared.
If any value isn't numeric, for example it's nil or string, then both
values coerced into string and get compared as strings
(lexicographicaly)

Nil values are always sent to the end.

Numeric values confirm to any type listed below:
uint8, uint16, uint32, uint64, int, int8, int16, int32, int64, float32, float64

Closes #5305
2019-01-20 13:05:20 +00:00
Bjørn Erik Pedersen e1a66c7343 Fix Params case handling in the new site global
Fixes #5615
2019-01-20 12:42:24 +00:00
Anton Harniakou db3c49d049 Make hugo server -t work again
This commit solves an issue where hugo would ignore the cli -t flag
and only use a theme defined in config.toml.

Also allow -t flag to accept a string slice.

Closes #5569
Closes #5061
Related #4868
2019-01-13 20:13:59 +00:00
Anthony Fok e3cb8e6c78 Add configFile(s) back to the watch list after RENAME event too
Alleviates #5205
2019-01-10 15:57:30 -07:00
mywaiting 55251aa890 Remove historical rssURI config 2019-01-10 18:24:38 +01:00
Anton Harniakou 843fcd19d4 Use subtests with server_test.go
Use Golang's subtests to provide a convenient way
to run specific tests.
Example:
go test -run=TestFixURL/Basic_production
2019-01-08 14:54:11 +01:00
Bjørn Erik Pedersen ce8a09a4c0 resources: Move resource interfaces into its own package 2019-01-02 14:25:37 +01:00
Bjørn Erik Pedersen 669ada4367 resource: Move resource processors into sub-packages 2019-01-02 14:25:37 +01:00
Marc Robinson 507451229c Update _index.md
Corrects misspelling of sync (synch)
2019-01-02 09:58:39 +01:00
Bjørn Erik Pedersen 40ffb0484b hugolib: Restore 0.48 slash handling in taxonomies
Fixes #5571
2018-12-30 18:50:09 +01:00
Bjørn Erik Pedersen 4bae8b04aa Revert " Fix handling of taxonomy terms containing slashes"
See #4090
See #5571

This reverts commit fff132537b.
2018-12-30 18:50:09 +01:00
Bjørn Erik Pedersen 0584432b07 Update go.sum 2018-12-30 17:07:31 +01:00
Bjørn Erik Pedersen 65fa069271 Revert "hugolib: Restore taxonomy term path separation"
See #5571

This reverts commit 9ce0a1fb70.
2018-12-29 10:00:17 +01:00
Cameron Moore 9e4f9e0bb6 tpl: Fix reflect
Fixes #5564
2018-12-28 10:41:46 +01:00
Bjørn Erik Pedersen 3f3187de0f cache/namedmemcache: Fix data race 2018-12-27 12:05:42 +01:00
Bjørn Erik Pedersen cc351958e1 Update Chroma
Fixes #4993
2018-12-27 10:58:34 +01:00
Bjørn Erik Pedersen c24f3ae22b Make docshelper run again
Fixes #5568
2018-12-27 10:08:44 +01:00
Bjørn Erik Pedersen 214e9745b6 releaser: Use Git short commit in release binaries
Fixes #5562
2018-12-26 11:31:58 +01:00
Bjørn Erik Pedersen ecc8922752 releaser: Bump Goreleaser version 2018-12-26 11:30:05 +01:00
Bjørn Erik Pedersen 22afe28047 Merge commit '978856e2ad12d2bcaf37bb9e31f806b30a4c42f4' 2018-12-26 10:27:54 +01:00
Bjørn Erik Pedersen 978856e2ad Squashed 'docs/' changes from bd91d1cfd..785e375f5
785e375f5 Change 'my-another-post' to 'my-other-post'
ba9a69d25 Update reflect.IsSlice.md
806344258 Update reflect.IsMap.md
757c0dafa Update index.md
d3f20a2d5 Update index.md
9952e72a0 Formatting
70458ccf2 Formatting
7e0dd3969 Merge branch 'config-dir'
06a5c11fc Release 0.53
01c00229f releaser: Prepare repository for 0.54-DEV
29b223f78 releaser: Add release notes to /docs for release of 0.53
4f61d1194 releaser: Bump versions for release of 0.53
320a0ac68 Refactor config below /config
ec16b611e docs: Adjust CSV example
cecf97dfc Rename CSV option from comma to delimiter
18d06df58 docs: Document transform.Unmarshal
fdace78b5 docs: Regenerate CLI docs
b8f84ac59 hugolib: Add .Name as a shortcode variable
6612dd1b8 Merge commit '5a83bf314f4c0ce1d61341e0a1df21c9998e8154'
9b211089f docs: Regenerate CLI docs
9af46af3c Merge commit 'eb16165694f868d73e57b6aed5c26ba5e98229de'
12f46f356 tpl: Add reflect namespace

git-subtree-dir: docs
git-subtree-split: 785e375f57
2018-12-26 10:27:12 +01:00
hugoreleaser 8431871201 releaser: Prepare repository for 0.54-DEV
[ci skip]
2018-12-24 08:26:54 +00:00
hugoreleaser 8fc339dc25 releaser: Add release notes to /docs for release of 0.53
[ci skip]
2018-12-24 08:24:42 +00:00
hugoreleaser 5236cb8e9a releaser: Bump versions for release of 0.53
[ci skip]
2018-12-24 08:24:42 +00:00
Bjørn Erik Pedersen a28865cfc3 release: Fix goreleaser config 2018-12-24 09:20:09 +01:00
hugoreleaser cb6c77b813 Release 0.53 2018-12-24 09:05:26 +01:00
Bjørn Erik Pedersen be58c7b9c8 tpl/transform: Include options in cache key
See #5555
2018-12-23 21:34:17 +01:00
Bjørn Erik Pedersen 62d031aedf docs: Adjust CSV example
See #5555
2018-12-23 21:12:41 +01:00
Bjørn Erik Pedersen ce06bdb16a Rename CSV option from comma to delimiter
See #5555
2018-12-23 21:09:09 +01:00
Bjørn Erik Pedersen 2efc1a64c3 docs: Document transform.Unmarshal
Fixes #5556
2018-12-23 19:43:17 +01:00
Bjørn Erik Pedersen 25ddbb09fe hugolib: Adjust test
See #5544
2018-12-23 19:42:51 +01:00
Bjørn Erik Pedersen e691c48a5a docs: Regenerate CLI docs
Fixes #5544
2018-12-23 19:05:40 +01:00
Bjørn Erik Pedersen 094709e105 tpl/transform: Simplify transform.Unmarshal func
See #5428
2018-12-23 16:43:04 +01:00
Bjørn Erik Pedersen a574469797 Add CSV support to transform.Unmarshal
Fixes #5555
2018-12-23 16:33:21 +01:00
Bjørn Erik Pedersen 822dc627a1 tpl/transform: Add transform.Unmarshal func
Fixes #5428
2018-12-23 10:02:42 +01:00
Bjørn Erik Pedersen 43f9df0194 Prevent resource publishing for transformed inline resources
That is, if only `.Content` is accessed.

This means that, for a transformed resource to be published to `/public`, you need to access either `.RelPermalink` or `Permalink`.

Fixes #4944
2018-12-21 13:41:46 +01:00
Bjørn Erik Pedersen 1021714449 hugolib: Add .Name as a shortcode variable
Fixes #5546
2018-12-21 09:51:15 +01:00
Bjørn Erik Pedersen 5a83bf314f Squashed 'docs/' changes from d1cf9adc4..bd91d1cfd
bd91d1cfd Fix typo
0d45ea9cf Fix order of arguments in another strings.TrimLeft example
0982f65c1 Fix the order of arguments to strings.TrimRight
f1f9b7cd6 Arguments in example
5d9c7327f Fix shortcode example escape chars

git-subtree-dir: docs
git-subtree-split: bd91d1cfdd
2018-12-21 09:45:41 +01:00
Bjørn Erik Pedersen 6f069e549b Merge commit '5a83bf314f4c0ce1d61341e0a1df21c9998e8154' 2018-12-21 09:45:41 +01:00
Cameron Moore 0483299bc0 hugolib: Improve logic of output path trimming
Fixes #4666
2018-12-21 09:42:37 +01:00
Anthony Fok 27b62a546c snap: Revert build-snap to 1.11/stable channel for go
This is to fix the following snap build error:

    Failed to install or refresh a snap: 'go' does not exist
    or is not available on the desired channel '1.11.4/stable'.
    Use `snap info go` to get a list of channels the snap is available on.

`snap info go` reveals that the '1.11/stable' channel automatically
follows the latest minor point release as it becomes available.
2018-12-20 21:46:47 -07:00
Bjørn Erik Pedersen 35bfca3b14 commands: Remove the benchmark command
It's not particulary useful, and when we start to get bug reports about it, it is easier to remove it.

Closes #5543
2018-12-20 20:55:26 +01:00
Bjørn Erik Pedersen 9cd54cab20 Move the emoji parsing to pageparser
This avoids double parsing the page content when `enableEmoji=true`.

This commit also adds some general improvements to the parser, making it in general much faster:

```bash
benchmark                     old ns/op     new ns/op     delta
BenchmarkShortcodeLexer-4     90258         101730        +12.71%
BenchmarkParse-4              148940        15037         -89.90%

benchmark                     old allocs     new allocs     delta
BenchmarkShortcodeLexer-4     456            700            +53.51%
BenchmarkParse-4              28             33             +17.86%

benchmark                     old bytes     new bytes     delta
BenchmarkShortcodeLexer-4     69875         81014         +15.94%
BenchmarkParse-4              8128          8304          +2.17%
```

Running some site benchmarks with Emoji support turned on:

```bash
benchmark                                                                                     old ns/op     new ns/op     delta
BenchmarkSiteBuilding/TOML,num_langs=3,num_pages=5000,tags_per_page=5,shortcodes,render-4     924556797     818115620     -11.51%

benchmark                                                                                     old allocs     new allocs     delta
BenchmarkSiteBuilding/TOML,num_langs=3,num_pages=5000,tags_per_page=5,shortcodes,render-4     4112613        4133787        +0.51%

benchmark                                                                                     old bytes     new bytes     delta
BenchmarkSiteBuilding/TOML,num_langs=3,num_pages=5000,tags_per_page=5,shortcodes,render-4     426982864     424363832     -0.61%
```

Fixes #5534
2018-12-20 20:08:01 +01:00
Bjørn Erik Pedersen a8853f1c5a parser/pageparser: Split the page lexer into some more files
See #5534
2018-12-20 20:08:01 +01:00
Bjørn Erik Pedersen 4d93aca27d hugolib: Enable Emoji in site benchmark 2018-12-20 17:24:51 +01:00
Bjørn Erik Pedersen f2167de834 parser/pageparser: Add a benchmark 2018-12-19 20:08:22 +01:00
Bjørn Erik Pedersen 64b6b29075 tpl: Fix case handling in cast params
Fixes #5538
2018-12-19 13:19:22 +01:00
Bjørn Erik Pedersen bb9c2988f8 Update to Go 1.11.4
Fixes #5524
2018-12-19 11:48:17 +01:00
Bjørn Erik Pedersen c04030b14c releaser: Get ldflags for build date etc. in line for all builds
Closes #5539
Closes ##5388
2018-12-19 10:01:26 +01:00
Bjørn Erik Pedersen f7691fe965 transform/urlreplacers: Simplify implementation 2018-12-17 19:17:56 +01:00
Bjørn Erik Pedersen efe0b4e5c0 transform/urlreplacers: Support unquoted URLs in canonifyURLs replacer
Fixes #5529
2018-12-17 19:17:56 +01:00
Bjørn Erik Pedersen d5a0b6bbbc hugolib: Remove "double layout" lookup
Fixes #5390
2018-12-17 11:34:32 +01:00
Bjørn Erik Pedersen 5178cd13a7 Fix "failed to create file caches from configuration: file exists" on Windows
Fixes #5497
2018-12-17 10:36:52 +01:00
Bjørn Erik Pedersen 9ce0a1fb70 hugolib: Restore taxonomy term path separation
Fixes #5513
2018-12-14 10:29:32 +01:00
Jean-François YUEN ab9214768d importer: fix jekyll import highlight options 2018-12-12 19:12:12 +01:00
Bjørn Erik Pedersen 5068681707 docs: Regenerate CLI docs
Fixes #5507
2018-12-12 09:09:45 +01:00
Bjørn Erik Pedersen b17a61a605 Merge commit 'eb16165694f868d73e57b6aed5c26ba5e98229de' 2018-12-12 09:06:42 +01:00
Bjørn Erik Pedersen eb16165694 Squashed 'docs/' changes from 37095d540..d1cf9adc4
d1cf9adc4 Fix typo
26e10a690 Fix the name and arg mismatch between partial defn and call
2db0e53cd Merge commit '9c36cff15224f6cbd19058ad61311229b7a23c83'
9c36cff15 Squashed 'themes/gohugoioTheme/' changes from 68ddff44..b8202f53
4b021eff8 Update lang.Merge.md
b37af2916 Add title to yaml
a9a281233 Fixed incorrect usage of the code-toggle shortcode
4560a0169 Update Warning for Theme Links (#676)
0305e3c6b Document .File.ContentBaseName
6d30c5aa1 Update configuration.md
158df174a Document .Sites and .Sites.First
0c0f583b8 Add stale config
e2531afd8 Document path template functions
4dd779057 Clarify that partialCached is per site/language
19e5bbe0c Update index.md
44b000857 Add missing dot
a41300cf9 Release 0.52
2d1d92b88 Merge branch 'temp52'
c5925250d releaser: Prepare repository for 0.53-DEV
d000b04a2 releaser: Add release notes to /docs for release of 0.52
4bb983a0a releaser: Bump versions for release of 0.52
36736ca28 tpl: Add "param" shortcode
378677aa6 Add Elasticsearch/bonsai.io to services doc.
4c3fd4fa4 docs: Document inline shortcodes
6c64c374c Whitelist CSS modules from purge
817a872b9 Improve search icon position
cf86ff1c7 Add minification and resource cache clear to build command
fd77e8df3 Update asset dependencies and adopt Hugo Pipes
cdbe97e8c Update render.md
b0e279220 git command to update submodule to latest
a1cb98c12 cache/filecache: Add a :project placeholder
07c1b2b46 cache/filecache: Use time.Duration for maxAge
ffa9b165e Add AND as a title
6e7733b40 Add OR as a sub title to make it easier to find in search
72b6791a1 docs: Document the new file cache
714d3ca91 Fix minification issues
cd1e961da Revert "Add Elasticsearch/bonsai.io to services doc."
15a0cda6e Add Elasticsearch/bonsai.io to services doc.
f931d86de Release 0.51
e2ffe867a Merge branch 'temp51'
423e7f5c8 releaser: Prepare repository for 0.52-DEV
c6f2d6ae1 releaser: Add release notes to /docs for release of 0.51
5bbb556dc releaser: Bump versions for release of 0.51
3b2b172b9 docs: Document shortcode error handling
b8672f3d4 docs: Document symdiff
4bc6071e6 docs: Document complement
d1baab752 docs: Re-generate CLI docs
9ea667e24 Revert "tpl: Update Jsonify to return pretty-print output"
ce5a1403d docs: Regenerate the docs helper
99a1f4a94 Fix note for reserved partial name(starting with -> including).
eba3cbc42 fix accidentally modification on paragraph.
3eebd98c3 Add note for reserved partial name.
40b881cc2 Document templates.Exists
b5c3bcd3b Update multilingual.md
61c59c67e Fix misspelling (#648)
f21d8c4a4 Correct minor typo (#5372)
e967001b9 Release 0.50
685fd6b08 releaser: Prepare repository for 0.51-DEV
f245a9faa releaser: Add release notes to /docs for release of 0.50
4354da30d releaser: Bump versions for release of 0.50
feaa05469 docs: Regenerate CLI docs
5c724200c Merge commit 'd6a4af7018e8618944a6471ceeb7aae1d4df6afa'
2ddab36c2 Merge commit '74309fe5699a595080fdb3a14711e0869babce99'
8cf296a7c docs: Regenerate CLI docs
9097683dd tpl: Update Jsonify to return pretty-print output

git-subtree-dir: docs
git-subtree-split: d1cf9adc41
2018-12-12 09:05:31 +01:00
Bjørn Erik Pedersen 7829474088 Add /config dir support
This commit adds support for a configuration directory (default `config`). The different pieces in this puzzle are:

* A new `--environment` (or `-e`) flag. This can also be set with the `HUGO_ENVIRONMENT` OS environment variable. The value for `environment` defaults to `production` when running `hugo` and `development` when running `hugo server`. You can set it to any value you want (e.g. `hugo server -e "Sensible Environment"`), but as it is used to load configuration from the file system, the letter case may be important. You can get this value in your templates with `{{ hugo.Environment }}`.
* A new `--configDir` flag (defaults to `config` below your project). This can also be set with `HUGO_CONFIGDIR` OS environment variable.

If the `configDir` exists, the configuration files will be read and merged on top of each other from left to right; the right-most value will win on duplicates.

Given the example tree below:

If `environment` is `production`, the left-most `config.toml` would be the one directly below the project (this can now be omitted if you want), and then `_default/config.toml` and finally `production/config.toml`. And since these will be merged, you can just provide the environment specific configuration setting in you production config, e.g. `enableGitInfo = true`. The order within the directories will be lexical (`config.toml` and then `params.toml`).

```bash
config
├── _default
│   ├── config.toml
│   ├── languages.toml
│   ├── menus
│   │   ├── menus.en.toml
│   │   └── menus.zh.toml
│   └── params.toml
├── development
│   └── params.toml
└── production
    ├── config.toml
    └── params.toml
```

Some configuration maps support the language code in the filename (e.g. `menus.en.toml`): `menus` (`menu` also works) and `params`.

Also note that the only folders with "a meaning" in the above listing is the top level directories below `config`. The `menus` sub folder is just added for better organization.

We use `TOML` in the example above, but Hugo also supports `JSON` and `YAML` as configuration formats. These can be mixed.

Fixes #5422
2018-12-11 13:08:36 +01:00
Iskander (Alex) Sharipov 256418917c resource/image: Fix "always false" condition
Found using gocritic linter.
2018-12-10 15:31:44 +01:00
Cameron Moore c84f506f8e tpl: Add reflect namespace
Add a reflect namespace that offers a two boolean functions for
testing if a value is a map or slice.

Fixes #4081
2018-12-07 23:29:37 +01:00
Bjørn Erik Pedersen 4b5f743959 minifiers: Fixx CSS2 color code handling
Fixes #5506
2018-12-07 07:49:26 +01:00
Bjørn Erik Pedersen 931a132450 tpl/hugo: Use the correct Hugo var
See #5467
2018-12-06 14:57:56 +01:00
Bjørn Erik Pedersen 8378358857 hugolib: Add .Site.Sites
Fixes #5504
2018-12-06 14:37:25 +01:00
Bjørn Erik Pedersen 831d23cb4d Add tpl/site and tpl/hugo
This means that the current `.Site` and ´.Hugo` is available as a globals, so you can do `site.IsServer`, `hugo.Version` etc.

Fixes #5470
Fixes #5467
Fixes #5503
2018-12-06 14:37:25 +01:00
Bjørn Erik Pedersen 514e18dc27 cache/filecache: Simplify test
See #5497
2018-12-04 19:19:20 +01:00
Bjørn Erik Pedersen b804a70881 cache/filecache: Use OS fs for test
See #5497
2018-12-04 18:03:49 +01:00
Cameron Moore 30a7c9ea37 tpl: Add godoc packages comments
Also fix package name in tpl/templates.
2018-11-30 08:56:30 +01:00
Christian Oliff 8346848109 common/collections: Fix defines typo 2018-11-29 09:57:51 +01:00
hugoreleaser 54ecade02f releaser: Prepare repository for 0.53-DEV
[ci skip]
2018-11-28 14:08:36 +00:00
hugoreleaser 9433cf5a92 releaser: Add release notes to /docs for release of 0.52
[ci skip]
2018-11-28 14:06:31 +00:00
hugoreleaser 3c909eb3f3 releaser: Bump versions for release of 0.52
[ci skip]
2018-11-28 14:06:31 +00:00
Bjørn Erik Pedersen 724b3e673b Release 0.52 2018-11-28 14:59:48 +01:00
hugoreleaser 056c754771 releaser: Add release notes draft for 0.52
Rename to *-ready.md to continue. [ci skip]
2018-11-28 13:14:49 +00:00
Bjørn Erik Pedersen a9a93d082d hugolib: Fall back to title in ByLinkTitle sort
Fixes #4953
2018-11-28 13:52:26 +01:00
Bjørn Erik Pedersen b09a40333f hugolib: Improve nil handling in IsDescendant and IsAncestor
Fixes #5461
2018-11-28 12:36:59 +01:00
Bjørn Erik Pedersen 7540a62834 parser/pageparser: Fix handling of commented out front matter
When the page parser was rewritten in 0.51, this was interpreted literally, but commented out front matter is used in the wild to "hide it from GitHub", e.g:

```
<!--
+++
title = "hello"
+++
-->
```

Fixes #5478
2018-11-28 10:28:50 +01:00
Bjørn Erik Pedersen 7e75aeca80 Remove duplicate mapstructure depdendency 2018-11-28 00:17:43 +01:00
Bjørn Erik Pedersen e14e0b192f Add dependency list to README 2018-11-28 00:08:27 +01:00
Cameron Moore ed698e94c1 tpl/path: Add tests 2018-11-27 19:17:35 +01:00
Bjørn Erik Pedersen 89e2716d29 tpl: Regenerate templates 2018-11-27 18:15:55 +01:00
Max Arnold aba2647c15 tpl: Fix whitespace issue
Introduced  in #5276.
2018-11-27 18:15:10 +01:00
Bjørn Erik Pedersen f37c5a2567 tpl: Add "param" shortcode
Fixes #4010
2018-11-27 17:34:03 +01:00
Bjørn Erik Pedersen aded0f25fd docs: Document inline shortcodes
See #4011
2018-11-27 16:14:09 +01:00
Bjørn Erik Pedersen bc337e6ab5 Add inline shortcode support
An inline shortcode's name must end with `.inline`, all lowercase.

E.g.:

```bash
{{< time.inline >}}{{ now }}{{< /time.inline >}}
```

The above will print the current date and time.

Note that an inline shortcode's inner content is parsed and executed as a Go text template with the same context as a regular shortcode template.

This means that the current page can be accessed via `.Page.Title` etc. This also means that there are no concept of "nested inline shortcodes".

The same inline shortcode can be reused later in the same content file, with different params if needed, using the self-closing syntax:

```
{{< time.inline />}}
```

Fixes #4011
2018-11-27 16:14:09 +01:00
Cameron Moore 112461fded tpl/collections: Add float64 support to where
Fixes #5466
2018-11-27 09:04:02 +01:00
Bjørn Erik Pedersen 94ab125b27 parser/pageparser: Fix when only shortcode and then summary
Fixes #5464
2018-11-24 18:23:23 +01:00
Bjørn Erik Pedersen dcfeed35c6 commands: Include drafts in convert command
Fixes #5457
2018-11-24 13:11:14 +01:00
Bjørn Erik Pedersen f9b4eb4f39 Handle themes in the new file cache (for images, assets)
In the newly consolidated file cache implementation, we forgot that we also look in the theme(s) for assets (SCSS transformations etc.), which is not good for Netlify and the demo sites.

Fixes #5460
2018-11-23 21:09:00 +01:00
Kris Budhram e82b2dc8c1 Fix ignored --config flag with 'new' command 2018-11-18 19:09:28 +01:00
Bjørn Erik Pedersen 5df2b79dd2 Fix Permalink for resource, baseURL with path and canonifyURLs set
Fixes #5226
2018-11-15 16:37:11 +01:00
Bjørn Erik Pedersen 12742bac71 Add tests for permalink on Resource with baseURL with path
See #5226
2018-11-15 08:45:15 +01:00
Bjørn Erik Pedersen fabf026f49 helpers: Add a comment about file mode for new files
See #5434
2018-11-14 23:14:51 +01:00
Bjørn Erik Pedersen 94f0f7e597 cache/filecache: Add a :project placeholder
This allows for "cache per Hugo project", making `hugo --gc` work as expected, even if you have several Hugo projects running on the same PC.

See #5439
2018-11-14 23:14:51 +01:00
Bjørn Erik Pedersen 3c29c5af8e cache/filecache: Add a cache prune func
Fixes #5439
2018-11-14 23:14:51 +01:00
Bjørn Erik Pedersen 33502667fb cache/filecache: Add a filecache root dir
This is just a safe guard to make sure we don't evict/remove files that do not belong to the cache.
2018-11-14 23:14:51 +01:00
Bjørn Erik Pedersen d3489eba5d cache/filecache: Use time.Duration for maxAge
Fixes #5438
2018-11-14 23:14:50 +01:00
Bjørn Erik Pedersen 17d7ecde2b cache/filecache: Split implementation and config into separate files 2018-11-14 23:14:50 +01:00
Bjørn Erik Pedersen e4b2572880 Update to LibSASS 3.5.5
Fixes #5432
See #5435
2018-11-14 17:47:08 +01:00
Bjørn Erik Pedersen 782dd15858 More spelling corrections 2018-11-13 18:28:40 +01:00
Bjørn Erik Pedersen aff9c09166 cache/filecache: Spelling corrections 2018-11-13 18:16:53 +01:00
Bjørn Erik Pedersen fdd4a768f0 Remove appveyor
We now build on Travis for all platforms.
2018-11-13 14:36:17 +01:00
Bjørn Erik Pedersen abeeff1325 docs: Document the new file cache
See #5404
2018-11-13 14:29:45 +01:00
Bjørn Erik Pedersen f7aeaa6129 Add a consolidated file cache
This commits reworks how file caching is performed in Hugo. Now there is only one way, and it can be configured.

This is the default configuration:

```toml
[caches]
[caches.getjson]
dir = ":cacheDir"
maxAge = -1
[caches.getcsv]
dir = ":cacheDir"
maxAge = -1
[caches.images]
dir = ":resourceDir/_gen"
maxAge = -1
[caches.assets]
dir = ":resourceDir/_gen"
maxAge = -1
```

You can override any of these cache setting in your own `config.toml`.

The placeholders explained:

`:cacheDir`: This is the value of the `cacheDir` config option if set (can also be set via OS env variable `HUGO_CACHEDIR`). It will fall back to `/opt/build/cache/hugo_cache/` on Netlify, or a `hugo_cache` directory below the OS temp dir for the others.
`:resourceDir`: This is the value of the `resourceDir` config option.

`maxAge` is the time in seconds before a cache entry will be evicted, -1 means forever and 0 effectively turns that particular cache off.

This means that if you run your builds on Netlify, all caches configured with `:cacheDir` will be saved and restored on the next build. For other CI vendors, please read their documentation. For an CircleCI example, see https://github.com/bep/hugo-sass-test/blob/6c3960a8f4b90e8938228688bc49bdcdd6b2d99e/.circleci/config.yml

Fixes #5404
2018-11-13 14:19:42 +01:00
Emir Beganović 7d78a2afd3 Add Windows build config to Travis 2018-11-13 11:39:54 +01:00
Bjørn Erik Pedersen 5570a6e478 Revert "Add Elasticsearch/bonsai.io to services doc."
This reverts commit c0b3a1af03.
2018-11-09 23:12:27 +01:00
Allison Zadrozny c0b3a1af03 Add Elasticsearch/bonsai.io to services doc.
Hip hip for OSS! 🙌
2018-11-09 22:56:38 +01:00
Ian Lance Taylor a8cb1b07b4 tpl: Fix test to pass with gccgo
When run under gccgo, the test looks for the name that gccgo gives to
a thunk method.  This name is not normally visible, but can be seen
when using reflect.FuncForPC as this code does.  That name changed in
https://golang.org/cl/89555.  Change the test to work with both the
old name "$thunk0" and the new name "thunk0".

Fixes golang/go#28669
2018-11-09 08:54:08 +01:00
hugoreleaser 2900801acf releaser: Prepare repository for 0.52-DEV
[ci skip]
2018-11-07 10:11:48 +00:00
hugoreleaser f3d5190793 releaser: Add release notes to /docs for release of 0.51
[ci skip]
2018-11-07 10:09:43 +00:00
hugoreleaser 1ccc0b79a2 releaser: Bump versions for release of 0.51
[ci skip]
2018-11-07 10:09:43 +00:00
Bjørn Erik Pedersen cbed50e22b Release 0.51 2018-11-07 11:00:25 +01:00
hugoreleaser 05ecd8111c releaser: Add release notes draft for 0.51
Rename to *-ready.md to continue. [ci skip]
2018-11-07 09:48:47 +00:00
Bjørn Erik Pedersen e456e34bdb docs: Document shortcode error handling
Closes https://github.com/gohugoio/hugoDocs/issues/660
2018-11-07 10:38:58 +01:00
Bjørn Erik Pedersen 5d14d04ac6 docs: Document symdiff
Closes https://github.com/gohugoio/hugoDocs/issues/659
2018-11-07 10:38:58 +01:00
Bjørn Erik Pedersen ddcb402859 docs: Document complement
Closes https://github.com/gohugoio/hugoDocs/issues/658
2018-11-07 10:38:58 +01:00
Bjørn Erik Pedersen 3a44920e79 hugolib: Improve error message on duplicate menu items 2018-11-07 10:38:58 +01:00
Bjørn Erik Pedersen 79a06aa4b6 tpl/collections: Properly handle pointer types in complement/symdiff
We cannot compare them by values, because that gets `hash of unhashable type` for the prime use case.
2018-11-07 09:29:13 +01:00
Bjørn Erik Pedersen d212f60949 deps: Update minify
No functional changes, just support for Go Modules.
2018-11-07 00:23:08 +01:00
Bjørn Erik Pedersen 488776b649 tpl/collections: Add collections.SymDiff
Fixes #5410
2018-11-06 16:51:49 +01:00
Bjørn Erik Pedersen b8b8436fcc hugolib: Fix changing paginators in lazy render
Fixes #5406
2018-11-06 11:04:10 +01:00
Bjørn Erik Pedersen 42d8dfc8c8 tpl/collections: Add collections.Complement
Fixes #5400
2018-11-06 08:48:58 +01:00
秦世成 47506d1644 commands: Fix spelling 2018-11-06 08:45:19 +01:00
Bjørn Erik Pedersen 2998fa0cd5 docs: Re-generate CLI docs 2018-11-05 14:18:45 +01:00
Bjørn Erik Pedersen d16a7a33ff Fix shortcode directly following a shortcode delimiter
Fixes #5402
2018-11-05 14:14:28 +01:00
Bjørn Erik Pedersen 5b1edd281a commands: Add --minify to hugo server 2018-11-04 18:39:14 +01:00
Bjørn Erik Pedersen 2bd9d9099d commands: Fix recently broken error template
We need a test for this ...
2018-11-03 16:55:45 +01:00
Bjørn Erik Pedersen 4b7d3e57a4 Make WARN the new default log log level
This commit also pulls down the log level for a set of WARN statements to INFO. There should be no ERRORs or WARNINGs in a regular Hugo build. That is the story about the Boy Who Cried Wolf.

Since the WARN log is now more visible, this commit also improves on some of them, most notable the "layout not found", which now would look something like this:

```bash
WARN 2018/11/02 09:02:18 Found no layout for "home", language "en", output format "CSS": create a template below /layouts with one of these filenames: index.en.css.css, home.en.css.css, list.en.css.css, index.css.css, home.css.css, list.css.css, index.en.css, home.en.css, list.en.css, index.css, home.css, list.css, _default/index.en.css.css, _default/home.en.css.css, _default/list.en.css.css, _default/index.css.css, _default/home.css.css, _default/list.css.css, _default/index.en.css, _default/home.en.css, _default/list.en.css, _default/index.css, _default/home.css, _default/list.css
```

Fixes #5203
2018-11-03 12:06:23 +01:00
Bjørn Erik Pedersen 4f3c095963 Revert "tpl: Update Jsonify to return pretty-print output"
This reverts commit 5a52cd5f92.

Closes #5394
2018-11-02 19:03:48 +01:00
Bjørn Erik Pedersen 486bc46a52 docs: Regenerate the docs helper 2018-11-02 13:36:09 +01:00
Bjørn Erik Pedersen 61f210dd7a tpl: Fix the docshelper 2018-11-02 13:36:09 +01:00
Kris Budhram f8446188db Skip watcher event files if matched in ignoreFiles 2018-11-02 09:50:31 +01:00
Bjørn Erik Pedersen d523aa4bb0 deps: Update Chroma
Fixes #5392
2018-11-02 09:31:51 +01:00
Lorenz Cuno Klopfenstein b8725f5181 Fix ANSI character output regression on Windows
Fixes #5377
2018-11-02 09:09:02 +01:00
Bjørn Erik Pedersen 0bc4b0246d hugolib: Remove deprecated useModTimeAsFallback 2018-11-01 21:14:30 +01:00
Bjørn Erik Pedersen faeb55c1d8 hugolib: Bump to ERROR for the deprecated Pages.Sort 2018-11-01 21:11:45 +01:00
Bjørn Erik Pedersen 6c6a6c87ec hugolib: Deprecate .Site.Ref and .Site.RelRef
Fixes #5386
2018-11-01 21:08:12 +01:00
Bjørn Erik Pedersen 1d18eb0574 Add file (line/col) info to ref/relref errors
See #5371
2018-11-01 21:06:35 +01:00
Bjørn Erik Pedersen 33a7b36fd4 hugolib: Add .Position to shortcode
To allow for better error logging in shortcodes. Note that this may be expensive to calculate, so this is primarily for error situations.

See #5371
2018-11-01 21:06:35 +01:00
Bjørn Erik Pedersen 6180c85fb8 hugolib: Fix REF_NOT_FOUND logging to include page path
Fixes #5371
2018-11-01 21:06:35 +01:00
Bjørn Erik Pedersen d3a98325c3 common/loggers: Improve log color regexp
To avoid coloring WARNING inside log errors.
2018-11-01 09:33:32 +01:00
Bjørn Erik Pedersen b2a676f5f0 hugolib: Fix broken manual summary handling
Fixes #5381
2018-10-31 23:14:37 +01:00
Bjørn Erik Pedersen 3a786a248d tpl: Fix BOM issue in templates
Fixes #4895
2018-10-30 18:12:14 +01:00
Bjørn Erik Pedersen 729593c842 hugolib: Fix deadlock when content building times out
Fixes #5375
2018-10-30 12:18:29 +01:00
Christian Oliff e65268f2c2 Correct minor typo (#5372)
> Errors will no show up

should be:

> Errors will now show up
2018-10-29 12:09:19 +01:00
hugoreleaser f863b6a07e releaser: Prepare repository for 0.51-DEV
[ci skip]
2018-10-29 09:54:42 +00:00
hugoreleaser f5be599204 releaser: Add release notes to /docs for release of 0.50
[ci skip]
2018-10-29 09:51:50 +00:00
hugoreleaser b14c11b0e1 releaser: Bump versions for release of 0.50
[ci skip]
2018-10-29 09:51:50 +00:00
Bjørn Erik Pedersen 0addb2add6 Release 0.50 2018-10-29 10:39:51 +01:00
hugoreleaser 8bba85601f releaser: Add release notes draft for 0.50
Rename to *-ready.md to continue. [ci skip]
2018-10-29 10:39:51 +01:00
Bjørn Erik Pedersen 7082a5d143 Update go.sum 2018-10-29 09:42:53 +01:00
Bjørn Erik Pedersen aa281b5135 mod: Update minify
Closes #5261
2018-10-29 09:35:14 +01:00
Bjørn Erik Pedersen 3250198724 docs: Regenerate CLI docs 2018-10-29 09:29:27 +01:00
Bjørn Erik Pedersen d6a4af7018 Squashed 'docs/' changes from 084804447..37095d540
37095d540 Fix shortcode example

git-subtree-dir: docs
git-subtree-split: 37095d5403
2018-10-29 09:28:01 +01:00
Bjørn Erik Pedersen 27569275b1 Merge commit 'd6a4af7018e8618944a6471ceeb7aae1d4df6afa' 2018-10-29 09:28:01 +01:00
Bjørn Erik Pedersen 4b2738d871 Merge commit '74309fe5699a595080fdb3a14711e0869babce99' 2018-10-29 09:23:25 +01:00
Bjørn Erik Pedersen 74309fe569 Squashed 'docs/' changes from e5e98b950..084804447
084804447 Update shortcode-templates.md
c01b02434 Correct misspelling of 'default'
52a831cca Added missing parenthesis
59e8e660a Fix spelling typos
29ad53c9c Yes, HTML is a valid content format
c6b193c6f Update shortcode-templates.md
1f2846e6d Fix typo in output format README
5882f7a4c Fix typo
a90a00bb0 Update multilingual.md
62bf0f184 Documentation for Open Graph & Twitter Cards
f4d624da3 Document "images", "videos", etc. in front-matter
6a85b5df1 Document anchorize and Resources.Content
04c8a5b0e Fix minor typo in 0.49.2 release note
dbe77e948 Release 0.49.2
ea6c9658e Merge branch 'temp492'
85c45b725 Merge branch 'release-0.49.2'
7ad1fba29 releaser: Prepare repository for 0.50-DEV
b25bcc3f2 releaser: Add release notes to /docs for release of 0.49.2
78b751b91 releaser: Bump versions for release of 0.49.2
e3f09762c Release 0.49.1
bd5b94558 Merge branch 'temp491'
0007e0661 Merge branch 'release-0.49.1'
74d2f3a6f releaser: Prepare repository for 0.50-DEV
bbee7e9d3 releaser: Add release notes to /docs for release of 0.49.1
ae40c89c7 releaser: Bump versions for release of 0.49.1
11079fb48 Add draft statement to FAQ
069b9472f Addin Hokus CMS to frontends list.
6e8850670 Add MediaType docs
f3ca6209a Add `languageName` to configuration
fd1cde5ea tpl: Add a delimiter parameter to lang.NumFmt
c620ff78a Update doc to use proper variable
7317c339a add tools->hugo-elasticsearch description to docs
d758ef94a hugolib: Introduce Page.NextPage and Page.PrevPage
9c93ac031 Update installing.md
7c0b5b7f5 Use ISO 639-1 code for examples
9a9e40ba8 Fix spelling
9a6216c18 Hugo 0.49
55aa91185 Merge branch 'temp49'
e0a36421e releaser: Prepare repository for 0.50-DEV
c07b3b385 releaser: Add release notes to /docs for release of 0.49
c1175a12a releaser: Bump versions for release of 0.49
2966f6254 docs: Document directory based archetypes
73dcd02ed Add showcase archetype folder
0a55ad11b docs: Regenerate CLI docs
e09866c2d docs: Document group
ef986358a Merge commit '807c551922707fc5ae0eb26e8f01638c0c63fdb3'
681f14fc9 tpl/collections: Allow first function to return an empty slice
f6dcc93bc docs: Add docs for append
aae528ca3 Merge commit '13e64d72763bf8d6d92d4cdfc15ed45ee9debfab'
02b62294c tpl/strings: Add strings.FirstUpper
bf3e61ba3 hugolib: Do not FirstUpper taxonomy titles

git-subtree-dir: docs
git-subtree-split: 0848044474
2018-10-29 09:19:20 +01:00
Bjørn Erik Pedersen 9c88a8a55a common/loggers: Make sure the global logger also gets colored labels
See #4414
2018-10-28 16:06:50 +01:00
Bjørn Erik Pedersen 95e72f5e8e i18n: Avoid using the global logger
See #4414
2018-10-28 14:42:41 +01:00
Bjørn Erik Pedersen 1c7b7b4ef2 common/loggers: Add color to ERROR and WARN
Fixes #4414
2018-10-28 14:16:23 +01:00
Bjørn Erik Pedersen 1ad117cbe2 common/herrors: Make the file error log format configurable
Will check for an OS environment variable named `HUGO_FILE_LOG_FORMAT`.

The tokens available are `:file` (absolute filename), `:line` (line number) and `:col` (column number).

The default format is: \":file::line::col\"`

How to set OS environment variables is OS specific, but an example on Unix setting an alternative format when running Hugo:

```bash
env HUGO_FILE_LOG_FORMAT="\":file::line\"" hugo
```

The above will include filename and line number quoted.

Fixes #5352
2018-10-27 19:14:16 +02:00
Bjørn Erik Pedersen dac7092a9c common/collections: Allow a mix of slice types in append/Scratch.Add
The type handling in these was improved in Hugo 0.49, but this also meant that it was no longer possible to start out with a string slice and later append `Page` etc. to it.

This commit makes sure that the old behaviour is now possible again by falling back to a `[]interface{}` as a last resort.

Fixes #5361
2018-10-27 15:05:40 +02:00
Bjørn Erik Pedersen b27ccf34bf resource: Allow .Data.Integrity to be accessed on its own
Fixes #5296
2018-10-27 11:34:15 +02:00
Bjørn Erik Pedersen 286d0b7dc3 Revert "mod: Update minify"
This reverts commit 83c873ff37.
2018-10-26 19:30:01 +02:00
Bjørn Erik Pedersen 83c873ff37 mod: Update minify
Closes #5261
2018-10-26 17:16:01 +02:00
Bjørn Erik Pedersen a2440dc0e2 mod: Update cast
Closes #5340
2018-10-26 17:13:22 +02:00
Bjørn Erik Pedersen 1e9ac3dcc2 commands: Truncate the error log on repeated config errors 2018-10-26 17:02:53 +02:00
Bjørn Erik Pedersen 40e99672b6 docs: Regenerate CLI docs
Closes #5354
2018-10-26 15:10:43 +02:00
Bjørn Erik Pedersen 3a3badfd1d resource: Serialize image processing
Fixes #5220
2018-10-26 14:40:05 +02:00
Bjørn Erik Pedersen df021317a9 commands: Only show Ansi escape codes if in a terminal 2018-10-26 14:33:44 +02:00
Bjørn Erik Pedersen 78578632f5 Fix archetype handling of directories in theme
Fixes #5318
2018-10-26 12:16:28 +02:00
Bjørn Erik Pedersen 6b78b3810a Revert "commands: Read disableFastRender from flag even if it's not changed"
On second thought, removing this isn't worth it.

This reverts commit 78a4c2e32e.
2018-10-24 22:15:57 +02:00
Bjørn Erik Pedersen 78a4c2e32e commands: Read disableFastRender from flag even if it's not changed
Fixes #5353
2018-10-24 20:33:07 +02:00
Bjørn Erik Pedersen d4ebfea1ff comamnds: Use overflow-x: auto; for browser errors 2018-10-24 19:20:37 +02:00
Bjørn Erik Pedersen 93aa6261b4 common/loggers: Remove the ANSI color for the browser error version 2018-10-24 17:22:07 +02:00
Bjørn Erik Pedersen acc14b4646 hugolib: Adjust error test to make it pass on Go tip 2018-10-24 15:19:49 +02:00
Bjørn Erik Pedersen 2d7709d155 tpl: Handle truncated identifiers in Go template errors
Long identifiers will give errors on the format:

```bash
 _default/single.html:5:14: executing "main" at <.ThisIsAVeryLongTitl...>: can't evaluate field ThisIsAVeryLongTitle
```

Hugo use this value to match the "base template or not", so we need to strip the "...".

Fixes #5346
2018-10-24 13:54:04 +02:00
Bjørn Erik Pedersen deff9e154b Add some color to the relevant filenames in terminal log
Fixes #5344
2018-10-24 13:02:18 +02:00
Bjørn Erik Pedersen 889aca054a Run gofmt -s 2018-10-24 00:12:32 +02:00
Bjørn Erik Pedersen e3ed4a83b8 hugolib: Rename some page_* files
To make it easier to see/work with the source files that is about the `Page` struct.
2018-10-23 22:21:21 +02:00
Bjørn Erik Pedersen 6636cf1bea Resolve error handling/parser related TODOs
See #5324
2018-10-23 19:41:22 +02:00
Bjørn Erik Pedersen f669ef6bec herrors: Improve handling of JSON errors
`*json.UnmarshalTypeError` and `*json.SyntaxError` has a byte `Offset`, so use that.

This commit also reworks/simplifies the errror line matching logic. This also makes the file reading unbuffered, but that should be fine in this error case.

See #5324
2018-10-23 14:35:43 +02:00
Bjørn Erik Pedersen ed7b3e2619 commands, hugolib: Get file context in "config parse failed" errors
Fixes #5325
2018-10-23 08:09:41 +02:00
Bjørn Erik Pedersen 2bf686ee21 hugolib: Improve errors in /i18n handlling
See #5324
2018-10-22 20:46:14 +02:00
Bjørn Erik Pedersen 9f74dc2a52 hugolib: Improve errors in /data handlling
See #5324
2018-10-22 20:46:14 +02:00
Bjørn Erik Pedersen d1661b823a hugolib: Continue the file context/line number errors work
See #5324
2018-10-22 20:46:14 +02:00
Bjørn Erik Pedersen 7930d2132a hugolib: Remove the now superflous Source struct
See #5324
2018-10-22 20:46:14 +02:00
Bjørn Erik Pedersen eb038cfa0a Convert the rest to new page parser code paths
And remove some now unused code.

See #5324
2018-10-22 20:46:14 +02:00
Bjørn Erik Pedersen 129c27ee6e parser/metadecoders: Consolidate the metadata decoders
See #5324
2018-10-22 20:46:13 +02:00
Bjørn Erik Pedersen 44da60d869 hugolib: Redo the summary delimiter logic
Now that we have a proper page parse tree, this can be greatly simplified.

See #5324
2018-10-22 20:46:13 +02:00
Bjørn Erik Pedersen 1e3e34002d hugolib: Integrate new page parser
See #5324
2018-10-22 20:46:13 +02:00
Bjørn Erik Pedersen 1b7ecfc2e1 hugolib: Use []byte in shortcode parsing
See #5324
2018-10-22 19:57:44 +02:00
Bjørn Erik Pedersen 27f5a906a2 parser/pageparser: Use []byte in page lexer
See #5324
2018-10-22 19:57:44 +02:00
Bjørn Erik Pedersen 2fdc4a24d5 parser/pageparser: Add front matter etc. support
See #5324
2018-10-22 19:57:43 +02:00
Bjørn Erik Pedersen f6863e1ef7 parser/pageparser: File renames and splitting
See #5324
2018-10-22 19:57:43 +02:00
Bjørn Erik Pedersen d6c16afde0 Move the shortcode parser to the new pageparser package
See #5324
2018-10-22 19:57:43 +02:00
Bjørn Erik Pedersen 6f3716dc22 commands: Avoid panic in error handler on config errors 2018-10-22 19:51:59 +02:00
Sean Prashad 5a52cd5f92 tpl: Update Jsonify to return pretty-print output
Fixes #5040
2018-10-21 23:36:35 +02:00
Bjørn Erik Pedersen 4a366fcfee Prevent stale content in Fast Render Mode
We do that by re-render visited pages that is not already in the stack. This may potentially do some double work, but that small penalty should be well worth it.

Fixes #5281
2018-10-17 10:15:22 +02:00
Bjørn Erik Pedersen 083311d033 hugolib: Fix test on Windows 2018-10-17 08:37:02 +02:00
Bjørn Erik Pedersen 0fe4ff1875 tpl: Improve the Execute panic error message
See #5327
2018-10-17 08:25:57 +02:00
Janus 1f42e47e47 Allow date and slug from filename for leaf bundles
Fixes #4558
2018-10-16 23:51:48 +02:00
Bjørn Erik Pedersen 35fbfb19a1 commands: Show server error info in browser
The main item in this commit is showing of errors with a file context when running `hugo server`.

This can be turned off: `hugo server --disableBrowserError` (can also be set in `config.toml`).

But to get there, the error handling in Hugo needed a revision. There are some items left TODO for commits soon to follow, most notable errors in content and config files.

Fixes #5284
Fixes #5290
See #5325
See #5324
2018-10-16 22:10:56 +02:00
Kris Budhram 3a3089121b Simple doc fix in CONTRIBUTING.md 2018-10-16 13:30:00 +02:00
Akshay Raj Gollahalli c21e5179ce tpl: Use .Lastmod in embedded schema template
Fixes #5320
2018-10-16 11:52:32 +02:00
Bjørn Erik Pedersen a205f24ba5 Revert "commands: Add .gitignore "hugo new site""
This fails on Windows, so it needs to be reconsidered.

This reverts commit 92979d9288.
2018-10-16 08:43:38 +02:00
Nathaniel Peiffer 92979d9288 commands: Add .gitignore "hugo new site" 2018-10-16 08:36:27 +02:00
Cameron Moore 0a3340e952 resource: Optimize integrity string generation
Remove use of fmt.Sprintf for simple string concatenation.  A simple
change for a small perf boost.

```
name         old time/op    new time/op    delta
Integrity-4     525ns ± 2%     268ns ± 2%  -48.92%  (p=0.000 n=10+10)

name         old alloc/op   new alloc/op   delta
Integrity-4      144B ± 0%      112B ± 0%  -22.22%  (p=0.000 n=10+10)

name         old allocs/op  new allocs/op  delta
Integrity-4      5.00 ± 0%      3.00 ± 0%  -40.00%  (p=0.000 n=10+10)
```
2018-10-16 08:33:38 +02:00
Elliot Forbes 6b21ac3e67 commands: Add help text to "hugo new" 2018-10-15 17:48:19 +02:00
Anthony Fok d14420539a snap: Set "extended" tag based on build_url on Launchpad
Read build_url from $SNAPCRAFT_IMAGE_INFO to determine whether
to add the "extended" build tag or not.  This allows us to do away
with the extended-snap-master and extended-snap-stable branches.
2018-10-12 11:10:38 +08:00
Shreyansh Khajanchi 3d4a9882bf helpers: Call rst2html directly on *nix
Initially, rst2html was called via the python interpreter which would
fail if the script was wrapped in a launcher as on NixOS.
Ideally, on *nix, binaries should be invoked directly to ensure that
shebangs work properly as is being done now.
Handle the case of windows as it doesn't do shebangs.
2018-10-11 22:46:10 +02:00
Ben Abbott bdca972794 Update URLs to stop 301 redirects 2018-10-11 22:44:06 +02:00
Bjørn Erik Pedersen 604ddb90c5 Merge branch 'release-0.49.2' 2018-10-11 12:01:51 +02:00
hugoreleaser b09e495a71 releaser: Prepare repository for 0.50-DEV
[ci skip]
2018-10-11 09:49:59 +00:00
Bjørn Erik Pedersen 535755e4f8 common/collections: Fix type checking in Append
The fix introduced in Hugo `0.49.1` had an unintended side-effect in the `Append` func used in both `append` and `.Scratch.Add`.

This commit fixes that by loosen/fixing the type checking so concrete types can be appended to interface slices.

Fixes #5303
2018-10-11 11:24:10 +02:00
Bjørn Erik Pedersen 3583dd6d71 Merge branch 'release-0.49.1' 2018-10-10 13:00:01 +02:00
hugoreleaser e5b4cb2419 releaser: Prepare repository for 0.50-DEV
[ci skip]
2018-10-10 10:38:45 +00:00
Bjørn Erik Pedersen b5e17f7c83 Add GOPATH Hugo building tip 2018-10-09 11:09:00 +02:00
Bjørn Erik Pedersen 31a8bb8c07 common/maps: Improve append in Scratch
This commit consolidates the reflective collections handling in `.Scratch` vs the `tpl` package so they use the same code paths.

This commit also adds support for a corner case where a typed slice is appended to a nil or empty `[]interface{}`.

Fixes #5275
2018-10-08 12:30:50 +02:00
Bjørn Erik Pedersen 8e825ddf5b Revert "tpl: Fix baseof.html in error message"
I need to rethink this.

This reverts commit 646a52a5c5.
2018-10-07 21:08:41 +02:00
Bjørn Erik Pedersen 646a52a5c5 tpl: Fix baseof.html in error message
This fix should also make the template loadin slightly faster, as we avoid to reparse the baseof.html files more than one time.

Fixes #5288
2018-10-06 12:04:29 +02:00
Bjørn Erik Pedersen e421696d02 helpers: Consolidate MakeSegment vs MakePathSanitized
In short:

* Avoid double tolower in MakeSegment
* Use MakePathSanitized for taxonomies in pageToPermalinkTitle; this matches what MakeSegment does.
* Move the "double hyphen and space" logic into UnicodeSanitize

The last bullet may be slightly breaking for some that now does not get the "--" in some URLs, but we need to reduce the amount of URL logic.

See #4926
2018-10-03 15:55:25 +02:00
Gregorio Martinez 4b4af2c52e hugolib: Use stdlib context package 2018-10-03 14:59:35 +02:00
Cameron Moore fae48d7457 hugolib: Normalize permalink path segments
When constructing permalinks, ensure that most inputs used as path
segments are normalized with PathSpec.MakeSegment instead of
PathSpec.URLize.

The primary exception to that rule is with taxonomy titles in
pageToPermalinkTitle(). The approach taken here is to use URLize for
taxonomy pages. Everything else will use MakeSegment. The reason for
this exception is that people use taxonomies such as "s1/p1" to generate
URLs precisely they way they wish (see #5223). Tests have been added to
check for this case.

Fixes #4926
2018-10-03 11:02:15 +03:00
Gregorio Martinez 06d28a464d hugolib: Fix FuzzyWordCount test error message 2018-10-03 10:01:30 +03:00
Kaushal Modi 6818170308 Render Markdown in figure shortcode "caption" and "attr" params
Fixes https://github.com/gohugoio/hugo/issues/4406.
2018-10-03 09:55:53 +03:00
Kaushal Modi c5279064df Re-organize the figure shortcode for better readability 2018-10-03 09:55:53 +03:00
Gregorio Martinez 152cffb13a Update README & CONTRIBUTING
Fix broken links for Dev Chat that point to broken gitter.im room.
Remove lines about `mage vendor` target that is no longer available.
Remove broken table of contents links for headings in CONTRIBUTING.md
Fix typo
2018-10-03 09:50:02 +03:00
Cameron Moore 0d5110d033 tpl: Cast IsSet key to int for indexed types
Don't assume that the user sends an int as the key when checking against
indexed types.

Fixes #3681
2018-10-03 09:36:27 +03:00
Cameron Moore d3b81ee58e hugolib: Improve error message for bad taxonomy weights
Error is now "Unable to convert taxonomy weight []string{"40"} to int
for variables/files.md"
2018-10-03 09:34:45 +03:00
Cameron Moore 1fd30d462e hugolib: Cast taxonomy weight parameters to int
Fixes #4628
2018-10-03 09:34:45 +03:00
Cameron Moore 498d629958 hugolib: Allow nil to be unwrapped as *Page
Previously, calls to *Page.Eq(nil) would always return false because the
unwrapPage func didn't support the nil case.  Add support for unwrapping
nil to a *Page.

Fixes #5043
2018-10-03 09:33:42 +03:00
Bjørn Erik Pedersen 10ac2ec446 tpl/collections: Fix handling of different interface types in Slice
In Hugo `0.49` we improved type support in `slice`. This has an unfortunate side effect in that `resources.Concat` now expects something that can resolve to `resource.Resources`.

This worked for most situations, but when you try to `slice` different `Resource` objects, you would be getting `[]interface {}` and not `resource.Resources`. And `concat` would fail:

```bash
error calling Concat: slice []interface {} not supported in concat.
```

This commit fixes that by simplifying the type checking logic in `Slice`:

* If the first item implements the `Slicer` interface, we try that
* If the above fails or the first item does not implement `Slicer`, we just return the `[]interface {}`

Fixes #5269
2018-10-02 23:54:16 +03:00
Cameron Moore ce264b936c tpl: Add a delimiter parameter to lang.NumFmt
The original implementation of NumFmt did not take into account that the
options delimiter (a space) could be a valid option.  Adding a delim
parameter seems like the simplest, safest, and most flexible way to
solve this oversight in a backwards-compatible way.

Fixes #5260
2018-10-02 17:41:48 +03:00
Anthony Fok 91f49c0700 snap: Add custom x-nodejs plugin to support ppc64el and s390x 2018-09-30 23:03:05 -06:00
Anthony Fok a475bf125c snap: Fetch mage with GO111MODULE=off 2018-09-30 23:03:01 -06:00
Anthony Fok f1dede3708 snap: Revert 'Skip "mage -v test" due to build failure on Launchpad'
This reverts commit 52ac85fbc4.
2018-09-30 23:02:58 -06:00
Anthony Fok fa873a6cb3 snap: Use build-snaps instead of building go from source
See https://forum.snapcraft.io/t/go-part-fails-with-go1-11-if-go-mod-exists-in-the-top-level-directory/7546/11
2018-09-30 23:02:34 -06:00
Bjørn Erik Pedersen fb732d5322 hugolib: Be a litle more specific in NextPage TODO 2018-09-26 09:26:53 +02:00
Ricardo N Feliciano ad705aac06 hugolib: Introduce Page.NextPage and Page.PrevPage
Introduce new page position variables in order to fix the ordering issue
of `.Next` and `.Prev` while also allowing an upgrade path via
deprecation.

`.NextInSection` becomes `.NextPageInSection`.
`.PrevInSection` becomes `.PrevPageInSection`.

`.Next` becomes a function returning `.PrevPage`.
`.Prev` becomes a function returning `.NextPage`.

Fixes #1061
2018-09-26 09:22:43 +02:00
Anthony Fok 52ac85fbc4 snap: Skip "mage -v test" due to build failure on Launchpad
The run "go test ./... -tags none" fails with multiple errors of

    use of internal package github.com/gohugoio/hugo/tpl/internal not allowed

See https://launchpadlibrarian.net/390252700/buildlog_snap_ubuntu_xenial_amd64_hugo-dev_BUILDING.txt.gz

I was unable to reproduce it with snapcraft in LXD
on my local Debian laptop, so this error is still a mystery to me.
2018-09-25 16:08:22 -06:00
Anthony Fok 048a64be1c releaser: Update path to snap/snapcraft.yaml 2018-09-25 07:21:09 -06:00
Anthony Fok 3033a9a37e snap: Fix go plugin build failure by renaming go.mod
as a temporary workaround.

See https://forum.snapcraft.io/t/go-plugin-go1-11-fails-if-go-mod-exists-in-the-top-level-directory/7546
and https://discourse.gohugo.io/t/hugo-0-48-released/13908/12
2018-09-25 07:05:55 -06:00
Anthony Fok 27d4211187 snap: Move snapcraft.yaml to snap/snapcraft.yaml 2018-09-25 07:03:51 -06:00
Anthony Fok 4730a78a76 snapcraft: Try installing postcss again
Revert "snap: Skip installing postcss due to failure on build server"

This reverts commit 66f688f712.
2018-09-24 22:20:45 -06:00
Anthony Fok b7706d6aec snapcraft: Set GO111MODULE=on in override-build script
Apparently, snapcraft's yet-to-be-documented environment declaration
feature is for run-time only.

See https://discourse.gohugo.io/t/hugo-0-48-released/13908/9
and https://forum.snapcraft.io/t/declaratively-defining-environment-variables/175/29
2018-09-24 22:15:42 -06:00
Bjørn Erik Pedersen 48413d76f4 build: Update the temp docker script 2018-09-24 12:41:12 +02:00
hugoreleaser 66b9e2bff2 releaser: Prepare repository for 0.50-DEV
[ci skip]
2018-09-24 10:04:24 +00:00
1456 changed files with 103444 additions and 55977 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
defaults: &defaults
docker:
- image: bepsays/ci-goreleaser:1.11-2
- image: bepsays/ci-goreleaser:1.13-4
environment:
CGO_ENABLED: "0"
+1
View File
@@ -6,3 +6,4 @@
.circleci
docs
examples
Dockerfile
+18
View File
@@ -0,0 +1,18 @@
---
name: 'Bug report'
labels: ''
assignees: ''
about: Create a report to help us improve
---
<!-- Please answer these questions before submitting your issue. Thanks! -->
### What version of Hugo are you using (`hugo version`)?
<pre>
$ hugo version
</pre>
### Does this issue reproduce with the latest release?
@@ -0,0 +1,8 @@
---
name: Proposal
about: Suggest an idea for Hugo
title: ''
labels: 'Proposal'
assignees: ''
---
+10
View File
@@ -0,0 +1,10 @@
---
name: Support (Do not use)
about: Please do not use Github for support requests. Visit https://discourse.gohugo.io for support
title: ''
labels: support
assignees: ''
---
Issues created with this template will be automatically closed. Please visit https://discourse.gohugo.io for the support you really, really, want!
+14
View File
@@ -0,0 +1,14 @@
on:
schedule:
- cron: 0 5 * * 3
name: Weekly Issue Closure
jobs:
cycle-weekly-close:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- name: weekly-issue-closure
uses: bdougie/close-issues-based-on-label@master
env:
LABEL: support
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+6 -1
View File
@@ -1,4 +1,4 @@
hugo
/hugo
docs/public*
/.idea
hugo.exe
@@ -19,3 +19,8 @@ dock.sh
GoBuilds
dist
resources/sunset.jpg
vendor
+61 -17
View File
@@ -1,33 +1,77 @@
language: go
sudo: false
dist: trusty
dist: bionic
env:
HUGO_BUILD_TAGS="extended"
global:
- CACHE_NAME=${TRAVIS_ARCH}
- GO111MODULE=on
- GOPROXY=https://proxy.golang.org
- HUGO_BUILD_TAGS=extended
git:
depth: false
go:
- 1.11
- tip
- "1.12.13"
- "1.13.4"
- master
arch:
- amd64
- arm64
os:
- linux
- osx
matrix:
- windows
jobs:
allow_failures:
- go: tip
- go: master
- arch: arm64
fast_finish: true
exclude:
- os: windows
go: master
- arch: arm64
os: osx
- arch: arm64
os: windows
cache:
directories:
- $HOME/gopath/pkg/mod
- $HOME/.cache/go-build
- $HOME/Library/Caches/go-build
- $HOME/AppData/Local/go-build
before_install:
- df -h
# https://travis-ci.community/t/go-cant-find-gcc-with-go1-11-1-on-windows/293/5
- if [ "$TRAVIS_OS_NAME" = "windows" ]; then
choco install mingw -y;
export PATH=/c/tools/mingw64/bin:"$PATH";
fi
- gem install asciidoctor
- type asciidoctor
install:
- mkdir -p $HOME/src
- mv $HOME/gopath/src/github.com/gohugoio/hugo $HOME/src
- mv $TRAVIS_BUILD_DIR $HOME/src
- export TRAVIS_BUILD_DIR=$HOME/src/hugo
- cd $HOME/src/hugo
- go get github.com/magefile/mage
script:
- go mod download
- mage -v test
- mage -v check
- mage -v hugo
- ./hugo -s docs/
- ./hugo --renderToMemory -s docs/
before_install:
- gem install asciidoctor
- type asciidoctor
- go mod download || true
- mage -v test
- if [ "$TRAVIS_ARCH" = "amd64" ]; then
mage -v check;
else
HUGO_TIMEOUT=30000 mage -v check;
fi
- mage -v hugo
- ./hugo -s docs/
- ./hugo --renderToMemory -s docs/
- df -h
+12 -21
View File
@@ -18,11 +18,8 @@ The Hugo community and maintainers are [very active](https://github.com/gohugoio
* [Submitting Patches](#submitting-patches)
* [Code Contribution Guidelines](#code-contribution-guidelines)
* [Git Commit Message Guidelines](#git-commit-message-guidelines)
* [Vendored Dependencies](#vendored-dependencies)
* [Fetching the Sources From GitHub](#fetching-the-sources-from-github)
* [Using Git Remotes](#using-git-remotes)
* [Build Hugo with Your Changes](#build-hugo-with-your-changes)
* [Updating the Hugo Sources](#updating-the-hugo-sources)
* [Building Hugo with Your Changes](#building-hugo-with-your-changes)
## Asking Support Questions
@@ -32,12 +29,16 @@ Please don't use the GitHub issue tracker to ask questions.
## Reporting Issues
If you believe you have found a defect in Hugo or its documentation, use
the GitHub [issue tracker](https://github.com/gohugoio/hugo/issues) to report
the GitHub issue tracker to report
the problem to the Hugo maintainers. If you're not sure if it's a bug or not,
start by asking in the [discussion forum](https://discourse.gohugo.io).
When reporting the issue, please provide the version of Hugo in use (`hugo
version`) and your operating system.
- [Hugo Issues · gohugoio/hugo](https://github.com/gohugoio/hugo/issues)
- [Hugo Documentation Issues · gohugoio/hugoDocs](https://github.com/gohugoio/hugoDocs/issues)
- [Hugo Website Theme Issues · gohugoio/hugoThemesSite](https://github.com/gohugoio/hugoThemesSite/issues)
## Code Contribution
Hugo has become a fully featured static site generator, so any new functionality must:
@@ -73,7 +74,7 @@ To make the contribution process as seamless as possible, we ask for the followi
* Run `go fmt`.
* Add documentation if you are adding new features or changing functionality. The docs site lives in `/docs`.
* Squash your commits into a single commit. `git rebase -i`. Its okay to force update your pull request with `git push -f`.
* Ensure that `mage check` succeeds. [Travis CI](https://travis-ci.org/gohugoio/hugo) (Linux and macOS) and [AppVeyor](https://ci.appveyor.com/project/gohugoio/hugo/branch/master) (Windows) will fail the build if `mage check` fails.
* Ensure that `mage check` succeeds. [Travis CI](https://travis-ci.org/gohugoio/hugo) (Windows, Linux and macOS) will fail the build if `mage check` fails.
* Follow the **Git Commit Message Guidelines** below.
### Git Commit Message Guidelines
@@ -106,7 +107,7 @@ Fixes #1949
### Fetching the Sources From GitHub
Since Hugo 0.48, Hugo uses the Go Modules support built into Go 1.11 to build. The easiest is is to clone Hugo in a directory outside of `GOPATH`, as in the following example:
Since Hugo 0.48, Hugo uses the Go Modules support built into Go 1.11 to build. The easiest is to clone Hugo in a directory outside of `GOPATH`, as in the following example:
```bash
mkdir $HOME/src
@@ -116,13 +117,15 @@ cd hugo
go install
```
>Note: Some Go tools may not be fully updated to support Go Modules yet. One example would be LiteIDE. Follow [this workaround](https://github.com/visualfc/liteide/issues/986#issuecomment-428117702) for how to continue to work with Hugo below `GOPATH`.
For some convenient build and test targets, you also will want to install Mage:
```bash
go get github.com/magefile/mage
```
Now, to make a change to Hugos's source:
Now, to make a change to Hugo's source:
1. Create a new branch for your changes (the branch name is arbitrary):
@@ -160,7 +163,7 @@ Hugo uses [mage](https://github.com/magefile/mage) to sync vendor dependencies,
cd $HOME/go/src/github.com/gohugoio/hugo
```
To build Hugo:
To build Hugo:
```bash
mage hugo
@@ -190,15 +193,3 @@ mage -l
```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
the source changes, but you'll need to keep the vendored packages up-to-date as
well.
```bash
git pull
mage vendor
```
+31 -12
View File
@@ -2,25 +2,44 @@
# Twitter: https://twitter.com/gohugoio
# Website: https://gohugo.io/
FROM golang:1.11-alpine3.7 AS build
FROM golang:1.13-alpine AS build
ENV CGO_ENABLED=0
# Optionally set HUGO_BUILD_TAGS to "extended" when building like so:
# docker build --build-arg HUGO_BUILD_TAGS=extended .
ARG HUGO_BUILD_TAGS
ARG CGO=1
ENV CGO_ENABLED=${CGO}
ENV GOOS=linux
ENV GO111MODULE=on
WORKDIR /go/src/github.com/gohugoio/hugo
RUN apk add --no-cache \
git \
musl-dev
COPY . /go/src/github.com/gohugoio/hugo/
RUN go install -ldflags '-s -w'
# gcc/g++ are required to build SASS libraries for extended version
RUN apk update && \
apk add --no-cache gcc g++ musl-dev && \
go get github.com/magefile/mage
RUN mage hugo && mage install
# ---
FROM scratch
COPY --from=build /go/bin/hugo /hugo
FROM alpine:3.10
COPY --from=build /go/bin/hugo /usr/bin/hugo
# libc6-compat & libstdc++ are required for extended SASS libraries
# ca-certificates are required to fetch outside resources (like Twitter oEmbeds)
RUN apk update && \
apk add --no-cache ca-certificates libc6-compat libstdc++
VOLUME /site
WORKDIR /site
VOLUME /site
EXPOSE 1313
ENTRYPOINT [ "/hugo" ]
CMD [ "--help" ]
# Expose port for live server
EXPOSE 1313
ENTRYPOINT ["hugo"]
CMD ["--help"]
+78 -13
View File
@@ -1,19 +1,16 @@
![Hugo](https://raw.githubusercontent.com/gohugoio/hugoDocs/master/static/img/hugo-logo.png)
<img src="https://raw.githubusercontent.com/gohugoio/gohugoioTheme/master/static/images/hugo-logo-wide.svg?sanitize=true" alt="Hugo" width="565">
A Fast and Flexible Static Site Generator built with love by [bep](https://github.com/bep), [spf13](http://spf13.com/) and [friends](https://github.com/gohugoio/hugo/graphs/contributors) in [Go][].
[Website](https://gohugo.io) |
[Forum](https://discourse.gohugo.io) |
[Developer Chat (no support)](https://gitter.im/gohugoio/hugo) |
[Documentation](https://gohugo.io/overview/introduction/) |
[Installation Guide](https://gohugo.io/overview/installing/) |
[Documentation](https://gohugo.io/getting-started/) |
[Installation Guide](https://gohugo.io/getting-started/installing/) |
[Contribution Guide](CONTRIBUTING.md) |
[Twitter](https://twitter.com/gohugoio)
[![GoDoc](https://godoc.org/github.com/gohugoio/hugo?status.svg)](https://godoc.org/github.com/gohugoio/hugo)
[![Linux and macOS Build Status](https://api.travis-ci.org/gohugoio/hugo.svg?branch=master&label=Linux+and+macOS+build "Linux and macOS Build Status")](https://travis-ci.org/gohugoio/hugo)
[![Windows Build Status](https://ci.appveyor.com/api/projects/status/a5mr220vsd091kua?svg=true&label=Windows+build "Windows Build Status")](https://ci.appveyor.com/project/bep/hugo/branch/master)
[![Dev chat at https://gitter.im/gohugoio/hugo](https://img.shields.io/badge/gitter-developer_chat-46bc99.svg)](https://gitter.im/spf13/hugo?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Linux and macOS Build Status](https://api.travis-ci.org/gohugoio/hugo.svg?branch=master&label=Windows+and+Linux+and+macOS+build "Windows, Linux and macOS Build Status")](https://travis-ci.org/gohugoio/hugo)
[![Go Report Card](https://goreportcard.com/badge/github.com/gohugoio/hugo)](https://goreportcard.com/report/github.com/gohugoio/hugo)
## Overview
@@ -32,11 +29,11 @@ Hugo is designed to work well for any kind of website including blogs, tumbles,
#### Supported Architectures
Currently, we provide pre-built Hugo binaries for Windows, Linux, FreeBSD, NetBSD, macOS (Darwin), and [Android](https://gist.github.com/bep/a0d8a26cf6b4f8bc992729b8e50b480b) for x64, i386 and ARM architectures.
Currently, we provide pre-built Hugo binaries for Windows, Linux, FreeBSD, NetBSD, DragonFly BSD, Open BSD, macOS (Darwin), and [Android](https://gist.github.com/bep/a0d8a26cf6b4f8bc992729b8e50b480b) for x64, i386 and ARM architectures.
Hugo may also be compiled from source wherever the Go compiler tool chain can run, e.g. for other operating systems including DragonFly BSD, OpenBSD, Plan 9, and Solaris.
Hugo may also be compiled from source wherever the Go compiler tool chain can run, e.g. for other operating systems including Plan 9 and Solaris.
**Complete documentation is available at [Hugo Documentation][].**
**Complete documentation is available at [Hugo Documentation](https://gohugo.io/getting-started/).**
## Choose How to Install
@@ -50,7 +47,7 @@ Building the binaries is an easy task for an experienced `go` getter.
### Install Hugo as Your Site Generator (Binary Install)
Use the [installation instructions in the Hugo documentation](https://gohugo.io/overview/installing/).
Use the [installation instructions in the Hugo documentation](https://gohugo.io/getting-started/installing/).
### Build and Install the Binaries from Source (Advanced Install)
@@ -61,7 +58,7 @@ Use the [installation instructions in the Hugo documentation](https://gohugo.io/
#### Fetch from GitHub
Since Hugo 0.48, Hugo uses the Go Modules support built into Go 1.11 to build. The easiest is is to clone Hugo in a directory outside of `GOPATH`, as in the following example:
Since Hugo 0.48, Hugo uses the Go Modules support built into Go 1.11 to build. The easiest is to clone Hugo in a directory outside of `GOPATH`, as in the following example:
```bash
mkdir $HOME/src
@@ -109,7 +106,7 @@ The Hugo project welcomes all contributors and contributions regardless of skill
If you are interested in helping with the project, we will help you with your contribution.
Hugo is a very active project with many contributions happening daily.
Because we want to create the best possible product for our users and the best contribution experience for our developers,
We want to create the best possible product for our users and the best contribution experience for our developers,
we have a set of guidelines which ensure that all contributions are acceptable.
The guidelines are not intended as a filter or barrier to participation.
If you are unfamiliar with the contribution process, the Hugo team will help you and teach you how to bring your contribution in accordance with the guidelines.
@@ -120,3 +117,71 @@ For a complete guide to contributing code to Hugo, see the [Contribution Guide](
[Go]: https://golang.org/
[Hugo Documentation]: https://gohugo.io/overview/introduction/
## Dependencies
Hugo stands on the shoulder of many great open source libraries, in lexical order:
| Dependency | License |
| :------------- | :------------- |
| [github.com/BurntSushi/locker](https://github.com/BurntSushi/locker) | The Unlicense |
| [github.com/BurntSushi/toml](https://github.com/BurntSushi/toml) | MIT License |
| [github.com/PuerkitoBio/purell](https://github.com/PuerkitoBio/purell) | BSD 3-Clause "New" or "Revised" License |
| [github.com/PuerkitoBio/urlesc](https://github.com/PuerkitoBio/urlesc) | BSD 3-Clause "New" or "Revised" License |
| [github.com/alecthomas/chroma](https://github.com/alecthomas/chroma) | MIT License |
| [github.com/bep/debounce](https://github.com/bep/debounce) | MIT License |
| [github.com/bep/gitmap](https://github.com/bep/gitmap) | MIT License |
| [github.com/bep/go-tocss](https://github.com/bep/go-tocss) | MIT License |
| [github.com/niklasfasching/go-org](https://github.com/niklasfasching/go-org) | MIT License |
| [github.com/cpuguy83/go-md2man](https://github.com/cpuguy83/go-md2man) | MIT License |
| [github.com/danwakefield/fnmatch](https://github.com/danwakefield/fnmatch) | BSD 2-Clause "Simplified" License |
| [github.com/disintegration/imaging](https://github.com/disintegration/imaging) | MIT License |
| [github.com/dlclark/regexp2](https://github.com/dlclark/regexp2) | MIT License |
| [github.com/eknkc/amber](https://github.com/eknkc/amber) | MIT License |
| [github.com/fsnotify/fsnotify](https://github.com/fsnotify/fsnotify) | BSD 3-Clause "New" or "Revised" License |
| [github.com/gobwas/glob](https://github.com/gobwas/glob) | MIT License |
| [github.com/gorilla/websocket](https://github.com/gorilla/websocket) | BSD 2-Clause "Simplified" License |
| [github.com/hashicorp/go-immutable-radix](https://github.com/hashicorp/go-immutable-radix) | Mozilla Public License 2.0 |
| [github.com/hashicorp/golang-lru](https://github.com/hashicorp/golang-lru) | Mozilla Public License 2.0 |
| [github.com/hashicorp/hcl](https://github.com/hashicorp/hcl) | Mozilla Public License 2.0 |
| [github.com/jdkato/prose](https://github.com/jdkato/prose) | MIT License |
| [github.com/kyokomi/emoji](https://github.com/kyokomi/emoji) | MIT License |
| [github.com/magiconair/properties](https://github.com/magiconair/properties) | BSD 2-Clause "Simplified" License |
| [github.com/markbates/inflect](https://github.com/markbates/inflect) | MIT License |
| [github.com/mattn/go-isatty](https://github.com/mattn/go-isatty) | MIT License |
| [github.com/mattn/go-runewidth](https://github.com/mattn/go-runewidth) | MIT License |
| [github.com/miekg/mmark](https://github.com/miekg/mmark) | Simplified BSD License |
| [github.com/mitchellh/hashstructure](https://github.com/mitchellh/hashstructure) | MIT License |
| [github.com/mitchellh/mapstructure](https://github.com/mitchellh/mapstructure) | MIT License |
| [github.com/muesli/smartcrop](https://github.com/muesli/smartcrop) | MIT License |
| [github.com/nicksnyder/go-i18n](https://github.com/nicksnyder/go-i18n) | MIT License |
| [github.com/olekukonko/tablewriter](https://github.com/olekukonko/tablewriter) | MIT License |
| [github.com/pelletier/go-toml](https://github.com/pelletier/go-toml) | MIT License |
| [github.com/pkg/errors](https://github.com/pkg/errors) | BSD 2-Clause "Simplified" License |
| [github.com/russross/blackfriday](https://github.com/russross/blackfriday) | Simplified BSD License |
| [github.com/shurcooL/sanitized_anchor_name](https://github.com/shurcooL/sanitized_anchor_name) | MIT License |
| [github.com/spf13/afero](https://github.com/spf13/afero) | Apache License 2.0 |
| [github.com/spf13/cast](https://github.com/spf13/cast) | MIT License |
| [github.com/spf13/cobra](https://github.com/spf13/cobra) | Apache License 2.0 |
| [github.com/spf13/fsync](https://github.com/spf13/fsync) | MIT License |
| [github.com/spf13/jwalterweatherman](https://github.com/spf13/jwalterweatherman) | MIT License |
| [github.com/spf13/nitro](https://github.com/spf13/nitro) | Apache License 2.0 |
| [github.com/spf13/pflag](https://github.com/spf13/pflag) | BSD 3-Clause "New" or "Revised" License |
| [github.com/spf13/viper](https://github.com/spf13/viper) | MIT License |
| [github.com/tdewolff/minify](https://github.com/tdewolff/minify) | MIT License |
| [github.com/tdewolff/parse](https://github.com/tdewolff/parse) | MIT License |
| [github.com/wellington/go-libsass](https://github.com/wellington/go-libsass) | Apache License 2.0 |
| [github.com/yosssi/ace](https://github.com/yosssi/ace) | MIT License |
| [golang.org/x/image](https://golang.org/x/image) | BSD 3-Clause "New" or "Revised" License |
| [golang.org/x/net](https://golang.org/x/net) | BSD 3-Clause "New" or "Revised" License |
| [golang.org/x/sync](https://golang.org/x/sync) | BSD 3-Clause "New" or "Revised" License |
| [golang.org/x/sys](https://golang.org/x/sys) | BSD 3-Clause "New" or "Revised" License |
| [golang.org/x/text](https://golang.org/x/text) | BSD 3-Clause "New" or "Revised" License
| [gopkg.in/yaml.v2](https://gopkg.in/yaml.v2) | Apache License 2.0 |
-24
View File
@@ -1,24 +0,0 @@
image: Visual Studio 2015
init:
- 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:
HUGO_BUILD_TAGS: extended
# clones and cd's to path
clone_folder: C:\hugo
install:
# - gem install asciidoctor
- pip install docutils
- go get github.com/magefile/mage
build_script:
- go mod download
- mage hugoRace
- mage -v check
- hugo -s docs/
- hugo --renderToMemory -s docs/
Executable
+1
View File
@@ -0,0 +1 @@
gobench -package=./hugolib -bench="BenchmarkSiteNew/Deep_content_tree"
+1 -2
View File
@@ -1,2 +1 @@
# 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
docker run --rm --mount type=bind,source="$(pwd)",target=/hugo -w /hugo -i -t bepsays/ci-goreleaser:1.11-2 /bin/bash
+7 -3
View File
@@ -14,14 +14,18 @@
package bufferpool
import (
"github.com/stretchr/testify/assert"
"testing"
qt "github.com/frankban/quicktest"
)
func TestBufferPool(t *testing.T) {
c := qt.New(t)
buff := GetBuffer()
buff.WriteString("do be do be do")
assert.Equal(t, "do be do be do", buff.String())
c.Assert(buff.String(), qt.Equals, "do be do be do")
PutBuffer(buff)
assert.Equal(t, 0, buff.Len())
c.Assert(buff.Len(), qt.Equals, 0)
}
+376
View File
@@ -0,0 +1,376 @@
// 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 filecache
import (
"bytes"
"errors"
"io"
"io/ioutil"
"os"
"path/filepath"
"strings"
"sync"
"time"
"github.com/gohugoio/hugo/common/hugio"
"github.com/gohugoio/hugo/helpers"
"github.com/BurntSushi/locker"
"github.com/spf13/afero"
)
// ErrFatal can be used to signal an unrecoverable error.
var ErrFatal = errors.New("fatal filecache error")
const (
filecacheRootDirname = "filecache"
)
// Cache caches a set of files in a directory. This is usually a file on
// disk, but since this is backed by an Afero file system, it can be anything.
type Cache struct {
Fs afero.Fs
// Max age for items in this cache. Negative duration means forever,
// 0 is effectively turning this cache off.
maxAge time.Duration
// When set, we just remove this entire root directory on expiration.
pruneAllRootDir string
nlocker *lockTracker
}
type lockTracker struct {
seenMu sync.RWMutex
seen map[string]struct{}
*locker.Locker
}
// Lock tracks the ids in use. We use this information to do garbage collection
// after a Hugo build.
func (l *lockTracker) Lock(id string) {
l.seenMu.RLock()
if _, seen := l.seen[id]; !seen {
l.seenMu.RUnlock()
l.seenMu.Lock()
l.seen[id] = struct{}{}
l.seenMu.Unlock()
} else {
l.seenMu.RUnlock()
}
l.Locker.Lock(id)
}
// ItemInfo contains info about a cached file.
type ItemInfo struct {
// This is the file's name relative to the cache's filesystem.
Name string
}
// NewCache creates a new file cache with the given filesystem and max age.
func NewCache(fs afero.Fs, maxAge time.Duration, pruneAllRootDir string) *Cache {
return &Cache{
Fs: fs,
nlocker: &lockTracker{Locker: locker.NewLocker(), seen: make(map[string]struct{})},
maxAge: maxAge,
pruneAllRootDir: pruneAllRootDir,
}
}
// lockedFile is a file with a lock that is released on Close.
type lockedFile struct {
afero.File
unlock func()
}
func (l *lockedFile) Close() error {
defer l.unlock()
return l.File.Close()
}
// WriteCloser returns a transactional writer into the cache.
// It's important that it's closed when done.
func (c *Cache) WriteCloser(id string) (ItemInfo, io.WriteCloser, error) {
id = cleanID(id)
c.nlocker.Lock(id)
info := ItemInfo{Name: id}
f, err := helpers.OpenFileForWriting(c.Fs, id)
if err != nil {
c.nlocker.Unlock(id)
return info, nil, err
}
return info, &lockedFile{
File: f,
unlock: func() { c.nlocker.Unlock(id) },
}, nil
}
// ReadOrCreate tries to lookup the file in cache.
// If found, it is passed to read and then closed.
// If not found a new file is created and passed to create, which should close
// it when done.
func (c *Cache) ReadOrCreate(id string,
read func(info ItemInfo, r io.ReadSeeker) error,
create func(info ItemInfo, w io.WriteCloser) error) (info ItemInfo, err error) {
id = cleanID(id)
c.nlocker.Lock(id)
defer c.nlocker.Unlock(id)
info = ItemInfo{Name: id}
if r := c.getOrRemove(id); r != nil {
err = read(info, r)
defer r.Close()
if err == nil || err == ErrFatal {
// See https://github.com/gohugoio/hugo/issues/6401
// To recover from file corruption we handle read errors
// as the cache item was not found.
// Any file permission issue will also fail in the next step.
return
}
}
f, err := helpers.OpenFileForWriting(c.Fs, id)
if err != nil {
return
}
err = create(info, f)
return
}
// GetOrCreate tries to get the file with the given id from cache. If not found or expired, create will
// be invoked and the result cached.
// This method is protected by a named lock using the given id as identifier.
func (c *Cache) GetOrCreate(id string, create func() (io.ReadCloser, error)) (ItemInfo, io.ReadCloser, error) {
id = cleanID(id)
c.nlocker.Lock(id)
defer c.nlocker.Unlock(id)
info := ItemInfo{Name: id}
if r := c.getOrRemove(id); r != nil {
return info, r, nil
}
r, err := create()
if err != nil {
return info, nil, err
}
if c.maxAge == 0 {
// No caching.
return info, hugio.ToReadCloser(r), nil
}
var buff bytes.Buffer
return info,
hugio.ToReadCloser(&buff),
afero.WriteReader(c.Fs, id, io.TeeReader(r, &buff))
}
// GetOrCreateBytes is the same as GetOrCreate, but produces a byte slice.
func (c *Cache) GetOrCreateBytes(id string, create func() ([]byte, error)) (ItemInfo, []byte, error) {
id = cleanID(id)
c.nlocker.Lock(id)
defer c.nlocker.Unlock(id)
info := ItemInfo{Name: id}
if r := c.getOrRemove(id); r != nil {
defer r.Close()
b, err := ioutil.ReadAll(r)
return info, b, err
}
b, err := create()
if err != nil {
return info, nil, err
}
if c.maxAge == 0 {
return info, b, nil
}
if err := afero.WriteReader(c.Fs, id, bytes.NewReader(b)); err != nil {
return info, nil, err
}
return info, b, nil
}
// GetBytes gets the file content with the given id from the cahce, nil if none found.
func (c *Cache) GetBytes(id string) (ItemInfo, []byte, error) {
id = cleanID(id)
c.nlocker.Lock(id)
defer c.nlocker.Unlock(id)
info := ItemInfo{Name: id}
if r := c.getOrRemove(id); r != nil {
defer r.Close()
b, err := ioutil.ReadAll(r)
return info, b, err
}
return info, nil, nil
}
// Get gets the file with the given id from the cahce, nil if none found.
func (c *Cache) Get(id string) (ItemInfo, io.ReadCloser, error) {
id = cleanID(id)
c.nlocker.Lock(id)
defer c.nlocker.Unlock(id)
info := ItemInfo{Name: id}
r := c.getOrRemove(id)
return info, r, nil
}
// getOrRemove gets the file with the given id. If it's expired, it will
// be removed.
func (c *Cache) getOrRemove(id string) hugio.ReadSeekCloser {
if c.maxAge == 0 {
// No caching.
return nil
}
if c.maxAge > 0 {
fi, err := c.Fs.Stat(id)
if err != nil {
return nil
}
if c.isExpired(fi.ModTime()) {
c.Fs.Remove(id)
return nil
}
}
f, err := c.Fs.Open(id)
if err != nil {
return nil
}
return f
}
func (c *Cache) isExpired(modTime time.Time) bool {
if c.maxAge < 0 {
return false
}
return c.maxAge == 0 || time.Since(modTime) > c.maxAge
}
// For testing
func (c *Cache) getString(id string) string {
id = cleanID(id)
c.nlocker.Lock(id)
defer c.nlocker.Unlock(id)
f, err := c.Fs.Open(id)
if err != nil {
return ""
}
defer f.Close()
b, _ := ioutil.ReadAll(f)
return string(b)
}
// Caches is a named set of caches.
type Caches map[string]*Cache
// Get gets a named cache, nil if none found.
func (f Caches) Get(name string) *Cache {
return f[strings.ToLower(name)]
}
// NewCaches creates a new set of file caches from the given
// configuration.
func NewCaches(p *helpers.PathSpec) (Caches, error) {
var dcfg Configs
if c, ok := p.Cfg.Get("filecacheConfigs").(Configs); ok {
dcfg = c
} else {
var err error
dcfg, err = DecodeConfig(p.Fs.Source, p.Cfg)
if err != nil {
return nil, err
}
}
fs := p.Fs.Source
m := make(Caches)
for k, v := range dcfg {
var cfs afero.Fs
if v.isResourceDir {
cfs = p.BaseFs.ResourcesCache
} else {
cfs = fs
}
if cfs == nil {
// TODO(bep) we still have some places that do not initialize the
// full dependencies of a site, e.g. the import Jekyll command.
// That command does not need these caches, so let us just continue
// for now.
continue
}
baseDir := v.Dir
if err := cfs.MkdirAll(baseDir, 0777); err != nil && !os.IsExist(err) {
return nil, err
}
bfs := afero.NewBasePathFs(cfs, baseDir)
var pruneAllRootDir string
if k == cacheKeyModules {
pruneAllRootDir = "pkg"
}
m[k] = NewCache(bfs, v.MaxAge, pruneAllRootDir)
}
return m, nil
}
func cleanID(name string) string {
return strings.TrimPrefix(filepath.Clean(name), helpers.FilePathSeparator)
}
+230
View File
@@ -0,0 +1,230 @@
// 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 filecache
import (
"path"
"path/filepath"
"strings"
"time"
"github.com/gohugoio/hugo/config"
"github.com/gohugoio/hugo/helpers"
"github.com/mitchellh/mapstructure"
"github.com/pkg/errors"
"github.com/spf13/afero"
)
const (
cachesConfigKey = "caches"
resourcesGenDir = ":resourceDir/_gen"
)
var defaultCacheConfig = Config{
MaxAge: -1, // Never expire
Dir: ":cacheDir/:project",
}
const (
cacheKeyGetJSON = "getjson"
cacheKeyGetCSV = "getcsv"
cacheKeyImages = "images"
cacheKeyAssets = "assets"
cacheKeyModules = "modules"
)
type Configs map[string]Config
func (c Configs) CacheDirModules() string {
return c[cacheKeyModules].Dir
}
var defaultCacheConfigs = Configs{
cacheKeyModules: {
MaxAge: -1,
Dir: ":cacheDir/modules",
},
cacheKeyGetJSON: defaultCacheConfig,
cacheKeyGetCSV: defaultCacheConfig,
cacheKeyImages: {
MaxAge: -1,
Dir: resourcesGenDir,
},
cacheKeyAssets: {
MaxAge: -1,
Dir: resourcesGenDir,
},
}
type Config struct {
// Max age of cache entries in this cache. Any items older than this will
// be removed and not returned from the cache.
// a negative value means forever, 0 means cache is disabled.
MaxAge time.Duration
// The directory where files are stored.
Dir string
// Will resources/_gen will get its own composite filesystem that
// also checks any theme.
isResourceDir bool
}
// GetJSONCache gets the file cache for getJSON.
func (f Caches) GetJSONCache() *Cache {
return f[cacheKeyGetJSON]
}
// GetCSVCache gets the file cache for getCSV.
func (f Caches) GetCSVCache() *Cache {
return f[cacheKeyGetCSV]
}
// ImageCache gets the file cache for processed images.
func (f Caches) ImageCache() *Cache {
return f[cacheKeyImages]
}
// ModulesCache gets the file cache for Hugo Modules.
func (f Caches) ModulesCache() *Cache {
return f[cacheKeyModules]
}
// AssetsCache gets the file cache for assets (processed resources, SCSS etc.).
func (f Caches) AssetsCache() *Cache {
return f[cacheKeyAssets]
}
func DecodeConfig(fs afero.Fs, cfg config.Provider) (Configs, error) {
c := make(Configs)
valid := make(map[string]bool)
// Add defaults
for k, v := range defaultCacheConfigs {
c[k] = v
valid[k] = true
}
m := cfg.GetStringMap(cachesConfigKey)
_, isOsFs := fs.(*afero.OsFs)
for k, v := range m {
cc := defaultCacheConfig
dc := &mapstructure.DecoderConfig{
Result: &cc,
DecodeHook: mapstructure.StringToTimeDurationHookFunc(),
WeaklyTypedInput: true,
}
decoder, err := mapstructure.NewDecoder(dc)
if err != nil {
return c, err
}
if err := decoder.Decode(v); err != nil {
return nil, err
}
if cc.Dir == "" {
return c, errors.New("must provide cache Dir")
}
name := strings.ToLower(k)
if !valid[name] {
return nil, errors.Errorf("%q is not a valid cache name", name)
}
c[name] = cc
}
// This is a very old flag in Hugo, but we need to respect it.
disabled := cfg.GetBool("ignoreCache")
for k, v := range c {
dir := filepath.ToSlash(filepath.Clean(v.Dir))
hadSlash := strings.HasPrefix(dir, "/")
parts := strings.Split(dir, "/")
for i, part := range parts {
if strings.HasPrefix(part, ":") {
resolved, isResource, err := resolveDirPlaceholder(fs, cfg, part)
if err != nil {
return c, err
}
if isResource {
v.isResourceDir = true
}
parts[i] = resolved
}
}
dir = path.Join(parts...)
if hadSlash {
dir = "/" + dir
}
v.Dir = filepath.Clean(filepath.FromSlash(dir))
if !v.isResourceDir {
if isOsFs && !filepath.IsAbs(v.Dir) {
return c, errors.Errorf("%q must resolve to an absolute directory", v.Dir)
}
// Avoid cache in root, e.g. / (Unix) or c:\ (Windows)
if len(strings.TrimPrefix(v.Dir, filepath.VolumeName(v.Dir))) == 1 {
return c, errors.Errorf("%q is a root folder and not allowed as cache dir", v.Dir)
}
}
if !strings.HasPrefix(v.Dir, "_gen") {
// We do cache eviction (file removes) and since the user can set
// his/hers own cache directory, we really want to make sure
// we do not delete any files that do not belong to this cache.
// We do add the cache name as the root, but this is an extra safe
// guard. We skip the files inside /resources/_gen/ because
// that would be breaking.
v.Dir = filepath.Join(v.Dir, filecacheRootDirname, k)
} else {
v.Dir = filepath.Join(v.Dir, k)
}
if disabled {
v.MaxAge = 0
}
c[k] = v
}
return c, nil
}
// Resolves :resourceDir => /myproject/resources etc., :cacheDir => ...
func resolveDirPlaceholder(fs afero.Fs, cfg config.Provider, placeholder string) (cacheDir string, isResource bool, err error) {
workingDir := cfg.GetString("workingDir")
switch strings.ToLower(placeholder) {
case ":resourcedir":
return "", true, nil
case ":cachedir":
d, err := helpers.GetCacheDir(fs, cfg)
return d, false, err
case ":project":
return filepath.Base(workingDir), false, nil
}
return "", false, errors.Errorf("%q is not a valid placeholder (valid values are :cacheDir or :resourceDir)", placeholder)
}
+196
View File
@@ -0,0 +1,196 @@
// 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 filecache
import (
"path/filepath"
"runtime"
"strings"
"testing"
"time"
"github.com/spf13/afero"
"github.com/gohugoio/hugo/config"
qt "github.com/frankban/quicktest"
"github.com/spf13/viper"
)
func TestDecodeConfig(t *testing.T) {
t.Parallel()
c := qt.New(t)
configStr := `
resourceDir = "myresources"
contentDir = "content"
dataDir = "data"
i18nDir = "i18n"
layoutDir = "layouts"
assetDir = "assets"
archetypeDir = "archetypes"
[caches]
[caches.getJSON]
maxAge = "10m"
dir = "/path/to/c1"
[caches.getCSV]
maxAge = "11h"
dir = "/path/to/c2"
[caches.images]
dir = "/path/to/c3"
`
cfg, err := config.FromConfigString(configStr, "toml")
c.Assert(err, qt.IsNil)
fs := afero.NewMemMapFs()
decoded, err := DecodeConfig(fs, cfg)
c.Assert(err, qt.IsNil)
c.Assert(len(decoded), qt.Equals, 5)
c2 := decoded["getcsv"]
c.Assert(c2.MaxAge.String(), qt.Equals, "11h0m0s")
c.Assert(c2.Dir, qt.Equals, filepath.FromSlash("/path/to/c2/filecache/getcsv"))
c3 := decoded["images"]
c.Assert(c3.MaxAge, qt.Equals, time.Duration(-1))
c.Assert(c3.Dir, qt.Equals, filepath.FromSlash("/path/to/c3/filecache/images"))
}
func TestDecodeConfigIgnoreCache(t *testing.T) {
t.Parallel()
c := qt.New(t)
configStr := `
resourceDir = "myresources"
contentDir = "content"
dataDir = "data"
i18nDir = "i18n"
layoutDir = "layouts"
assetDir = "assets"
archeTypedir = "archetypes"
ignoreCache = true
[caches]
[caches.getJSON]
maxAge = 1234
dir = "/path/to/c1"
[caches.getCSV]
maxAge = 3456
dir = "/path/to/c2"
[caches.images]
dir = "/path/to/c3"
`
cfg, err := config.FromConfigString(configStr, "toml")
c.Assert(err, qt.IsNil)
fs := afero.NewMemMapFs()
decoded, err := DecodeConfig(fs, cfg)
c.Assert(err, qt.IsNil)
c.Assert(len(decoded), qt.Equals, 5)
for _, v := range decoded {
c.Assert(v.MaxAge, qt.Equals, time.Duration(0))
}
}
func TestDecodeConfigDefault(t *testing.T) {
c := qt.New(t)
cfg := newTestConfig()
if runtime.GOOS == "windows" {
cfg.Set("resourceDir", "c:\\cache\\resources")
cfg.Set("cacheDir", "c:\\cache\\thecache")
} else {
cfg.Set("resourceDir", "/cache/resources")
cfg.Set("cacheDir", "/cache/thecache")
}
fs := afero.NewMemMapFs()
decoded, err := DecodeConfig(fs, cfg)
c.Assert(err, qt.IsNil)
c.Assert(len(decoded), qt.Equals, 5)
imgConfig := decoded[cacheKeyImages]
jsonConfig := decoded[cacheKeyGetJSON]
if runtime.GOOS == "windows" {
c.Assert(imgConfig.Dir, qt.Equals, filepath.FromSlash("_gen/images"))
} else {
c.Assert(imgConfig.Dir, qt.Equals, "_gen/images")
c.Assert(jsonConfig.Dir, qt.Equals, "/cache/thecache/hugoproject/filecache/getjson")
}
c.Assert(imgConfig.isResourceDir, qt.Equals, true)
c.Assert(jsonConfig.isResourceDir, qt.Equals, false)
}
func TestDecodeConfigInvalidDir(t *testing.T) {
t.Parallel()
c := qt.New(t)
configStr := `
resourceDir = "myresources"
contentDir = "content"
dataDir = "data"
i18nDir = "i18n"
layoutDir = "layouts"
assetDir = "assets"
archeTypedir = "archetypes"
[caches]
[caches.getJSON]
maxAge = "10m"
dir = "/"
`
if runtime.GOOS == "windows" {
configStr = strings.Replace(configStr, "/", "c:\\\\", 1)
}
cfg, err := config.FromConfigString(configStr, "toml")
c.Assert(err, qt.IsNil)
fs := afero.NewMemMapFs()
_, err = DecodeConfig(fs, cfg)
c.Assert(err, qt.Not(qt.IsNil))
}
func newTestConfig() *viper.Viper {
cfg := viper.New()
cfg.Set("workingDir", filepath.FromSlash("/my/cool/hugoproject"))
cfg.Set("contentDir", "content")
cfg.Set("dataDir", "data")
cfg.Set("resourceDir", "resources")
cfg.Set("i18nDir", "i18n")
cfg.Set("layoutDir", "layouts")
cfg.Set("archetypeDir", "archetypes")
cfg.Set("assetDir", "assets")
return cfg
}
+138
View File
@@ -0,0 +1,138 @@
// 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 filecache
import (
"io"
"os"
"github.com/pkg/errors"
"github.com/spf13/afero"
)
// Prune removes expired and unused items from this cache.
// The last one requires a full build so the cache usage can be tracked.
// Note that we operate directly on the filesystem here, so this is not
// thread safe.
func (c Caches) Prune() (int, error) {
counter := 0
for k, cache := range c {
count, err := cache.Prune(false)
counter += count
if err != nil {
if os.IsNotExist(err) {
continue
}
return counter, errors.Wrapf(err, "failed to prune cache %q", k)
}
}
return counter, nil
}
// Prune removes expired and unused items from this cache.
// If force is set, everything will be removed not considering expiry time.
func (c *Cache) Prune(force bool) (int, error) {
if c.pruneAllRootDir != "" {
return c.pruneRootDir(force)
}
counter := 0
err := afero.Walk(c.Fs, "", func(name string, info os.FileInfo, err error) error {
if info == nil {
return nil
}
name = cleanID(name)
if info.IsDir() {
f, err := c.Fs.Open(name)
if err != nil {
// This cache dir may not exist.
return nil
}
defer f.Close()
_, err = f.Readdirnames(1)
if err == io.EOF {
// Empty dir.
err = c.Fs.Remove(name)
}
if err != nil && !os.IsNotExist(err) {
return err
}
return nil
}
shouldRemove := force || c.isExpired(info.ModTime())
if !shouldRemove && len(c.nlocker.seen) > 0 {
// Remove it if it's not been touched/used in the last build.
_, seen := c.nlocker.seen[name]
shouldRemove = !seen
}
if shouldRemove {
err := c.Fs.Remove(name)
if err == nil {
counter++
}
if err != nil && !os.IsNotExist(err) {
return err
}
}
return nil
})
return counter, err
}
func (c *Cache) pruneRootDir(force bool) (int, error) {
info, err := c.Fs.Stat(c.pruneAllRootDir)
if err != nil {
if os.IsNotExist(err) {
return 0, nil
}
return 0, err
}
if !force && !c.isExpired(info.ModTime()) {
return 0, nil
}
counter := 0
// Module cache has 0555 directories; make them writable in order to remove content.
afero.Walk(c.Fs, c.pruneAllRootDir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return nil
}
if info.IsDir() {
counter++
c.Fs.Chmod(path, 0777)
}
return nil
})
return 1, c.Fs.RemoveAll(c.pruneAllRootDir)
}
+111
View File
@@ -0,0 +1,111 @@
// 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 filecache
import (
"fmt"
"testing"
"time"
"github.com/spf13/afero"
qt "github.com/frankban/quicktest"
)
func TestPrune(t *testing.T) {
t.Parallel()
c := qt.New(t)
configStr := `
resourceDir = "myresources"
contentDir = "content"
dataDir = "data"
i18nDir = "i18n"
layoutDir = "layouts"
assetDir = "assets"
archeTypedir = "archetypes"
[caches]
[caches.getjson]
maxAge = "200ms"
dir = "/cache/c"
[caches.getcsv]
maxAge = "200ms"
dir = "/cache/d"
[caches.assets]
maxAge = "200ms"
dir = ":resourceDir/_gen"
[caches.images]
maxAge = "200ms"
dir = ":resourceDir/_gen"
`
for _, name := range []string{cacheKeyGetCSV, cacheKeyGetJSON, cacheKeyAssets, cacheKeyImages} {
msg := qt.Commentf("cache: %s", name)
p := newPathsSpec(t, afero.NewMemMapFs(), configStr)
caches, err := NewCaches(p)
c.Assert(err, qt.IsNil)
cache := caches[name]
for i := 0; i < 10; i++ {
id := fmt.Sprintf("i%d", i)
cache.GetOrCreateBytes(id, func() ([]byte, error) {
return []byte("abc"), nil
})
if i == 4 {
// This will expire the first 5
time.Sleep(201 * time.Millisecond)
}
}
count, err := caches.Prune()
c.Assert(err, qt.IsNil)
c.Assert(count, qt.Equals, 5, msg)
for i := 0; i < 10; i++ {
id := fmt.Sprintf("i%d", i)
v := cache.getString(id)
if i < 5 {
c.Assert(v, qt.Equals, "")
} else {
c.Assert(v, qt.Equals, "abc")
}
}
caches, err = NewCaches(p)
c.Assert(err, qt.IsNil)
cache = caches[name]
// Touch one and then prune.
cache.GetOrCreateBytes("i5", func() ([]byte, error) {
return []byte("abc"), nil
})
count, err = caches.Prune()
c.Assert(err, qt.IsNil)
c.Assert(count, qt.Equals, 4)
// Now only the i5 should be left.
for i := 0; i < 10; i++ {
id := fmt.Sprintf("i%d", i)
v := cache.getString(id)
if i != 5 {
c.Assert(v, qt.Equals, "")
} else {
c.Assert(v, qt.Equals, "abc")
}
}
}
}
+348
View File
@@ -0,0 +1,348 @@
// 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 filecache
import (
"errors"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"strings"
"sync"
"testing"
"time"
"github.com/gohugoio/hugo/langs"
"github.com/gohugoio/hugo/modules"
"github.com/gohugoio/hugo/common/hugio"
"github.com/gohugoio/hugo/config"
"github.com/gohugoio/hugo/helpers"
"github.com/gohugoio/hugo/hugofs"
"github.com/spf13/afero"
qt "github.com/frankban/quicktest"
)
func TestFileCache(t *testing.T) {
t.Parallel()
c := qt.New(t)
tempWorkingDir, err := ioutil.TempDir("", "hugo_filecache_test_work")
c.Assert(err, qt.IsNil)
defer os.Remove(tempWorkingDir)
tempCacheDir, err := ioutil.TempDir("", "hugo_filecache_test_cache")
c.Assert(err, qt.IsNil)
defer os.Remove(tempCacheDir)
osfs := afero.NewOsFs()
for _, test := range []struct {
cacheDir string
workingDir string
}{
// Run with same dirs twice to make sure that works.
{tempCacheDir, tempWorkingDir},
{tempCacheDir, tempWorkingDir},
} {
configStr := `
workingDir = "WORKING_DIR"
resourceDir = "resources"
cacheDir = "CACHEDIR"
contentDir = "content"
dataDir = "data"
i18nDir = "i18n"
layoutDir = "layouts"
assetDir = "assets"
archeTypedir = "archetypes"
[caches]
[caches.getJSON]
maxAge = "10h"
dir = ":cacheDir/c"
`
winPathSep := "\\\\"
replacer := strings.NewReplacer("CACHEDIR", test.cacheDir, "WORKING_DIR", test.workingDir)
configStr = replacer.Replace(configStr)
configStr = strings.Replace(configStr, "\\", winPathSep, -1)
p := newPathsSpec(t, osfs, configStr)
caches, err := NewCaches(p)
c.Assert(err, qt.IsNil)
cache := caches.Get("GetJSON")
c.Assert(cache, qt.Not(qt.IsNil))
c.Assert(cache.maxAge.String(), qt.Equals, "10h0m0s")
bfs, ok := cache.Fs.(*afero.BasePathFs)
c.Assert(ok, qt.Equals, true)
filename, err := bfs.RealPath("key")
c.Assert(err, qt.IsNil)
if test.cacheDir != "" {
c.Assert(filename, qt.Equals, filepath.Join(test.cacheDir, "c/"+filecacheRootDirname+"/getjson/key"))
} else {
// Temp dir.
c.Assert(filename, qt.Matches, ".*hugo_cache.*"+filecacheRootDirname+".*key")
}
cache = caches.Get("Images")
c.Assert(cache, qt.Not(qt.IsNil))
c.Assert(cache.maxAge, qt.Equals, time.Duration(-1))
bfs, ok = cache.Fs.(*afero.BasePathFs)
c.Assert(ok, qt.Equals, true)
filename, _ = bfs.RealPath("key")
c.Assert(filename, qt.Equals, filepath.FromSlash("_gen/images/key"))
rf := func(s string) func() (io.ReadCloser, error) {
return func() (io.ReadCloser, error) {
return struct {
io.ReadSeeker
io.Closer
}{
strings.NewReader(s),
ioutil.NopCloser(nil),
}, nil
}
}
bf := func() ([]byte, error) {
return []byte("bcd"), nil
}
for _, ca := range []*Cache{caches.ImageCache(), caches.AssetsCache(), caches.GetJSONCache(), caches.GetCSVCache()} {
for i := 0; i < 2; i++ {
info, r, err := ca.GetOrCreate("a", rf("abc"))
c.Assert(err, qt.IsNil)
c.Assert(r, qt.Not(qt.IsNil))
c.Assert(info.Name, qt.Equals, "a")
b, _ := ioutil.ReadAll(r)
r.Close()
c.Assert(string(b), qt.Equals, "abc")
info, b, err = ca.GetOrCreateBytes("b", bf)
c.Assert(err, qt.IsNil)
c.Assert(r, qt.Not(qt.IsNil))
c.Assert(info.Name, qt.Equals, "b")
c.Assert(string(b), qt.Equals, "bcd")
_, b, err = ca.GetOrCreateBytes("a", bf)
c.Assert(err, qt.IsNil)
c.Assert(string(b), qt.Equals, "abc")
_, r, err = ca.GetOrCreate("a", rf("bcd"))
c.Assert(err, qt.IsNil)
b, _ = ioutil.ReadAll(r)
r.Close()
c.Assert(string(b), qt.Equals, "abc")
}
}
c.Assert(caches.Get("getJSON"), qt.Not(qt.IsNil))
info, w, err := caches.ImageCache().WriteCloser("mykey")
c.Assert(err, qt.IsNil)
c.Assert(info.Name, qt.Equals, "mykey")
io.WriteString(w, "Hugo is great!")
w.Close()
c.Assert(caches.ImageCache().getString("mykey"), qt.Equals, "Hugo is great!")
info, r, err := caches.ImageCache().Get("mykey")
c.Assert(err, qt.IsNil)
c.Assert(r, qt.Not(qt.IsNil))
c.Assert(info.Name, qt.Equals, "mykey")
b, _ := ioutil.ReadAll(r)
r.Close()
c.Assert(string(b), qt.Equals, "Hugo is great!")
info, b, err = caches.ImageCache().GetBytes("mykey")
c.Assert(err, qt.IsNil)
c.Assert(info.Name, qt.Equals, "mykey")
c.Assert(string(b), qt.Equals, "Hugo is great!")
}
}
func TestFileCacheConcurrent(t *testing.T) {
t.Parallel()
c := qt.New(t)
configStr := `
resourceDir = "myresources"
contentDir = "content"
dataDir = "data"
i18nDir = "i18n"
layoutDir = "layouts"
assetDir = "assets"
archeTypedir = "archetypes"
[caches]
[caches.getjson]
maxAge = "1s"
dir = "/cache/c"
`
p := newPathsSpec(t, afero.NewMemMapFs(), configStr)
caches, err := NewCaches(p)
c.Assert(err, qt.IsNil)
const cacheName = "getjson"
filenameData := func(i int) (string, string) {
data := fmt.Sprintf("data: %d", i)
filename := fmt.Sprintf("file%d", i)
return filename, data
}
var wg sync.WaitGroup
for i := 0; i < 50; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
for j := 0; j < 20; j++ {
ca := caches.Get(cacheName)
c.Assert(ca, qt.Not(qt.IsNil))
filename, data := filenameData(i)
_, r, err := ca.GetOrCreate(filename, func() (io.ReadCloser, error) {
return hugio.ToReadCloser(strings.NewReader(data)), nil
})
c.Assert(err, qt.IsNil)
b, _ := ioutil.ReadAll(r)
r.Close()
c.Assert(string(b), qt.Equals, data)
// Trigger some expiration.
time.Sleep(50 * time.Millisecond)
}
}(i)
}
wg.Wait()
}
func TestFileCacheReadOrCreateErrorInRead(t *testing.T) {
t.Parallel()
c := qt.New(t)
var result string
rf := func(failLevel int) func(info ItemInfo, r io.ReadSeeker) error {
return func(info ItemInfo, r io.ReadSeeker) error {
if failLevel > 0 {
if failLevel > 1 {
return ErrFatal
}
return errors.New("fail")
}
b, _ := ioutil.ReadAll(r)
result = string(b)
return nil
}
}
bf := func(s string) func(info ItemInfo, w io.WriteCloser) error {
return func(info ItemInfo, w io.WriteCloser) error {
defer w.Close()
result = s
_, err := w.Write([]byte(s))
return err
}
}
cache := NewCache(afero.NewMemMapFs(), 100*time.Hour, "")
const id = "a32"
_, err := cache.ReadOrCreate(id, rf(0), bf("v1"))
c.Assert(err, qt.IsNil)
c.Assert(result, qt.Equals, "v1")
_, err = cache.ReadOrCreate(id, rf(0), bf("v2"))
c.Assert(err, qt.IsNil)
c.Assert(result, qt.Equals, "v1")
_, err = cache.ReadOrCreate(id, rf(1), bf("v3"))
c.Assert(err, qt.IsNil)
c.Assert(result, qt.Equals, "v3")
_, err = cache.ReadOrCreate(id, rf(2), bf("v3"))
c.Assert(err, qt.Equals, ErrFatal)
}
func TestCleanID(t *testing.T) {
c := qt.New(t)
c.Assert(cleanID(filepath.FromSlash("/a/b//c.txt")), qt.Equals, filepath.FromSlash("a/b/c.txt"))
c.Assert(cleanID(filepath.FromSlash("a/b//c.txt")), qt.Equals, filepath.FromSlash("a/b/c.txt"))
}
func initConfig(fs afero.Fs, cfg config.Provider) error {
if _, err := langs.LoadLanguageSettings(cfg, nil); err != nil {
return err
}
modConfig, err := modules.DecodeConfig(cfg)
if err != nil {
return err
}
workingDir := cfg.GetString("workingDir")
themesDir := cfg.GetString("themesDir")
if !filepath.IsAbs(themesDir) {
themesDir = filepath.Join(workingDir, themesDir)
}
modulesClient := modules.NewClient(modules.ClientConfig{
Fs: fs,
WorkingDir: workingDir,
ThemesDir: themesDir,
ModuleConfig: modConfig,
IgnoreVendor: true,
})
moduleConfig, err := modulesClient.Collect()
if err != nil {
return err
}
if err := modules.ApplyProjectConfigDefaults(cfg, moduleConfig.ActiveModules[len(moduleConfig.ActiveModules)-1]); err != nil {
return err
}
cfg.Set("allModules", moduleConfig.ActiveModules)
return nil
}
func newPathsSpec(t *testing.T, fs afero.Fs, configStr string) *helpers.PathSpec {
c := qt.New(t)
cfg, err := config.FromConfigString(configStr, "toml")
c.Assert(err, qt.IsNil)
initConfig(fs, cfg)
p, err := helpers.NewPathSpec(hugofs.NewFrom(fs, cfg), cfg, nil)
c.Assert(err, qt.IsNil)
return p
}
+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 namedmemcache provides a memory cache with a named lock. This is suitable
// for situations where creating the cached resource can be time consuming or otherwise
// resource hungry, or in situations where a "once only per key" is a requirement.
package namedmemcache
import (
"sync"
"github.com/BurntSushi/locker"
)
// Cache holds the cached values.
type Cache struct {
nlocker *locker.Locker
cache map[string]cacheEntry
mu sync.RWMutex
}
type cacheEntry struct {
value interface{}
err error
}
// New creates a new cache.
func New() *Cache {
return &Cache{
nlocker: locker.NewLocker(),
cache: make(map[string]cacheEntry),
}
}
// Clear clears the cache state.
func (c *Cache) Clear() {
c.mu.Lock()
defer c.mu.Unlock()
c.cache = make(map[string]cacheEntry)
c.nlocker = locker.NewLocker()
}
// GetOrCreate tries to get the value with the given cache key, if not found
// create will be called and cached.
// This method is thread safe. It also guarantees that the create func for a given
// key is invoced only once for this cache.
func (c *Cache) GetOrCreate(key string, create func() (interface{}, error)) (interface{}, error) {
c.mu.RLock()
entry, found := c.cache[key]
c.mu.RUnlock()
if found {
return entry.value, entry.err
}
c.nlocker.Lock(key)
defer c.nlocker.Unlock(key)
// Create it.
value, err := create()
c.mu.Lock()
c.cache[key] = cacheEntry{value: value, err: err}
c.mu.Unlock()
return value, err
}
+80
View File
@@ -0,0 +1,80 @@
// 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 namedmemcache
import (
"fmt"
"sync"
"testing"
qt "github.com/frankban/quicktest"
)
func TestNamedCache(t *testing.T) {
t.Parallel()
c := qt.New(t)
cache := New()
counter := 0
create := func() (interface{}, error) {
counter++
return counter, nil
}
for i := 0; i < 5; i++ {
v1, err := cache.GetOrCreate("a1", create)
c.Assert(err, qt.IsNil)
c.Assert(v1, qt.Equals, 1)
v2, err := cache.GetOrCreate("a2", create)
c.Assert(err, qt.IsNil)
c.Assert(v2, qt.Equals, 2)
}
cache.Clear()
v3, err := cache.GetOrCreate("a2", create)
c.Assert(err, qt.IsNil)
c.Assert(v3, qt.Equals, 3)
}
func TestNamedCacheConcurrent(t *testing.T) {
t.Parallel()
c := qt.New(t)
var wg sync.WaitGroup
cache := New()
create := func(i int) func() (interface{}, error) {
return func() (interface{}, error) {
return i, nil
}
}
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for j := 0; j < 100; j++ {
id := fmt.Sprintf("id%d", j)
v, err := cache.GetOrCreate(id, create(j))
c.Assert(err, qt.IsNil)
c.Assert(v, qt.Equals, j)
}
}()
}
wg.Wait()
}
+20 -20
View File
@@ -18,13 +18,13 @@ import (
"sync"
"testing"
"github.com/stretchr/testify/require"
qt "github.com/frankban/quicktest"
)
func TestNewPartitionedLazyCache(t *testing.T) {
t.Parallel()
assert := require.New(t)
c := qt.New(t)
p1 := Partition{
Key: "p1",
@@ -51,28 +51,28 @@ func TestNewPartitionedLazyCache(t *testing.T) {
cache := NewPartitionedLazyCache(p1, p2)
v, err := cache.Get("p1", "p1_1")
assert.NoError(err)
assert.Equal("p1v1", v)
c.Assert(err, qt.IsNil)
c.Assert(v, qt.Equals, "p1v1")
v, err = cache.Get("p1", "p2_1")
assert.NoError(err)
assert.Nil(v)
c.Assert(err, qt.IsNil)
c.Assert(v, qt.IsNil)
v, err = cache.Get("p1", "p1_nil")
assert.NoError(err)
assert.Nil(v)
c.Assert(err, qt.IsNil)
c.Assert(v, qt.IsNil)
v, err = cache.Get("p2", "p2_3")
assert.NoError(err)
assert.Equal("p2v3", v)
c.Assert(err, qt.IsNil)
c.Assert(v, qt.Equals, "p2v3")
v, err = cache.Get("doesnotexist", "p1_1")
assert.NoError(err)
assert.Nil(v)
c.Assert(err, qt.IsNil)
c.Assert(v, qt.IsNil)
v, err = cache.Get("p1", "doesnotexist")
assert.NoError(err)
assert.Nil(v)
c.Assert(err, qt.IsNil)
c.Assert(v, qt.IsNil)
errorP := Partition{
Key: "p3",
@@ -84,18 +84,18 @@ func TestNewPartitionedLazyCache(t *testing.T) {
cache = NewPartitionedLazyCache(errorP)
v, err = cache.Get("p1", "doesnotexist")
assert.NoError(err)
assert.Nil(v)
c.Assert(err, qt.IsNil)
c.Assert(v, qt.IsNil)
_, err = cache.Get("p3", "doesnotexist")
assert.Error(err)
c.Assert(err, qt.Not(qt.IsNil))
}
func TestConcurrentPartitionedLazyCache(t *testing.T) {
t.Parallel()
assert := require.New(t)
c := qt.New(t)
var wg sync.WaitGroup
@@ -129,8 +129,8 @@ func TestConcurrentPartitionedLazyCache(t *testing.T) {
defer wg.Done()
for j := 0; j < 10; j++ {
v, err := cache.Get("p1", "p1_1")
assert.NoError(err)
assert.Equal("p1v1", v)
c.Assert(err, qt.IsNil)
c.Assert(v, qt.Equals, "p1v1")
}
}()
}
+548
View File
@@ -0,0 +1,548 @@
// Copyright 2019 The Hugo Authors. All rights reserved.
// Some functions in this file (see comments) is based on the Go source code,
// copyright The Go Authors and governed by a BSD-style license.
//
// 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 codegen contains helpers for code generation.
package codegen
import (
"fmt"
"go/ast"
"go/parser"
"go/token"
"os"
"path"
"path/filepath"
"reflect"
"regexp"
"sort"
"strings"
"sync"
)
// Make room for insertions
const weightWidth = 1000
// NewInspector creates a new Inspector given a source root.
func NewInspector(root string) *Inspector {
return &Inspector{ProjectRootDir: root}
}
// Inspector provides methods to help code generation. It uses a combination
// of reflection and source code AST to do the heavy lifting.
type Inspector struct {
ProjectRootDir string
init sync.Once
// Determines method order. Go's reflect sorts lexicographically, so
// we must parse the source to preserve this order.
methodWeight map[string]map[string]int
}
// MethodsFromTypes create a method set from the include slice, excluding any
// method in exclude.
func (c *Inspector) MethodsFromTypes(include []reflect.Type, exclude []reflect.Type) Methods {
c.parseSource()
var methods Methods
var excludes = make(map[string]bool)
if len(exclude) > 0 {
for _, m := range c.MethodsFromTypes(exclude, nil) {
excludes[m.Name] = true
}
}
// There may be overlapping interfaces in types. Do a simple check for now.
seen := make(map[string]bool)
nameAndPackage := func(t reflect.Type) (string, string) {
var name, pkg string
isPointer := t.Kind() == reflect.Ptr
if isPointer {
t = t.Elem()
}
pkgPrefix := ""
if pkgPath := t.PkgPath(); pkgPath != "" {
pkgPath = strings.TrimSuffix(pkgPath, "/")
_, shortPath := path.Split(pkgPath)
pkgPrefix = shortPath + "."
pkg = pkgPath
}
name = t.Name()
if name == "" {
// interface{}
name = t.String()
}
if isPointer {
pkgPrefix = "*" + pkgPrefix
}
name = pkgPrefix + name
return name, pkg
}
for _, t := range include {
for i := 0; i < t.NumMethod(); i++ {
m := t.Method(i)
if excludes[m.Name] || seen[m.Name] {
continue
}
seen[m.Name] = true
if m.PkgPath != "" {
// Not exported
continue
}
numIn := m.Type.NumIn()
ownerName, _ := nameAndPackage(t)
method := Method{Owner: t, OwnerName: ownerName, Name: m.Name}
for i := 0; i < numIn; i++ {
in := m.Type.In(i)
name, pkg := nameAndPackage(in)
if pkg != "" {
method.Imports = append(method.Imports, pkg)
}
method.In = append(method.In, name)
}
numOut := m.Type.NumOut()
if numOut > 0 {
for i := 0; i < numOut; i++ {
out := m.Type.Out(i)
name, pkg := nameAndPackage(out)
if pkg != "" {
method.Imports = append(method.Imports, pkg)
}
method.Out = append(method.Out, name)
}
}
methods = append(methods, method)
}
}
sort.SliceStable(methods, func(i, j int) bool {
mi, mj := methods[i], methods[j]
wi := c.methodWeight[mi.OwnerName][mi.Name]
wj := c.methodWeight[mj.OwnerName][mj.Name]
if wi == wj {
return mi.Name < mj.Name
}
return wi < wj
})
return methods
}
func (c *Inspector) parseSource() {
c.init.Do(func() {
if !strings.Contains(c.ProjectRootDir, "hugo") {
panic("dir must be set to the Hugo root")
}
c.methodWeight = make(map[string]map[string]int)
dirExcludes := regexp.MustCompile("docs|examples")
fileExcludes := regexp.MustCompile("autogen")
var filenames []string
filepath.Walk(c.ProjectRootDir, func(path string, info os.FileInfo, err error) error {
if info.IsDir() {
if dirExcludes.MatchString(info.Name()) {
return filepath.SkipDir
}
}
if !strings.HasSuffix(path, ".go") || fileExcludes.MatchString(path) {
return nil
}
filenames = append(filenames, path)
return nil
})
for _, filename := range filenames {
pkg := c.packageFromPath(filename)
fset := token.NewFileSet()
node, err := parser.ParseFile(fset, filename, nil, parser.ParseComments)
if err != nil {
panic(err)
}
ast.Inspect(node, func(n ast.Node) bool {
switch t := n.(type) {
case *ast.TypeSpec:
if t.Name.IsExported() {
switch it := t.Type.(type) {
case *ast.InterfaceType:
iface := pkg + "." + t.Name.Name
methodNames := collectMethodsRecursive(pkg, it.Methods.List)
weights := make(map[string]int)
weight := weightWidth
for _, name := range methodNames {
weights[name] = weight
weight += weightWidth
}
c.methodWeight[iface] = weights
}
}
}
return true
})
}
// Complement
for _, v1 := range c.methodWeight {
for k2, w := range v1 {
if v, found := c.methodWeight[k2]; found {
for k3, v3 := range v {
v1[k3] = (v3 / weightWidth) + w
}
}
}
}
})
}
func (c *Inspector) packageFromPath(p string) string {
p = filepath.ToSlash(p)
base := path.Base(p)
if !strings.Contains(base, ".") {
return base
}
return path.Base(strings.TrimSuffix(p, base))
}
// Method holds enough information about it to recreate it.
type Method struct {
// The interface we extracted this method from.
Owner reflect.Type
// String version of the above, on the form PACKAGE.NAME, e.g.
// page.Page
OwnerName string
// Method name.
Name string
// Imports needed to satisfy the method signature.
Imports []string
// Argument types, including any package prefix, e.g. string, int, interface{},
// net.Url
In []string
// Return types.
Out []string
}
// Declaration creates a method declaration (without any body) for the given receiver.
func (m Method) Declaration(receiver string) string {
return fmt.Sprintf("func (%s %s) %s%s %s", receiverShort(receiver), receiver, m.Name, m.inStr(), m.outStr())
}
// DeclarationNamed creates a method declaration (without any body) for the given receiver
// with named return values.
func (m Method) DeclarationNamed(receiver string) string {
return fmt.Sprintf("func (%s %s) %s%s %s", receiverShort(receiver), receiver, m.Name, m.inStr(), m.outStrNamed())
}
// Delegate creates a delegate call string.
func (m Method) Delegate(receiver, delegate string) string {
ret := ""
if len(m.Out) > 0 {
ret = "return "
}
return fmt.Sprintf("%s%s.%s.%s%s", ret, receiverShort(receiver), delegate, m.Name, m.inOutStr())
}
func (m Method) String() string {
return m.Name + m.inStr() + " " + m.outStr() + "\n"
}
func (m Method) inOutStr() string {
if len(m.In) == 0 {
return "()"
}
args := make([]string, len(m.In))
for i := 0; i < len(args); i++ {
args[i] = fmt.Sprintf("arg%d", i)
}
return "(" + strings.Join(args, ", ") + ")"
}
func (m Method) inStr() string {
if len(m.In) == 0 {
return "()"
}
args := make([]string, len(m.In))
for i := 0; i < len(args); i++ {
args[i] = fmt.Sprintf("arg%d %s", i, m.In[i])
}
return "(" + strings.Join(args, ", ") + ")"
}
func (m Method) outStr() string {
if len(m.Out) == 0 {
return ""
}
if len(m.Out) == 1 {
return m.Out[0]
}
return "(" + strings.Join(m.Out, ", ") + ")"
}
func (m Method) outStrNamed() string {
if len(m.Out) == 0 {
return ""
}
outs := make([]string, len(m.Out))
for i := 0; i < len(outs); i++ {
outs[i] = fmt.Sprintf("o%d %s", i, m.Out[i])
}
return "(" + strings.Join(outs, ", ") + ")"
}
// Methods represents a list of methods for one or more interfaces.
// The order matches the defined order in their source file(s).
type Methods []Method
// Imports returns a sorted list of package imports needed to satisfy the
// signatures of all methods.
func (m Methods) Imports() []string {
var pkgImports []string
for _, method := range m {
pkgImports = append(pkgImports, method.Imports...)
}
if len(pkgImports) > 0 {
pkgImports = uniqueNonEmptyStrings(pkgImports)
sort.Strings(pkgImports)
}
return pkgImports
}
// ToMarshalJSON creates a MarshalJSON method for these methods. Any method name
// matchin any of the regexps in excludes will be ignored.
func (m Methods) ToMarshalJSON(receiver, pkgPath string, excludes ...string) (string, []string) {
var sb strings.Builder
r := receiverShort(receiver)
what := firstToUpper(trimAsterisk(receiver))
pgkName := path.Base(pkgPath)
fmt.Fprintf(&sb, "func Marshal%sToJSON(%s %s) ([]byte, error) {\n", what, r, receiver)
var methods Methods
var excludeRes = make([]*regexp.Regexp, len(excludes))
for i, exclude := range excludes {
excludeRes[i] = regexp.MustCompile(exclude)
}
for _, method := range m {
// Exclude methods with arguments and incompatible return values
if len(method.In) > 0 || len(method.Out) == 0 || len(method.Out) > 2 {
continue
}
if len(method.Out) == 2 {
if method.Out[1] != "error" {
continue
}
}
for _, re := range excludeRes {
if re.MatchString(method.Name) {
continue
}
}
methods = append(methods, method)
}
for _, method := range methods {
varn := varName(method.Name)
if len(method.Out) == 1 {
fmt.Fprintf(&sb, "\t%s := %s.%s()\n", varn, r, method.Name)
} else {
fmt.Fprintf(&sb, "\t%s, err := %s.%s()\n", varn, r, method.Name)
fmt.Fprint(&sb, "\tif err != nil {\n\t\treturn nil, err\n\t}\n")
}
}
fmt.Fprint(&sb, "\n\ts := struct {\n")
for _, method := range methods {
fmt.Fprintf(&sb, "\t\t%s %s\n", method.Name, typeName(method.Out[0], pgkName))
}
fmt.Fprint(&sb, "\n\t}{\n")
for _, method := range methods {
varn := varName(method.Name)
fmt.Fprintf(&sb, "\t\t%s: %s,\n", method.Name, varn)
}
fmt.Fprint(&sb, "\n\t}\n\n")
fmt.Fprint(&sb, "\treturn json.Marshal(&s)\n}")
pkgImports := append(methods.Imports(), "encoding/json")
if pkgPath != "" {
// Exclude self
for i, pkgImp := range pkgImports {
if pkgImp == pkgPath {
pkgImports = append(pkgImports[:i], pkgImports[i+1:]...)
}
}
}
return sb.String(), pkgImports
}
func collectMethodsRecursive(pkg string, f []*ast.Field) []string {
var methodNames []string
for _, m := range f {
if m.Names != nil {
methodNames = append(methodNames, m.Names[0].Name)
continue
}
if ident, ok := m.Type.(*ast.Ident); ok && ident.Obj != nil {
// Embedded interface
methodNames = append(
methodNames,
collectMethodsRecursive(
pkg,
ident.Obj.Decl.(*ast.TypeSpec).Type.(*ast.InterfaceType).Methods.List)...)
} else {
// Embedded, but in a different file/package. Return the
// package.Name and deal with that later.
name := packageName(m.Type)
if !strings.Contains(name, ".") {
// Assume current package
name = pkg + "." + name
}
methodNames = append(methodNames, name)
}
}
return methodNames
}
func firstToLower(name string) string {
return strings.ToLower(name[:1]) + name[1:]
}
func firstToUpper(name string) string {
return strings.ToUpper(name[:1]) + name[1:]
}
func packageName(e ast.Expr) string {
switch tp := e.(type) {
case *ast.Ident:
return tp.Name
case *ast.SelectorExpr:
return fmt.Sprintf("%s.%s", packageName(tp.X), packageName(tp.Sel))
}
return ""
}
func receiverShort(receiver string) string {
return strings.ToLower(trimAsterisk(receiver))[:1]
}
func trimAsterisk(name string) string {
return strings.TrimPrefix(name, "*")
}
func typeName(name, pkg string) string {
return strings.TrimPrefix(name, pkg+".")
}
func uniqueNonEmptyStrings(s []string) []string {
var unique []string
set := map[string]interface{}{}
for _, val := range s {
if val == "" {
continue
}
if _, ok := set[val]; !ok {
unique = append(unique, val)
set[val] = val
}
}
return unique
}
func varName(name string) string {
name = firstToLower(name)
// Adjust some reserved keywords, see https://golang.org/ref/spec#Keywords
switch name {
case "type":
name = "typ"
case "package":
name = "pkg"
// Not reserved, but syntax highlighters has it as a keyword.
case "len":
name = "length"
}
return name
}
+20
View File
@@ -0,0 +1,20 @@
// Copyright 2019 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package codegen
type IEmbed interface {
MethodEmbed3(s string) string
MethodEmbed1() string
MethodEmbed2()
}
+100
View File
@@ -0,0 +1,100 @@
// Copyright 2019 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package codegen
import (
"fmt"
"net"
"os"
"reflect"
"testing"
qt "github.com/frankban/quicktest"
"github.com/gohugoio/hugo/common/herrors"
)
func TestMethods(t *testing.T) {
var (
zeroIE = reflect.TypeOf((*IEmbed)(nil)).Elem()
zeroIEOnly = reflect.TypeOf((*IEOnly)(nil)).Elem()
zeroI = reflect.TypeOf((*I)(nil)).Elem()
)
dir, _ := os.Getwd()
insp := NewInspector(dir)
t.Run("MethodsFromTypes", func(t *testing.T) {
c := qt.New(t)
methods := insp.MethodsFromTypes([]reflect.Type{zeroI}, nil)
methodsStr := fmt.Sprint(methods)
c.Assert(methodsStr, qt.Contains, "Method1(arg0 herrors.ErrorContext)")
c.Assert(methodsStr, qt.Contains, "Method7() interface {}")
c.Assert(methodsStr, qt.Contains, "Method0() string\n Method4() string")
c.Assert(methodsStr, qt.Contains, "MethodEmbed3(arg0 string) string\n MethodEmbed1() string")
c.Assert(methods.Imports(), qt.Contains, "github.com/gohugoio/hugo/common/herrors")
})
t.Run("EmbedOnly", func(t *testing.T) {
c := qt.New(t)
methods := insp.MethodsFromTypes([]reflect.Type{zeroIEOnly}, nil)
methodsStr := fmt.Sprint(methods)
c.Assert(methodsStr, qt.Contains, "MethodEmbed3(arg0 string) string")
})
t.Run("ToMarshalJSON", func(t *testing.T) {
c := qt.New(t)
m, pkg := insp.MethodsFromTypes(
[]reflect.Type{zeroI},
[]reflect.Type{zeroIE}).ToMarshalJSON("*page", "page")
c.Assert(m, qt.Contains, "method6 := p.Method6()")
c.Assert(m, qt.Contains, "Method0: method0,")
c.Assert(m, qt.Contains, "return json.Marshal(&s)")
c.Assert(pkg, qt.Contains, "github.com/gohugoio/hugo/common/herrors")
c.Assert(pkg, qt.Contains, "encoding/json")
fmt.Println(pkg)
})
}
type I interface {
IEmbed
Method0() string
Method4() string
Method1(myerr herrors.ErrorContext)
Method3(myint int, mystring string)
Method5() (string, error)
Method6() *net.IP
Method7() interface{}
Method8() herrors.ErrorContext
method2()
method9() os.FileInfo
}
type IEOnly interface {
IEmbed
}
-115
View File
@@ -1,115 +0,0 @@
// 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
import (
"os"
"runtime"
"runtime/pprof"
"time"
"github.com/spf13/cobra"
jww "github.com/spf13/jwalterweatherman"
)
type benchmarkCmd struct {
benchmarkTimes int
cpuProfileFile string
memProfileFile string
*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 (c *benchmarkCmd) benchmark(cmd *cobra.Command, args []string) error {
cfgInit := func(c *commandeer) error {
return nil
}
comm, err := initializeConfig(true, false, &c.hugoBuilderCommon, c, cfgInit)
if err != nil {
return err
}
var memProf *os.File
if c.memProfileFile != "" {
memProf, err = os.Create(c.memProfileFile)
if err != nil {
return err
}
}
var cpuProf *os.File
if c.cpuProfileFile != "" {
cpuProf, err = os.Create(c.cpuProfileFile)
if err != nil {
return err
}
}
var memStats runtime.MemStats
runtime.ReadMemStats(&memStats)
memAllocated := memStats.TotalAlloc
mallocs := memStats.Mallocs
if cpuProf != nil {
pprof.StartCPUProfile(cpuProf)
}
t := time.Now()
for i := 0; i < c.benchmarkTimes; i++ {
if err = comm.resetAndBuildSites(); err != nil {
return err
}
}
totalTime := time.Since(t)
if memProf != nil {
pprof.WriteHeapProfile(memProf)
memProf.Close()
}
if cpuProf != nil {
pprof.StopCPUProfile()
cpuProf.Close()
}
runtime.ReadMemStats(&memStats)
totalMemAllocated := memStats.TotalAlloc - memAllocated
totalMallocs := memStats.Mallocs - mallocs
jww.FEEDBACK.Println()
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
}
+130 -46
View File
@@ -1,4 +1,4 @@
// Copyright 2018 The Hugo Authors. All rights reserved.
// Copyright 2019 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -14,20 +14,33 @@
package commands
import (
"bytes"
"errors"
"sync"
"golang.org/x/sync/semaphore"
"github.com/gohugoio/hugo/modules"
"io/ioutil"
"github.com/gohugoio/hugo/common/herrors"
"github.com/gohugoio/hugo/common/hugo"
jww "github.com/spf13/jwalterweatherman"
"os"
"path/filepath"
"regexp"
"strings"
"sync"
"time"
"github.com/gohugoio/hugo/common/loggers"
"github.com/gohugoio/hugo/config"
"github.com/spf13/cobra"
"github.com/spf13/afero"
"github.com/gohugoio/hugo/hugolib"
"github.com/spf13/afero"
"github.com/bep/debounce"
"github.com/gohugoio/hugo/common/types"
@@ -39,13 +52,16 @@ import (
type commandeerHugoState struct {
*deps.DepsCfg
hugo *hugolib.HugoSites
fsCreate sync.Once
hugoSites *hugolib.HugoSites
fsCreate sync.Once
created chan struct{}
}
type commandeer struct {
*commandeerHugoState
logger *loggers.Logger
// 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
@@ -69,9 +85,59 @@ type commandeer struct {
serverPorts []int
languagesConfigured bool
languages langs.Languages
doLiveReload bool
fastRenderMode bool
showErrorInBrowser bool
wasError bool
configured bool
paused bool
fullRebuildSem *semaphore.Weighted
// Any error from the last build.
buildErr error
}
func newCommandeerHugoState() *commandeerHugoState {
return &commandeerHugoState{
created: make(chan struct{}),
}
}
func (c *commandeerHugoState) hugo() *hugolib.HugoSites {
<-c.created
return c.hugoSites
}
func (c *commandeer) errCount() int {
return int(c.logger.ErrorCounter.Count())
}
func (c *commandeer) getErrorWithContext() interface{} {
errCount := c.errCount()
if errCount == 0 {
return nil
}
m := make(map[string]interface{})
m["Error"] = errors.New(removeErrorPrefixFromLog(c.logger.Errors()))
m["Version"] = hugo.BuildVersionString()
fe := herrors.UnwrapErrorWithFileContext(c.buildErr)
if fe != nil {
m["File"] = fe
}
if c.h.verbose {
var b bytes.Buffer
herrors.FprintStackTrace(&b, c.buildErr)
m["StackTrace"] = b.String()
}
return m
}
func (c *commandeer) Set(key string, value interface{}) {
@@ -95,16 +161,24 @@ func newCommandeer(mustHaveConfigFile, running bool, h *hugoBuilderCommon, f fla
// 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)
rebuildDebouncer = debounce.New(4 * time.Second)
}
out := ioutil.Discard
if !h.quiet {
out = os.Stdout
}
c := &commandeer{
h: h,
ftch: f,
commandeerHugoState: &commandeerHugoState{},
commandeerHugoState: newCommandeerHugoState(),
doWithCommandeer: doWithCommandeer,
visitedURLs: types.NewEvictingStringQueue(10),
debounce: rebuildDebouncer,
fullRebuildSem: semaphore.NewWeighted(1),
// This will be replaced later, but we need something to log to before the configuration is read.
logger: loggers.NewLogger(jww.LevelError, jww.LevelError, out, ioutil.Discard, running),
}
return c, c.loadConfig(mustHaveConfigFile, running)
@@ -178,6 +252,11 @@ func (c *commandeer) loadConfig(mustHaveConfigFile, running bool) error {
c.DepsCfg = &deps.DepsCfg{}
}
if c.logger != nil {
// Truncate the error log if this is a reload.
c.logger.Reset()
}
cfg := c.DepsCfg
c.configured = false
cfg.Running = running
@@ -194,6 +273,8 @@ func (c *commandeer) loadConfig(mustHaveConfigFile, running bool) error {
sourceFs = c.DepsCfg.Fs.Source
}
environment := c.h.getEnvironment(running)
doWithConfig := func(cfg config.Provider) error {
if c.ftch != nil {
@@ -201,7 +282,7 @@ func (c *commandeer) loadConfig(mustHaveConfigFile, running bool) error {
}
cfg.Set("workingDir", dir)
cfg.Set("environment", environment)
return nil
}
@@ -214,8 +295,20 @@ func (c *commandeer) loadConfig(mustHaveConfigFile, running bool) error {
return err
}
configPath := c.h.source
if configPath == "" {
configPath = dir
}
config, configFiles, err := hugolib.LoadConfig(
hugolib.ConfigSourceDescriptor{Fs: sourceFs, Path: c.h.source, WorkingDir: dir, Filename: c.h.cfgFile},
hugolib.ConfigSourceDescriptor{
Fs: sourceFs,
Logger: c.logger,
Path: configPath,
WorkingDir: dir,
Filename: c.h.cfgFile,
AbsConfigDir: c.h.getConfigDir(dir),
Environ: os.Environ(),
Environment: environment},
doWithCommandeer,
doWithConfig)
@@ -223,10 +316,12 @@ func (c *commandeer) loadConfig(mustHaveConfigFile, running bool) error {
if mustHaveConfigFile {
return err
}
if err != hugolib.ErrNoConfigFile {
if err != hugolib.ErrNoConfigFile && !modules.IsNotExist(err) {
return err
}
} else if mustHaveConfigFile && len(configFiles) == 0 {
return hugolib.ErrNoConfigFile
}
c.configFiles = configFiles
@@ -236,6 +331,11 @@ func (c *commandeer) loadConfig(mustHaveConfigFile, running bool) error {
c.languages = l
}
// Set some commonly used flags
c.doLiveReload = running && !c.Cfg.GetBool("disableLiveReload")
c.fastRenderMode = c.doLiveReload && !c.Cfg.GetBool("disableFastRender")
c.showErrorInBrowser = c.doLiveReload && !c.Cfg.GetBool("disableBrowserError")
// 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 {
@@ -244,12 +344,13 @@ func (c *commandeer) loadConfig(mustHaveConfigFile, running bool) error {
}
}
logger, err := c.createLogger(config)
logger, err := c.createLogger(config, running)
if err != nil {
return err
}
cfg.Logger = logger
c.logger = logger
createMemFs := config.GetBool("renderToMemory")
@@ -269,10 +370,7 @@ func (c *commandeer) loadConfig(mustHaveConfigFile, running bool) error {
fs.Destination = new(afero.MemMapFs)
}
doLiveReload := !c.h.buildWatch && !config.GetBool("disableLiveReload")
fastRenderMode := doLiveReload && !config.GetBool("disableFastRender")
if fastRenderMode {
if c.fastRenderMode {
// For now, fast render mode only. It should, however, be fast enough
// for the full variant, too.
changeDetector := &fileChangeDetector{
@@ -281,20 +379,30 @@ func (c *commandeer) loadConfig(mustHaveConfigFile, running bool) error {
// to make that decision.
irrelevantRe: regexp.MustCompile(`\.map$`),
}
changeDetector.PrepareNew()
fs.Destination = hugofs.NewHashingFs(fs.Destination, changeDetector)
c.changeDetector = changeDetector
}
if c.Cfg.GetBool("logPathWarnings") {
fs.Destination = hugofs.NewCreateCountingFs(fs.Destination)
}
// To debug hard-to-find path issues.
//fs.Destination = hugofs.NewStacktracerFs(fs.Destination, `fr/fr`)
err = c.initFs(fs)
if err != nil {
close(c.created)
return
}
var h *hugolib.HugoSites
h, err = hugolib.NewHugoSites(*c.DepsCfg)
c.hugo = h
c.hugoSites = h
close(c.created)
})
@@ -302,38 +410,14 @@ func (c *commandeer) loadConfig(mustHaveConfigFile, running bool) error {
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))
cacheDir, err := helpers.GetCacheDir(sourceFs, config)
if err != nil {
return err
}
config.Set("cacheDir", cacheDir)
cfg.Logger.INFO.Println("Using config file:", config.ConfigFileUsed())
themeDir := c.hugo.PathSpec.GetFirstThemeDir()
if themeDir != "" {
if _, err := sourceFs.Stat(themeDir); os.IsNotExist(err) {
return newSystemError("Unable to find theme Directory:", themeDir)
}
}
dir, themeVersionMismatch, minVersion := c.isThemeVsHugoVersionMismatch(sourceFs)
if themeVersionMismatch {
name := filepath.Base(dir)
cfg.Logger.ERROR.Printf("%s theme does not support Hugo version %s. Minimum version required is %s\n",
strings.ToUpper(name), helpers.CurrentHugoVersion.ReleaseVersion(), minVersion)
}
return nil
}
+89 -40
View File
@@ -1,4 +1,4 @@
// Copyright 2017 The Hugo Authors. All rights reserved.
// Copyright 2019 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -14,14 +14,17 @@
package commands
import (
"fmt"
"os"
"time"
"github.com/gohugoio/hugo/hugolib/paths"
"github.com/gohugoio/hugo/common/hugo"
"github.com/gohugoio/hugo/common/loggers"
"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 {
@@ -46,13 +49,14 @@ func (b *commandsBuilder) addAll() *commandsBuilder {
newEnvCmd(),
newConfigCmd(),
newCheckCmd(),
b.newBenchmarkCmd(),
newDeployCmd(),
newConvertCmd(),
newNewCmd(),
b.newNewCmd(),
newListCmd(),
newImportCmd(),
newGenCmd(),
createReleaser(),
b.newModCmd(),
)
return b
@@ -82,14 +86,14 @@ var _ commandsBuilderGetter = (*baseBuilderCmd)(nil)
// Used in tests.
type commandsBuilderGetter interface {
getCmmandsBuilder() *commandsBuilder
getCommandsBuilder() *commandsBuilder
}
type baseBuilderCmd struct {
*baseCmd
*commandsBuilder
}
func (b *baseBuilderCmd) getCmmandsBuilder() *commandsBuilder {
func (b *baseBuilderCmd) getCommandsBuilder() *commandsBuilder {
return b.commandsBuilder
}
@@ -144,6 +148,7 @@ built with love by spf13 and friends in Go.
Complete documentation is available at http://gohugo.io/.`,
RunE: func(cmd *cobra.Command, args []string) error {
defer cc.timeTrack(time.Now(), "Total")
cfgInit := func(c *commandeer) error {
if cc.buildWatch {
c.Set("disableLiveReload", true)
@@ -162,11 +167,11 @@ Complete documentation is available at http://gohugo.io/.`,
})
cc.cmd.PersistentFlags().StringVar(&cc.cfgFile, "config", "", "config file (default is path/config.yaml|json|toml)")
cc.cmd.PersistentFlags().StringVar(&cc.cfgDir, "configDir", "config", "config dir")
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().SetAnnotation("config", cobra.BashCompFilenameExt, config.ValidConfigFileExtensions)
cc.cmd.PersistentFlags().BoolVarP(&cc.verbose, "verbose", "v", false, "verbose output")
cc.cmd.PersistentFlags().BoolVarP(&cc.debug, "debug", "", false, "debug output")
@@ -177,7 +182,6 @@ Complete documentation is available at http://gohugo.io/.`,
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)")
cc.cmd.Flags().Bool("minify", false, "minify any supported output format (HTML, XML etc.)")
// Set bash-completion
_ = cc.cmd.PersistentFlags().SetAnnotation("logFile", cobra.BashCompFilenameExt, []string{})
@@ -189,13 +193,20 @@ Complete documentation is available at http://gohugo.io/.`,
}
type hugoBuilderCommon struct {
source string
baseURL string
source string
baseURL string
environment string
buildWatch bool
gc bool
// Profile flags (for debugging of performance problems)
cpuprofile string
memprofile string
mutexprofile string
traceprofile string
// TODO(bep) var vs string
logging bool
verbose bool
@@ -204,36 +215,96 @@ type hugoBuilderCommon struct {
quiet bool
cfgFile string
cfgDir string
logFile string
}
func (cc *hugoBuilderCommon) timeTrack(start time.Time, name string) {
if cc.quiet {
return
}
elapsed := time.Since(start)
fmt.Printf("%s in %v ms\n", name, int(1000*elapsed.Seconds()))
}
func (cc *hugoBuilderCommon) getConfigDir(baseDir string) string {
if cc.cfgDir != "" {
return paths.AbsPathify(baseDir, cc.cfgDir)
}
if v, found := os.LookupEnv("HUGO_CONFIGDIR"); found {
return paths.AbsPathify(baseDir, v)
}
return paths.AbsPathify(baseDir, "config")
}
func (cc *hugoBuilderCommon) getEnvironment(isServer bool) string {
if cc.environment != "" {
return cc.environment
}
if v, found := os.LookupEnv("HUGO_ENVIRONMENT"); found {
return v
}
// Used by Netlify and Forestry
if v, found := os.LookupEnv("HUGO_ENV"); found {
return v
}
if isServer {
return hugo.EnvironmentDevelopment
}
return hugo.EnvironmentProduction
}
func (cc *hugoBuilderCommon) handleCommonBuilderFlags(cmd *cobra.Command) {
cmd.PersistentFlags().StringVarP(&cc.source, "source", "s", "", "filesystem path to read files relative from")
cmd.PersistentFlags().SetAnnotation("source", cobra.BashCompSubdirsInDir, []string{})
cmd.PersistentFlags().StringVarP(&cc.environment, "environment", "e", "", "build environment")
cmd.PersistentFlags().StringP("themesDir", "", "", "filesystem path to themes directory")
cmd.PersistentFlags().BoolP("ignoreVendor", "", false, "ignores any _vendor directory")
}
func (cc *hugoBuilderCommon) handleFlags(cmd *cobra.Command) {
cc.handleCommonBuilderFlags(cmd)
cmd.Flags().Bool("cleanDestinationDir", false, "remove files from destination not found in static directories")
cmd.Flags().BoolP("buildDrafts", "D", false, "include content marked as draft")
cmd.Flags().BoolP("buildFuture", "F", false, "include content with publishdate in the future")
cmd.Flags().BoolP("buildExpired", "E", false, "include expired content")
cmd.Flags().StringVarP(&cc.source, "source", "s", "", "filesystem path to read files relative from")
cmd.Flags().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().StringSliceP("theme", "t", []string{}, "themes to use (located in /themes/THEMENAME/)")
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().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().BoolP("path-warnings", "", false, "print warnings on duplicate target paths etc.")
cmd.Flags().StringVarP(&cc.cpuprofile, "profile-cpu", "", "", "write cpu profile to `file`")
cmd.Flags().StringVarP(&cc.memprofile, "profile-mem", "", "", "write memory profile to `file`")
cmd.Flags().StringVarP(&cc.mutexprofile, "profile-mutex", "", "", "write Mutex profile to `file`")
cmd.Flags().StringVarP(&cc.traceprofile, "trace", "", "", "write trace to `file` (not useful in general)")
// Hide these for now.
cmd.Flags().MarkHidden("profile-cpu")
cmd.Flags().MarkHidden("profile-mem")
cmd.Flags().MarkHidden("profile-mutex")
cmd.Flags().StringSlice("disableKinds", []string{}, "disable different kind of pages (home, RSS etc.)")
cmd.Flags().Bool("minify", false, "minify any supported output format (HTML, XML etc.)")
// Set bash-completion.
// Each flag must first be defined before using the SetAnnotation() call.
_ = cmd.Flags().SetAnnotation("source", cobra.BashCompSubdirsInDir, []string{})
@@ -242,7 +313,7 @@ func (cc *hugoBuilderCommon) handleFlags(cmd *cobra.Command) {
_ = cmd.Flags().SetAnnotation("theme", cobra.BashCompSubdirsInDir, []string{"themes"})
}
func checkErr(logger *jww.Notepad, err error, s ...string) {
func checkErr(logger *loggers.Logger, err error, s ...string) {
if err == nil {
return
}
@@ -255,25 +326,3 @@ func checkErr(logger *jww.Notepad, err error, s ...string) {
}
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)
}
}
}
+78 -44
View File
@@ -1,4 +1,4 @@
// Copyright 2018 The Hugo Authors. All rights reserved.
// Copyright 2019 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -20,32 +20,34 @@ import (
"path/filepath"
"testing"
"github.com/gohugoio/hugo/common/types"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/stretchr/testify/require"
qt "github.com/frankban/quicktest"
)
func TestExecute(t *testing.T) {
assert := require.New(t)
c := qt.New(t)
dir, err := createSimpleTestSite(t)
assert.NoError(err)
dir, err := createSimpleTestSite(t, testSiteConfig{})
c.Assert(err, qt.IsNil)
defer func() {
os.RemoveAll(dir)
}()
resp := Execute([]string{"-s=" + dir})
assert.NoError(resp.Err)
c.Assert(resp.Err, qt.IsNil)
result := resp.Result
assert.True(len(result.Sites) == 1)
assert.True(len(result.Sites[0].RegularPages) == 1)
c.Assert(len(result.Sites) == 1, qt.Equals, true)
c.Assert(len(result.Sites[0].RegularPages()) == 1, qt.Equals, true)
}
func TestCommandsPersistentFlags(t *testing.T) {
assert := require.New(t)
c := qt.New(t)
noOpRunE := func(cmd *cobra.Command, args []string) error {
return nil
@@ -56,8 +58,11 @@ func TestCommandsPersistentFlags(t *testing.T) {
check func(command []cmder)
}{{[]string{"server",
"--config=myconfig.toml",
"--configDir=myconfigdir",
"--contentDir=mycontent",
"--disableKinds=page,home",
"--environment=testing",
"--configDir=myconfigdir",
"--layoutDir=mylayouts",
"--theme=mytheme",
"--gc",
@@ -72,14 +77,16 @@ func TestCommandsPersistentFlags(t *testing.T) {
"--port=1366",
"--renderToDisk",
"--source=mysource",
"--path-warnings",
}, 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)
v := b.getCommandsBuilder().hugoBuilderCommon
c.Assert(v.cfgFile, qt.Equals, "myconfig.toml")
c.Assert(v.cfgDir, qt.Equals, "myconfigdir")
c.Assert(v.source, qt.Equals, "mysource")
c.Assert(v.baseURL, qt.Equals, "https://example.com/b/")
}
if srvCmd, ok := command.(*serverCmd); ok {
@@ -87,28 +94,32 @@ func TestCommandsPersistentFlags(t *testing.T) {
}
}
assert.NotNil(sc)
assert.True(sc.navigateToChanged)
assert.True(sc.disableLiveReload)
assert.True(sc.noHTTPCache)
assert.True(sc.renderToDisk)
assert.Equal(1366, sc.serverPort)
c.Assert(sc, qt.Not(qt.IsNil))
c.Assert(sc.navigateToChanged, qt.Equals, true)
c.Assert(sc.disableLiveReload, qt.Equals, true)
c.Assert(sc.noHTTPCache, qt.Equals, true)
c.Assert(sc.renderToDisk, qt.Equals, true)
c.Assert(sc.serverPort, qt.Equals, 1366)
c.Assert(sc.environment, qt.Equals, "testing")
cfg := viper.New()
sc.flagsToConfig(cfg)
assert.Equal("/tmp/mydestination", cfg.GetString("publishDir"))
assert.Equal("mycontent", cfg.GetString("contentDir"))
assert.Equal("mylayouts", cfg.GetString("layoutDir"))
assert.Equal("mytheme", cfg.GetString("theme"))
assert.Equal("mythemes", cfg.GetString("themesDir"))
assert.Equal("https://example.com/b/", cfg.GetString("baseURL"))
c.Assert(cfg.GetString("publishDir"), qt.Equals, "/tmp/mydestination")
c.Assert(cfg.GetString("contentDir"), qt.Equals, "mycontent")
c.Assert(cfg.GetString("layoutDir"), qt.Equals, "mylayouts")
c.Assert(cfg.GetStringSlice("theme"), qt.DeepEquals, []string{"mytheme"})
c.Assert(cfg.GetString("themesDir"), qt.Equals, "mythemes")
c.Assert(cfg.GetString("baseURL"), qt.Equals, "https://example.com/b/")
assert.Equal([]string{"page", "home"}, cfg.Get("disableKinds"))
c.Assert(cfg.Get("disableKinds"), qt.DeepEquals, []string{"page", "home"})
assert.True(cfg.GetBool("gc"))
c.Assert(cfg.GetBool("gc"), qt.Equals, true)
// The flag is named path-warnings
c.Assert(cfg.GetBool("logPathWarnings"), qt.Equals, true)
// The flag is named i18n-warnings
assert.True(cfg.GetBool("logI18nWarnings"))
c.Assert(cfg.GetBool("logI18nWarnings"), qt.Equals, true)
}}}
@@ -125,7 +136,7 @@ func TestCommandsPersistentFlags(t *testing.T) {
}
rootCmd := root.getCommand()
rootCmd.SetArgs(test.args)
assert.NoError(rootCmd.Execute())
c.Assert(rootCmd.Execute(), qt.IsNil)
test.check(b.commands)
}
@@ -133,13 +144,13 @@ func TestCommandsPersistentFlags(t *testing.T) {
func TestCommandsExecute(t *testing.T) {
assert := require.New(t)
c := qt.New(t)
dir, err := createSimpleTestSite(t)
assert.NoError(err)
dir, err := createSimpleTestSite(t, testSiteConfig{})
c.Assert(err, qt.IsNil)
dirOut, err := ioutil.TempDir("", "hugo-cli-out")
assert.NoError(err)
c.Assert(err, qt.IsNil)
defer func() {
os.RemoveAll(dir)
@@ -160,7 +171,6 @@ func TestCommandsExecute(t *testing.T) {
{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")}, ""},
@@ -179,8 +189,8 @@ func TestCommandsExecute(t *testing.T) {
}
for _, test := range tests {
hugoCmd := newCommandsBuilder().addAll().build().getCommand()
b := newCommandsBuilder().addAll().build()
hugoCmd := b.getCommand()
test.flags = append(test.flags, "--quiet")
hugoCmd.SetArgs(append(test.commands, test.flags...))
@@ -190,31 +200,54 @@ func TestCommandsExecute(t *testing.T) {
_, err := hugoCmd.ExecuteC()
if test.expectErrToContain != "" {
assert.Error(err, fmt.Sprintf("%v", test.commands))
assert.Contains(err.Error(), test.expectErrToContain)
c.Assert(err, qt.Not(qt.IsNil))
c.Assert(err.Error(), qt.Contains, test.expectErrToContain)
} else {
assert.NoError(err, fmt.Sprintf("%v", test.commands))
c.Assert(err, qt.IsNil)
}
// Assert that we have not left any development debug artifacts in
// the code.
if b.c != nil {
_, ok := b.c.destinationFs.(types.DevMarker)
c.Assert(ok, qt.Equals, false)
}
}
}
func createSimpleTestSite(t *testing.T) (string, error) {
type testSiteConfig struct {
configTOML string
contentDir string
}
func createSimpleTestSite(t *testing.T, cfg testSiteConfig) (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"), `
cfgStr := `
baseURL = "https://example.org"
title = "Hugo Commands"
`)
`
writeFile(t, filepath.Join(d, "content", "p1.md"), `
contentDir := "content"
if cfg.configTOML != "" {
cfgStr = cfg.configTOML
}
if cfg.contentDir != "" {
contentDir = cfg.contentDir
}
// Just the basic. These are for CLI tests, not site testing.
writeFile(t, filepath.Join(d, "config.toml"), cfgStr)
writeFile(t, filepath.Join(d, contentDir, "p1.md"), `
---
title: "P1"
weight: 1
@@ -233,6 +266,7 @@ Single: {{ .Title }}
writeFile(t, filepath.Join(d, "layouts", "_default", "list.html"), `
List: {{ .Title }}
Environment: {{ hugo.Environment }}
`)
+76 -6
View File
@@ -14,8 +14,17 @@
package commands
import (
"encoding/json"
"os"
"reflect"
"regexp"
"sort"
"strings"
"github.com/gohugoio/hugo/parser"
"github.com/gohugoio/hugo/parser/metadecoders"
"github.com/gohugoio/hugo/modules"
"github.com/spf13/cobra"
jww "github.com/spf13/jwalterweatherman"
@@ -38,29 +47,58 @@ func newConfigCmd() *configCmd {
RunE: cc.printConfig,
})
cc.cmd.Flags().StringVarP(&cc.source, "source", "s", "", "filesystem path to read files relative from")
cc.cmd.PersistentFlags().StringVarP(&cc.source, "source", "s", "", "filesystem path to read files relative from")
printMountsCmd := &cobra.Command{
Use: "mounts",
Short: "Print the configured file mounts",
RunE: cc.printMounts,
}
cc.cmd.AddCommand(printMountsCmd)
return cc
}
func (c *configCmd) printMounts(cmd *cobra.Command, args []string) error {
cfg, err := initializeConfig(true, false, &c.hugoBuilderCommon, c, nil)
if err != nil {
return err
}
allModules := cfg.Cfg.Get("allmodules").(modules.Modules)
for _, m := range allModules {
if err := parser.InterfaceToConfig(&modMounts{m: m}, metadecoders.JSON, os.Stdout); err != nil {
return err
}
}
return nil
}
func (c *configCmd) printConfig(cmd *cobra.Command, args []string) error {
cfg, err := initializeConfig(true, false, &c.hugoBuilderCommon, c, nil)
if err != nil {
return err
}
allSettings := cfg.Cfg.(*viper.Viper).AllSettings()
var separator string
if allSettings["metadataformat"] == "toml" {
// We need to clean up this, but we store objects in the config that
// isn't really interesting to the end user, so filter these.
ignoreKeysRe := regexp.MustCompile("client|sorted|filecacheconfigs|allmodules|multilingual")
separator := ": "
if len(cfg.configFiles) > 0 && strings.HasSuffix(cfg.configFiles[0], ".toml") {
separator = " = "
} else {
separator = ": "
}
var keys []string
for k := range allSettings {
if ignoreKeysRe.MatchString(k) {
continue
}
keys = append(keys, k)
}
sort.Strings(keys)
@@ -75,3 +113,35 @@ func (c *configCmd) printConfig(cmd *cobra.Command, args []string) error {
return nil
}
type modMounts struct {
m modules.Module
}
type modMount struct {
Source string `json:"source"`
Target string `json:"target"`
Lang string `json:"lang,omitempty"`
}
func (m *modMounts) MarshalJSON() ([]byte, error) {
var mounts []modMount
for _, mount := range m.m.Mounts() {
mounts = append(mounts, modMount{
Source: mount.Source,
Target: mount.Target,
Lang: mount.Lang,
})
}
return json.Marshal(&struct {
Path string `json:"path"`
Dir string `json:"dir"`
Mounts []modMount `json:"mounts"`
}{
Path: m.m.Path(),
Dir: m.m.Dir(),
Mounts: mounts,
})
}
+103 -47
View File
@@ -1,4 +1,4 @@
// Copyright 2015 The Hugo Authors. All rights reserved.
// Copyright 2019 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -14,17 +14,28 @@
package commands
import (
"bytes"
"fmt"
"io"
"strings"
"time"
src "github.com/gohugoio/hugo/source"
"github.com/gohugoio/hugo/resources/page"
"github.com/gohugoio/hugo/hugofs"
"github.com/gohugoio/hugo/helpers"
"github.com/gohugoio/hugo/parser"
"github.com/gohugoio/hugo/parser/metadecoders"
"github.com/gohugoio/hugo/parser/pageparser"
"github.com/pkg/errors"
"github.com/gohugoio/hugo/hugolib"
"path/filepath"
"github.com/gohugoio/hugo/parser"
"github.com/spf13/cast"
"github.com/spf13/cobra"
)
@@ -60,7 +71,7 @@ See convert's subcommands toJSON, toTOML and toYAML for more information.`,
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 cc.convertContents(rune([]byte(parser.JSONLead)[0]))
return cc.convertContents(metadecoders.JSON)
},
},
&cobra.Command{
@@ -69,7 +80,7 @@ to use JSON for the front matter.`,
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 cc.convertContents(rune([]byte(parser.TOMLLead)[0]))
return cc.convertContents(metadecoders.TOML)
},
},
&cobra.Command{
@@ -78,7 +89,7 @@ to use TOML for the front matter.`,
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 cc.convertContents(rune([]byte(parser.YAMLLead)[0]))
return cc.convertContents(metadecoders.YAML)
},
},
)
@@ -91,7 +102,7 @@ to use YAML for the front matter.`,
return cc
}
func (cc *convertCmd) convertContents(mark rune) error {
func (cc *convertCmd) convertContents(format metadecoders.Format) error {
if cc.outputDir == "" && !cc.unsafe {
return newUserError("Unsafe operation not allowed, use --unsafe or set a different output path")
}
@@ -101,6 +112,8 @@ func (cc *convertCmd) convertContents(mark rune) error {
return err
}
c.Cfg.Set("buildDrafts", true)
h, err := hugolib.NewHugoSites(*c.DepsCfg)
if err != nil {
return err
@@ -112,83 +125,126 @@ func (cc *convertCmd) convertContents(mark rune) error {
site := h.Sites[0]
site.Log.FEEDBACK.Println("processing", len(site.AllPages), "content files")
for _, p := range site.AllPages {
if err := cc.convertAndSavePage(p, site, mark); err != nil {
site.Log.FEEDBACK.Println("processing", len(site.AllPages()), "content files")
for _, p := range site.AllPages() {
if err := cc.convertAndSavePage(p, site, format); err != nil {
return err
}
}
return nil
}
func (cc *convertCmd) convertAndSavePage(p *hugolib.Page, site *hugolib.Site, mark rune) error {
func (cc *convertCmd) convertAndSavePage(p page.Page, site *hugolib.Site, targetFormat metadecoders.Format) error {
// The resources are not in .Site.AllPages.
for _, r := range p.Resources.ByType("page") {
if err := cc.convertAndSavePage(r.(*hugolib.Page), site, mark); err != nil {
for _, r := range p.Resources().ByType("page") {
if err := cc.convertAndSavePage(r.(page.Page), site, targetFormat); err != nil {
return err
}
}
if p.Filename() == "" {
if p.File().IsZero() {
// No content file.
return nil
}
site.Log.INFO.Println("Attempting to convert", p.LogicalName())
newPage, err := site.NewPage(p.LogicalName())
if err != nil {
return err
}
errMsg := fmt.Errorf("Error processing file %q", p.Path())
f, _ := p.File.(src.ReadableFile)
file, err := f.Open()
site.Log.INFO.Println("Attempting to convert", p.File().Filename())
f := p.File()
file, err := f.FileInfo().Meta().Open()
if err != nil {
site.Log.ERROR.Println("Error reading file:", p.Path())
site.Log.ERROR.Println(errMsg)
file.Close()
return nil
}
psr, err := parser.ReadFrom(file)
pf, err := parseContentFile(file)
if err != nil {
site.Log.ERROR.Println("Error processing file:", p.Path())
site.Log.ERROR.Println(errMsg)
file.Close()
return err
}
file.Close()
metadata, err := psr.Metadata()
// better handling of dates in formats that don't have support for them
if pf.frontMatterFormat == metadecoders.JSON || pf.frontMatterFormat == metadecoders.YAML || pf.frontMatterFormat == metadecoders.TOML {
for k, v := range pf.frontMatter {
switch vv := v.(type) {
case time.Time:
pf.frontMatter[k] = vv.Format(time.RFC3339)
}
}
}
var newContent bytes.Buffer
err = parser.InterfaceToFrontMatter(pf.frontMatter, targetFormat, &newContent)
if err != nil {
site.Log.ERROR.Println("Error processing file:", p.Path())
site.Log.ERROR.Println(errMsg)
return err
}
// better handling of dates in formats that don't have support for them
if mark == parser.FormatToLeadRune("json") || mark == parser.FormatToLeadRune("yaml") || mark == parser.FormatToLeadRune("toml") {
newMetadata := cast.ToStringMap(metadata)
for k, v := range newMetadata {
switch vv := v.(type) {
case time.Time:
newMetadata[k] = vv.Format(time.RFC3339)
}
}
metadata = newMetadata
}
newContent.Write(pf.content)
newPage.SetSourceContent(psr.Content())
if err = newPage.SetSourceMetaData(metadata, mark); err != nil {
site.Log.ERROR.Printf("Failed to set source metadata for file %q: %s. For more info see For more info see https://github.com/gohugoio/hugo/issues/2458", newPage.FullFilePath(), err)
return nil
}
newFilename := p.File().Filename()
newFilename := p.Filename()
if cc.outputDir != "" {
newFilename = filepath.Join(cc.outputDir, p.Dir(), newPage.LogicalName())
contentDir := strings.TrimSuffix(newFilename, p.Path())
contentDir = filepath.Base(contentDir)
newFilename = filepath.Join(cc.outputDir, contentDir, p.Path())
}
if err = newPage.SaveSourceAs(newFilename); err != nil {
return fmt.Errorf("Failed to save file %q: %s", newFilename, err)
fs := hugofs.Os
if err := helpers.WriteToDisk(newFilename, &newContent, fs); err != nil {
return errors.Wrapf(err, "Failed to save file %q:", newFilename)
}
return nil
}
type parsedFile struct {
frontMatterFormat metadecoders.Format
frontMatterSource []byte
frontMatter map[string]interface{}
// Everything after Front Matter
content []byte
}
func parseContentFile(r io.Reader) (parsedFile, error) {
var pf parsedFile
psr, err := pageparser.Parse(r, pageparser.Config{})
if err != nil {
return pf, err
}
iter := psr.Iterator()
walkFn := func(item pageparser.Item) bool {
if pf.frontMatterSource != nil {
// The rest is content.
pf.content = psr.Input()[item.Pos:]
// Done
return false
} else if item.IsFrontMatter() {
pf.frontMatterFormat = metadecoders.FormatFromFrontMatterType(item.Type)
pf.frontMatterSource = item.Val
}
return true
}
iter.PeekWalk(walkFn)
metadata, err := metadecoders.Default.UnmarshalToMap(pf.frontMatterSource, pf.frontMatterFormat)
if err != nil {
return pf, err
}
pf.frontMatter = metadata
return pf, nil
}
+77
View File
@@ -0,0 +1,77 @@
// Copyright 2019 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package commands
import (
"context"
"github.com/gohugoio/hugo/deploy"
"github.com/spf13/cobra"
)
var _ cmder = (*deployCmd)(nil)
// deployCmd supports deploying sites to Cloud providers.
type deployCmd struct {
hugoBuilderCommon
*baseCmd
}
// TODO: In addition to the "deploy" command, consider adding a "--deploy"
// flag for the default command; this would build the site and then deploy it.
// It's not obvious how to do this; would all of the deploy-specific flags
// have to exist at the top level as well?
// TODO: The output files change every time "hugo" is executed, it looks
// like because of map order randomization. This means that you can
// run "hugo && hugo deploy" again and again and upload new stuff every time. Is
// this intended?
func newDeployCmd() *deployCmd {
cc := &deployCmd{}
cc.baseCmd = newBaseCmd(&cobra.Command{
Use: "deploy",
Short: "Deploy your site to a Cloud provider.",
Long: `Deploy your site to a Cloud provider.
See https://gohugo.io/hosting-and-deployment/hugo-deploy/ for detailed
documentation.
`,
RunE: func(cmd *cobra.Command, args []string) error {
cfgInit := func(c *commandeer) error {
return nil
}
comm, err := initializeConfig(true, false, &cc.hugoBuilderCommon, cc, cfgInit)
if err != nil {
return err
}
deployer, err := deploy.New(comm.Cfg, comm.hugo().PathSpec.PublishFs)
if err != nil {
return err
}
return deployer.Deploy(context.Background())
},
})
cc.cmd.Flags().String("target", "", "target deployment from deployments section in config file; defaults to the first one")
cc.cmd.Flags().Bool("confirm", false, "ask for confirmation before making changes to the target")
cc.cmd.Flags().Bool("dryRun", false, "dry run")
cc.cmd.Flags().Bool("force", false, "force upload of all files")
cc.cmd.Flags().Bool("invalidateCDN", true, "invalidate the CDN cache listed in the deployment target")
cc.cmd.Flags().Int("maxDeletes", 256, "maximum # of files to delete, or -1 to disable")
return cc
}
+1 -1
View File
@@ -68,7 +68,7 @@ func (g *genChromaStyles) generate() error {
if err != nil {
return err
}
formatter := html.New(html.WithClasses())
formatter := html.New(html.WithClasses(true))
formatter.WriteCSS(os.Stdout, style)
return nil
}
+2 -1
View File
@@ -17,6 +17,7 @@ import (
"fmt"
"strings"
"github.com/gohugoio/hugo/common/hugo"
"github.com/gohugoio/hugo/helpers"
"github.com/gohugoio/hugo/hugofs"
"github.com/spf13/cobra"
@@ -45,7 +46,7 @@ in the "man" directory under the current directory.`,
header := &doc.GenManHeader{
Section: "1",
Manual: "Hugo Manual",
Source: fmt.Sprintf("Hugo %s", helpers.CurrentHugoVersion),
Source: fmt.Sprintf("Hugo %s", hugo.CurrentVersion),
}
if !strings.HasSuffix(cc.genmandir, helpers.FilePathSeparator) {
cc.genmandir += helpers.FilePathSeparator
+7
View File
@@ -23,6 +23,13 @@ import (
"github.com/spf13/cobra"
)
const (
ansiEsc = "\u001B"
clearLine = "\r\033[K"
hideCursor = ansiEsc + "[?25l"
showCursor = ansiEsc + "[?25h"
)
type flagsToConfigHandler interface {
flagsToConfig(cfg config.Provider)
}
+621 -445
View File
File diff suppressed because it is too large Load Diff
+52
View File
@@ -0,0 +1,52 @@
// Copyright 2019 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package commands
import (
"os"
"testing"
qt "github.com/frankban/quicktest"
)
// Issue #5662
func TestHugoWithContentDirOverride(t *testing.T) {
c := qt.New(t)
hugoCmd := newCommandsBuilder().addAll().build()
cmd := hugoCmd.getCommand()
contentDir := "contentOverride"
cfgStr := `
baseURL = "https://example.org"
title = "Hugo Commands"
contentDir = "thisdoesnotexist"
`
dir, err := createSimpleTestSite(t, testSiteConfig{configTOML: cfgStr, contentDir: contentDir})
c.Assert(err, qt.IsNil)
defer func() {
os.RemoveAll(dir)
}()
cmd.SetArgs([]string{"-s=" + dir, "-c=" + contentDir})
_, err = cmd.ExecuteC()
c.Assert(err, qt.IsNil)
}
+96 -101
View File
@@ -1,4 +1,4 @@
// Copyright 2016 The Hugo Authors. All rights reserved.
// Copyright 2019 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -16,7 +16,7 @@ package commands
import (
"bytes"
"errors"
"io"
"fmt"
"io/ioutil"
"os"
"path/filepath"
@@ -24,13 +24,18 @@ import (
"strconv"
"strings"
"time"
"unicode"
"github.com/gohugoio/hugo/common/hugio"
"github.com/gohugoio/hugo/parser/metadecoders"
"github.com/gohugoio/hugo/common/maps"
"github.com/gohugoio/hugo/helpers"
"github.com/gohugoio/hugo/hugofs"
"github.com/gohugoio/hugo/hugolib"
"github.com/gohugoio/hugo/parser"
"github.com/spf13/afero"
"github.com/spf13/cast"
"github.com/spf13/cobra"
jww "github.com/spf13/jwalterweatherman"
)
@@ -100,7 +105,7 @@ func (i *importCmd) importFromJekyll(cmd *cobra.Command, args []string) error {
return errors.New("abort: jekyll root contains neither posts nor drafts")
}
site, err := i.createSiteFromJekyll(jekyllRoot, targetDir, jekyllPostDirs, forceImport)
err = i.createSiteFromJekyll(jekyllRoot, targetDir, jekyllPostDirs, forceImport)
if err != nil {
return newUserError(err)
@@ -109,7 +114,7 @@ func (i *importCmd) importFromJekyll(cmd *cobra.Command, args []string) error {
jww.FEEDBACK.Println("Importing...")
fileCount := 0
callback := func(path string, fi os.FileInfo, err error) error {
callback := func(path string, fi hugofs.FileMetaInfo, err error) error {
if err != nil {
return err
}
@@ -137,7 +142,7 @@ func (i *importCmd) importFromJekyll(cmd *cobra.Command, args []string) error {
}
fileCount++
return convertJekyllPost(site, path, relPath, targetDir, draft)
return convertJekyllPost(path, relPath, targetDir, draft)
}
for jekyllPostDir, hasAnyPostInDir := range jekyllPostDirs {
@@ -195,22 +200,22 @@ func (i *importCmd) retrieveJekyllPostDir(fs afero.Fs, dir string) (bool, bool)
return false, true
}
func (i *importCmd) createSiteFromJekyll(jekyllRoot, targetDir string, jekyllPostDirs map[string]bool, force bool) (*hugolib.Site, error) {
func (i *importCmd) createSiteFromJekyll(jekyllRoot, targetDir string, jekyllPostDirs map[string]bool, force bool) error {
s, err := hugolib.NewSiteDefaultLang()
if err != nil {
return nil, err
return err
}
fs := s.Fs.Source
if exists, _ := helpers.Exists(targetDir, fs); exists {
if isDir, _ := helpers.IsDir(targetDir, fs); !isDir {
return nil, errors.New("target path \"" + targetDir + "\" exists but is not a directory")
return errors.New("target path \"" + targetDir + "\" exists but is not a directory")
}
isEmpty, _ := helpers.IsEmpty(targetDir, fs)
if !isEmpty && !force {
return nil, errors.New("target path \"" + targetDir + "\" exists and is not empty")
return errors.New("target path \"" + targetDir + "\" exists and is not empty")
}
}
@@ -227,7 +232,7 @@ func (i *importCmd) createSiteFromJekyll(jekyllRoot, targetDir string, jekyllPos
i.copyJekyllFilesAndFolders(jekyllRoot, filepath.Join(targetDir, "static"), jekyllPostDirs)
return s, nil
return nil
}
func (i *importCmd) loadJekyllConfig(fs afero.Fs, jekyllRoot string) map[string]interface{} {
@@ -253,7 +258,7 @@ func (i *importCmd) loadJekyllConfig(fs afero.Fs, jekyllRoot string) map[string]
return nil
}
c, err := parser.HandleYAMLMetaData(b)
c, err := metadecoders.Default.UnmarshalToMap(b, metadecoders.YAML)
if err != nil {
return nil
@@ -262,7 +267,7 @@ func (i *importCmd) loadJekyllConfig(fs afero.Fs, jekyllRoot string) map[string]
return c
}
func (i *importCmd) createConfigFromJekyll(fs afero.Fs, inpath string, kind string, jekyllConfig map[string]interface{}) (err error) {
func (i *importCmd) createConfigFromJekyll(fs afero.Fs, inpath string, kind metadecoders.Format, jekyllConfig map[string]interface{}) (err error) {
title := "My New Hugo Site"
baseURL := "http://example.org/"
@@ -288,77 +293,20 @@ func (i *importCmd) createConfigFromJekyll(fs afero.Fs, inpath string, kind stri
"languageCode": "en-us",
"disablePathToLower": true,
}
kind = parser.FormatSanitize(kind)
var buf bytes.Buffer
err = parser.InterfaceToConfig(in, parser.FormatToLeadRune(kind), &buf)
err = parser.InterfaceToConfig(in, kind, &buf)
if err != nil {
return err
}
return helpers.WriteToDisk(filepath.Join(inpath, "config."+kind), &buf, fs)
}
func copyFile(source string, dest string) error {
sf, err := os.Open(source)
if err != nil {
return err
}
defer sf.Close()
df, err := os.Create(dest)
if err != nil {
return err
}
defer df.Close()
_, err = io.Copy(df, sf)
if err == nil {
si, err := os.Stat(source)
if err != nil {
err = os.Chmod(dest, si.Mode())
if err != nil {
return err
}
}
}
return nil
}
func copyDir(source string, dest string) error {
fi, err := os.Stat(source)
if err != nil {
return err
}
if !fi.IsDir() {
return errors.New(source + " is not a directory")
}
err = os.MkdirAll(dest, fi.Mode())
if err != nil {
return err
}
entries, err := ioutil.ReadDir(source)
for _, entry := range entries {
sfp := filepath.Join(source, entry.Name())
dfp := filepath.Join(dest, entry.Name())
if entry.IsDir() {
err = copyDir(sfp, dfp)
if err != nil {
jww.ERROR.Println(err)
}
} else {
err = copyFile(sfp, dfp)
if err != nil {
jww.ERROR.Println(err)
}
}
}
return nil
return helpers.WriteToDisk(filepath.Join(inpath, "config."+string(kind)), &buf, fs)
}
func (i *importCmd) copyJekyllFilesAndFolders(jekyllRoot, dest string, jekyllPostDirs map[string]bool) (err error) {
fi, err := os.Stat(jekyllRoot)
fs := hugofs.Os
fi, err := fs.Stat(jekyllRoot)
if err != nil {
return err
}
@@ -370,13 +318,17 @@ func (i *importCmd) copyJekyllFilesAndFolders(jekyllRoot, dest string, jekyllPos
return err
}
entries, err := ioutil.ReadDir(jekyllRoot)
if err != nil {
return err
}
for _, entry := range entries {
sfp := filepath.Join(jekyllRoot, entry.Name())
dfp := filepath.Join(dest, entry.Name())
if entry.IsDir() {
if entry.Name()[0] != '_' && entry.Name()[0] != '.' {
if _, ok := jekyllPostDirs[entry.Name()]; !ok {
err = copyDir(sfp, dfp)
err = hugio.CopyDir(fs, sfp, dfp, nil)
if err != nil {
jww.ERROR.Println(err)
}
@@ -395,7 +347,7 @@ func (i *importCmd) copyJekyllFilesAndFolders(jekyllRoot, dest string, jekyllPos
}
if !isExcept && entry.Name()[0] != '.' && entry.Name()[0] != '_' {
err = copyFile(sfp, dfp)
err = hugio.CopyFile(fs, sfp, dfp)
if err != nil {
jww.ERROR.Println(err)
}
@@ -423,7 +375,7 @@ func parseJekyllFilename(filename string) (time.Time, string, error) {
return postDate, postName, nil
}
func convertJekyllPost(s *hugolib.Site, path, relPath, targetDir string, draft bool) error {
func convertJekyllPost(path, relPath, targetDir string, draft bool) error {
jww.TRACE.Println("Converting", path)
filename := filepath.Base(path)
@@ -445,44 +397,34 @@ func convertJekyllPost(s *hugolib.Site, path, relPath, targetDir string, draft b
return err
}
psr, err := parser.ReadFrom(bytes.NewReader(contentBytes))
pf, err := parseContentFile(bytes.NewReader(contentBytes))
if err != nil {
jww.ERROR.Println("Parse file error:", path)
return err
}
metadata, err := psr.Metadata()
if err != nil {
jww.ERROR.Println("Processing file error:", path)
return err
}
newmetadata, err := convertJekyllMetaData(metadata, postName, postDate, draft)
newmetadata, err := convertJekyllMetaData(pf.frontMatter, postName, postDate, draft)
if err != nil {
jww.ERROR.Println("Convert metadata error:", path)
return err
}
jww.TRACE.Println(newmetadata)
content := convertJekyllContent(newmetadata, string(psr.Content()))
page, err := s.NewPage(filename)
content, err := convertJekyllContent(newmetadata, string(pf.content))
if err != nil {
jww.ERROR.Println("New page error", filename)
jww.ERROR.Println("Converting Jekyll error:", path)
return err
}
page.SetSourceContent([]byte(content))
page.SetSourceMetaData(newmetadata, parser.FormatToLeadRune("yaml"))
page.SaveSourceAs(targetFile)
jww.TRACE.Println("Target file:", targetFile)
fs := hugofs.Os
if err := helpers.WriteToDisk(targetFile, strings.NewReader(content), fs); err != nil {
return fmt.Errorf("failed to save file %q: %s", filename, err)
}
return nil
}
func convertJekyllMetaData(m interface{}, postName string, postDate time.Time, draft bool) (interface{}, error) {
metadata, err := cast.ToStringMapE(m)
metadata, err := maps.ToStringMapE(m)
if err != nil {
return nil, err
}
@@ -533,8 +475,8 @@ func convertJekyllMetaData(m interface{}, postName string, postDate time.Time, d
return metadata, nil
}
func convertJekyllContent(m interface{}, content string) string {
metadata, _ := cast.ToStringMapE(m)
func convertJekyllContent(m interface{}, content string) (string, error) {
metadata, _ := maps.ToStringMapE(m)
lines := strings.Split(content, "\n")
var resultLines []string
@@ -557,7 +499,6 @@ func convertJekyllContent(m interface{}, content string) string {
}{
{regexp.MustCompile("(?i)<!-- more -->"), "<!--more-->"},
{regexp.MustCompile(`\{%\s*raw\s*%\}\s*(.*?)\s*\{%\s*endraw\s*%\}`), "$1"},
{regexp.MustCompile(`{%\s*highlight\s*(.*?)\s*%}`), "{{< highlight $1 >}}"},
{regexp.MustCompile(`{%\s*endhighlight\s*%}`), "{{< / highlight >}}"},
}
@@ -571,13 +512,67 @@ func convertJekyllContent(m interface{}, content string) string {
}{
// Octopress image tag: http://octopress.org/docs/plugins/image-tag/
{regexp.MustCompile(`{%\s+img\s*(.*?)\s*%}`), replaceImageTag},
{regexp.MustCompile(`{%\s*highlight\s*(.*?)\s*%}`), replaceHighlightTag},
}
for _, replace := range replaceListFunc {
content = replace.re.ReplaceAllStringFunc(content, replace.replace)
}
return content
var buf bytes.Buffer
if len(metadata) != 0 {
err := parser.InterfaceToFrontMatter(m, metadecoders.YAML, &buf)
if err != nil {
return "", err
}
}
buf.WriteString(content)
return buf.String(), nil
}
func replaceHighlightTag(match string) string {
r := regexp.MustCompile(`{%\s*highlight\s*(.*?)\s*%}`)
parts := r.FindStringSubmatch(match)
lastQuote := rune(0)
f := func(c rune) bool {
switch {
case c == lastQuote:
lastQuote = rune(0)
return false
case lastQuote != rune(0):
return false
case unicode.In(c, unicode.Quotation_Mark):
lastQuote = c
return false
default:
return unicode.IsSpace(c)
}
}
// splitting string by space but considering quoted section
items := strings.FieldsFunc(parts[1], f)
result := bytes.NewBufferString("{{< highlight ")
result.WriteString(items[0]) // language
options := items[1:]
for i, opt := range options {
opt = strings.Replace(opt, "\"", "", -1)
if opt == "linenos" {
opt = "linenos=table"
}
if i == 0 {
opt = " \"" + opt
}
if i < len(options)-1 {
opt += ","
} else if i == len(options)-1 {
opt += "\""
}
result.WriteString(opt)
}
result.WriteString(" >}}")
return result.String()
}
func replaceImageTag(match string) string {
+24 -13
View File
@@ -15,12 +15,14 @@ package commands
import (
"encoding/json"
"github.com/stretchr/testify/assert"
"testing"
"time"
qt "github.com/frankban/quicktest"
)
func TestParseJekyllFilename(t *testing.T) {
c := qt.New(t)
filenameArray := []string{
"2015-01-02-test.md",
"2012-03-15-中文.markup",
@@ -36,13 +38,14 @@ func TestParseJekyllFilename(t *testing.T) {
for i, filename := range filenameArray {
postDate, postName, err := parseJekyllFilename(filename)
assert.Equal(t, err, nil)
assert.Equal(t, expectResult[i].postDate.Format("2006-01-02"), postDate.Format("2006-01-02"))
assert.Equal(t, expectResult[i].postName, postName)
c.Assert(err, qt.IsNil)
c.Assert(expectResult[i].postDate.Format("2006-01-02"), qt.Equals, postDate.Format("2006-01-02"))
c.Assert(expectResult[i].postName, qt.Equals, postName)
}
}
func TestConvertJekyllMetadata(t *testing.T) {
c := qt.New(t)
testDataList := []struct {
metadata interface{}
postName string
@@ -73,30 +76,35 @@ func TestConvertJekyllMetadata(t *testing.T) {
for _, data := range testDataList {
result, err := convertJekyllMetaData(data.metadata, data.postName, data.postDate, data.draft)
assert.Equal(t, nil, err)
c.Assert(err, qt.IsNil)
jsonResult, err := json.Marshal(result)
assert.Equal(t, nil, err)
assert.Equal(t, data.expect, string(jsonResult))
c.Assert(err, qt.IsNil)
c.Assert(string(jsonResult), qt.Equals, data.expect)
}
}
func TestConvertJekyllContent(t *testing.T) {
c := qt.New(t)
testDataList := []struct {
metadata interface{}
content string
expect string
}{
{map[interface{}]interface{}{},
`Test content\n<!-- more -->\npart2 content`, `Test content\n<!--more-->\npart2 content`},
"Test content\r\n<!-- more -->\npart2 content", "Test content\n<!--more-->\npart2 content"},
{map[interface{}]interface{}{},
`Test content\n<!-- More -->\npart2 content`, `Test content\n<!--more-->\npart2 content`},
"Test content\n<!-- More -->\npart2 content", "Test content\n<!--more-->\npart2 content"},
{map[interface{}]interface{}{"excerpt_separator": "<!--sep-->"},
`Test content\n<!--sep-->\npart2 content`, `Test content\n<!--more-->\npart2 content`},
"Test content\n<!--sep-->\npart2 content",
"---\nexcerpt_separator: <!--sep-->\n---\nTest content\n<!--more-->\npart2 content"},
{map[interface{}]interface{}{}, "{% raw %}text{% endraw %}", "text"},
{map[interface{}]interface{}{}, "{%raw%} text2 {%endraw %}", "text2"},
{map[interface{}]interface{}{},
"{% highlight go %}\nvar s int\n{% endhighlight %}",
"{{< highlight go >}}\nvar s int\n{{< / highlight >}}"},
{map[interface{}]interface{}{},
"{% highlight go linenos hl_lines=\"1 2\" %}\nvar s string\nvar i int\n{% endhighlight %}",
"{{< highlight go \"linenos=table,hl_lines=1 2\" >}}\nvar s string\nvar i int\n{{< / highlight >}}"},
// Octopress image tag
{map[interface{}]interface{}{},
@@ -117,10 +125,13 @@ func TestConvertJekyllContent(t *testing.T) {
{map[interface{}]interface{}{},
"{% img right /placekitten/300/500 'Place Kitten #4' 'An image of a very cute kitten' %}",
"{{< figure class=\"right\" src=\"/placekitten/300/500\" title=\"Place Kitten #4\" alt=\"An image of a very cute kitten\" >}}"},
{map[interface{}]interface{}{"category": "book", "layout": "post", "Date": "2015-10-01 12:13:11"},
"somecontent",
"---\nDate: \"2015-10-01 12:13:11\"\ncategory: book\nlayout: post\n---\nsomecontent"},
}
for _, data := range testDataList {
result := convertJekyllContent(data.metadata, data.content)
assert.Equal(t, data.expect, result)
result, err := convertJekyllContent(data.metadata, data.content)
c.Assert(result, qt.Equals, data.expect)
c.Assert(err, qt.IsNil)
}
}
+14 -8
View File
@@ -36,14 +36,17 @@ This is primarily to ensure that Hugo can watch enough files on some OSs`,
var rLimit syscall.Rlimit
err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit)
if err != nil {
return newSystemError("Error Getting Rlimit ", err)
return newSystemError("Error Getting rlimit ", err)
}
jww.FEEDBACK.Println("Current rLimit:", rLimit)
if rLimit.Cur >= newRlimit {
return nil
}
jww.FEEDBACK.Println("Attempting to increase limit")
rLimit.Max = 999999
rLimit.Cur = 999999
rLimit.Cur = newRlimit
err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rLimit)
if err != nil {
return newSystemError("Error Setting rLimit ", err)
@@ -61,18 +64,21 @@ This is primarily to ensure that Hugo can watch enough files on some OSs`,
return &limitCmd{baseCmd: newBaseCmd(ccmd)}
}
const newRlimit = 10240
func tweakLimit() {
var rLimit syscall.Rlimit
err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit)
if err != nil {
jww.ERROR.Println("Unable to obtain rLimit", err)
jww.WARN.Println("Unable to get rlimit:", err)
return
}
if rLimit.Cur < rLimit.Max {
rLimit.Max = 64000
rLimit.Cur = 64000
if rLimit.Cur < newRlimit {
rLimit.Cur = newRlimit
err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rLimit)
if err != nil {
jww.WARN.Println("Unable to increase number of open files limit", err)
// This may not succeed, see https://github.com/golang/go/issues/30401
jww.INFO.Println("Unable to increase number of open files limit:", err)
}
}
}
+112 -60
View File
@@ -1,4 +1,4 @@
// Copyright 2015 The Hugo Authors. All rights reserved.
// Copyright 2019 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -14,9 +14,14 @@
package commands
import (
"path/filepath"
"encoding/csv"
"os"
"strconv"
"strings"
"time"
"github.com/gohugoio/hugo/hugolib"
"github.com/gohugoio/hugo/resources/resource"
"github.com/spf13/cobra"
jww "github.com/spf13/jwalterweatherman"
)
@@ -28,6 +33,32 @@ type listCmd struct {
*baseCmd
}
func (lc *listCmd) buildSites(config map[string]interface{}) (*hugolib.HugoSites, error) {
cfgInit := func(c *commandeer) error {
for key, value := range config {
c.Set(key, value)
}
return nil
}
c, err := initializeConfig(true, false, &lc.hugoBuilderCommon, lc, cfgInit)
if err != nil {
return nil, err
}
sites, err := hugolib.NewHugoSites(*c.DepsCfg)
if err != nil {
return nil, newSystemError("Error creating sites", err)
}
if err := sites.Build(hugolib.BuildCfg{SkipRender: true}); err != nil {
return nil, newSystemError("Error Processing Source Content", err)
}
return sites, nil
}
func newListCmd() *listCmd {
cc := &listCmd{}
@@ -46,106 +77,127 @@ List requires a subcommand, e.g. ` + "`hugo list drafts`.",
Short: "List all drafts",
Long: `List all of the drafts in your content directory.`,
RunE: func(cmd *cobra.Command, args []string) error {
cfgInit := func(c *commandeer) error {
c.Set("buildDrafts", true)
return nil
}
c, err := initializeConfig(true, false, &cc.hugoBuilderCommon, cc, cfgInit)
if err != nil {
return err
}
sites, err := hugolib.NewHugoSites(*c.DepsCfg)
sites, err := cc.buildSites(map[string]interface{}{"buildDrafts": true})
if err != nil {
return newSystemError("Error creating sites", err)
}
if err := sites.Build(hugolib.BuildCfg{SkipRender: true}); err != nil {
return newSystemError("Error Processing Source Content", err)
return newSystemError("Error building sites", err)
}
for _, p := range sites.Pages() {
if p.IsDraft() {
jww.FEEDBACK.Println(filepath.Join(p.File.Dir(), p.File.LogicalName()))
if p.Draft() {
jww.FEEDBACK.Println(strings.TrimPrefix(p.File().Filename(), sites.WorkingDir+string(os.PathSeparator)))
}
}
return nil
},
},
&cobra.Command{
Use: "future",
Short: "List all posts dated in the future",
Long: `List all of the posts in your content directory which will be
posted in the future.`,
Long: `List all of the posts in your content directory which will be posted in the future.`,
RunE: func(cmd *cobra.Command, args []string) error {
cfgInit := func(c *commandeer) error {
c.Set("buildFuture", true)
return nil
}
c, err := initializeConfig(true, false, &cc.hugoBuilderCommon, cc, cfgInit)
if err != nil {
return err
}
sites, err := hugolib.NewHugoSites(*c.DepsCfg)
sites, err := cc.buildSites(map[string]interface{}{"buildFuture": true})
if err != nil {
return newSystemError("Error creating sites", err)
return newSystemError("Error building sites", err)
}
if err := sites.Build(hugolib.BuildCfg{SkipRender: true}); err != nil {
return newSystemError("Error Processing Source Content", err)
}
writer := csv.NewWriter(os.Stdout)
defer writer.Flush()
for _, p := range sites.Pages() {
if p.IsFuture() {
jww.FEEDBACK.Println(filepath.Join(p.File.Dir(), p.File.LogicalName()))
if resource.IsFuture(p) {
err := writer.Write([]string{
strings.TrimPrefix(p.File().Filename(), sites.WorkingDir+string(os.PathSeparator)),
p.PublishDate().Format(time.RFC3339),
})
if err != nil {
return newSystemError("Error writing future posts to stdout", err)
}
}
}
return nil
},
},
&cobra.Command{
Use: "expired",
Short: "List all posts already expired",
Long: `List all of the posts in your content directory which has already
expired.`,
Long: `List all of the posts in your content directory which has already expired.`,
RunE: func(cmd *cobra.Command, args []string) error {
cfgInit := func(c *commandeer) error {
c.Set("buildExpired", true)
return nil
}
c, err := initializeConfig(true, false, &cc.hugoBuilderCommon, cc, cfgInit)
if err != nil {
return err
}
sites, err := hugolib.NewHugoSites(*c.DepsCfg)
sites, err := cc.buildSites(map[string]interface{}{"buildExpired": true})
if err != nil {
return newSystemError("Error creating sites", err)
return newSystemError("Error building sites", err)
}
if err := sites.Build(hugolib.BuildCfg{SkipRender: true}); err != nil {
return newSystemError("Error Processing Source Content", err)
}
writer := csv.NewWriter(os.Stdout)
defer writer.Flush()
for _, p := range sites.Pages() {
if p.IsExpired() {
jww.FEEDBACK.Println(filepath.Join(p.File.Dir(), p.File.LogicalName()))
if resource.IsExpired(p) {
err := writer.Write([]string{
strings.TrimPrefix(p.File().Filename(), sites.WorkingDir+string(os.PathSeparator)),
p.ExpiryDate().Format(time.RFC3339),
})
if err != nil {
return newSystemError("Error writing expired posts to stdout", err)
}
}
}
return nil
},
},
&cobra.Command{
Use: "all",
Short: "List all posts",
Long: `List all of the posts in your content directory, include drafts, future and expired pages.`,
RunE: func(cmd *cobra.Command, args []string) error {
sites, err := cc.buildSites(map[string]interface{}{
"buildExpired": true,
"buildDrafts": true,
"buildFuture": true,
})
if err != nil {
return newSystemError("Error building sites", err)
}
writer := csv.NewWriter(os.Stdout)
defer writer.Flush()
writer.Write([]string{
"path",
"slug",
"title",
"date",
"expiryDate",
"publishDate",
"draft",
"permalink",
})
for _, p := range sites.Pages() {
if !p.IsPage() {
continue
}
err := writer.Write([]string{
strings.TrimPrefix(p.File().Filename(), sites.WorkingDir+string(os.PathSeparator)),
p.Slug(),
p.Title(),
p.Date().Format(time.RFC3339),
p.ExpiryDate().Format(time.RFC3339),
p.PublishDate().Format(time.RFC3339),
strconv.FormatBool(p.Draft()),
p.Permalink(),
})
if err != nil {
return newSystemError("Error writing posts to stdout", err)
}
}
return nil
},
},
)
+72
View File
@@ -0,0 +1,72 @@
package commands
import (
"bytes"
"encoding/csv"
"io"
"os"
"path/filepath"
"strings"
"testing"
qt "github.com/frankban/quicktest"
"github.com/spf13/cobra"
)
func captureStdout(f func() (*cobra.Command, error)) (string, error) {
old := os.Stdout
r, w, _ := os.Pipe()
os.Stdout = w
_, err := f()
if err != nil {
return "", err
}
w.Close()
os.Stdout = old
var buf bytes.Buffer
io.Copy(&buf, r)
return buf.String(), nil
}
func TestListAll(t *testing.T) {
c := qt.New(t)
dir, err := createSimpleTestSite(t, testSiteConfig{})
c.Assert(err, qt.IsNil)
hugoCmd := newCommandsBuilder().addAll().build()
cmd := hugoCmd.getCommand()
defer func() {
os.RemoveAll(dir)
}()
cmd.SetArgs([]string{"-s=" + dir, "list", "all"})
out, err := captureStdout(cmd.ExecuteC)
c.Assert(err, qt.IsNil)
r := csv.NewReader(strings.NewReader(out))
header, err := r.Read()
c.Assert(err, qt.IsNil)
c.Assert(header, qt.DeepEquals, []string{
"path", "slug", "title",
"date", "expiryDate", "publishDate",
"draft", "permalink",
})
record, err := r.Read()
c.Assert(err, qt.IsNil)
c.Assert(record, qt.DeepEquals, []string{
filepath.Join("content", "p1.md"), "", "P1",
"0001-01-01T00:00:00Z", "0001-01-01T00:00:00Z", "0001-01-01T00:00:00Z",
"false", "https://example.org/p1/",
})
}
+188
View File
@@ -0,0 +1,188 @@
// Copyright 2019 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package commands
import (
"os"
"github.com/gohugoio/hugo/modules"
"github.com/spf13/cobra"
)
var _ cmder = (*modCmd)(nil)
type modCmd struct {
*baseBuilderCmd
}
func (b *commandsBuilder) newModCmd() *modCmd {
c := &modCmd{}
const commonUsage = `
Note that Hugo will always start out by resolving the components defined in the site
configuration, provided by a _vendor directory (if no --ignoreVendor flag provided),
Go Modules, or a folder inside the themes directory, in that order.
See https://gohugo.io/hugo-modules/ for more information.
`
cmd := &cobra.Command{
Use: "mod",
Short: "Various Hugo Modules helpers.",
Long: `Various helpers to help manage the modules in your project's dependency graph.
Most operations here requires a Go version installed on your system (>= Go 1.12) and the relevant VCS client (typically Git).
This is not needed if you only operate on modules inside /themes or if you have vendored them via "hugo mod vendor".
` + commonUsage,
RunE: nil,
}
cmd.AddCommand(
&cobra.Command{
Use: "get",
DisableFlagParsing: true,
Short: "Resolves dependencies in your current Hugo Project.",
Long: `
Resolves dependencies in your current Hugo Project.
Some examples:
Install the latest version possible for a given module:
hugo mod get github.com/gohugoio/testshortcodes
Install a specific version:
hugo mod get github.com/gohugoio/testshortcodes@v0.3.0
Install the latest versions of all module dependencies:
hugo mod get -u
Run "go help get" for more information. All flags available for "go get" is also relevant here.
` + commonUsage,
RunE: func(cmd *cobra.Command, args []string) error {
return c.withModsClient(false, func(c *modules.Client) error {
// We currently just pass on the flags we get to Go and
// need to do the flag handling manually.
if len(args) == 1 && args[0] == "-h" {
return cmd.Help()
}
return c.Get(args...)
})
},
},
&cobra.Command{
Use: "graph",
Short: "Print a module dependency graph.",
Long: `Print a module dependency graph with information about module status (disabled, vendored).
Note that for vendored modules, that is the version listed and not the one from go.mod.
`,
RunE: func(cmd *cobra.Command, args []string) error {
return c.withModsClient(true, func(c *modules.Client) error {
return c.Graph(os.Stdout)
})
},
},
&cobra.Command{
Use: "init",
Short: "Initialize this project as a Hugo Module.",
Long: `Initialize this project as a Hugo Module.
It will try to guess the module path, but you may help by passing it as an argument, e.g:
hugo mod init github.com/gohugoio/testshortcodes
Note that Hugo Modules supports multi-module projects, so you can initialize a Hugo Module
inside a subfolder on GitHub, as one example.
`,
RunE: func(cmd *cobra.Command, args []string) error {
var path string
if len(args) >= 1 {
path = args[0]
}
return c.withModsClient(false, func(c *modules.Client) error {
return c.Init(path)
})
},
},
&cobra.Command{
Use: "vendor",
Short: "Vendor all module dependencies into the _vendor directory.",
Long: `Vendor all module dependencies into the _vendor directory.
If a module is vendored, that is where Hugo will look for it's dependencies.
`,
RunE: func(cmd *cobra.Command, args []string) error {
return c.withModsClient(true, func(c *modules.Client) error {
return c.Vendor()
})
},
},
&cobra.Command{
Use: "tidy",
Short: "Remove unused entries in go.mod and go.sum.",
RunE: func(cmd *cobra.Command, args []string) error {
return c.withModsClient(true, func(c *modules.Client) error {
return c.Tidy()
})
},
},
&cobra.Command{
Use: "clean",
Short: "Delete the entire Hugo Module cache.",
Long: `Delete the entire Hugo Module cache.
Note that after you run this command, all of your dependencies will be re-downloaded next time you run "hugo".
Also note that if you configure a positive maxAge for the "modules" file cache, it will also be cleaned as part of "hugo --gc".
`,
RunE: func(cmd *cobra.Command, args []string) error {
com, err := c.initConfig(true)
if err != nil {
return err
}
_, err = com.hugo().FileCaches.ModulesCache().Prune(true)
return err
},
},
)
c.baseBuilderCmd = b.newBuilderCmd(cmd)
return c
}
func (c *modCmd) withModsClient(failOnMissingConfig bool, f func(*modules.Client) error) error {
com, err := c.initConfig(failOnMissingConfig)
if err != nil {
return err
}
return f(com.hugo().ModulesClient)
}
func (c *modCmd) initConfig(failOnNoConfig bool) (*commandeer, error) {
com, err := initializeConfig(failOnNoConfig, false, &c.hugoBuilderCommon, c, nil)
if err != nil {
return nil, err
}
return com, nil
}
+18 -18
View File
@@ -30,16 +30,14 @@ import (
var _ cmder = (*newCmd)(nil)
type newCmd struct {
hugoBuilderCommon
contentEditor string
contentType string
*baseCmd
*baseBuilderCmd
}
func newNewCmd() *newCmd {
cc := &newCmd{}
cc.baseCmd = newBaseCmd(&cobra.Command{
func (b *commandsBuilder) newNewCmd() *newCmd {
cmd := &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.
@@ -47,18 +45,20 @@ 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.`,
If archetypes are provided in your theme or site, they will be used.
RunE: cc.newContent,
})
Ensure you run this within the root directory of your site.`,
}
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 := &newCmd{baseBuilderCmd: b.newBuilderCmd(cmd)}
cc.cmd.AddCommand(newNewSiteCmd().getCommand())
cc.cmd.AddCommand(newNewThemeCmd().getCommand())
cmd.Flags().StringVarP(&cc.contentType, "kind", "k", "", "content type to create")
cmd.Flags().StringVar(&cc.contentEditor, "editor", "", "edit new content with this editor, if provided")
cmd.AddCommand(newNewSiteCmd().getCommand())
cmd.AddCommand(newNewThemeCmd().getCommand())
cmd.RunE = cc.newContent
return cc
}
@@ -85,13 +85,13 @@ func (n *newCmd) newContent(cmd *cobra.Command, args []string) error {
var kind string
createPath, kind = newContentPathSection(c.hugo, createPath)
createPath, kind = newContentPathSection(c.hugo(), createPath)
if n.contentType != "" {
kind = n.contentType
}
return create.NewContent(c.hugo, kind, createPath)
return create.NewContent(c.hugo(), kind, createPath)
}
func mkdir(x ...string) {
@@ -118,8 +118,8 @@ func newContentPathSection(h *hugolib.HugoSites, path string) (string, string) {
createpath := filepath.FromSlash(path)
if h != nil {
for _, s := range h.Sites {
createpath = strings.TrimPrefix(createpath, s.PathSpec.ContentDir)
for _, dir := range h.BaseFs.Content.Dirs {
createpath = strings.TrimPrefix(createpath, dir.Meta().Filename())
}
}
+27 -21
View File
@@ -1,4 +1,4 @@
// Copyright 2018 The Hugo Authors. All rights reserved.
// Copyright 2019 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -19,19 +19,20 @@ import (
"github.com/gohugoio/hugo/hugofs"
"github.com/spf13/viper"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
qt "github.com/frankban/quicktest"
)
// Issue #1133
func TestNewContentPathSectionWithForwardSlashes(t *testing.T) {
c := qt.New(t)
p, s := newContentPathSection(nil, "/post/new.md")
assert.Equal(t, filepath.FromSlash("/post/new.md"), p)
assert.Equal(t, "post", s)
c.Assert(p, qt.Equals, filepath.FromSlash("/post/new.md"))
c.Assert(s, qt.Equals, "post")
}
func checkNewSiteInited(fs *hugofs.Fs, basepath string, t *testing.T) {
c := qt.New(t)
paths := []string{
filepath.Join(basepath, "layouts"),
filepath.Join(basepath, "content"),
@@ -43,77 +44,82 @@ func checkNewSiteInited(fs *hugofs.Fs, basepath string, t *testing.T) {
for _, path := range paths {
_, err := fs.Source.Stat(path)
require.NoError(t, err)
c.Assert(err, qt.IsNil)
}
}
func TestDoNewSite(t *testing.T) {
c := qt.New(t)
n := newNewSiteCmd()
basepath := filepath.Join("base", "blog")
_, fs := newTestCfg()
require.NoError(t, n.doNewSite(fs, basepath, false))
c.Assert(n.doNewSite(fs, basepath, false), qt.IsNil)
checkNewSiteInited(fs, basepath, t)
}
func TestDoNewSite_noerror_base_exists_but_empty(t *testing.T) {
c := qt.New(t)
basepath := filepath.Join("base", "blog")
_, fs := newTestCfg()
n := newNewSiteCmd()
require.NoError(t, fs.Source.MkdirAll(basepath, 777))
c.Assert(fs.Source.MkdirAll(basepath, 0777), qt.IsNil)
require.NoError(t, n.doNewSite(fs, basepath, false))
c.Assert(n.doNewSite(fs, basepath, false), qt.IsNil)
}
func TestDoNewSite_error_base_exists(t *testing.T) {
c := qt.New(t)
basepath := filepath.Join("base", "blog")
_, fs := newTestCfg()
n := newNewSiteCmd()
require.NoError(t, fs.Source.MkdirAll(basepath, 777))
c.Assert(fs.Source.MkdirAll(basepath, 0777), qt.IsNil)
_, err := fs.Source.Create(filepath.Join(basepath, "foo"))
require.NoError(t, err)
c.Assert(err, qt.IsNil)
// Since the directory already exists and isn't empty, expect an error
require.Error(t, n.doNewSite(fs, basepath, false))
c.Assert(n.doNewSite(fs, basepath, false), qt.Not(qt.IsNil))
}
func TestDoNewSite_force_empty_dir(t *testing.T) {
c := qt.New(t)
basepath := filepath.Join("base", "blog")
_, fs := newTestCfg()
n := newNewSiteCmd()
require.NoError(t, fs.Source.MkdirAll(basepath, 777))
require.NoError(t, n.doNewSite(fs, basepath, true))
c.Assert(fs.Source.MkdirAll(basepath, 0777), qt.IsNil)
c.Assert(n.doNewSite(fs, basepath, true), qt.IsNil)
checkNewSiteInited(fs, basepath, t)
}
func TestDoNewSite_error_force_dir_inside_exists(t *testing.T) {
c := qt.New(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, n.doNewSite(fs, basepath, true))
c.Assert(fs.Source.MkdirAll(contentPath, 0777), qt.IsNil)
c.Assert(n.doNewSite(fs, basepath, true), qt.Not(qt.IsNil))
}
func TestDoNewSite_error_force_config_inside_exists(t *testing.T) {
c := qt.New(t)
basepath := filepath.Join("base", "blog")
_, fs := newTestCfg()
n := newNewSiteCmd()
configPath := filepath.Join(basepath, "config.toml")
require.NoError(t, fs.Source.MkdirAll(basepath, 777))
c.Assert(fs.Source.MkdirAll(basepath, 0777), qt.IsNil)
_, err := fs.Source.Create(configPath)
require.NoError(t, err)
c.Assert(err, qt.IsNil)
require.Error(t, n.doNewSite(fs, basepath, true))
c.Assert(n.doNewSite(fs, basepath, true), qt.Not(qt.IsNil))
}
func newTestCfg() (*viper.Viper, *hugofs.Fs) {
+8 -6
View File
@@ -16,10 +16,13 @@ package commands
import (
"bytes"
"errors"
"fmt"
"path/filepath"
"strings"
"github.com/gohugoio/hugo/parser/metadecoders"
_errors "github.com/pkg/errors"
"github.com/gohugoio/hugo/create"
"github.com/gohugoio/hugo/helpers"
"github.com/gohugoio/hugo/hugofs"
@@ -78,7 +81,7 @@ func (n *newSiteCmd) doNewSite(fs *hugofs.Fs, basepath string, force bool) error
switch {
case !isEmpty && !force:
return errors.New(basepath + " already exists and is not empty")
return errors.New(basepath + " already exists and is not empty. See --force.")
case !isEmpty && force:
all := append(dirs, filepath.Join(basepath, "config."+n.configFormat))
@@ -92,7 +95,7 @@ func (n *newSiteCmd) doNewSite(fs *hugofs.Fs, basepath string, force bool) error
for _, dir := range dirs {
if err := fs.Source.MkdirAll(dir, 0777); err != nil {
return fmt.Errorf("Failed to create dir: %s", err)
return _errors.Wrap(err, "Failed to create dir")
}
}
@@ -130,10 +133,9 @@ func createConfig(fs *hugofs.Fs, inpath string, kind string) (err error) {
"title": "My New Hugo Site",
"languageCode": "en-us",
}
kind = parser.FormatSanitize(kind)
var buf bytes.Buffer
err = parser.InterfaceToConfig(in, parser.FormatToLeadRune(kind), &buf)
err = parser.InterfaceToConfig(in, metadecoders.FormatFromString(kind), &buf)
if err != nil {
return err
}
@@ -147,7 +149,7 @@ func nextStepsText() string {
nextStepsText.WriteString(`Just a few more steps and you're ready to go:
1. Download a theme into the same-named folder.
Choose a theme from https://themes.gohugo.io/, or
Choose a theme from https://themes.gohugo.io/ or
create your own with the "hugo new theme <THEMENAME>" command.
2. Perhaps you want to add some content. You can add single files
with "hugo new `)
+1 -1
View File
@@ -63,7 +63,7 @@ func (n *newThemeCmd) newTheme(cmd *cobra.Command, args []string) error {
return newUserError("theme name needs to be provided")
}
createpath := c.hugo.PathSpec.AbsPathify(filepath.Join(c.Cfg.GetString("themesDir"), args[0]))
createpath := c.hugo().PathSpec.AbsPathify(filepath.Join(c.Cfg.GetString("themesDir"), args[0]))
jww.FEEDBACK.Println("Creating theme at", createpath)
cfg := c.DepsCfg
+93 -32
View File
@@ -1,4 +1,4 @@
// Copyright 2018 The Hugo Authors. All rights reserved.
// Copyright 2019 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -14,13 +14,16 @@
package commands
import (
"bytes"
"fmt"
"io"
"net"
"net/http"
"net/url"
"os"
"os/signal"
"path/filepath"
"regexp"
"runtime"
"strconv"
"strings"
@@ -28,10 +31,11 @@ import (
"syscall"
"time"
"github.com/pkg/errors"
"github.com/gohugoio/hugo/livereload"
"github.com/gohugoio/hugo/config"
"github.com/gohugoio/hugo/helpers"
"github.com/spf13/afero"
"github.com/spf13/cobra"
@@ -52,7 +56,8 @@ type serverCmd struct {
serverWatch bool
noHTTPCache bool
disableFastRender bool
disableFastRender bool
disableBrowserError bool
*baseBuilderCmd
}
@@ -93,6 +98,7 @@ of a second, you will be able to save and see your changes nearly instantly.`,
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().BoolVar(&cc.disableBrowserError, "disableBrowserError", false, "do not show build errors in the browser")
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\".")
@@ -142,6 +148,9 @@ func (sc *serverCmd) server(cmd *cobra.Command, args []string) error {
if cmd.Flags().Changed("disableFastRender") {
c.Set("disableFastRender", sc.disableFastRender)
}
if cmd.Flags().Changed("disableBrowserError") {
c.Set("disableBrowserError", sc.disableBrowserError)
}
if sc.serverWatch {
c.Set("watch", true)
}
@@ -176,7 +185,7 @@ func (sc *serverCmd) server(cmd *cobra.Command, args []string) error {
// port set explicitly by user -- he/she probably meant it!
err = newSystemErrorF("Server startup failed: %s", err)
}
jww.ERROR.Println("port", sc.serverPort, "already in use, attempting to use an available port")
c.logger.FEEDBACK.Println("port", sc.serverPort, "already in use, attempting to use an available port")
sp, err := helpers.FindAvailablePort()
if err != nil {
err = newSystemError("Unable to find alternative port to use:", err)
@@ -223,7 +232,7 @@ func (sc *serverCmd) server(cmd *cobra.Command, args []string) error {
}
if err := memStats(); err != nil {
jww.ERROR.Println("memstats error:", err)
jww.WARN.Println("memstats error:", err)
}
c, err := initializeConfig(true, true, &sc.hugoBuilderCommon, sc, cfgInit)
@@ -235,7 +244,7 @@ func (sc *serverCmd) server(cmd *cobra.Command, args []string) error {
return err
}
for _, s := range c.hugo.Sites {
for _, s := range c.hugo().Sites {
s.RegisterMediaTypes()
}
@@ -247,15 +256,11 @@ func (sc *serverCmd) server(cmd *cobra.Command, args []string) error {
return err
}
baseWatchDir := c.Cfg.GetString("workingDir")
relWatchDirs := make([]string, len(watchDirs))
for i, dir := range watchDirs {
relWatchDirs[i], _ = helpers.GetRelativePath(dir, baseWatchDir)
watchGroups := helpers.ExtractAndGroupRootPaths(watchDirs)
for _, group := range watchGroups {
jww.FEEDBACK.Printf("Watching for changes in %s\n", group)
}
rootWatchDirs := strings.Join(helpers.UniqueStrings(helpers.ExtractRootPaths(relWatchDirs)), ",")
jww.FEEDBACK.Printf("Watching for changes in %s%s{%s}\n", baseWatchDir, helpers.FilePathSeparator, rootWatchDirs)
watcher, err := c.newWatcher(watchDirs...)
if err != nil {
@@ -270,11 +275,21 @@ func (sc *serverCmd) server(cmd *cobra.Command, args []string) error {
}
func getRootWatchDirsStr(baseDir string, watchDirs []string) string {
relWatchDirs := make([]string, len(watchDirs))
for i, dir := range watchDirs {
relWatchDirs[i], _ = helpers.GetRelativePath(dir, baseDir)
}
return strings.Join(helpers.UniqueStringsSorted(helpers.ExtractRootPaths(relWatchDirs)), ",")
}
type fileServer struct {
baseURLs []string
roots []string
c *commandeer
s *serverCmd
baseURLs []string
roots []string
errorTemplate func(err interface{}) (io.Reader, error)
c *commandeer
s *serverCmd
}
func (f *fileServer) createEndpoint(i int) (*http.ServeMux, string, string, error) {
@@ -288,7 +303,9 @@ func (f *fileServer) createEndpoint(i int) (*http.ServeMux, string, string, erro
publishDir = filepath.Join(publishDir, root)
}
absPublishDir := f.c.hugo.PathSpec.AbsPathify(publishDir)
absPublishDir := f.c.hugo().PathSpec.AbsPathify(publishDir)
jww.FEEDBACK.Printf("Environment: %q", f.c.hugo().Deps.Site.Hugo().Environment)
if i == 0 {
if f.s.renderToDisk {
@@ -301,30 +318,59 @@ func (f *fileServer) createEndpoint(i int) (*http.ServeMux, string, string, erro
httpFs := afero.NewHttpFs(f.c.destinationFs)
fs := filesOnlyFs{httpFs.Dir(absPublishDir)}
doLiveReload := !f.s.buildWatch && !f.c.Cfg.GetBool("disableLiveReload")
fastRenderMode := doLiveReload && !f.c.Cfg.GetBool("disableFastRender")
if i == 0 && fastRenderMode {
if i == 0 && f.c.fastRenderMode {
jww.FEEDBACK.Println("Running in Fast Render Mode. For full rebuilds on change: hugo server --disableFastRender")
}
// We're only interested in the path
u, err := url.Parse(baseURL)
if err != nil {
return nil, "", "", fmt.Errorf("Invalid baseURL: %s", err)
return nil, "", "", errors.Wrap(err, "Invalid baseURL")
}
decorate := func(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if f.c.showErrorInBrowser {
// First check the error state
err := f.c.getErrorWithContext()
if err != nil {
f.c.wasError = true
w.WriteHeader(500)
r, err := f.errorTemplate(err)
if err != nil {
f.c.logger.ERROR.Println(err)
}
port = 1313
if !f.c.paused {
port = f.c.Cfg.GetInt("liveReloadPort")
}
fmt.Fprint(w, injectLiveReloadScript(r, port))
return
}
}
if f.s.noHTTPCache {
w.Header().Set("Cache-Control", "no-store, no-cache, must-revalidate, max-age=0")
w.Header().Set("Pragma", "no-cache")
}
if fastRenderMode {
if f.c.fastRenderMode && f.c.buildErr == nil {
p := r.RequestURI
if strings.HasSuffix(p, "/") || strings.HasSuffix(p, "html") || strings.HasSuffix(p, "htm") {
if !f.c.visitedURLs.Contains(p) {
// If not already on stack, re-render that single page.
if err := f.c.partialReRender(p); err != nil {
f.c.handleBuildErr(err, fmt.Sprintf("Failed to render %q", p))
if f.c.showErrorInBrowser {
http.Redirect(w, r, p, http.StatusMovedPermanently)
return
}
}
}
f.c.visitedURLs.Add(p)
}
}
h.ServeHTTP(w, r)
@@ -345,9 +391,14 @@ func (f *fileServer) createEndpoint(i int) (*http.ServeMux, string, string, erro
return mu, u.String(), endpoint, nil
}
var logErrorRe = regexp.MustCompile(`(?s)ERROR \d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} `)
func removeErrorPrefixFromLog(content string) string {
return logErrorRe.ReplaceAllLiteralString(content, "")
}
func (c *commandeer) serve(s *serverCmd) error {
isMultiHost := c.hugo.IsMultihost()
isMultiHost := c.hugo().IsMultihost()
var (
baseURLs []string
@@ -355,21 +406,31 @@ func (c *commandeer) serve(s *serverCmd) error {
)
if isMultiHost {
for _, s := range c.hugo.Sites {
for _, s := range c.hugo().Sites {
baseURLs = append(baseURLs, s.BaseURL.String())
roots = append(roots, s.Language.Lang)
roots = append(roots, s.Language().Lang)
}
} else {
s := c.hugo.Sites[0]
s := c.hugo().Sites[0]
baseURLs = []string{s.BaseURL.String()}
roots = []string{""}
}
templ, err := c.hugo().TextTmpl.Parse("__default_server_error", buildErrorTemplate)
if err != nil {
return err
}
srv := &fileServer{
baseURLs: baseURLs,
roots: roots,
c: c,
s: s,
errorTemplate: func(ctx interface{}) (io.Reader, error) {
b := &bytes.Buffer{}
err := c.hugo().Tmpl.Execute(templ, b, ctx)
return b, err
},
}
doLiveReload := !c.Cfg.GetBool("disableLiveReload")
@@ -378,7 +439,7 @@ func (c *commandeer) serve(s *serverCmd) error {
livereload.Initialize()
}
var sigs = make(chan os.Signal)
var sigs = make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
for i := range baseURLs {
@@ -392,7 +453,7 @@ func (c *commandeer) serve(s *serverCmd) error {
go func() {
err = http.ListenAndServe(endpoint, mu)
if err != nil {
jww.ERROR.Printf("Error: %s\n", err.Error())
c.logger.ERROR.Printf("Error: %s\n", err.Error())
os.Exit(1)
}
}()
@@ -453,7 +514,7 @@ func (sc *serverCmd) fixURL(cfg config.Provider, s string, port int) (string, er
if strings.Contains(u.Host, ":") {
u.Host, _, err = net.SplitHostPort(u.Host)
if err != nil {
return "", fmt.Errorf("Failed to split baseURL hostpost: %s", err)
return "", errors.Wrap(err, "Failed to split baseURL hostpost")
}
}
u.Host += fmt.Sprintf(":%d", port)
+95
View File
@@ -0,0 +1,95 @@
// 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"
"io"
"github.com/gohugoio/hugo/transform"
"github.com/gohugoio/hugo/transform/livereloadinject"
)
var buildErrorTemplate = `<!doctype html>
<html class="no-js" lang="">
<head>
<meta charset="utf-8">
<title>Hugo Server: Error</title>
<style type="text/css">
body {
font-family: "Muli",avenir, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
font-size: 16px;
background-color: black;
color: rgba(255, 255, 255, 0.9);
}
main {
margin: auto;
width: 95%;
padding: 1rem;
}
.version {
color: #ccc;
padding: 1rem 0;
}
.stack {
margin-top: 6rem;
}
pre {
white-space: pre-wrap;
white-space: -moz-pre-wrap;
white-space: -pre-wrap;
white-space: -o-pre-wrap;
word-wrap: break-word;
}
.highlight {
overflow-x: auto;
padding: 0.75rem;
margin-bottom: 1rem;
background-color: #272822;
border: 1px solid black;
}
a {
color: #0594cb;
text-decoration: none;
}
a:hover {
color: #ccc;
}
</style>
</head>
<body>
<main>
{{ highlight .Error "apl" "noclasses=true,style=monokai" }}
{{ with .File }}
{{ $params := printf "noclasses=true,style=monokai,linenos=table,hl_lines=%d,linenostart=%d" (add .LinesPos 1) (sub .Position.LineNumber .LinesPos) }}
{{ $lexer := .ChromaLexer | default "go-html-template" }}
{{ highlight (delimit .Lines "\n") $lexer $params }}
{{ end }}
{{ with .StackTrace }}
{{ highlight . "apl" "noclasses=true,style=monokai" }}
{{ end }}
<p class="version">{{ .Version }}</p>
<a href="">Reload Page</a>
</main>
</body>
</html>
`
func injectLiveReloadScript(src io.Reader, port int) string {
var b bytes.Buffer
chain := transform.Chain{livereloadinject.New(port)}
chain.Apply(&b, src)
return b.String()
}
+38 -22
View File
@@ -18,13 +18,14 @@ import (
"net/http"
"os"
"runtime"
"strings"
"testing"
"time"
"github.com/gohugoio/hugo/helpers"
qt "github.com/frankban/quicktest"
"github.com/spf13/viper"
"github.com/stretchr/testify/require"
)
func TestServer(t *testing.T) {
@@ -32,9 +33,9 @@ func TestServer(t *testing.T) {
// TODO(bep) not sure why server tests have started to fail on the Windows CI server.
t.Skip("Skip server test on appveyor")
}
assert := require.New(t)
dir, err := createSimpleTestSite(t)
assert.NoError(err)
c := qt.New(t)
dir, err := createSimpleTestSite(t, testSiteConfig{})
c.Assert(err, qt.IsNil)
// Let us hope that this port is available on all systems ...
port := 1331
@@ -53,7 +54,7 @@ func TestServer(t *testing.T) {
go func() {
_, err = cmd.ExecuteC()
assert.NoError(err)
c.Assert(err, qt.IsNil)
}()
// There is no way to know exactly when the server is ready for connections.
@@ -62,11 +63,12 @@ func TestServer(t *testing.T) {
time.Sleep(2 * time.Second)
resp, err := http.Get("http://localhost:1331/")
assert.NoError(err)
c.Assert(err, qt.IsNil)
defer resp.Body.Close()
homeContent := helpers.ReaderToString(resp.Body)
assert.Contains(homeContent, "List: Hugo Commands")
c.Assert(homeContent, qt.Contains, "List: Hugo Commands")
c.Assert(homeContent, qt.Contains, "Environment: development")
// Stop the server.
stop <- true
@@ -95,24 +97,38 @@ func TestFixURL(t *testing.T) {
{"No config", "", "", true, 1313, "//localhost:1313/"},
}
for i, test := range tests {
b := newCommandsBuilder()
s := b.newServerCmd()
v := viper.New()
baseURL := test.CLIBaseURL
v.Set("baseURL", test.CfgBaseURL)
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)
}
if result != test.Result {
t.Errorf("Test #%d %s: expected %q, got %q", i, test.TestName, test.Result, result)
}
for _, test := range tests {
t.Run(test.TestName, func(t *testing.T) {
b := newCommandsBuilder()
s := b.newServerCmd()
v := viper.New()
baseURL := test.CLIBaseURL
v.Set("baseURL", test.CfgBaseURL)
s.serverAppend = test.AppendPort
s.serverPort = test.Port
result, err := s.fixURL(v, baseURL, s.serverPort)
if err != nil {
t.Errorf("Unexpected error %s", err)
}
if result != test.Result {
t.Errorf("Expected %q, got %q", test.Result, result)
}
})
}
}
func TestRemoveErrorPrefixFromLog(t *testing.T) {
c := qt.New(t)
content := `ERROR 2018/10/07 13:11:12 Error while rendering "home": template: _default/baseof.html:4:3: executing "main" at <partial "logo" .>: error calling partial: template: partials/logo.html:5:84: executing "partials/logo.html" at <$resized.AHeight>: can't evaluate field AHeight in type *resource.Image
ERROR 2018/10/07 13:11:12 Rebuild failed: logged 1 error(s)
`
withoutError := removeErrorPrefixFromLog(content)
c.Assert(strings.Contains(withoutError, "ERROR"), qt.Equals, false)
}
func isWindowsCI() bool {
return runtime.GOOS == "windows" && os.Getenv("CI") != ""
}
+7 -5
View File
@@ -33,14 +33,14 @@ func newStaticSyncer(c *commandeer) (*staticSyncer, error) {
}
func (s *staticSyncer) isStatic(filename string) bool {
return s.c.hugo.BaseFs.SourceFilesystems.IsStatic(filename)
return s.c.hugo().BaseFs.SourceFilesystems.IsStatic(filename)
}
func (s *staticSyncer) syncsStaticEvents(staticEvents []fsnotify.Event) error {
c := s.c
syncFn := func(sourceFs *filesystems.SourceFilesystem) (uint64, error) {
publishDir := c.hugo.PathSpec.PublishDir
publishDir := c.hugo().PathSpec.PublishDir
// If root, remove the second '/'
if publishDir == "//" {
publishDir = helpers.FilePathSeparator
@@ -53,6 +53,7 @@ func (s *staticSyncer) syncsStaticEvents(staticEvents []fsnotify.Event) error {
syncer := fsync.NewSyncer()
syncer.NoTimes = c.Cfg.GetBool("noTimes")
syncer.NoChmod = c.Cfg.GetBool("noChmod")
syncer.ChmodFilter = chmodFilter
syncer.SrcFs = sourceFs.Fs
syncer.DestFs = c.Fs.Destination
@@ -79,6 +80,7 @@ func (s *staticSyncer) syncsStaticEvents(staticEvents []fsnotify.Event) error {
fromPath := ev.Name
relPath := sourceFs.MakePathRelative(fromPath)
if relPath == "" {
// Not member of this virtual host.
continue
@@ -105,10 +107,10 @@ func (s *staticSyncer) syncsStaticEvents(staticEvents []fsnotify.Event) error {
logger.Println("Syncing", relPath, "to", publishDir)
if err := syncer.Sync(filepath.Join(publishDir, relPath), relPath); err != nil {
c.Logger.ERROR.Println(err)
c.logger.ERROR.Println(err)
}
} else {
c.Logger.ERROR.Println(err)
c.logger.ERROR.Println(err)
}
continue
@@ -117,7 +119,7 @@ func (s *staticSyncer) syncsStaticEvents(staticEvents []fsnotify.Event) error {
// For all other event operations Hugo will sync static.
logger.Println("Syncing", relPath, "to", publishDir)
if err := syncer.Sync(filepath.Join(publishDir, relPath), relPath); err != nil {
c.Logger.ERROR.Println(err)
c.logger.ERROR.Println(err)
}
}
+2 -26
View File
@@ -14,12 +14,7 @@
package commands
import (
"runtime"
"strings"
"github.com/gohugoio/hugo/helpers"
"github.com/gohugoio/hugo/hugolib"
"github.com/gohugoio/hugo/resource/tocss/scss"
"github.com/gohugoio/hugo/common/hugo"
"github.com/spf13/cobra"
jww "github.com/spf13/jwalterweatherman"
)
@@ -45,24 +40,5 @@ func newVersionCmd() *versionCmd {
}
func printHugoVersion() {
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)
jww.FEEDBACK.Println(hugo.BuildVersionString())
}
+33 -3
View File
@@ -1,4 +1,4 @@
// Copyright 2018 The Hugo Authors. All rights reserved.
// Copyright 2019 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -19,7 +19,7 @@ import (
)
// Append appends from to a slice to and returns the resulting slice.
// If lenght of from is one and the only element is a slice of same type as to,
// If length of from is one and the only element is a slice of same type as to,
// it will be appended.
func Append(to interface{}, from ...interface{}) (interface{}, error) {
tov, toIsNil := indirect(reflect.ValueOf(to))
@@ -48,6 +48,10 @@ func Append(to interface{}, from ...interface{}) (interface{}, error) {
// If we get []string []string, we append the from slice to to
if tot == fromt {
return reflect.AppendSlice(tov, fromv).Interface(), nil
} else if !fromt.AssignableTo(tot) {
// Fall back to a []interface{} slice.
return appendToInterfaceSliceFromValues(tov, fromv)
}
}
}
@@ -60,7 +64,9 @@ func Append(to interface{}, from ...interface{}) (interface{}, error) {
for _, f := range from {
fv := reflect.ValueOf(f)
if !fv.Type().AssignableTo(tot) {
return nil, fmt.Errorf("append element type mismatch: expected %v, got %v", tot, fv.Type())
// Fall back to a []interface{} slice.
tov, _ := indirect(reflect.ValueOf(to))
return appendToInterfaceSlice(tov, from...)
}
tov = reflect.Append(tov, fv)
}
@@ -68,6 +74,30 @@ func Append(to interface{}, from ...interface{}) (interface{}, error) {
return tov.Interface(), nil
}
func appendToInterfaceSliceFromValues(slice1, slice2 reflect.Value) ([]interface{}, error) {
var tos []interface{}
for _, slice := range []reflect.Value{slice1, slice2} {
for i := 0; i < slice.Len(); i++ {
tos = append(tos, slice.Index(i).Interface())
}
}
return tos, nil
}
func appendToInterfaceSlice(tov reflect.Value, from ...interface{}) ([]interface{}, error) {
var tos []interface{}
for i := 0; i < tov.Len(); i++ {
tos = append(tos, tov.Index(i).Interface())
}
tos = append(tos, from...)
return tos, nil
}
// indirect is borrowed from the Go stdlib: 'text/template/exec.go'
// TODO(bep) consolidate
func indirect(v reflect.Value) (rv reflect.Value, isNil bool) {
+14 -15
View File
@@ -14,17 +14,17 @@
package collections
import (
"fmt"
"reflect"
"html/template"
"testing"
"github.com/stretchr/testify/require"
qt "github.com/frankban/quicktest"
)
func TestAppend(t *testing.T) {
t.Parallel()
c := qt.New(t)
for i, test := range []struct {
for _, test := range []struct {
start interface{}
addend []interface{}
expected interface{}
@@ -32,6 +32,7 @@ func TestAppend(t *testing.T) {
{[]string{"a", "b"}, []interface{}{"c"}, []string{"a", "b", "c"}},
{[]string{"a", "b"}, []interface{}{"c", "d", "e"}, []string{"a", "b", "c", "d", "e"}},
{[]string{"a", "b"}, []interface{}{[]string{"c", "d", "e"}}, []string{"a", "b", "c", "d", "e"}},
{[]string{"a"}, []interface{}{"b", template.HTML("c")}, []interface{}{"a", "b", template.HTML("c")}},
{nil, []interface{}{"a", "b"}, []string{"a", "b"}},
{nil, []interface{}{nil}, []interface{}{nil}},
{[]interface{}{}, []interface{}{[]string{"c", "d", "e"}}, []string{"c", "d", "e"}},
@@ -46,10 +47,12 @@ func TestAppend(t *testing.T) {
{testSlicerInterfaces{&tstSlicerIn1{"a"}, &tstSlicerIn1{"b"}},
[]interface{}{&tstSlicerIn1{"c"}},
testSlicerInterfaces{&tstSlicerIn1{"a"}, &tstSlicerIn1{"b"}, &tstSlicerIn1{"c"}}},
//https://github.com/gohugoio/hugo/issues/5361
{[]string{"a", "b"}, []interface{}{tstSlicers{&tstSlicer{"a"}, &tstSlicer{"b"}}},
[]interface{}{"a", "b", &tstSlicer{"a"}, &tstSlicer{"b"}}},
{[]string{"a", "b"}, []interface{}{&tstSlicer{"a"}},
[]interface{}{"a", "b", &tstSlicer{"a"}}},
// Errors
{testSlicerInterfaces{&tstSlicerIn1{"a"}, &tstSlicerIn1{"b"}},
[]interface{}{"c"},
false},
{"", []interface{}{[]string{"a", "b"}}, false},
// No string concatenation.
{"ab",
@@ -57,20 +60,16 @@ func TestAppend(t *testing.T) {
false},
} {
errMsg := fmt.Sprintf("[%d]", i)
result, err := Append(test.start, test.addend...)
if b, ok := test.expected.(bool); ok && !b {
require.Error(t, err, errMsg)
c.Assert(err, qt.Not(qt.IsNil))
continue
}
require.NoError(t, err, errMsg)
if !reflect.DeepEqual(test.expected, result) {
t.Fatalf("%s got\n%T: %v\nexpected\n%T: %v", errMsg, result, result, test.expected, test.expected)
}
c.Assert(err, qt.IsNil)
c.Assert(result, qt.DeepEquals, test.expected)
}
}
+1 -1
View File
@@ -17,7 +17,7 @@ import (
"reflect"
)
// Slicer definse a very generic way to create a typed slice. This is used
// Slicer defines a very generic way to create a typed slice. This is used
// in collections.Slice template func to get types such as Pages, PageGroups etc.
// instead of the less useful []interface{}.
type Slicer interface {
+10 -11
View File
@@ -1,4 +1,4 @@
// Copyright 2018 The Hugo Authors. All rights reserved.
// Copyright 2019 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -15,10 +15,9 @@ package collections
import (
"errors"
"fmt"
"testing"
"github.com/alecthomas/assert"
qt "github.com/frankban/quicktest"
)
var _ Slicer = (*tstSlicer)(nil)
@@ -34,15 +33,15 @@ type testSlicerInterface interface {
type testSlicerInterfaces []testSlicerInterface
type tstSlicerIn1 struct {
name string
TheName string
}
type tstSlicerIn2 struct {
name string
TheName string
}
type tstSlicer struct {
name string
TheName string
}
func (p *tstSlicerIn1) Slice(in interface{}) (interface{}, error) {
@@ -75,11 +74,11 @@ func (p *tstSlicerIn2) Slice(in interface{}) (interface{}, error) {
}
func (p *tstSlicerIn1) Name() string {
return p.Name()
return p.TheName
}
func (p *tstSlicerIn2) Name() string {
return p.Name()
return p.TheName
}
func (p *tstSlicer) Slice(in interface{}) (interface{}, error) {
@@ -100,6 +99,7 @@ type tstSlicers []*tstSlicer
func TestSlice(t *testing.T) {
t.Parallel()
c := qt.New(t)
for i, test := range []struct {
args []interface{}
@@ -114,12 +114,11 @@ func TestSlice(t *testing.T) {
{[]interface{}{&tstSlicerIn1{"a"}, &tstSlicerIn2{"b"}}, testSlicerInterfaces{&tstSlicerIn1{"a"}, &tstSlicerIn2{"b"}}},
{[]interface{}{&tstSlicerIn1{"a"}, &tstSlicer{"b"}}, []interface{}{&tstSlicerIn1{"a"}, &tstSlicer{"b"}}},
} {
errMsg := fmt.Sprintf("[%d] %v", i, test.args)
errMsg := qt.Commentf("[%d] %v", i, test.args)
result := Slice(test.args...)
assert.Equal(t, test.expected, result, errMsg)
c.Assert(test.expected, qt.DeepEquals, result, errMsg)
}
assert.Len(t, Slice(), 0)
}
+255
View File
@@ -0,0 +1,255 @@
// 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 herrors
import (
"io"
"io/ioutil"
"path/filepath"
"strings"
"github.com/gohugoio/hugo/common/text"
"github.com/spf13/afero"
)
// LineMatcher contains the elements used to match an error to a line
type LineMatcher struct {
Position text.Position
Error error
LineNumber int
Offset int
Line string
}
// LineMatcherFn is used to match a line with an error.
type LineMatcherFn func(m LineMatcher) bool
// SimpleLineMatcher simply matches by line number.
var SimpleLineMatcher = func(m LineMatcher) bool {
return m.Position.LineNumber == m.LineNumber
}
var _ text.Positioner = ErrorContext{}
// ErrorContext contains contextual information about an error. This will
// typically be the lines surrounding some problem in a file.
type ErrorContext struct {
// If a match will contain the matched line and up to 2 lines before and after.
// Will be empty if no match.
Lines []string
// The position of the error in the Lines above. 0 based.
LinesPos int
position text.Position
// The lexer to use for syntax highlighting.
// https://gohugo.io/content-management/syntax-highlighting/#list-of-chroma-highlighting-languages
ChromaLexer string
}
// Position returns the text position of this error.
func (e ErrorContext) Position() text.Position {
return e.position
}
var _ causer = (*ErrorWithFileContext)(nil)
// ErrorWithFileContext is an error with some additional file context related
// to that error.
type ErrorWithFileContext struct {
cause error
ErrorContext
}
func (e *ErrorWithFileContext) Error() string {
pos := e.Position()
if pos.IsValid() {
return pos.String() + ": " + e.cause.Error()
}
return e.cause.Error()
}
func (e *ErrorWithFileContext) Cause() error {
return e.cause
}
// WithFileContextForFile will try to add a file context with lines matching the given matcher.
// If no match could be found, the original error is returned with false as the second return value.
func WithFileContextForFile(e error, realFilename, filename string, fs afero.Fs, matcher LineMatcherFn) (error, bool) {
f, err := fs.Open(filename)
if err != nil {
return e, false
}
defer f.Close()
return WithFileContext(e, realFilename, f, matcher)
}
// WithFileContextForFile will try to add a file context with lines matching the given matcher.
// If no match could be found, the original error is returned with false as the second return value.
func WithFileContext(e error, realFilename string, r io.Reader, matcher LineMatcherFn) (error, bool) {
if e == nil {
panic("error missing")
}
le := UnwrapFileError(e)
if le == nil {
var ok bool
if le, ok = ToFileError("", e).(FileError); !ok {
return e, false
}
}
var errCtx ErrorContext
posle := le.Position()
if posle.Offset != -1 {
errCtx = locateError(r, le, func(m LineMatcher) bool {
if posle.Offset >= m.Offset && posle.Offset < m.Offset+len(m.Line) {
lno := posle.LineNumber - m.Position.LineNumber + m.LineNumber
m.Position = text.Position{LineNumber: lno}
}
return matcher(m)
})
} else {
errCtx = locateError(r, le, matcher)
}
pos := &errCtx.position
if pos.LineNumber == -1 {
return e, false
}
pos.Filename = realFilename
if le.Type() != "" {
errCtx.ChromaLexer = chromaLexerFromType(le.Type())
} else {
errCtx.ChromaLexer = chromaLexerFromFilename(realFilename)
}
return &ErrorWithFileContext{cause: e, ErrorContext: errCtx}, true
}
// UnwrapErrorWithFileContext tries to unwrap an ErrorWithFileContext from err.
// It returns nil if this is not possible.
func UnwrapErrorWithFileContext(err error) *ErrorWithFileContext {
for err != nil {
switch v := err.(type) {
case *ErrorWithFileContext:
return v
case causer:
err = v.Cause()
default:
return nil
}
}
return nil
}
func chromaLexerFromType(fileType string) string {
switch fileType {
case "html", "htm":
return "go-html-template"
}
return fileType
}
func extNoDelimiter(filename string) string {
return strings.TrimPrefix(filepath.Ext(filename), ".")
}
func chromaLexerFromFilename(filename string) string {
if strings.Contains(filename, "layouts") {
return "go-html-template"
}
ext := extNoDelimiter(filename)
return chromaLexerFromType(ext)
}
func locateErrorInString(src string, matcher LineMatcherFn) ErrorContext {
return locateError(strings.NewReader(src), &fileError{}, matcher)
}
func locateError(r io.Reader, le FileError, matches LineMatcherFn) ErrorContext {
if le == nil {
panic("must provide an error")
}
errCtx := ErrorContext{position: text.Position{LineNumber: -1, ColumnNumber: 1, Offset: -1}, LinesPos: -1}
b, err := ioutil.ReadAll(r)
if err != nil {
return errCtx
}
pos := &errCtx.position
lepos := le.Position()
lines := strings.Split(string(b), "\n")
if lepos.ColumnNumber >= 0 {
pos.ColumnNumber = lepos.ColumnNumber
}
lineNo := 0
posBytes := 0
for li, line := range lines {
lineNo = li + 1
m := LineMatcher{
Position: le.Position(),
Error: le,
LineNumber: lineNo,
Offset: posBytes,
Line: line,
}
if errCtx.LinesPos == -1 && matches(m) {
pos.LineNumber = lineNo
break
}
posBytes += len(line)
}
if pos.LineNumber != -1 {
low := pos.LineNumber - 3
if low < 0 {
low = 0
}
if pos.LineNumber > 2 {
errCtx.LinesPos = 2
} else {
errCtx.LinesPos = pos.LineNumber - 1
}
high := pos.LineNumber + 2
if high > len(lines) {
high = len(lines)
}
errCtx.Lines = lines[low:high]
}
return errCtx
}
+129
View File
@@ -0,0 +1,129 @@
// 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 herrors
import (
"strings"
"testing"
qt "github.com/frankban/quicktest"
)
func TestErrorLocator(t *testing.T) {
c := qt.New(t)
lineMatcher := func(m LineMatcher) bool {
return strings.Contains(m.Line, "THEONE")
}
lines := `LINE 1
LINE 2
LINE 3
LINE 4
This is THEONE
LINE 6
LINE 7
LINE 8
`
location := locateErrorInString(lines, lineMatcher)
c.Assert(location.Lines, qt.DeepEquals, []string{"LINE 3", "LINE 4", "This is THEONE", "LINE 6", "LINE 7"})
pos := location.Position()
c.Assert(pos.LineNumber, qt.Equals, 5)
c.Assert(location.LinesPos, qt.Equals, 2)
c.Assert(locateErrorInString(`This is THEONE`, lineMatcher).Lines, qt.DeepEquals, []string{"This is THEONE"})
location = locateErrorInString(`L1
This is THEONE
L2
`, lineMatcher)
c.Assert(location.Position().LineNumber, qt.Equals, 2)
c.Assert(location.LinesPos, qt.Equals, 1)
c.Assert(location.Lines, qt.DeepEquals, []string{"L1", "This is THEONE", "L2", ""})
location = locateErrorInString(`This is THEONE
L2
`, lineMatcher)
c.Assert(location.LinesPos, qt.Equals, 0)
c.Assert(location.Lines, qt.DeepEquals, []string{"This is THEONE", "L2", ""})
location = locateErrorInString(`L1
This THEONE
`, lineMatcher)
c.Assert(location.Lines, qt.DeepEquals, []string{"L1", "This THEONE", ""})
c.Assert(location.LinesPos, qt.Equals, 1)
location = locateErrorInString(`L1
L2
This THEONE
`, lineMatcher)
c.Assert(location.Lines, qt.DeepEquals, []string{"L1", "L2", "This THEONE", ""})
c.Assert(location.LinesPos, qt.Equals, 2)
location = locateErrorInString("NO MATCH", lineMatcher)
c.Assert(location.Position().LineNumber, qt.Equals, -1)
c.Assert(location.LinesPos, qt.Equals, -1)
c.Assert(len(location.Lines), qt.Equals, 0)
lineMatcher = func(m LineMatcher) bool {
return m.LineNumber == 6
}
location = locateErrorInString(`A
B
C
D
E
F
G
H
I
J`, lineMatcher)
c.Assert(location.Lines, qt.DeepEquals, []string{"D", "E", "F", "G", "H"})
c.Assert(location.Position().LineNumber, qt.Equals, 6)
c.Assert(location.LinesPos, qt.Equals, 2)
// Test match EOF
lineMatcher = func(m LineMatcher) bool {
return m.LineNumber == 4
}
location = locateErrorInString(`A
B
C
`, lineMatcher)
c.Assert(location.Lines, qt.DeepEquals, []string{"B", "C", ""})
c.Assert(location.Position().LineNumber, qt.Equals, 4)
c.Assert(location.LinesPos, qt.Equals, 2)
offsetMatcher := func(m LineMatcher) bool {
return m.Offset == 1
}
location = locateErrorInString(`A
B
C
D
E`, offsetMatcher)
c.Assert(location.Lines, qt.DeepEquals, []string{"A", "B", "C", "D"})
c.Assert(location.Position().LineNumber, qt.Equals, 2)
c.Assert(location.LinesPos, qt.Equals, 1)
}
+66
View File
@@ -0,0 +1,66 @@
// 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 herrors contains common Hugo errors and error related utilities.
package herrors
import (
"errors"
"fmt"
"io"
"os"
"runtime/debug"
_errors "github.com/pkg/errors"
)
// As defined in https://godoc.org/github.com/pkg/errors
type causer interface {
Cause() error
}
type stackTracer interface {
StackTrace() _errors.StackTrace
}
// PrintStackTrace prints the error's stack trace to stdoud.
func PrintStackTrace(err error) {
FprintStackTrace(os.Stdout, err)
}
// FprintStackTrace prints the error's stack trace to w.
func FprintStackTrace(w io.Writer, err error) {
if err, ok := err.(stackTracer); ok {
for _, f := range err.StackTrace() {
fmt.Fprintf(w, "%+s:%d\n", f, f)
}
}
}
// Recover is a helper function that can be used to capture panics.
// Put this at the top of a method/function that crashes in a template:
// defer herrors.Recover()
func Recover(args ...interface{}) {
if r := recover(); r != nil {
fmt.Println("ERR:", r)
args = append(args, "stacktrace from panic: \n"+string(debug.Stack()), "\n")
fmt.Println(args...)
}
}
// ErrFeatureNotAvailable denotes that a feature is unavailable.
//
// 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 ErrFeatureNotAvailable = errors.New("this feature is not available in your current Hugo version, see https://goo.gl/YMrWcn for more information")
+133
View File
@@ -0,0 +1,133 @@
// 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
// limitatio ns under the License.
package herrors
import (
"encoding/json"
"github.com/gohugoio/hugo/common/text"
"github.com/pkg/errors"
)
var (
_ causer = (*fileError)(nil)
)
// FileError represents an error when handling a file: Parsing a config file,
// execute a template etc.
type FileError interface {
error
text.Positioner
// A string identifying the type of file, e.g. JSON, TOML, markdown etc.
Type() string
}
var _ FileError = (*fileError)(nil)
type fileError struct {
position text.Position
fileType string
cause error
}
// Position returns the text position of this error.
func (e fileError) Position() text.Position {
return e.position
}
func (e *fileError) Type() string {
return e.fileType
}
func (e *fileError) Error() string {
if e.cause == nil {
return ""
}
return e.cause.Error()
}
func (f *fileError) Cause() error {
return f.cause
}
// NewFileError creates a new FileError.
func NewFileError(fileType string, offset, lineNumber, columnNumber int, err error) FileError {
pos := text.Position{Offset: offset, LineNumber: lineNumber, ColumnNumber: columnNumber}
return &fileError{cause: err, fileType: fileType, position: pos}
}
// UnwrapFileError tries to unwrap a FileError from err.
// It returns nil if this is not possible.
func UnwrapFileError(err error) FileError {
for err != nil {
switch v := err.(type) {
case FileError:
return v
case causer:
err = v.Cause()
default:
return nil
}
}
return nil
}
// ToFileErrorWithOffset will return a new FileError with a line number
// with the given offset from the original.
func ToFileErrorWithOffset(fe FileError, offset int) FileError {
pos := fe.Position()
return ToFileErrorWithLineNumber(fe, pos.LineNumber+offset)
}
// ToFileErrorWithOffset will return a new FileError with the given line number.
func ToFileErrorWithLineNumber(fe FileError, lineNumber int) FileError {
pos := fe.Position()
pos.LineNumber = lineNumber
return &fileError{cause: fe, fileType: fe.Type(), position: pos}
}
// ToFileError will convert the given error to an error supporting
// the FileError interface.
func ToFileError(fileType string, err error) FileError {
for _, handle := range lineNumberExtractors {
lno, col := handle(err)
offset, typ := extractOffsetAndType(err)
if fileType == "" {
fileType = typ
}
if lno > 0 || offset != -1 {
return NewFileError(fileType, offset, lno, col, err)
}
}
// Fall back to the pointing to line number 1.
return NewFileError(fileType, -1, 1, 1, err)
}
func extractOffsetAndType(e error) (int, string) {
e = errors.Cause(e)
switch v := e.(type) {
case *json.UnmarshalTypeError:
return int(v.Offset), "json"
case *json.SyntaxError:
return int(v.Offset), "json"
default:
return -1, ""
}
}
+56
View File
@@ -0,0 +1,56 @@
// 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 herrors
import (
"testing"
"github.com/pkg/errors"
qt "github.com/frankban/quicktest"
)
func TestToLineNumberError(t *testing.T) {
t.Parallel()
c := qt.New(t)
for i, test := range []struct {
in error
offset int
lineNumber int
columnNumber int
}{
{errors.New("no line number for you"), 0, 1, 1},
{errors.New(`template: _default/single.html:4:15: executing "_default/single.html" at <.Titles>: can't evaluate field Titles in type *hugolib.PageOutput`), 0, 4, 15},
{errors.New("parse failed: template: _default/bundle-resource-meta.html:11: unexpected in operand"), 0, 11, 1},
{errors.New(`failed:: template: _default/bundle-resource-meta.html:2:7: executing "main" at <.Titles>`), 0, 2, 7},
{errors.New("error in front matter: Near line 32 (last key parsed 'title')"), 0, 32, 1},
{errors.New(`failed to load translations: (6, 7): was expecting token =, but got "g" instead`), 0, 6, 7},
} {
got := ToFileError("template", test.in)
errMsg := qt.Commentf("[%d][%T]", i, got)
le, ok := got.(FileError)
c.Assert(ok, qt.Equals, true)
c.Assert(ok, qt.Equals, true, errMsg)
pos := le.Position()
c.Assert(pos.LineNumber, qt.Equals, test.lineNumber, errMsg)
c.Assert(pos.ColumnNumber, qt.Equals, test.columnNumber, errMsg)
c.Assert(errors.Cause(got), qt.Not(qt.IsNil))
}
}
+66
View File
@@ -0,0 +1,66 @@
// 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
// limitatio ns under the License.
package herrors
import (
"regexp"
"strconv"
)
var lineNumberExtractors = []lineNumberExtractor{
// Template/shortcode parse errors
newLineNumberErrHandlerFromRegexp(".*:(\\d+):(\\d*):"),
newLineNumberErrHandlerFromRegexp(".*:(\\d+):"),
// TOML parse errors
newLineNumberErrHandlerFromRegexp(".*Near line (\\d+)(\\s.*)"),
// YAML parse errors
newLineNumberErrHandlerFromRegexp("line (\\d+):"),
// i18n bundle errors
newLineNumberErrHandlerFromRegexp("\\((\\d+),\\s(\\d*)"),
}
type lineNumberExtractor func(e error) (int, int)
func newLineNumberErrHandlerFromRegexp(expression string) lineNumberExtractor {
re := regexp.MustCompile(expression)
return extractLineNo(re)
}
func extractLineNo(re *regexp.Regexp) lineNumberExtractor {
return func(e error) (int, int) {
if e == nil {
panic("no error")
}
col := 1
s := e.Error()
m := re.FindStringSubmatch(s)
if len(m) >= 2 {
lno, _ := strconv.Atoi(m[1])
if len(m) > 2 {
col, _ = strconv.Atoi(m[2])
}
if col <= 0 {
col = 1
}
return lno, col
}
return -1, col
}
}
+91
View File
@@ -0,0 +1,91 @@
// Copyright 2019 The Hugo Authors. All rights reserved.
// Some functions in this file (see comments) is based on the Go source code,
// copyright The Go Authors and governed by a BSD-style license.
//
// 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 hreflect contains reflect helpers.
package hreflect
import (
"reflect"
"github.com/gohugoio/hugo/common/types"
)
// IsTruthful returns whether in represents a truthful value.
// See IsTruthfulValue
func IsTruthful(in interface{}) bool {
switch v := in.(type) {
case reflect.Value:
return IsTruthfulValue(v)
default:
return IsTruthfulValue(reflect.ValueOf(in))
}
}
var zeroType = reflect.TypeOf((*types.Zeroer)(nil)).Elem()
// IsTruthfulValue returns whether the given value has a meaningful truth value.
// This is based on template.IsTrue in Go's stdlib, but also considers
// IsZero and any interface value will be unwrapped before it's considered
// for truthfulness.
//
// Based on:
// https://github.com/golang/go/blob/178a2c42254166cffed1b25fb1d3c7a5727cada6/src/text/template/exec.go#L306
func IsTruthfulValue(val reflect.Value) (truth bool) {
val = indirectInterface(val)
if !val.IsValid() {
// Something like var x interface{}, never set. It's a form of nil.
return
}
if val.Type().Implements(zeroType) {
return !val.Interface().(types.Zeroer).IsZero()
}
switch val.Kind() {
case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
truth = val.Len() > 0
case reflect.Bool:
truth = val.Bool()
case reflect.Complex64, reflect.Complex128:
truth = val.Complex() != 0
case reflect.Chan, reflect.Func, reflect.Ptr, reflect.Interface:
truth = !val.IsNil()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
truth = val.Int() != 0
case reflect.Float32, reflect.Float64:
truth = val.Float() != 0
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
truth = val.Uint() != 0
case reflect.Struct:
truth = true // Struct values are always true.
default:
return
}
return
}
// Based on: https://github.com/golang/go/blob/178a2c42254166cffed1b25fb1d3c7a5727cada6/src/text/template/exec.go#L931
func indirectInterface(v reflect.Value) reflect.Value {
if v.Kind() != reflect.Interface {
return v
}
if v.IsNil() {
return reflect.Value{}
}
return v.Elem()
}
+42
View File
@@ -0,0 +1,42 @@
// Copyright 2019 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package hreflect
import (
"reflect"
"testing"
"time"
qt "github.com/frankban/quicktest"
)
func TestIsTruthful(t *testing.T) {
c := qt.New(t)
c.Assert(IsTruthful(true), qt.Equals, true)
c.Assert(IsTruthful(false), qt.Equals, false)
c.Assert(IsTruthful(time.Now()), qt.Equals, true)
c.Assert(IsTruthful(time.Time{}), qt.Equals, false)
}
func BenchmarkIsTruthFul(b *testing.B) {
v := reflect.ValueOf("Hugo")
b.ResetTimer()
for i := 0; i < b.N; i++ {
if !IsTruthfulValue(v) {
b.Fatal("not truthful")
}
}
}
+90
View File
@@ -0,0 +1,90 @@
// Copyright 2019 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package hugio
import (
"io"
"io/ioutil"
"os"
"path/filepath"
"github.com/pkg/errors"
"github.com/spf13/afero"
)
// CopyFile copies a file.
func CopyFile(fs afero.Fs, from, to string) error {
sf, err := os.Open(from)
if err != nil {
return err
}
defer sf.Close()
df, err := os.Create(to)
if err != nil {
return err
}
defer df.Close()
_, err = io.Copy(df, sf)
if err == nil {
si, err := os.Stat(from)
if err != nil {
err = os.Chmod(to, si.Mode())
if err != nil {
return err
}
}
}
return nil
}
// CopyDir copies a directory.
func CopyDir(fs afero.Fs, from, to string, shouldCopy func(filename string) bool) error {
fi, err := os.Stat(from)
if err != nil {
return err
}
if !fi.IsDir() {
return errors.Errorf("%q is not a directory", from)
}
err = fs.MkdirAll(to, 0777) // before umask
if err != nil {
return err
}
entries, _ := ioutil.ReadDir(from)
for _, entry := range entries {
fromFilename := filepath.Join(from, entry.Name())
toFilename := filepath.Join(to, entry.Name())
if entry.IsDir() {
if shouldCopy != nil && !shouldCopy(fromFilename) {
continue
}
if err := CopyDir(fs, fromFilename, toFilename, shouldCopy); err != nil {
return err
}
} else {
if err := CopyFile(fs, fromFilename, toFilename); err != nil {
return err
}
}
}
return nil
}
+2 -1
View File
@@ -1,4 +1,4 @@
// Copyright 2018 The Hugo Authors. All rights reserved.
// Copyright 2019 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -32,6 +32,7 @@ type ReadSeekCloser interface {
}
// ReadSeekerNoOpCloser implements ReadSeekCloser by doing nothing in Close.
// TODO(bep) rename this and simila to ReadSeekerNopCloser, naming used in stdlib, which kind of makes sense.
type ReadSeekerNoOpCloser struct {
ReadSeeker
}
+33
View File
@@ -15,6 +15,7 @@ package hugio
import (
"io"
"io/ioutil"
)
type multiWriteCloser struct {
@@ -41,3 +42,35 @@ func NewMultiWriteCloser(writeClosers ...io.WriteCloser) io.WriteCloser {
}
return multiWriteCloser{Writer: io.MultiWriter(writers...), closers: writeClosers}
}
// ToWriteCloser creates an io.WriteCloser from the given io.Writer.
// If it's not already, one will be created with a Close method that does nothing.
func ToWriteCloser(w io.Writer) io.WriteCloser {
if rw, ok := w.(io.WriteCloser); ok {
return rw
}
return struct {
io.Writer
io.Closer
}{
w,
ioutil.NopCloser(nil),
}
}
// ToReadCloser creates an io.ReadCloser from the given io.Reader.
// If it's not already, one will be created with a Close method that does nothing.
func ToReadCloser(r io.Reader) io.ReadCloser {
if rc, ok := r.(io.ReadCloser); ok {
return rc
}
return struct {
io.Reader
io.Closer
}{
r,
ioutil.NopCloser(nil),
}
}
+67
View File
@@ -0,0 +1,67 @@
// 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 hugo
import (
"fmt"
"html/template"
)
const (
EnvironmentDevelopment = "development"
EnvironmentProduction = "production"
)
var (
// commitHash contains the current Git revision. Use make to build to make
// sure this gets set.
commitHash string
// buildDate contains the date of the current build.
buildDate string
)
// Info contains information about the current Hugo environment
type Info struct {
CommitHash string
BuildDate string
// The build environment.
// Defaults are "production" (hugo) and "development" (hugo server).
// This can also be set by the user.
// It can be any string, but it will be all lower case.
Environment string
}
// Version returns the current version as a comparable version string.
func (i Info) Version() VersionString {
return CurrentVersion.Version()
}
// Generator a Hugo meta generator HTML tag.
func (i Info) Generator() template.HTML {
return template.HTML(fmt.Sprintf(`<meta name="generator" content="Hugo %s" />`, CurrentVersion.String()))
}
// NewInfo creates a new Hugo Info object.
func NewInfo(environment string) Info {
if environment == "" {
environment = EnvironmentProduction
}
return Info{
CommitHash: commitHash,
BuildDate: buildDate,
Environment: environment,
}
}
@@ -11,23 +11,25 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package hugolib
package hugo
import (
"fmt"
"testing"
"github.com/gohugoio/hugo/helpers"
"github.com/stretchr/testify/require"
qt "github.com/frankban/quicktest"
)
func TestHugoInfo(t *testing.T) {
assert := require.New(t)
c := qt.New(t)
assert.Equal(helpers.CurrentHugoVersion.Version(), hugoInfo.Version)
assert.IsType(helpers.HugoVersionString(""), hugoInfo.Version)
assert.Equal(CommitHash, hugoInfo.CommitHash)
assert.Equal(BuildDate, hugoInfo.BuildDate)
assert.Contains(hugoInfo.Generator, fmt.Sprintf("Hugo %s", hugoInfo.Version))
hugoInfo := NewInfo("")
c.Assert(hugoInfo.Version(), qt.Equals, CurrentVersion.Version())
c.Assert(fmt.Sprintf("%T", VersionString("")), qt.Equals, fmt.Sprintf("%T", hugoInfo.Version()))
c.Assert(hugoInfo.CommitHash, qt.Equals, commitHash)
c.Assert(hugoInfo.BuildDate, qt.Equals, buildDate)
c.Assert(hugoInfo.Environment, qt.Equals, "production")
c.Assert(string(hugoInfo.Generator()), qt.Contains, fmt.Sprintf("Hugo %s", hugoInfo.Version()))
}
@@ -11,13 +11,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// +build windows
// +build extended
package commands
package hugo
const (
ansiEsc = ""
clearLine = ""
hideCursor = ""
showCursor = ""
)
var IsExtended = true
@@ -11,13 +11,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// +build !windows
// +build !extended
package commands
package hugo
const (
ansiEsc = "\u001B"
clearLine = "\r\033[K"
hideCursor = ansiEsc + "[?25l"
showCursor = ansiEsc + "[?25h"
)
var IsExtended = false
+71 -39
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,18 +11,21 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package helpers
package hugo
import (
"fmt"
"strconv"
"runtime"
"strings"
"github.com/gohugoio/hugo/compare"
"github.com/spf13/cast"
)
// HugoVersion represents the Hugo build version.
type HugoVersion struct {
// Version represents the Hugo build version.
type Version struct {
// Major and minor version.
Number float32
@@ -35,34 +38,34 @@ type HugoVersion struct {
}
var (
_ compare.Eqer = (*HugoVersionString)(nil)
_ compare.Comparer = (*HugoVersionString)(nil)
_ compare.Eqer = (*VersionString)(nil)
_ compare.Comparer = (*VersionString)(nil)
)
func (v HugoVersion) String() string {
return hugoVersion(v.Number, v.PatchLevel, v.Suffix)
func (v Version) String() string {
return version(v.Number, v.PatchLevel, v.Suffix)
}
// Version returns the Hugo version.
func (v HugoVersion) Version() HugoVersionString {
return HugoVersionString(v.String())
func (v Version) Version() VersionString {
return VersionString(v.String())
}
// HugoVersionString represents a Hugo version string.
type HugoVersionString string
// VersionString represents a Hugo version string.
type VersionString string
func (h HugoVersionString) String() string {
func (h VersionString) String() string {
return string(h)
}
// Compare implements the compare.Comparer interface.
func (h HugoVersionString) Compare(other interface{}) int {
v := MustParseHugoVersion(h.String())
func (h VersionString) Compare(other interface{}) int {
v := MustParseVersion(h.String())
return compareVersionsWithSuffix(v.Number, v.PatchLevel, v.Suffix, other)
}
// Eq implements the compare.Eqer interface.
func (h HugoVersionString) Eq(other interface{}) bool {
func (h VersionString) Eq(other interface{}) bool {
s, err := cast.ToStringE(other)
if err != nil {
return false
@@ -72,9 +75,9 @@ func (h HugoVersionString) Eq(other interface{}) bool {
var versionSuffixes = []string{"-test", "-DEV"}
// ParseHugoVersion parses a version string.
func ParseHugoVersion(s string) (HugoVersion, error) {
var vv HugoVersion
// ParseVersion parses a version string.
func ParseVersion(s string) (Version, error) {
var vv Version
for _, suffix := range versionSuffixes {
if strings.HasSuffix(s, suffix) {
vv.Suffix = suffix
@@ -90,10 +93,10 @@ func ParseHugoVersion(s string) (HugoVersion, error) {
return vv, nil
}
// MustParseHugoVersion parses a version string
// MustParseVersion parses a version string
// and panics if any error occurs.
func MustParseHugoVersion(s string) HugoVersion {
vv, err := ParseHugoVersion(s)
func MustParseVersion(s string) Version {
vv, err := ParseVersion(s)
if err != nil {
panic(err)
}
@@ -101,37 +104,53 @@ func MustParseHugoVersion(s string) HugoVersion {
}
// ReleaseVersion represents the release version.
func (v HugoVersion) ReleaseVersion() HugoVersion {
func (v Version) ReleaseVersion() Version {
v.Suffix = ""
return v
}
// Next returns the next Hugo release version.
func (v HugoVersion) Next() HugoVersion {
return HugoVersion{Number: v.Number + 0.01}
func (v Version) Next() Version {
return Version{Number: v.Number + 0.01}
}
// Prev returns the previous Hugo release version.
func (v HugoVersion) Prev() HugoVersion {
return HugoVersion{Number: v.Number - 0.01}
func (v Version) Prev() Version {
return Version{Number: v.Number - 0.01}
}
// NextPatchLevel returns the next patch/bugfix Hugo version.
// This will be a patch increment on the previous Hugo version.
func (v HugoVersion) NextPatchLevel(level int) HugoVersion {
return HugoVersion{Number: v.Number - 0.01, PatchLevel: level}
func (v Version) NextPatchLevel(level int) Version {
return Version{Number: v.Number - 0.01, PatchLevel: level}
}
// CurrentHugoVersion represents the current build version.
// This should be the only one.
var CurrentHugoVersion = HugoVersion{
Number: 0.49,
PatchLevel: 2,
Suffix: "",
// BuildVersionString creates a version string. This is what you see when
// running "hugo version".
func BuildVersionString() string {
program := "Hugo Static Site Generator"
version := "v" + CurrentVersion.String()
if commitHash != "" {
version += "-" + strings.ToUpper(commitHash)
}
if IsExtended {
version += "/extended"
}
osArch := runtime.GOOS + "/" + runtime.GOARCH
date := buildDate
if date == "" {
date = "unknown"
}
return fmt.Sprintf("%s %s %s BuildDate: %s", program, version, osArch, date)
}
func hugoVersion(version float32, patchVersion int, suffix string) string {
if patchVersion > 0 {
func version(version float32, patchVersion int, suffix string) string {
if patchVersion > 0 || version > 0.53 {
return fmt.Sprintf("%.2f.%d%s", version, patchVersion, suffix)
}
return fmt.Sprintf("%.2f%s", version, suffix)
@@ -142,7 +161,7 @@ func hugoVersion(version float32, patchVersion int, suffix string) string {
// It returns -1 if the given version is less than, 0 if equal and 1 if greater than
// the running version.
func CompareVersion(version interface{}) int {
return compareVersionsWithSuffix(CurrentHugoVersion.Number, CurrentHugoVersion.PatchLevel, CurrentHugoVersion.Suffix, version)
return compareVersionsWithSuffix(CurrentVersion.Number, CurrentVersion.PatchLevel, CurrentVersion.Suffix, version)
}
func compareVersions(inVersion float32, inPatchVersion int, in interface{}) int {
@@ -168,7 +187,7 @@ func compareVersionsWithSuffix(inVersion float32, inPatchVersion int, suffix str
return -1
}
v, err := ParseHugoVersion(s)
v, err := ParseVersion(s)
if err != nil {
return -1
}
@@ -217,3 +236,16 @@ func compareFloatVersions(version float32, v float32) int {
}
return 1
}
func GoMinorVersion() int {
return goMinorVersion(runtime.Version())
}
func goMinorVersion(version string) int {
if strings.HasPrefix(version, "devel") {
return 9999 // magic
}
i, _ := strconv.Atoi(strings.Split(version, ".")[1])
return i
}
+22
View File
@@ -0,0 +1,22 @@
// 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 hugo
// CurrentVersion represents the current build version.
// This should be the only one.
var CurrentVersion = Version{
Number: 0.62,
PatchLevel: 0,
Suffix: "",
}
+88
View File
@@ -0,0 +1,88 @@
// 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 hugo
import (
"testing"
qt "github.com/frankban/quicktest"
)
func TestHugoVersion(t *testing.T) {
c := qt.New(t)
c.Assert(version(0.15, 0, "-DEV"), qt.Equals, "0.15-DEV")
c.Assert(version(0.15, 2, "-DEV"), qt.Equals, "0.15.2-DEV")
v := Version{Number: 0.21, PatchLevel: 0, Suffix: "-DEV"}
c.Assert(v.ReleaseVersion().String(), qt.Equals, "0.21")
c.Assert(v.String(), qt.Equals, "0.21-DEV")
c.Assert(v.Next().String(), qt.Equals, "0.22")
nextVersionString := v.Next().Version()
c.Assert(nextVersionString.String(), qt.Equals, "0.22")
c.Assert(nextVersionString.Eq("0.22"), qt.Equals, true)
c.Assert(nextVersionString.Eq("0.21"), qt.Equals, false)
c.Assert(nextVersionString.Eq(nextVersionString), qt.Equals, true)
c.Assert(v.NextPatchLevel(3).String(), qt.Equals, "0.20.3")
// We started to use full semver versions even for main
// releases in v0.54.0
v = Version{Number: 0.53, PatchLevel: 0}
c.Assert(v.String(), qt.Equals, "0.53")
c.Assert(v.Next().String(), qt.Equals, "0.54.0")
c.Assert(v.Next().Next().String(), qt.Equals, "0.55.0")
v = Version{Number: 0.54, PatchLevel: 0, Suffix: "-DEV"}
c.Assert(v.String(), qt.Equals, "0.54.0-DEV")
}
func TestCompareVersions(t *testing.T) {
c := qt.New(t)
c.Assert(compareVersions(0.20, 0, 0.20), qt.Equals, 0)
c.Assert(compareVersions(0.20, 0, float32(0.20)), qt.Equals, 0)
c.Assert(compareVersions(0.20, 0, float64(0.20)), qt.Equals, 0)
c.Assert(compareVersions(0.19, 1, 0.20), qt.Equals, 1)
c.Assert(compareVersions(0.19, 3, "0.20.2"), qt.Equals, 1)
c.Assert(compareVersions(0.19, 1, 0.01), qt.Equals, -1)
c.Assert(compareVersions(0, 1, 3), qt.Equals, 1)
c.Assert(compareVersions(0, 1, int32(3)), qt.Equals, 1)
c.Assert(compareVersions(0, 1, int64(3)), qt.Equals, 1)
c.Assert(compareVersions(0.20, 0, "0.20"), qt.Equals, 0)
c.Assert(compareVersions(0.20, 1, "0.20.1"), qt.Equals, 0)
c.Assert(compareVersions(0.20, 1, "0.20"), qt.Equals, -1)
c.Assert(compareVersions(0.20, 0, "0.20.1"), qt.Equals, 1)
c.Assert(compareVersions(0.20, 1, "0.20.2"), qt.Equals, 1)
c.Assert(compareVersions(0.21, 1, "0.22.1"), qt.Equals, 1)
c.Assert(compareVersions(0.22, 0, "0.22-DEV"), qt.Equals, -1)
c.Assert(compareVersions(0.22, 0, "0.22.1-DEV"), qt.Equals, 1)
c.Assert(compareVersionsWithSuffix(0.22, 0, "-DEV", "0.22"), qt.Equals, 1)
c.Assert(compareVersionsWithSuffix(0.22, 1, "-DEV", "0.22"), qt.Equals, -1)
c.Assert(compareVersionsWithSuffix(0.22, 1, "-DEV", "0.22.1-DEV"), qt.Equals, 0)
}
func TestParseHugoVersion(t *testing.T) {
c := qt.New(t)
c.Assert(MustParseVersion("0.25").String(), qt.Equals, "0.25")
c.Assert(MustParseVersion("0.25.2").String(), qt.Equals, "0.25.2")
c.Assert(MustParseVersion("0.25-test").String(), qt.Equals, "0.25-test")
c.Assert(MustParseVersion("0.25-DEV").String(), qt.Equals, "0.25-DEV")
}
func TestGoMinorVersion(t *testing.T) {
c := qt.New(t)
c.Assert(goMinorVersion("go1.12.5"), qt.Equals, 12)
c.Assert(GoMinorVersion() >= 11, qt.Equals, true)
}
+190 -6
View File
@@ -14,24 +14,208 @@
package loggers
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"log"
"os"
"regexp"
"runtime"
"time"
"github.com/gohugoio/hugo/common/terminal"
jww "github.com/spf13/jwalterweatherman"
)
var (
// Counts ERROR logs to the global jww logger.
GlobalErrorCounter *jww.Counter
)
func init() {
GlobalErrorCounter = &jww.Counter{}
jww.SetLogListeners(jww.LogCounter(GlobalErrorCounter, jww.LevelError))
}
// Logger wraps a *loggers.Logger and some other related logging state.
type Logger struct {
*jww.Notepad
// The writer that represents stdout.
// Will be ioutil.Discard when in quiet mode.
Out io.Writer
ErrorCounter *jww.Counter
WarnCounter *jww.Counter
// This is only set in server mode.
errors *bytes.Buffer
}
// PrintTimerIfDelayed prints a time statement to the FEEDBACK logger
// if considerable time is spent.
func (l *Logger) PrintTimerIfDelayed(start time.Time, name string) {
elapsed := time.Since(start)
milli := int(1000 * elapsed.Seconds())
if milli < 500 {
return
}
l.FEEDBACK.Printf("%s in %v ms", name, milli)
}
func (l *Logger) PrintTimer(start time.Time, name string) {
elapsed := time.Since(start)
milli := int(1000 * elapsed.Seconds())
l.FEEDBACK.Printf("%s in %v ms", name, milli)
}
func (l *Logger) Errors() string {
if l.errors == nil {
return ""
}
return ansiColorRe.ReplaceAllString(l.errors.String(), "")
}
// Reset resets the logger's internal state.
func (l *Logger) Reset() {
l.ErrorCounter.Reset()
if l.errors != nil {
l.errors.Reset()
}
}
// NewLogger creates a new Logger for the given thresholds
func NewLogger(stdoutThreshold, logThreshold jww.Threshold, outHandle, logHandle io.Writer, saveErrors bool) *Logger {
return newLogger(stdoutThreshold, logThreshold, outHandle, logHandle, saveErrors)
}
// 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)
func NewDebugLogger() *Logger {
return newBasicLogger(jww.LevelDebug)
}
// 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)
func NewWarningLogger() *Logger {
return newBasicLogger(jww.LevelWarn)
}
// 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)
func NewErrorLogger() *Logger {
return newBasicLogger(jww.LevelError)
}
var (
ansiColorRe = regexp.MustCompile("(?s)\\033\\[\\d*(;\\d*)*m")
errorRe = regexp.MustCompile("^(ERROR|FATAL|WARN)")
)
type ansiCleaner struct {
w io.Writer
}
func (a ansiCleaner) Write(p []byte) (n int, err error) {
return a.w.Write(ansiColorRe.ReplaceAll(p, []byte("")))
}
type labelColorizer struct {
w io.Writer
}
func (a labelColorizer) Write(p []byte) (n int, err error) {
replaced := errorRe.ReplaceAllStringFunc(string(p), func(m string) string {
switch m {
case "ERROR", "FATAL":
return terminal.Error(m)
case "WARN":
return terminal.Warning(m)
default:
return m
}
})
// io.MultiWriter will abort if we return a bigger write count than input
// bytes, so we lie a little.
_, err = a.w.Write([]byte(replaced))
return len(p), err
}
// InitGlobalLogger initializes the global logger, used in some rare cases.
func InitGlobalLogger(stdoutThreshold, logThreshold jww.Threshold, outHandle, logHandle io.Writer) {
outHandle, logHandle = getLogWriters(outHandle, logHandle)
jww.SetStdoutOutput(outHandle)
jww.SetLogOutput(logHandle)
jww.SetLogThreshold(logThreshold)
jww.SetStdoutThreshold(stdoutThreshold)
}
func getLogWriters(outHandle, logHandle io.Writer) (io.Writer, io.Writer) {
isTerm := terminal.IsTerminal(os.Stdout)
if logHandle != ioutil.Discard && isTerm {
// Remove any Ansi coloring from log output
logHandle = ansiCleaner{w: logHandle}
}
if isTerm {
outHandle = labelColorizer{w: outHandle}
}
return outHandle, logHandle
}
type fatalLogWriter int
func (s fatalLogWriter) Write(p []byte) (n int, err error) {
trace := make([]byte, 1500)
runtime.Stack(trace, true)
fmt.Printf("\n===========\n\n%s\n", trace)
os.Exit(-1)
return 0, nil
}
var fatalLogListener = func(t jww.Threshold) io.Writer {
if t != jww.LevelError {
// Only interested in ERROR
return nil
}
return new(fatalLogWriter)
}
func newLogger(stdoutThreshold, logThreshold jww.Threshold, outHandle, logHandle io.Writer, saveErrors bool) *Logger {
errorCounter := &jww.Counter{}
warnCounter := &jww.Counter{}
outHandle, logHandle = getLogWriters(outHandle, logHandle)
listeners := []jww.LogListener{jww.LogCounter(errorCounter, jww.LevelError), jww.LogCounter(warnCounter, jww.LevelWarn)}
var errorBuff *bytes.Buffer
if saveErrors {
errorBuff = new(bytes.Buffer)
errorCapture := func(t jww.Threshold) io.Writer {
if t != jww.LevelError {
// Only interested in ERROR
return nil
}
return errorBuff
}
listeners = append(listeners, errorCapture)
}
return &Logger{
Notepad: jww.NewNotepad(stdoutThreshold, logThreshold, outHandle, logHandle, "", log.Ldate|log.Ltime, listeners...),
Out: outHandle,
ErrorCounter: errorCounter,
WarnCounter: warnCounter,
errors: errorBuff,
}
}
func newBasicLogger(t jww.Threshold) *Logger {
return newLogger(t, jww.LevelError, os.Stdout, ioutil.Discard, false)
}
@@ -11,15 +11,22 @@
// 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
package loggers
import (
"errors"
"testing"
qt "github.com/frankban/quicktest"
)
// ErrFeatureNotAvailable denotes that a feature is unavailable.
//
// 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 ErrFeatureNotAvailable = errors.New("this feature is not available in your current Hugo version")
func TestLogger(t *testing.T) {
c := qt.New(t)
l := NewWarningLogger()
l.ERROR.Println("One error")
l.ERROR.Println("Two error")
l.WARN.Println("A warning")
c.Assert(l.ErrorCounter.Count(), qt.Equals, uint64(2))
}
+98 -7
View File
@@ -16,6 +16,8 @@ package maps
import (
"strings"
"github.com/gobwas/glob"
"github.com/spf13/cast"
)
@@ -23,22 +25,111 @@ import (
// recursively.
// Notes:
// * This will modify the map given.
// * Any nested map[interface{}]interface{} will be converted to map[string]interface{}.
func ToLower(m map[string]interface{}) {
// * Any nested map[interface{}]interface{} will be converted to Params.
func ToLower(m Params) {
for k, v := range m {
var retyped bool
switch v.(type) {
case map[interface{}]interface{}:
v = cast.ToStringMap(v)
ToLower(v.(map[string]interface{}))
var p Params = cast.ToStringMap(v)
v = p
ToLower(p)
retyped = true
case map[string]interface{}:
ToLower(v.(map[string]interface{}))
var p Params = v.(map[string]interface{})
v = p
ToLower(p)
retyped = true
}
lKey := strings.ToLower(k)
if k != lKey {
if retyped || k != lKey {
delete(m, k)
m[lKey] = v
}
}
}
func ToStringMapE(in interface{}) (map[string]interface{}, error) {
switch in.(type) {
case Params:
return in.(Params), nil
default:
return cast.ToStringMapE(in)
}
}
func ToStringMap(in interface{}) map[string]interface{} {
m, _ := ToStringMapE(in)
return m
}
type keyRename struct {
pattern glob.Glob
newKey string
}
// KeyRenamer supports renaming of keys in a map.
type KeyRenamer struct {
renames []keyRename
}
// NewKeyRenamer creates a new KeyRenamer given a list of pattern and new key
// value pairs.
func NewKeyRenamer(patternKeys ...string) (KeyRenamer, error) {
var renames []keyRename
for i := 0; i < len(patternKeys); i += 2 {
g, err := glob.Compile(strings.ToLower(patternKeys[i]), '/')
if err != nil {
return KeyRenamer{}, err
}
renames = append(renames, keyRename{pattern: g, newKey: patternKeys[i+1]})
}
return KeyRenamer{renames: renames}, nil
}
func (r KeyRenamer) getNewKey(keyPath string) string {
for _, matcher := range r.renames {
if matcher.pattern.Match(keyPath) {
return matcher.newKey
}
}
return ""
}
// Rename renames the keys in the given map according
// to the patterns in the current KeyRenamer.
func (r KeyRenamer) Rename(m map[string]interface{}) {
r.renamePath("", m)
}
func (KeyRenamer) keyPath(k1, k2 string) string {
k1, k2 = strings.ToLower(k1), strings.ToLower(k2)
if k1 == "" {
return k2
} else {
return k1 + "/" + k2
}
}
func (r KeyRenamer) renamePath(parentKeyPath string, m map[string]interface{}) {
for key, val := range m {
keyPath := r.keyPath(parentKeyPath, key)
switch val.(type) {
case map[interface{}]interface{}:
val = cast.ToStringMap(val)
r.renamePath(keyPath, val.(map[string]interface{}))
case map[string]interface{}:
r.renamePath(keyPath, val.(map[string]interface{}))
}
newKey := r.getNewKey(keyPath)
if newKey != "" {
delete(m, key)
m[newKey] = val
}
}
}
+31
View File
@@ -0,0 +1,31 @@
// Copyright 2019 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package maps
import (
"github.com/spf13/cast"
)
// GetString tries to get a value with key from map m and convert it to a string.
// It will return an empty string if not found or if it cannot be convertd to a string.
func GetString(m map[string]interface{}, key string) string {
if m == nil {
return ""
}
v, found := m[key]
if !found {
return ""
}
return cast.ToString(v)
}
+64 -11
View File
@@ -14,12 +14,14 @@
package maps
import (
"fmt"
"reflect"
"testing"
qt "github.com/frankban/quicktest"
)
func TestToLower(t *testing.T) {
tests := []struct {
input map[string]interface{}
expected map[string]interface{}
@@ -28,7 +30,7 @@ func TestToLower(t *testing.T) {
map[string]interface{}{
"abC": 32,
},
map[string]interface{}{
Params{
"abc": 32,
},
},
@@ -46,16 +48,16 @@ func TestToLower(t *testing.T) {
"J": 25,
},
},
map[string]interface{}{
Params{
"abc": 32,
"def": map[string]interface{}{
"def": Params{
"23": "A value",
"24": map[string]interface{}{
"24": Params{
"abcde": "A value",
"efghi": "Another value",
},
},
"ghi": map[string]interface{}{
"ghi": Params{
"j": 25,
},
},
@@ -63,10 +65,61 @@ func TestToLower(t *testing.T) {
}
for i, test := range tests {
// ToLower modifies input.
ToLower(test.input)
if !reflect.DeepEqual(test.expected, test.input) {
t.Errorf("[%d] Expected\n%#v, got\n%#v\n", i, test.expected, test.input)
}
t.Run(fmt.Sprint(i), func(t *testing.T) {
// ToLower modifies input.
ToLower(test.input)
if !reflect.DeepEqual(test.expected, test.input) {
t.Errorf("[%d] Expected\n%#v, got\n%#v\n", i, test.expected, test.input)
}
})
}
}
func TestRenameKeys(t *testing.T) {
c := qt.New(t)
m := map[string]interface{}{
"a": 32,
"ren1": "m1",
"ren2": "m1_2",
"sub": map[string]interface{}{
"subsub": map[string]interface{}{
"REN1": "m2",
"ren2": "m2_2",
},
},
"no": map[string]interface{}{
"ren1": "m2",
"ren2": "m2_2",
},
}
expected := map[string]interface{}{
"a": 32,
"new1": "m1",
"new2": "m1_2",
"sub": map[string]interface{}{
"subsub": map[string]interface{}{
"new1": "m2",
"ren2": "m2_2",
},
},
"no": map[string]interface{}{
"ren1": "m2",
"ren2": "m2_2",
},
}
renamer, err := NewKeyRenamer(
"{ren1,sub/*/ren1}", "new1",
"{Ren2,sub/ren2}", "new2",
)
c.Assert(err, qt.IsNil)
renamer.Rename(m)
if !reflect.DeepEqual(expected, m) {
t.Errorf("Expected\n%#v, got\n%#v\n", expected, m)
}
}
+107
View File
@@ -0,0 +1,107 @@
// Copyright 2019 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package maps
import (
"strings"
"github.com/spf13/cast"
)
// Params is a map where all keys are lower case.
type Params map[string]interface{}
// Get does a lower case and nested search in this map.
// It will return nil if none found.
func (p Params) Get(indices ...string) interface{} {
v, _, _ := getNested(p, indices)
return v
}
func getNested(m map[string]interface{}, indices []string) (interface{}, string, map[string]interface{}) {
if len(indices) == 0 {
return nil, "", nil
}
first := indices[0]
v, found := m[strings.ToLower(cast.ToString(first))]
if !found {
return nil, "", nil
}
if len(indices) == 1 {
return v, first, m
}
switch m2 := v.(type) {
case Params:
return getNested(m2, indices[1:])
case map[string]interface{}:
return getNested(m2, indices[1:])
default:
return nil, "", nil
}
}
// GetNestedParam gets the first match of the keyStr in the candidates given.
// It will first try the exact match and then try to find it as a nested map value,
// using the given separator, e.g. "mymap.name".
// It assumes that all the maps given have lower cased keys.
func GetNestedParam(keyStr, separator string, candidates ...Params) (interface{}, error) {
keyStr = strings.ToLower(keyStr)
// Try exact match first
for _, m := range candidates {
if v, ok := m[keyStr]; ok {
return v, nil
}
}
keySegments := strings.Split(keyStr, separator)
for _, m := range candidates {
if v := m.Get(keySegments...); v != nil {
return v, nil
}
}
return nil, nil
}
func GetNestedParamFn(keyStr, separator string, lookupFn func(key string) interface{}) (interface{}, string, map[string]interface{}, error) {
keySegments := strings.Split(strings.ToLower(keyStr), separator)
if len(keySegments) == 0 {
return nil, "", nil, nil
}
first := lookupFn(keySegments[0])
if first == nil {
return nil, "", nil, nil
}
if len(keySegments) == 1 {
return first, keySegments[0], nil, nil
}
switch m := first.(type) {
case map[string]interface{}:
v, key, owner := getNested(m, keySegments[1:])
return v, key, owner, nil
case Params:
v, key, owner := getNested(m, keySegments[1:])
return v, key, owner, nil
}
return nil, "", nil, nil
}
+51
View File
@@ -0,0 +1,51 @@
// Copyright 2019 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package maps
import (
"testing"
qt "github.com/frankban/quicktest"
)
func TestGetNestedParam(t *testing.T) {
m := map[string]interface{}{
"string": "value",
"first": 1,
"with_underscore": 2,
"nested": map[string]interface{}{
"color": "blue",
"nestednested": map[string]interface{}{
"color": "green",
},
},
}
c := qt.New(t)
must := func(keyStr, separator string, candidates ...Params) interface{} {
v, err := GetNestedParam(keyStr, separator, candidates...)
c.Assert(err, qt.IsNil)
return v
}
c.Assert(must("first", "_", m), qt.Equals, 1)
c.Assert(must("First", "_", m), qt.Equals, 1)
c.Assert(must("with_underscore", "_", m), qt.Equals, 2)
c.Assert(must("nested_color", "_", m), qt.Equals, "blue")
c.Assert(must("nested.nestednested.color", ".", m), qt.Equals, "green")
c.Assert(must("string.name", ".", m), qt.IsNil)
}
+19 -1
View File
@@ -1,4 +1,4 @@
// Copyright 2018 The Hugo Authors. All rights reserved.
// Copyright 2019 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -28,6 +28,24 @@ type Scratch struct {
mu sync.RWMutex
}
// Scratcher provides a scratching service.
type Scratcher interface {
Scratch() *Scratch
}
type scratcher struct {
s *Scratch
}
func (s scratcher) Scratch() *Scratch {
return s.s
}
// NewScratcher creates a new Scratcher.
func NewScratcher() Scratcher {
return scratcher{s: NewScratch()}
}
// Add will, for single values, add (using the + operator) the addend to the existing addend (if found).
// Supports numeric values and strings.
//
+33 -19
View File
@@ -18,31 +18,31 @@ import (
"sync"
"testing"
"github.com/stretchr/testify/require"
qt "github.com/frankban/quicktest"
)
func TestScratchAdd(t *testing.T) {
t.Parallel()
assert := require.New(t)
c := qt.New(t)
scratch := NewScratch()
scratch.Add("int1", 10)
scratch.Add("int1", 20)
scratch.Add("int2", 20)
assert.Equal(int64(30), scratch.Get("int1"))
assert.Equal(20, scratch.Get("int2"))
c.Assert(scratch.Get("int1"), qt.Equals, int64(30))
c.Assert(scratch.Get("int2"), qt.Equals, 20)
scratch.Add("float1", float64(10.5))
scratch.Add("float1", float64(20.1))
assert.Equal(float64(30.6), scratch.Get("float1"))
c.Assert(scratch.Get("float1"), qt.Equals, float64(30.6))
scratch.Add("string1", "Hello ")
scratch.Add("string1", "big ")
scratch.Add("string1", "World!")
assert.Equal("Hello big World!", scratch.Get("string1"))
c.Assert(scratch.Get("string1"), qt.Equals, "Hello big World!")
scratch.Add("scratch", scratch)
_, err := scratch.Add("scratch", scratch)
@@ -55,14 +55,14 @@ func TestScratchAdd(t *testing.T) {
func TestScratchAddSlice(t *testing.T) {
t.Parallel()
assert := require.New(t)
c := qt.New(t)
scratch := NewScratch()
_, err := scratch.Add("intSlice", []int{1, 2})
assert.NoError(err)
c.Assert(err, qt.IsNil)
_, err = scratch.Add("intSlice", 3)
assert.NoError(err)
c.Assert(err, qt.IsNil)
sl := scratch.Get("intSlice")
expected := []int{1, 2, 3}
@@ -72,7 +72,7 @@ func TestScratchAddSlice(t *testing.T) {
}
_, err = scratch.Add("intSlice", []int{4, 5})
assert.NoError(err)
c.Assert(err, qt.IsNil)
sl = scratch.Get("intSlice")
expected = []int{1, 2, 3, 4, 5}
@@ -85,35 +85,49 @@ func TestScratchAddSlice(t *testing.T) {
// https://github.com/gohugoio/hugo/issues/5275
func TestScratchAddTypedSliceToInterfaceSlice(t *testing.T) {
t.Parallel()
assert := require.New(t)
c := qt.New(t)
scratch := NewScratch()
scratch.Set("slice", []interface{}{})
_, err := scratch.Add("slice", []int{1, 2})
assert.NoError(err)
assert.Equal([]int{1, 2}, scratch.Get("slice"))
c.Assert(err, qt.IsNil)
c.Assert(scratch.Get("slice"), qt.DeepEquals, []int{1, 2})
}
// https://github.com/gohugoio/hugo/issues/5361
func TestScratchAddDifferentTypedSliceToInterfaceSlice(t *testing.T) {
t.Parallel()
c := qt.New(t)
scratch := NewScratch()
scratch.Set("slice", []string{"foo"})
_, err := scratch.Add("slice", []int{1, 2})
c.Assert(err, qt.IsNil)
c.Assert(scratch.Get("slice"), qt.DeepEquals, []interface{}{"foo", 1, 2})
}
func TestScratchSet(t *testing.T) {
t.Parallel()
assert := require.New(t)
c := qt.New(t)
scratch := NewScratch()
scratch.Set("key", "val")
assert.Equal("val", scratch.Get("key"))
c.Assert(scratch.Get("key"), qt.Equals, "val")
}
func TestScratchDelete(t *testing.T) {
t.Parallel()
assert := require.New(t)
c := qt.New(t)
scratch := NewScratch()
scratch.Set("key", "val")
scratch.Delete("key")
scratch.Add("key", "Lucy Parsons")
assert.Equal("Lucy Parsons", scratch.Get("key"))
c.Assert(scratch.Get("key"), qt.Equals, "Lucy Parsons")
}
// Issue #2005
@@ -163,7 +177,7 @@ func TestScratchGet(t *testing.T) {
func TestScratchSetInMap(t *testing.T) {
t.Parallel()
assert := require.New(t)
c := qt.New(t)
scratch := NewScratch()
scratch.SetInMap("key", "lux", "Lux")
@@ -171,7 +185,7 @@ func TestScratchSetInMap(t *testing.T) {
scratch.SetInMap("key", "zyx", "Zyx")
scratch.SetInMap("key", "abc", "Abc (updated)")
scratch.SetInMap("key", "def", "Def")
assert.Equal([]interface{}{0: "Abc (updated)", 1: "Def", 2: "Lux", 3: "Zyx"}, scratch.GetSortedMapValues("key"))
c.Assert(scratch.GetSortedMapValues("key"), qt.DeepEquals, []interface{}{0: "Abc (updated)", 1: "Def", 2: "Lux", 3: "Zyx"})
}
func TestScratchGetSortedMapValues(t *testing.T) {
+7 -7
View File
@@ -46,7 +46,7 @@ func DoArithmetic(a, b interface{}, op rune) (interface{}, error) {
bu = 0
}
default:
return nil, errors.New("Can't apply the operator to the values")
return nil, errors.New("can't apply the operator to the values")
}
case reflect.Float32, reflect.Float64:
af = av.Float()
@@ -58,7 +58,7 @@ func DoArithmetic(a, b interface{}, op rune) (interface{}, error) {
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")
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()
@@ -79,7 +79,7 @@ func DoArithmetic(a, b interface{}, op rune) (interface{}, error) {
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")
return nil, errors.New("can't apply the operator to the values")
}
case reflect.String:
as := av.String()
@@ -87,9 +87,9 @@ func DoArithmetic(a, b interface{}, op rune) (interface{}, error) {
bs := bv.String()
return as + bs, nil
}
return nil, errors.New("Can't apply the operator to the values")
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")
return nil, errors.New("can't apply the operator to the values")
}
switch op {
@@ -128,8 +128,8 @@ func DoArithmetic(a, b interface{}, op rune) (interface{}, error) {
} else if bu != 0 {
return au / bu, nil
}
return nil, errors.New("Can't divide the value by 0")
return nil, errors.New("can't divide the value by 0")
default:
return nil, errors.New("There is no such an operation")
return nil, errors.New("there is no such an operation")
}
}
+6 -9
View File
@@ -14,17 +14,16 @@
package math
import (
"fmt"
"testing"
"github.com/alecthomas/assert"
"github.com/stretchr/testify/require"
qt "github.com/frankban/quicktest"
)
func TestDoArithmetic(t *testing.T) {
t.Parallel()
c := qt.New(t)
for i, test := range []struct {
for _, test := range []struct {
a interface{}
b interface{}
op rune
@@ -94,16 +93,14 @@ func TestDoArithmetic(t *testing.T) {
{"foo", "bar", '-', false},
{3, 2, '%', false},
} {
errMsg := fmt.Sprintf("[%d] %v", i, test)
result, err := DoArithmetic(test.a, test.b, test.op)
if b, ok := test.expect.(bool); ok && !b {
require.Error(t, err, errMsg)
c.Assert(err, qt.Not(qt.IsNil))
continue
}
require.NoError(t, err, errMsg)
assert.Equal(t, test.expect, result, errMsg)
c.Assert(err, qt.IsNil)
c.Assert(test.expect, qt.Equals, result)
}
}
+73
View File
@@ -0,0 +1,73 @@
// Copyright 2019 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package para implements parallel execution helpers.
package para
import (
"context"
"golang.org/x/sync/errgroup"
)
// Workers configures a task executor with the most number of tasks to be executed in parallel.
type Workers struct {
sem chan struct{}
}
// Runner wraps the lifecycle methods of a new task set.
//
// Run wil block until a worker is available or the context is cancelled,
// and then run the given func in a new goroutine.
// Wait will wait for all the running goroutines to finish.
type Runner interface {
Run(func() error)
Wait() error
}
type errGroupRunner struct {
*errgroup.Group
w *Workers
ctx context.Context
}
func (g *errGroupRunner) Run(fn func() error) {
select {
case g.w.sem <- struct{}{}:
case <-g.ctx.Done():
return
}
g.Go(func() error {
err := fn()
<-g.w.sem
return err
})
}
// New creates a new Workers with the given number of workers.
func New(numWorkers int) *Workers {
return &Workers{
sem: make(chan struct{}, numWorkers),
}
}
// Start starts a new Runner.
func (w *Workers) Start(ctx context.Context) (Runner, context.Context) {
g, ctx := errgroup.WithContext(ctx)
return &errGroupRunner{
Group: g,
ctx: ctx,
w: w,
}, ctx
}
+89
View File
@@ -0,0 +1,89 @@
// Copyright 2019 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package para
import (
"context"
"runtime"
"sort"
"sync"
"sync/atomic"
"testing"
"time"
qt "github.com/frankban/quicktest"
)
func TestPara(t *testing.T) {
if runtime.NumCPU() < 4 {
t.Skipf("skip para test, CPU count is %d", runtime.NumCPU())
}
c := qt.New(t)
c.Run("Order", func(c *qt.C) {
n := 500
ints := make([]int, n)
for i := 0; i < n; i++ {
ints[i] = i
}
p := New(4)
r, _ := p.Start(context.Background())
var result []int
var mu sync.Mutex
for i := 0; i < n; i++ {
i := i
r.Run(func() error {
mu.Lock()
defer mu.Unlock()
result = append(result, i)
return nil
})
}
c.Assert(r.Wait(), qt.IsNil)
c.Assert(result, qt.HasLen, len(ints))
c.Assert(sort.IntsAreSorted(result), qt.Equals, false, qt.Commentf("Para does not seem to be parallel"))
sort.Ints(result)
c.Assert(result, qt.DeepEquals, ints)
})
c.Run("Time", func(c *qt.C) {
const n = 100
p := New(5)
r, _ := p.Start(context.Background())
start := time.Now()
var counter int64
for i := 0; i < n; i++ {
r.Run(func() error {
atomic.AddInt64(&counter, 1)
time.Sleep(1 * time.Millisecond)
return nil
})
}
c.Assert(r.Wait(), qt.IsNil)
c.Assert(counter, qt.Equals, int64(n))
c.Assert(time.Since(start) < n/2*time.Millisecond, qt.Equals, true)
})
}
+70
View File
@@ -0,0 +1,70 @@
// 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 terminal contains helper for the terminal, such as coloring output.
package terminal
import (
"fmt"
"os"
"runtime"
"strings"
isatty "github.com/mattn/go-isatty"
)
const (
errorColor = "\033[1;31m%s\033[0m"
warningColor = "\033[0;33m%s\033[0m"
noticeColor = "\033[1;36m%s\033[0m"
)
// IsTerminal return true if the file descriptor is terminal and the TERM
// environment variable isn't a dumb one.
func IsTerminal(f *os.File) bool {
if runtime.GOOS == "windows" {
return false
}
fd := f.Fd()
return os.Getenv("TERM") != "dumb" && (isatty.IsTerminal(fd) || isatty.IsCygwinTerminal(fd))
}
// Notice colorizes the string in a noticeable color.
func Notice(s string) string {
return colorize(s, noticeColor)
}
// Error colorizes the string in a colour that grabs attention.
func Error(s string) string {
return colorize(s, errorColor)
}
// Warning colorizes the string in a colour that warns.
func Warning(s string) string {
return colorize(s, warningColor)
}
// colorize s in color.
func colorize(s, color string) string {
s = fmt.Sprintf(color, doublePercent(s))
return singlePercent(s)
}
func doublePercent(str string) string {
return strings.Replace(str, "%", "%%", -1)
}
func singlePercent(str string) string {
return strings.Replace(str, "%%", "%", -1)
}
+99
View File
@@ -0,0 +1,99 @@
// 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 text
import (
"fmt"
"os"
"strings"
"github.com/gohugoio/hugo/common/terminal"
)
// Positioner represents a thing that knows its position in a text file or stream,
// typically an error.
type Positioner interface {
Position() Position
}
// Position holds a source position in a text file or stream.
type Position struct {
Filename string // filename, if any
Offset int // byte offset, starting at 0. It's set to -1 if not provided.
LineNumber int // line number, starting at 1
ColumnNumber int // column number, starting at 1 (character count per line)
}
func (pos Position) String() string {
if pos.Filename == "" {
pos.Filename = "<stream>"
}
return positionStringFormatfunc(pos)
}
// IsValid returns true if line number is > 0.
func (pos Position) IsValid() bool {
return pos.LineNumber > 0
}
var positionStringFormatfunc func(p Position) string
func createPositionStringFormatter(formatStr string) func(p Position) string {
if formatStr == "" {
formatStr = "\":file::line::col\""
}
var identifiers = []string{":file", ":line", ":col"}
var identifiersFound []string
for i := range formatStr {
for _, id := range identifiers {
if strings.HasPrefix(formatStr[i:], id) {
identifiersFound = append(identifiersFound, id)
}
}
}
replacer := strings.NewReplacer(":file", "%s", ":line", "%d", ":col", "%d")
format := replacer.Replace(formatStr)
f := func(pos Position) string {
args := make([]interface{}, len(identifiersFound))
for i, id := range identifiersFound {
switch id {
case ":file":
args[i] = pos.Filename
case ":line":
args[i] = pos.LineNumber
case ":col":
args[i] = pos.ColumnNumber
}
}
msg := fmt.Sprintf(format, args...)
if terminal.IsTerminal(os.Stdout) {
return terminal.Notice(msg)
}
return msg
}
return f
}
func init() {
positionStringFormatfunc = createPositionStringFormatter(os.Getenv("HUGO_FILE_LOG_FORMAT"))
}
+33
View File
@@ -0,0 +1,33 @@
// 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 text
import (
"testing"
qt "github.com/frankban/quicktest"
)
func TestPositionStringFormatter(t *testing.T) {
c := qt.New(t)
pos := Position{Filename: "/my/file.txt", LineNumber: 12, ColumnNumber: 13, Offset: 14}
c.Assert(createPositionStringFormatter(":file|:col|:line")(pos), qt.Equals, "/my/file.txt|13|12")
c.Assert(createPositionStringFormatter(":col|:file|:line")(pos), qt.Equals, "13|/my/file.txt|12")
c.Assert(createPositionStringFormatter("好::col")(pos), qt.Equals, "好:13")
c.Assert(createPositionStringFormatter("")(pos), qt.Equals, "\"/my/file.txt:12:13\"")
c.Assert(pos.String(), qt.Equals, "\"/my/file.txt:12:13\"")
}
+7
View File
@@ -52,6 +52,13 @@ func (q *EvictingStringQueue) Add(v string) {
q.mu.Unlock()
}
// Contains returns whether the queue contains v.
func (q *EvictingStringQueue) Contains(v string) bool {
q.mu.Lock()
defer q.mu.Unlock()
return q.set[v]
}
// Peek looks at the last element added to the queue.
func (q *EvictingStringQueue) Peek() string {
q.mu.Lock()
+13 -10
View File
@@ -17,33 +17,36 @@ import (
"sync"
"testing"
"github.com/stretchr/testify/require"
qt "github.com/frankban/quicktest"
)
func TestEvictingStringQueue(t *testing.T) {
assert := require.New(t)
c := qt.New(t)
queue := NewEvictingStringQueue(3)
assert.Equal("", queue.Peek())
c.Assert(queue.Peek(), qt.Equals, "")
queue.Add("a")
queue.Add("b")
queue.Add("a")
assert.Equal("b", queue.Peek())
c.Assert(queue.Peek(), qt.Equals, "b")
queue.Add("b")
assert.Equal("b", queue.Peek())
c.Assert(queue.Peek(), qt.Equals, "b")
queue.Add("a")
queue.Add("b")
assert.Equal([]string{"b", "a"}, queue.PeekAll())
assert.Equal("b", queue.Peek())
c.Assert(queue.Contains("a"), qt.Equals, true)
c.Assert(queue.Contains("foo"), qt.Equals, false)
c.Assert(queue.PeekAll(), qt.DeepEquals, []string{"b", "a"})
c.Assert(queue.Peek(), qt.Equals, "b")
queue.Add("c")
queue.Add("d")
// Overflowed, a should now be removed.
assert.Equal([]string{"d", "c", "b"}, queue.PeekAll())
assert.Len(queue.PeekAllSet(), 3)
assert.True(queue.PeekAllSet()["c"])
c.Assert(queue.PeekAll(), qt.DeepEquals, []string{"d", "c", "b"})
c.Assert(len(queue.PeekAllSet()), qt.Equals, 3)
c.Assert(queue.PeekAllSet()["c"], qt.Equals, true)
}
func TestEvictingStringQueueConcurrent(t *testing.T) {
+29 -1
View File
@@ -1,4 +1,4 @@
// Copyright 2018 The Hugo Authors. All rights reserved.
// Copyright 2019 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@ package types
import (
"fmt"
"reflect"
"github.com/spf13/cast"
)
@@ -50,3 +51,30 @@ func NewKeyValuesStrings(key string, values ...string) KeyValues {
}
return KeyValues{Key: key, Values: iv}
}
// Zeroer, as implemented by time.Time, will be used by the truth template
// funcs in Hugo (if, with, not, and, or).
type Zeroer interface {
IsZero() bool
}
// IsNil reports whether v is nil.
func IsNil(v interface{}) bool {
if v == nil {
return true
}
value := reflect.ValueOf(v)
switch value.Kind() {
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
return value.IsNil()
}
return false
}
// DevMarker is a marker interface for types that should only be used during
// development.
type DevMarker interface {
DevOnly()
}
+4 -4
View File
@@ -16,14 +16,14 @@ package types
import (
"testing"
"github.com/stretchr/testify/require"
qt "github.com/frankban/quicktest"
)
func TestKeyValues(t *testing.T) {
assert := require.New(t)
c := qt.New(t)
kv := NewKeyValuesStrings("key", "a1", "a2")
assert.Equal("key", kv.KeyString())
assert.Equal([]interface{}{"a1", "a2"}, kv.Values)
c.Assert(kv.KeyString(), qt.Equals, "key")
c.Assert(kv.Values, qt.DeepEquals, []interface{}{"a1", "a2"})
}
+22
View File
@@ -0,0 +1,22 @@
// 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 urls
// RefLinker is implemented by those who support reference linking.
// args must contain a path, but can also point to the target
// language or output format.
type RefLinker interface {
Ref(args map[string]interface{}) (string, error)
RelRef(args map[string]interface{}) (string, error)
}
+7 -1
View File
@@ -1,4 +1,4 @@
// Copyright 2017-present The Hugo Authors. All rights reserved.
// Copyright 2019 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -20,6 +20,12 @@ type Eqer interface {
Eq(other interface{}) bool
}
// ProbablyEqer is an equal check that may return false positives, but never
// a false negative.
type ProbablyEqer interface {
ProbablyEq(other interface{}) bool
}
// Comparer can be used to compare two values.
// This will be used when using the le, ge etc. operators in the templates.
// Compare returns -1 if the given version is less than, 0 if equal and 1 if greater than
+113
View File
@@ -0,0 +1,113 @@
// Copyright 2019 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package compare
import (
"strings"
"unicode"
"unicode/utf8"
)
// Strings returns an integer comparing two strings lexicographically.
func Strings(s, t string) int {
c := compareFold(s, t)
if c == 0 {
// "B" and "b" would be the same so we need a tiebreaker.
return strings.Compare(s, t)
}
return c
}
// This function is derived from strings.EqualFold in Go's stdlib.
// https://github.com/golang/go/blob/ad4a58e31501bce5de2aad90a620eaecdc1eecb8/src/strings/strings.go#L893
func compareFold(s, t string) int {
for s != "" && t != "" {
var sr, tr rune
if s[0] < utf8.RuneSelf {
sr, s = rune(s[0]), s[1:]
} else {
r, size := utf8.DecodeRuneInString(s)
sr, s = r, s[size:]
}
if t[0] < utf8.RuneSelf {
tr, t = rune(t[0]), t[1:]
} else {
r, size := utf8.DecodeRuneInString(t)
tr, t = r, t[size:]
}
if tr == sr {
continue
}
c := 1
if tr < sr {
tr, sr = sr, tr
c = -c
}
// ASCII only.
if tr < utf8.RuneSelf {
if sr >= 'A' && sr <= 'Z' {
if tr <= 'Z' {
// Same case.
return -c
}
diff := tr - (sr + 'a' - 'A')
if diff == 0 {
continue
}
if diff < 0 {
return c
}
if diff > 0 {
return -c
}
}
}
// Unicode.
r := unicode.SimpleFold(sr)
for r != sr && r < tr {
r = unicode.SimpleFold(r)
}
if r == tr {
continue
}
return -c
}
if s == "" && t == "" {
return 0
}
if s == "" {
return -1
}
return 1
}
// LessStrings returns whether s is less than t lexicographically.
func LessStrings(s, t string) bool {
return Strings(s, t) < 0
}
+65
View File
@@ -0,0 +1,65 @@
// Copyright 2019 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package compare
import (
"sort"
"strings"
"testing"
qt "github.com/frankban/quicktest"
)
func TestCompare(t *testing.T) {
c := qt.New(t)
for _, test := range []struct {
a string
b string
}{
{"a", "a"},
{"A", "a"},
{"Ab", "Ac"},
{"az", "Za"},
{"C", "D"},
{"B", "a"},
{"C", ""},
{"", ""},
{"αβδC", "ΑΒΔD"},
{"αβδC", "ΑΒΔ"},
{"αβδ", "ΑΒΔD"},
{"αβδ", "ΑΒΔ"},
{"β", "δ"},
{"好", strings.ToLower("好")},
} {
expect := strings.Compare(strings.ToLower(test.a), strings.ToLower(test.b))
got := compareFold(test.a, test.b)
c.Assert(got, qt.Equals, expect)
}
}
func TestLexicographicSort(t *testing.T) {
c := qt.New(t)
s := []string{"b", "Bz", "ba", "A", "Ba", "ba"}
sort.Slice(s, func(i, j int) bool {
return LessStrings(s[i], s[j])
})
c.Assert(s, qt.DeepEquals, []string{"A", "b", "Ba", "ba", "ba", "Bz"})
}

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