Compare commits

..

180 Commits

Author SHA1 Message Date
Bjørn Erik Pedersen 10ddc2ef92 Improve error messages for PostCSS etc.
Fixes #9730
2023-07-17 19:42:13 +02:00
Bjørn Erik Pedersen c406fd3a0e Fix setting config from env with complex (e.g. YAML) strings
So you can do

```
HUGO_OUTPUTS="home: [rss]"  hugo
```

And similar.

Fixes #11249
2023-07-16 18:08:23 +02:00
David Karlsson 286821e360 Fix for data mounts in sub folders
Before this change, data files from Hugo modules were always mounted at the
root of the `data` directory. The File and FileMetaInfo structs for modules
are different from 'native' data directories.

This changes how the keyParts for data files are generated so that data
from modules or native directories are treated the same.
2023-07-15 11:13:08 +02:00
hugoreleaser 79f15be5b0 releaser: Prepare repository for 0.116.0-DEV
[ci skip]
2023-07-13 16:23:50 +00:00
hugoreleaser 5c2e014a51 releaser: Bump versions for release of 0.115.3
[ci skip]
2023-07-13 16:11:34 +00:00
Bjørn Erik Pedersen cc44583cc3 Improve behavior of defaultContentLanguageInSubdir when only the default language is enabled
1 .Create sitemapindex in root of publishDir (will contain link to sitemap.xml in defaultContentLanguage site)
2. Create index.html in root of publishDir (will redirect to defaultContentLanguage site)

Fixes #11229
2023-07-13 18:06:36 +02:00
Bjørn Erik Pedersen 4da672af88 Return error when .Render is invoked without arg
Fixes #11243
2023-07-13 18:06:36 +02:00
Joe Mooring f1886f8c37 js: Pass tsconfig.json to esBuild
Note that esBuild only inspects/honors certain fields.
See https://esbuild.github.io/content-types/#tsconfig-json.

Fixes #11232
2023-07-13 15:19:04 +02:00
Bjørn Erik Pedersen 5bec50838c tpl/collections: Fix WordCount (etc.) regression in Where, Sort, Delimit
Fixes #11234
2023-07-11 12:11:39 +02:00
Joe Mooring f650e4d751 config/allconfig: Update timeout description 2023-07-08 23:22:26 +02:00
Joe Mooring c934a45069 docs: Refresh docs.json 2023-07-08 23:20:11 +02:00
hugoreleaser 91b02091a5 releaser: Prepare repository for 0.116.0-DEV
[ci skip]
2023-07-08 17:19:03 +00:00
hugoreleaser 8966424e0e releaser: Bump versions for release of 0.115.2
[ci skip]
2023-07-08 17:06:56 +00:00
Joe Mooring 72510969a6 snap: Allow access to AWS, Azure, and GCS config/credentials
Fixes #11122
2023-07-08 09:43:04 -07:00
Joe Mooring 70c5e485bb snap: Update metadata and security.exec.osEnv
See #11217
2023-07-08 09:43:04 -07:00
Bjørn Erik Pedersen a78b17d7f1 Make imageConfig work with modules
Fixes #11205
2023-07-08 17:20:18 +02:00
Bjørn Erik Pedersen a481942532 Restore language.disabled config
Fixes #11219
2023-07-08 16:51:48 +02:00
Bjørn Erik Pedersen 0f921ace6f Fix hugo mod vendor for modules with hugo.toml
Fixes #11221
2023-07-08 16:08:46 +02:00
Bjørn Erik Pedersen 6019953769 Fix static content files multilingual root regression
Fixes #11223
2023-07-08 16:08:46 +02:00
Bjørn Erik Pedersen 92e86702ea Fix defaultContentLanguageInSubdir with only 1 language
Fixes #10064
2023-07-08 16:08:46 +02:00
David Karlsson 6c9ea022a9 config: Expand default security.exec.osEnv policy
To better support private Hugo modules and automatically
launching a text editor on content creation, this change
adds the following environment variables to the default
security policy:

- HOME
- XDG_CONFIG_HOME
- USERPROFILE
- SSH_AUTH_SOCK
- DISPLAY
- LANG

Fixes #9333
2023-07-07 13:54:06 +02:00
Bjørn Erik Pedersen 12d3469dd1 Add titleCaseStyle none and firstupper
Fixes #11204
2023-07-05 20:35:20 +02:00
Anthony Fok bf7ee8a91a Bump github.com/bep/clock v0.3.0 to renamed github.com/bep/clocks v0.5.0 2023-07-04 09:14:48 +02:00
hugoreleaser d912491f2d releaser: Prepare repository for 0.116.0-DEV
[ci skip]
2023-07-03 17:39:56 +00:00
hugoreleaser 857374e693 releaser: Bump versions for release of 0.115.1
[ci skip]
2023-07-03 17:28:25 +00:00
Bjørn Erik Pedersen c27639b9a0 docs: Regen docs helper 2023-07-03 19:25:27 +02:00
Bjørn Erik Pedersen ceb486f98c Fix buildStats when tags and classes are disabled
Fixes #11202
2023-07-03 09:58:33 +02:00
Bjørn Erik Pedersen 5afc89f2bf Rework the build.writeStats struct
Mostly to make it easier to toggle on/off this feature from the env.

See #11191
2023-07-02 13:04:11 +02:00
Joe Mooring c1eac616d5 snap: Explicitly set security.exec.osenv during build
Fixes #11199
2023-07-01 17:55:23 -07:00
Joe Mooring 3c8256a137 snap: Restore security.exec.osenv whitelist
Fixes #11195
2023-07-01 14:55:57 -07:00
Bjørn Erik Pedersen 19d76ae96b github: Build for Dragonfly in CI build
To discover upstream issues before we release.
2023-07-01 18:53:48 +02:00
Bjørn Erik Pedersen 11ecea6106 Make build.writeStats a struct
So you can do

```toml
[build.writeStats]
  tags = true
  classes = true
  ids = false
```

Fixes #11191
2023-07-01 15:38:32 +02:00
dependabot[bot] da98724bc8 build(deps): bump github.com/evanw/esbuild from 0.18.10 to 0.18.11
Bumps [github.com/evanw/esbuild](https://github.com/evanw/esbuild) from 0.18.10 to 0.18.11.
- [Release notes](https://github.com/evanw/esbuild/releases)
- [Changelog](https://github.com/evanw/esbuild/blob/main/CHANGELOG.md)
- [Commits](https://github.com/evanw/esbuild/compare/v0.18.10...v0.18.11)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-01 15:33:24 +02:00
dependabot[bot] 4d470bb732 build(deps): bump github.com/alecthomas/chroma/v2 from 2.7.0 to 2.8.0
Bumps [github.com/alecthomas/chroma/v2](https://github.com/alecthomas/chroma) from 2.7.0 to 2.8.0.
- [Release notes](https://github.com/alecthomas/chroma/releases)
- [Changelog](https://github.com/alecthomas/chroma/blob/master/.goreleaser.yml)
- [Commits](https://github.com/alecthomas/chroma/compare/v2.7.0...v2.8.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-01 10:33:49 +02:00
Bjørn Erik Pedersen 0ff8e13c1c commands: Fix index out of range in hugo mod get
Fixes #11190
2023-06-30 15:57:46 +02:00
Bjørn Erik Pedersen ffd37d4f75 Only print the path warnings once
We could reset and rerun it on server rebuilds, but that report needs a full build to make sense.

Also clean up the config vs flags in this area: Make all config settings match the flags e.g. `printPathWarnings`, but set up aliases for the
old.

Fixes #11187
2023-06-30 10:24:28 +02:00
Bjørn Erik Pedersen b4b65245b2 Update README.md 2023-06-30 08:01:25 +02:00
hugoreleaser 87886f40d1 releaser: Prepare repository for 0.116.0-DEV
[ci skip]
2023-06-29 16:09:06 +00:00
hugoreleaser 67caf50698 releaser: Bump versions for release of 0.115.0
[ci skip]
2023-06-29 15:56:39 +00:00
Bjørn Erik Pedersen 7917961d59 Misc permalinks adjustments
* Move config loading to the page package
* Fix a lower bound panic for the `:sections` slice syntax.
* Always return the `:title`
* Add some permalinks integration tests
* Also see issues below

Fixes #9448
Fixes #11184
See #8523
2023-06-29 10:14:19 +02:00
Bjørn Erik Pedersen 80ecb95895 commands: Handle hugo mod get --help
Fixes #11141
2023-06-29 08:53:50 +02:00
Joe Mooring 58e09cc6c7 Update README.md 2023-06-28 20:14:41 +02:00
Andreas Deininger 635cc346ce commands: Fix panic when running hugo new theme without theme name
Closes #11162.
2023-06-28 16:20:54 +02:00
Mos Roshanavand 12646750aa Print help message when triggered with no flags 2023-06-28 14:58:36 +02:00
Bjørn Erik Pedersen 79639c981c Fix output formats and media type per language config regression
Fixes #11159
2023-06-28 12:33:33 +02:00
dependabot[bot] 9b313cec1b build(deps): bump github.com/evanw/esbuild from 0.18.5 to 0.18.10
Bumps [github.com/evanw/esbuild](https://github.com/evanw/esbuild) from 0.18.5 to 0.18.10.
- [Release notes](https://github.com/evanw/esbuild/releases)
- [Changelog](https://github.com/evanw/esbuild/blob/main/CHANGELOG.md)
- [Commits](https://github.com/evanw/esbuild/compare/v0.18.5...v0.18.10)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-28 10:22:19 +02:00
khayyam b74b8d6478 common/collections: Fix append regression to allow appending nil
Closes #11180
2023-06-28 09:41:36 +02:00
Andreas Deininger 793e38f5ce commands: Fix help message for hugo new theme
Closes #11161.
2023-06-28 09:30:27 +02:00
Bjørn Erik Pedersen 7f698c8934 Don't panic on invalid security whitelist regexp
Fixes #11176
2023-06-28 08:57:28 +02:00
Bjørn Erik Pedersen fa0e16f4c7 Fix false path warnings with resources.PostProcess
Fixes #7735
2023-06-27 21:55:35 +02:00
Joe Mooring 12e4c4d5dc docs: Update permalinks documentation
See #8523
See #10847
2023-06-27 11:04:49 +02:00
Bjørn Erik Pedersen bac03f4076 Merge branch 'master' of github.com:gohugoio/hugo 2023-06-26 20:48:44 +02:00
Mai-Lapyst cc14c6a52c resources/page: Allow section and taxonomy pages to have a permalink configuration
Allows using permalink configuration for sections (branch bundles) and
also for taxonomy pages. Extends the current permalink configuration to
be able to specified per page kind while also staying backward compatible:
all permalink patterns not dedicated to a certain kind, get automatically
added for both normal pages and term pages.

Fixes #8523
2023-06-26 15:31:01 +02:00
Oleksandr Redko e3308a0bbc tpl/tplimpl: Fix typo in global variable name 2023-06-26 15:12:21 +02:00
Joe Mooring 019299b0b0 commands: Enable format flag with hugo new site
Fixes #11155
2023-06-24 20:26:54 +02:00
Bjørn Erik Pedersen 23ed087c4e Update README.md 2023-06-24 11:28:29 +02:00
Bjørn Erik Pedersen a018259bcf Merge branch 'release-0.114.1' 2023-06-23 13:18:21 +02:00
hugoreleaser ad5e04daa4 releaser: Prepare repository for 0.115.0-DEV
[ci skip]
2023-06-23 11:14:00 +00:00
hugoreleaser e9b716ad98 releaser: Bump versions for release of 0.114.1
[ci skip]
2023-06-23 11:02:58 +00:00
Bjørn Erik Pedersen ae31dbdd1e Revert "build(deps): bump gocloud.dev from 0.24.0 to 0.30.0"
This reverts commit 941818295d.
2023-06-23 13:01:09 +02:00
Bjørn Erik Pedersen 5b4bfc2db7 Fix broken nodeploy setup
Fixes #11149
2023-06-23 12:40:43 +02:00
dependabot[bot] 92f55f1121 build(deps): bump github.com/niklasfasching/go-org from 1.6.6 to 1.7.0
Bumps [github.com/niklasfasching/go-org](https://github.com/niklasfasching/go-org) from 1.6.6 to 1.7.0.
- [Commits](https://github.com/niklasfasching/go-org/compare/v1.6.6...v1.7.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-23 12:17:35 +02:00
Bjørn Erik Pedersen 078226dd66 Fix broken nodeploy setup
Fixes #11149
2023-06-23 12:11:45 +02:00
Joe Mooring 06d228aad1 snap: Switch from Embedded Dart Sass to Dart Sass (#11146)
- Continues to get latest version of Dart Sass during each build
- Removes superfluous BUILD_TAGS logic (we only build extended)
2023-06-21 15:39:02 -07:00
Bjørn Erik Pedersen b1016d2e26 commands: Make hugo env respect --logLevel
Fixes #11145
2023-06-21 23:18:38 +02:00
Brian Knight 49336bfc58 commands: Update Jekyll post-import output
Update CLI output after a successful Jekyll import to
suggest a maintained theme and include clearer steps
to running a server locally.

Fixes #10715

Co-authored-by: Joe Mooring <joe@mooring.com>
2023-06-21 20:38:54 +02:00
dependabot[bot] 941818295d build(deps): bump gocloud.dev from 0.24.0 to 0.30.0
Bumps [gocloud.dev](https://github.com/google/go-cloud) from 0.24.0 to 0.30.0.
- [Release notes](https://github.com/google/go-cloud/releases)
- [Commits](https://github.com/google/go-cloud/compare/v0.24.0...v0.30.0)

---
updated-dependencies:
- dependency-name: gocloud.dev
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-20 14:25:37 +02:00
dependabot[bot] 5491e55477 build(deps): bump github.com/evanw/esbuild from 0.18.4 to 0.18.5
Bumps [github.com/evanw/esbuild](https://github.com/evanw/esbuild) from 0.18.4 to 0.18.5.
- [Release notes](https://github.com/evanw/esbuild/releases)
- [Changelog](https://github.com/evanw/esbuild/blob/main/CHANGELOG.md)
- [Commits](https://github.com/evanw/esbuild/compare/v0.18.4...v0.18.5)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-20 09:57:34 +02:00
Joe Mooring bf7af9043d deps: Update github.com/tdewolff/minify/v2 v2.12.5 => v2.12.7
Fixes #11132
2023-06-20 09:18:18 +02:00
hugoreleaser 5e12bf7dc3 releaser: Prepare repository for 0.115.0-DEV
[ci skip]
2023-06-19 17:12:27 +00:00
hugoreleaser 9df2ec7988 releaser: Bump versions for release of 0.114.0
[ci skip]
2023-06-19 17:01:43 +00:00
Bjørn Erik Pedersen 59300faae4 Revert "build(deps): bump gocloud.dev from 0.24.0 to 0.29.0"
This reverts commit 7bed16c30f.

Again ...

It doesn't build on Dragonfly:

```
../gomodcache/github.com/!azure/azure-sdk-for-go/sdk/storage/azblob@v1.0.0/blockblob/chunkwriting.go:273:15: undefined: mmb
../gomodcache/github.com/!azure/azure-sdk-for-go/sdk/storage/azblob@v1.0.0/blockblob/chunkwriting.go:279:65: undefined: mmb
../gomodcache/github.com/!azure/azure-sdk-for-go/sdk/storage/azblob@v1.0.0/blockblob/chunkwriting.go:281:22: undefined: mmb
../gomodcache/github.com/!azure/azure-sdk-for-go/sdk/storage/azblob@v1.0.0/blockblob/chunkwriting.go:287:39: undefined: mmb
../gomodcache/github.com/!azure/azure-sdk-for-go/sdk/storage/azblob@v1.0.0/blockblob/chunkwriting.go:293:18: undefined: newMMB
../gomodcache/github.com/!azure/azure-sdk-for-go/sdk/storage/azblob@v1.0.0/blockblob/chunkwriting.go:303:37: undefined: mmb
• core: Total in 123.22s …
error running command: exit status 1

Exited with code exit status 1

```
2023-06-19 18:56:31 +02:00
Bjørn Erik Pedersen 9f98b3e718 docs: Regen docshelper 2023-06-19 17:52:52 +02:00
Bjørn Erik Pedersen 3ab84651c6 Add empty Environ when loading test config
To prevent OS environment vars confusing the tests.
2023-06-19 17:49:45 +02:00
Bjørn Erik Pedersen 7241b5fd51 docs: Regen CLI docs 2023-06-19 17:40:17 +02:00
Bjørn Erik Pedersen 6dfbd24797 common/loggers: Drop the bold INFO etc. prefixes
That looked a little too much.
2023-06-19 17:35:43 +02:00
Bjørn Erik Pedersen f59c3c0214 loggers: Avoid using Logf for the LevelLoggerToWriter
To prevent issues with percentage chars.
2023-06-19 15:56:44 +02:00
Bjørn Erik Pedersen 3ca29b1563 tocss/dartsas: Avoid using Logf for the internal Dart Sass logging
As that does not work when percentages are used in the log messages.
2023-06-19 13:27:03 +02:00
Bjørn Erik Pedersen fdb0b7fb19 helpers: Remove superflous formatting flag in deprecation warnings 2023-06-19 13:02:47 +02:00
Bjørn Erik Pedersen 49dd53a405 Revert "deps: Update github.com/tdewolff/minify/v2 v2.12.5 => v2.12.6"
This reverts commit 409c6c3fcd.

See #11132
2023-06-19 12:54:15 +02:00
Andreas Deininger 68d9d3ebd7 all: Fix some typos 2023-06-19 09:28:10 +02:00
Oleksandr Redko 9009c8cdca all: Fix typos in function names and comments 2023-06-19 09:26:29 +02:00
Bjørn Erik Pedersen 12dc9a6e4a deploy: Fix deploy defaults for non-zero flag values (e.g. maxDeletes, invalidateCDN)
This was broken in the config rewrite in Hugo 0.112.0.

The workaround is to be explicit about setting these flag values (even if just using the defaults), e.g.:

```
hugo deploy --invalidateCDN --maxDeletes 256
```

Fixes #11127
2023-06-18 19:38:34 +02:00
Bjørn Erik Pedersen 1b85303ac2 common/loggers: Re-add trailing newline in logger.Printf
Fixes #11130
2023-06-18 18:56:45 +02:00
dependabot[bot] 8a04d47ab7 build(deps): bump github.com/evanw/esbuild from 0.18.3 to 0.18.4
Bumps [github.com/evanw/esbuild](https://github.com/evanw/esbuild) from 0.18.3 to 0.18.4.
- [Release notes](https://github.com/evanw/esbuild/releases)
- [Changelog](https://github.com/evanw/esbuild/blob/main/CHANGELOG.md)
- [Commits](https://github.com/evanw/esbuild/compare/v0.18.3...v0.18.4)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-18 13:43:00 +02:00
Bjørn Erik Pedersen 7c9fada778 Replace the old log setup, with structured logging etc.
Fixes #11124
2023-06-18 13:03:04 +02:00
Joe Mooring 0e79446586 Revert "snap: Transition base snap from core20 to core22 (#11101)" (#11125)
Closes #11116
2023-06-17 08:41:15 -07:00
dependabot[bot] aaf2e9693a build(deps): bump github.com/evanw/esbuild from 0.18.2 to 0.18.3
Bumps [github.com/evanw/esbuild](https://github.com/evanw/esbuild) from 0.18.2 to 0.18.3.
- [Release notes](https://github.com/evanw/esbuild/releases)
- [Changelog](https://github.com/evanw/esbuild/blob/main/CHANGELOG.md)
- [Commits](https://github.com/evanw/esbuild/compare/v0.18.2...v0.18.3)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-16 07:42:25 +02:00
Bjørn Erik Pedersen ee359df172 Fix upstream Go templates bug with reversed key/value assignment
The template packages are based on go1.20.5 with the patch in befec5ddbbfbd81ec84e74e15a38044d67f8785b  added.

This also includes a security fix that now disallows Go template actions in JS literals (inside backticks).

This will throw an error saying "... appears in a JS template literal".

If you're really sure this isn't a security risk in your case, you can revert to the old behaviour:

```toml
[security]
[security.gotemplates]
allowActionJSTmpl = true
```

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

Fixes #11112
2023-06-15 23:04:33 +02:00
dependabot[bot] 0f989d5e21 build(deps): bump golang.org/x/sync from 0.2.0 to 0.3.0
Bumps [golang.org/x/sync](https://github.com/golang/sync) from 0.2.0 to 0.3.0.
- [Commits](https://github.com/golang/sync/compare/v0.2.0...v0.3.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-15 19:52:14 +02:00
Bjørn Erik Pedersen f73c567534 common/collections: Always make a copy of the input slice in Append
Fixes #10458.
2023-06-14 20:18:54 +02:00
Bjørn Erik Pedersen d178fe94fe tpl/collections: Fix append when appending a slice to a slice of slices
Fixes #11093
2023-06-14 20:18:54 +02:00
dependabot[bot] 732dcb848f build(deps): bump google.golang.org/api from 0.123.0 to 0.127.0
Bumps [google.golang.org/api](https://github.com/googleapis/google-api-go-client) from 0.123.0 to 0.127.0.
- [Release notes](https://github.com/googleapis/google-api-go-client/releases)
- [Changelog](https://github.com/googleapis/google-api-go-client/blob/main/CHANGES.md)
- [Commits](https://github.com/googleapis/google-api-go-client/compare/v0.123.0...v0.127.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-14 18:59:07 +02:00
dependabot[bot] 944859f1ad build(deps): bump golang.org/x/tools from 0.9.1 to 0.9.3
Bumps [golang.org/x/tools](https://github.com/golang/tools) from 0.9.1 to 0.9.3.
- [Release notes](https://github.com/golang/tools/releases)
- [Commits](https://github.com/golang/tools/compare/v0.9.1...v0.9.3)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-14 14:43:15 +02:00
Bjørn Erik Pedersen 90b2674ddc Re-add site.RSSLink (and deprecate it)
Fixes #11110
2023-06-14 12:18:11 +02:00
dependabot[bot] bb9377b5e5 build(deps): bump github.com/kyokomi/emoji/v2 from 2.2.11 to 2.2.12
Bumps [github.com/kyokomi/emoji/v2](https://github.com/kyokomi/emoji) from 2.2.11 to 2.2.12.
- [Release notes](https://github.com/kyokomi/emoji/releases)
- [Commits](https://github.com/kyokomi/emoji/compare/v2.2.11...v2.2.12)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-14 12:06:11 +02:00
dependabot[bot] e88f1b80b8 build(deps): bump github.com/getkin/kin-openapi from 0.117.0 to 0.118.0
Bumps [github.com/getkin/kin-openapi](https://github.com/getkin/kin-openapi) from 0.117.0 to 0.118.0.
- [Release notes](https://github.com/getkin/kin-openapi/releases)
- [Commits](https://github.com/getkin/kin-openapi/compare/v0.117.0...v0.118.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-14 12:05:47 +02:00
dependabot[bot] 516f0cb6ce build(deps): bump golang.org/x/net from 0.10.0 to 0.11.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.10.0 to 0.11.0.
- [Commits](https://github.com/golang/net/compare/v0.10.0...v0.11.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-14 11:58:31 +02:00
Bjørn Erik Pedersen 21d17566a3 Fix .Width and .Height for animated gifs
Fixes #11079
2023-06-14 09:21:22 +02:00
Joe Mooring 35e9b3ed1e snap: Transition base snap from core20 to core22 (#11101)
- Syntax changes
- Bump Go from 1.19 to 1.20
- Remove unused build tag logic (we only build the extended version)
2023-06-13 14:52:19 -07:00
Bjørn Erik Pedersen a0009e070a Merge commit '3c1deaf201a35de08d23cc58f8f03682cace3349' 2023-06-13 20:43:03 +02:00
Bjørn Erik Pedersen 3c1deaf201 Squashed 'docs/' changes from 1d5548d73..85befbb4d
85befbb4d Update plainify.md
56e137043 Update comparison operators (#2104)
4241135e0 Front matter docu: improve link to TOML spec (#2102)
5115de3c0 netlify: Hugo 0.113.0
99b74a053 Merge branch 'temp01130'
1622d5d1a docs: Regenerate CLI docs
adb4297eb netlify: Hugo 0.112.7
cd6813309 Update editors.md to include vim-hugo (#2098)
f7c2406dd netlify: Hugo 0.112.6
b891028c3 docs: Regenerate CLI docs

git-subtree-dir: docs
git-subtree-split: 85befbb4dc
2023-06-13 20:43:03 +02:00
dependabot[bot] 7bed16c30f build(deps): bump gocloud.dev from 0.24.0 to 0.29.0
Bumps [gocloud.dev](https://github.com/google/go-cloud) from 0.24.0 to 0.29.0.
- [Release notes](https://github.com/google/go-cloud/releases)
- [Commits](https://github.com/google/go-cloud/compare/v0.24.0...v0.29.0)

---
updated-dependencies:
- dependency-name: gocloud.dev
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-13 20:42:04 +02:00
Bjørn Erik Pedersen 2ba2271e4a tpl/math: Allow variadic math functions to take slice args, add math.Product, math.Sum
* Update math.Min and math.Max to allow 1 or more args, either scalar or slice, or combination of the two
* Add math.Sum (allow 1 or more args, either scalar or slice, or combination of the two)
* Add math.Product (allow 1 or more args, either scalar or slice, or combination of the two)

Fixes #11030
2023-06-13 20:00:00 +02:00
Bjørn Erik Pedersen 60a2cdf72d Fix config merge regression with root slices (e.g. disableKinds)
Fixes #11089
2023-06-13 18:01:23 +02:00
dependabot[bot] e08cfc8ca0 build(deps): bump golang.org/x/image from 0.7.0 to 0.8.0
Bumps [golang.org/x/image](https://github.com/golang/image) from 0.7.0 to 0.8.0.
- [Commits](https://github.com/golang/image/compare/v0.7.0...v0.8.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-13 17:55:34 +02:00
Bjørn Erik Pedersen ef147f4e87 commands: Remove flags log, verboseLog, add flag logLevel, deprecate flags verbose and debug
Fixes #9648
Fixes #11071
2023-06-13 17:49:38 +02:00
dependabot[bot] 489519566e build(deps): bump github.com/magefile/mage from 1.14.0 to 1.15.0
Bumps [github.com/magefile/mage](https://github.com/magefile/mage) from 1.14.0 to 1.15.0.
- [Release notes](https://github.com/magefile/mage/releases)
- [Changelog](https://github.com/magefile/mage/blob/master/.goreleaser.yml)
- [Commits](https://github.com/magefile/mage/compare/v1.14.0...v1.15.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-13 12:59:49 +02:00
dependabot[bot] 91c0b0f76b build(deps): bump github.com/pelletier/go-toml/v2 from 2.0.6 to 2.0.8
Bumps [github.com/pelletier/go-toml/v2](https://github.com/pelletier/go-toml) from 2.0.6 to 2.0.8.
- [Release notes](https://github.com/pelletier/go-toml/releases)
- [Changelog](https://github.com/pelletier/go-toml/blob/v2/.goreleaser.yaml)
- [Commits](https://github.com/pelletier/go-toml/compare/v2.0.6...v2.0.8)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-13 12:58:44 +02:00
dependabot[bot] baef235d50 build(deps): bump github.com/evanw/esbuild from 0.17.19 to 0.18.2
Bumps [github.com/evanw/esbuild](https://github.com/evanw/esbuild) from 0.17.19 to 0.18.2.
- [Release notes](https://github.com/evanw/esbuild/releases)
- [Changelog](https://github.com/evanw/esbuild/blob/main/CHANGELOG.md)
- [Commits](https://github.com/evanw/esbuild/compare/v0.17.19...v0.18.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-13 12:57:46 +02:00
Bjørn Erik Pedersen 0541a1b57d Fix handling of aliases (e.g. hugo serve)
Fixes #11090
2023-06-13 10:47:51 +02:00
Erica Mays 258884f44f cache: Set default cache path based on $USER
Change the default cache directory to `$TMPDIR/hugo_cache_$USER`, so
that multi-user systems do not have caches that interfere with each
other.  The other cache-choosing logic (e.g. Netlify exceptions,
configuration options) are not affected.

Fixes #7391
2023-06-12 21:33:35 +02:00
dependabot[bot] 254c2b323c build(deps): bump go.uber.org/atomic from 1.10.0 to 1.11.0
Bumps [go.uber.org/atomic](https://github.com/uber-go/atomic) from 1.10.0 to 1.11.0.
- [Release notes](https://github.com/uber-go/atomic/releases)
- [Changelog](https://github.com/uber-go/atomic/blob/master/CHANGELOG.md)
- [Commits](https://github.com/uber-go/atomic/compare/v1.10.0...v1.11.0)

---
updated-dependencies:
- dependency-name: go.uber.org/atomic
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-12 21:02:49 +02:00
dependabot[bot] 84f71ba8ff build(deps): bump github.com/hairyhenderson/go-codeowners
Bumps [github.com/hairyhenderson/go-codeowners](https://github.com/hairyhenderson/go-codeowners) from 0.2.3-0.20201026200250-cdc7c0759690 to 0.3.0.
- [Release notes](https://github.com/hairyhenderson/go-codeowners/releases)
- [Commits](https://github.com/hairyhenderson/go-codeowners/commits/v0.3.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-12 18:00:11 +02:00
Bjørn Erik Pedersen 69f0e88a4a resources: Remove failing and superflous test assertion 2023-06-12 17:57:18 +02:00
dependabot[bot] 82adc972e8 build(deps): bump github.com/frankban/quicktest from 1.14.4 to 1.14.5
Bumps [github.com/frankban/quicktest](https://github.com/frankban/quicktest) from 1.14.4 to 1.14.5.
- [Commits](https://github.com/frankban/quicktest/compare/v1.14.4...v1.14.5)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-12 17:57:18 +02:00
dependabot[bot] 60533fdc06 build(deps): bump github.com/mattn/go-isatty from 0.0.17 to 0.0.19
Bumps [github.com/mattn/go-isatty](https://github.com/mattn/go-isatty) from 0.0.17 to 0.0.19.
- [Commits](https://github.com/mattn/go-isatty/compare/v0.0.17...v0.0.19)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-12 17:03:22 +02:00
dependabot[bot] 261143bbbc build(deps): bump github.com/spf13/afero from 1.9.3 to 1.9.5
Bumps [github.com/spf13/afero](https://github.com/spf13/afero) from 1.9.3 to 1.9.5.
- [Release notes](https://github.com/spf13/afero/releases)
- [Commits](https://github.com/spf13/afero/compare/v1.9.3...v1.9.5)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-12 17:03:04 +02:00
Oleksandr Redko b8526f32fa commands,config: Fix typo in log and error messages 2023-06-12 16:45:20 +02:00
Bjørn Erik Pedersen ed7e250068 helpers: Avoid url.Parse in RelURL and AbsURL if we can
```
RelURL-10            159ns ± 5%      18ns ± 4%   -88.89%  (p=0.029 n=4+4)
AbsURL/relurl-10     532ns ± 0%     537ns ± 0%    +1.09%  (p=0.029 n=4+4)
AbsURL/absurl-10     142ns ± 0%       4ns ± 3%   -96.91%  (p=0.029 n=4+4)

name              old alloc/op   new alloc/op   delta
RelURL-10             144B ± 0%        0B       -100.00%  (p=0.029 n=4+4)
AbsURL/relurl-10      544B ± 0%      544B ± 0%      ~     (all equal)
AbsURL/absurl-10      144B ± 0%        0B       -100.00%  (p=0.029 n=4+4)

name              old allocs/op  new allocs/op  delta
RelURL-10             1.00 ± 0%      0.00       -100.00%  (p=0.029 n=4+4)
AbsURL/relurl-10      10.0 ± 0%      10.0 ± 0%      ~     (all equal)
AbsURL/absurl-10      1.00 ± 0%      0.00       -100.00%  (p=0.029 n=4+4)
```
2023-06-12 16:15:59 +02:00
Bjørn Erik Pedersen 6a09e7f28e Adjust benchmarks 2023-06-12 16:06:11 +02:00
Bjørn Erik Pedersen 29e5cbb699 Adjust benchmark 2023-06-12 15:18:41 +02:00
Bjørn Erik Pedersen ded6866001 Add BenchmarkAbsURL 2023-06-12 15:15:28 +02:00
Joe Mooring e1d43021ca helpers: Improve schema detection when creating relative URLs
Fixes #11080
2023-06-12 15:01:30 +02:00
Bjørn Erik Pedersen 5db215d4d6 helpers: Add a basic benchmark for RelURL 2023-06-12 14:44:07 +02:00
Bjørn Erik Pedersen b7dc93ca11 config: Remove unexpected _merge keys introduced in author and social maps
Fixes #11083
2023-06-12 14:30:43 +02:00
Bjørn Erik Pedersen f210188da3 Upgrade to v2 of the Dart Sass Embedded Protocol
Fixes #11059
2023-06-12 13:47:38 +02:00
Bjørn Erik Pedersen c782ebd89c Fix indented SASS imports for Dart Sass
Fixes #11074
2023-06-12 13:47:38 +02:00
hugoreleaser 73779707a2 releaser: Prepare repository for 0.114.0-DEV
[ci skip]
2023-06-05 15:16:33 +00:00
hugoreleaser 085c1b3d61 releaser: Bump versions for release of 0.113.0
[ci skip]
2023-06-05 15:04:51 +00:00
Bjørn Erik Pedersen 6c955cc3df docs: Regenerate CLI docs 2023-06-05 11:54:57 +02:00
Bjørn Erik Pedersen 5446900dee commands: Update CLI docs vs server and production
Fixes #11067
2023-06-05 11:53:14 +02:00
Bjørn Erik Pedersen cf38c73f53 commands: Add TLS/HTTPS support to hugo server
* commands: Add TLS/HTTPS support to hugo server

The "auto cert" handling in this PR is backed by mkcert (see link below).

To get this up and running on a new PC, you can:

```
hugo server trust
hugo server --tlsAuto
```

When `--tlsAuto` (or `--tlsCertFile` and `--tlsKeyFile`) is set and no `--baseURL` is provided as a flag, the server is
started with TLS and `https` as the protocol.

Note that you only need to run `hugo server trust` once per PC.

If you already have the key and the cert file (e.g. by using mkcert directly), you can do:

```
hugo server --tlsCertFile mycert.pem --tlsKeyFile mykey.pem
```

See https://github.com/FiloSottile/mkcert

Fixes #11064
2023-06-05 09:53:53 +02:00
hugoreleaser 536bf71abe releaser: Prepare repository for 0.113.0-DEV
[ci skip]
2023-06-02 07:19:22 +00:00
hugoreleaser ea3c95a7b0 releaser: Bump versions for release of 0.112.7
[ci skip]
2023-06-02 07:07:11 +00:00
Bjørn Erik Pedersen 5e5ce00d41 Fix menuItem.URL when pageRef is not set
Fixes #11062
2023-06-02 09:04:00 +02:00
Bjørn Erik Pedersen a191b38ac8 Don't inject livereload script on hugo -w
Fixes #11061
2023-06-02 09:04:00 +02:00
Oleksandr Redko 382c726e63 markup: Fix typo in function and struct names 2023-06-01 17:59:44 +02:00
Oleksandr Redko 4c46f9400b all: Replace deprecated ioutil with io and os 2023-06-01 17:52:21 +02:00
hugoreleaser 8c7a4e995b releaser: Prepare repository for 0.113.0-DEV
[ci skip]
2023-06-01 09:15:08 +00:00
hugoreleaser 2ca0fcc448 releaser: Bump versions for release of 0.112.6
[ci skip]
2023-06-01 09:03:29 +00:00
Bjørn Erik Pedersen a6d774e809 docs: Regenerate CLI docs 2023-06-01 10:51:41 +02:00
Bjørn Erik Pedersen dfb1895e4b Squashed 'docs/' changes from 1798dc0d5..1d5548d73
1d5548d73 build.cachebusters
3c966904d netlify: Hugo 0.112.5
b32c3a811 Bump min Go version to 1.19 when building from source (#2095)
9dea2d2f9 netlify: Hugo 0.112.4
b3fb4a1bc docs: Regenerate CLI docs
291ecd301 docs: Regen CLI docs
c886958e2 Merge commit 'd3927310d5b2404c3238f9b899db3329ea516490'

git-subtree-dir: docs
git-subtree-split: 1d5548d735
2023-06-01 10:51:24 +02:00
Bjørn Erik Pedersen 9e4072ac23 Merge commit 'dfb1895e4b82b2249d9baaed37ac7ae5e855a126' 2023-06-01 10:51:24 +02:00
Bjørn Erik Pedersen 0ef2952846 commands: Add --lang to hugo config
Fixes #11057
2023-06-01 10:49:21 +02:00
Bjørn Erik Pedersen e3ae8f025d Make sure any default mounts show up in "hugo config"
Fixes #11040
2023-06-01 10:49:21 +02:00
Bjørn Erik Pedersen 06faee5beb github: Fix Windows build
Also update some Actions to get rid of some warnings.

Fixes #11052
2023-06-01 09:54:40 +02:00
Joe Mooring 409c6c3fcd deps: Update github.com/tdewolff/minify/v2 v2.12.5 => v2.12.6 2023-05-31 08:08:26 +02:00
Joe Mooring ff77a927f9 tpl/tplimpl: Use .Language.LanguageCode in built-in templates 2023-05-30 20:10:16 +02:00
Bjørn Erik Pedersen 9cdca1f958 Fail on invalid defaultContentLanguage
Fixes #11044
2023-05-30 15:59:43 +02:00
Bjørn Erik Pedersen 6462eecfbd Avoid panic in invalid language config
Fixes #11046
2023-05-30 15:59:43 +02:00
Bjørn Erik Pedersen a7d6b1413f Don't panic on empty yaml config params
Fixes #11047
2023-05-30 15:59:43 +02:00
Bjørn Erik Pedersen 3f497d496f Prevent double escaping of image alt-text in Goldmar typographer
Fixes #11045
2023-05-30 15:03:54 +02:00
Bjørn Erik Pedersen 32585696be Fix potential deadlock in ByParam
Fixes #11039
2023-05-29 14:01:07 +02:00
hugoreleaser d47225ce9e releaser: Bump versions for release of 0.112.5
[ci skip]
2023-05-29 06:43:02 +00:00
Bjørn Erik Pedersen e3dfc76fa8 Fix it so languageCode on top level config still works
This is common for monolingual sites, and we broke this in Hugo 0.112.4.

Fixes #11037
2023-05-28 18:42:10 +02:00
hugoreleaser cd59216de4 releaser: Prepare repository for 0.113.0-DEV
[ci skip]
2023-05-28 13:15:07 +00:00
hugoreleaser e285153d7f releaser: Bump versions for release of 0.112.4
[ci skip]
2023-05-28 13:04:00 +00:00
Bjørn Erik Pedersen 20ea2e0c65 docs: Regenerate CLI docs 2023-05-28 13:07:47 +02:00
Bjørn Erik Pedersen 51d0a0ab01 commands: Add the common build flags to the config commands
Which allows to see the config with `--theme` applied.

Updates #11018
2023-05-28 13:06:26 +02:00
Bjørn Erik Pedersen fd099331ec Fix Processed images count regression for multiple languages
Fixes #11002
2023-05-28 12:55:44 +02:00
Bjørn Erik Pedersen 43f1282e73 commands: Reinstate some of the removed build flags (e.g. --theme) to new and mod
Fixes #11018
2023-05-28 12:55:44 +02:00
Bjørn Erik Pedersen e96cdfe966 Don't create the public folder unless needed
Fixes #11031
2023-05-28 12:55:44 +02:00
Bjørn Erik Pedersen ffdbce5787 docs: Regen CLI docs 2023-05-27 17:03:14 +02:00
Bjørn Erik Pedersen a838a27e4c Merge commit 'd3927310d5b2404c3238f9b899db3329ea516490' 2023-05-27 17:02:23 +02:00
Bjørn Erik Pedersen d3927310d5 Squashed 'docs/' changes from 39af43ef1..1798dc0d5
1798dc0d5 Update theme
403fa716e Update CLI documentation (#2092)
aade5a09e Correct media subtype example
53cd9dea6 netlify: Hugo 0.112.3
b78b86cb1 Add source/target warning to resources.Copy (#2091)
50c299729 netlify: Hugo 0.112.2
73197046f Change config.xxx to hugo.xxx throughout the documentation (#2090)
d489d4c6f Add hugo.WorkingDir to docs (#2089)
7487df809 Fix typos (#2088)
6d0572cd6 netlify: Hugo 0.112.1
6838600b2 netlify: Hugo 0.112.0
513e7a80f Merge branch 'tempv0.112.0'
91eb44275 Some more about 0.112.0
bd3b33a27 docs: Regen docshelper
fb3027daf docs: Regen CLI docs
8e7b8e987 Merge commit 'f96384a3b596f9bc0a3a035970b09b2c601f0ccb'
a942ceef4 tpl/tplimpl: Add img loading attribute to figure shortcode  (#10927)
0e0c7b25e tpl/urls: Return empty string when JoinPath has zero args
310ce949a tpl/urls: Add JoinPath template function
ae435ca77 tpl: Add math.Abs
f340139f8 Revert "Update syntax-highlighting.md (#10929)" (#10930)
917a0e24d Update syntax-highlighting.md (#10929)

git-subtree-dir: docs
git-subtree-split: 1798dc0d54
2023-05-27 16:59:59 +02:00
Bjørn Erik Pedersen 273d9f69a6 commands: Fail the build when no config file or config dir
Fixes #11019
2023-05-27 16:56:54 +02:00
Bjørn Erik Pedersen a6257d8a44 langs: Remove the Language.Params deprecation message for now
Closes #11025
2023-05-27 16:56:54 +02:00
Bjørn Erik Pedersen 6c2db0dfb0 Add language.LanguageCode
But keep an alias at Site

Closes #11027
2023-05-27 16:56:54 +02:00
Bjørn Erik Pedersen 8f293a1855 Fix --renderStaticToDisk regression
Fixes #11026
2023-05-27 16:56:54 +02:00
Bjørn Erik Pedersen 901cd970db commands: Re-introduce the -f shorthand for hugo new site
Fixes #11015
2023-05-27 16:56:54 +02:00
Bjørn Erik Pedersen f86b5f70a6 commands: Move the --format flag to only the commands that support it
Fixes #11022
2023-05-27 16:56:54 +02:00
hugoreleaser 3297b395d8 releaser: Prepare repository for 0.113.0-DEV
[ci skip]
2023-05-24 14:54:43 +00:00
hugoreleaser ba6f74e404 releaser: Bump versions for release of 0.112.3
[ci skip]
2023-05-24 14:42:50 +00:00
Bjørn Erik Pedersen 231374a1fa Fix regression when loading config -e is empty or HUGO_ENV or HUGO_ENVIRONMENT is set
Fixes #11013
2023-05-24 16:39:31 +02:00
hugoreleaser 5adc837904 releaser: Prepare repository for 0.113.0-DEV
[ci skip]
2023-05-24 10:57:20 +00:00
hugoreleaser f89108f2b1 releaser: Bump versions for release of 0.112.2
[ci skip]
2023-05-24 10:45:31 +00:00
Bjørn Erik Pedersen dd67922013 minifiers: Make sure JS.Version always has a value
Fixes #11012
2023-05-24 12:42:56 +02:00
Bjørn Erik Pedersen 9a235d0afc Fix regression with site.IsServer when not running a server
Fixes #11006
2023-05-24 12:42:56 +02:00
hugoreleaser 99407c39ba releaser: Prepare repository for 0.113.0-DEV
[ci skip]
2023-05-23 17:38:44 +00:00
332 changed files with 5934 additions and 2669 deletions
+73
View File
@@ -0,0 +1,73 @@
on:
push:
branches: [ master ]
pull_request:
name: TestDartSassV1
env:
GOPROXY: https://proxy.golang.org
GO111MODULE: on
DART_SASS_VERSION: 1.62.1
DART_SASS_SHA_LINUX: 3574da75a7322a539034648b8ff84ff2cca162eb924d72b663d718cd3936f075
permissions:
contents: read
jobs:
test:
strategy:
matrix:
go-version: [1.20.x]
os: [ubuntu-latest]
runs-on: ${{ matrix.os }}
steps:
- name: Checkout code
uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab
- name: Install Go
uses: actions/setup-go@fac708d6674e30b6ba41289acaab6d4b75aa0753
with:
go-version: ${{ matrix.go-version }}
check-latest: true
cache: true
cache-dependency-path: |
**/go.sum
**/go.mod
- name: Install Ruby
uses: ruby/setup-ruby@ee2113536afb7f793eed4ce60e8d3b26db912da4
with:
ruby-version: '2.7'
bundler-cache: true #
- name: Install Python
uses: actions/setup-python@3105fb18c05ddd93efea5f9e0bef7a03a6e9e7df
with:
python-version: '3.x'
- name: Install Mage
run: go install github.com/magefile/mage@v1.15.0
- name: Install asciidoctor
uses: reitzig/actions-asciidoctor@7570212ae20b63653481675fb1ff62d1073632b0
- name: Install docutils
run: |
pip install docutils
rst2html.py --version
- if: matrix.os == 'ubuntu-latest'
name: Install pandoc on Linux
run: |
sudo apt-get update -y
sudo apt-get install -y pandoc
- if: matrix.os == 'macos-latest'
run: |
brew install pandoc
- if: matrix.os == 'windows-latest'
run: |
Choco-Install -PackageName pandoc
- run: pandoc -v
- name: Install dart-sass-embedded Linux
run: |
echo "Install Dart Sass version ${DART_SASS_VERSION} ..."
curl -LJO "https://github.com/sass/dart-sass-embedded/releases/download/${DART_SASS_VERSION}/sass_embedded-${DART_SASS_VERSION}-linux-x64.tar.gz";
echo "${DART_SASS_SHA_LINUX} sass_embedded-${DART_SASS_VERSION}-linux-x64.tar.gz" | sha256sum -c;
tar -xvf "sass_embedded-${DART_SASS_VERSION}-linux-x64.tar.gz";
echo "$GITHUB_WORKSPACE/sass_embedded/" >> $GITHUB_PATH
- name: Check
run: |
dart-sass-embedded --version
mage -v check;
env:
HUGO_BUILD_TAGS: extended
+43 -24
View File
@@ -6,10 +6,10 @@ name: Test
env:
GOPROXY: https://proxy.golang.org
GO111MODULE: on
DART_SASS_VERSION: 1.56.2
DART_SASS_SHA_LINUX: 9e4f455f7b8619959d7878af2862383be58392eb963a14ff87cc512c03701e2a
DART_SASS_SHA_MACOS: 5992e979e2c30ec363f8e338822bb2b4443c74232b3340501a76180f5652cb09
DART_SASS_SHA_WINDOWS: 8d3d9117c54840e3e6a4919e43acf75ea52f28a64fc87a8e29d80ec72ee36cfb
SASS_VERSION: 1.63.2
DART_SASS_SHA_LINUX: 3ea33c95ad5c35fda6e9a0956199eef38a398f496cfb8750e02479d7d1dd42af
DART_SASS_SHA_MACOS: 11c70f259836b250b44a9cb57fed70e030f21f45069b467d371685855f1eb4f0
DART_SASS_SHA_WINDOWS: cd8cd36a619dd8e27f93d3186c52d70eb7d69472aa6c85f5094b29693e773f64
permissions:
contents: read
jobs:
@@ -21,9 +21,9 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- name: Checkout code
uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8
uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab
- name: Install Go
uses: actions/setup-go@268d8c0ca0432bb2cf416faae41297df9d262d7f
uses: actions/setup-go@fac708d6674e30b6ba41289acaab6d4b75aa0753
with:
go-version: ${{ matrix.go-version }}
check-latest: true
@@ -41,7 +41,7 @@ jobs:
with:
python-version: '3.x'
- name: Install Mage
run: go install github.com/magefile/mage@07afc7d24f4d6d6442305d49552f04fbda5ccb3e
run: go install github.com/magefile/mage@v1.15.0
- name: Install asciidoctor
uses: reitzig/actions-asciidoctor@7570212ae20b63653481675fb1ff62d1073632b0
- name: Install docutils
@@ -62,33 +62,52 @@ jobs:
- run: pandoc -v
- if: matrix.os == 'windows-latest'
run: |
Choco-Install -PackageName mingw -ArgumentList "--version","10.2.0","--allow-downgrade"
Choco-Install -PackageName mingw -ArgumentList "--version","12.2.0","--allow-downgrade"
- if: matrix.os == 'ubuntu-latest'
name: Install dart-sass-embedded Linux
run: |
echo "Install Dart Sass version ${DART_SASS_VERSION} ..."
curl -LJO "https://github.com/sass/dart-sass-embedded/releases/download/${DART_SASS_VERSION}/sass_embedded-${DART_SASS_VERSION}-linux-x64.tar.gz";
echo "${DART_SASS_SHA_LINUX} sass_embedded-${DART_SASS_VERSION}-linux-x64.tar.gz" | sha256sum -c;
tar -xvf "sass_embedded-${DART_SASS_VERSION}-linux-x64.tar.gz";
echo "$GITHUB_WORKSPACE/sass_embedded/" >> $GITHUB_PATH
echo "Install Dart Sass version ${SASS_VERSION} ..."
curl -LJO "https://github.com/sass/dart-sass/releases/download/${SASS_VERSION}/dart-sass-${SASS_VERSION}-linux-x64.tar.gz";
echo "${DART_SASS_SHA_LINUX} dart-sass-${SASS_VERSION}-linux-x64.tar.gz" | sha256sum -c;
tar -xvf "dart-sass-${SASS_VERSION}-linux-x64.tar.gz";
echo "$GOBIN"
echo "$GITHUB_WORKSPACE/dart-sass/" >> $GITHUB_PATH
- if: matrix.os == 'macos-latest'
name: Install dart-sass-embedded MacOS
run: |
echo "Install Dart Sass version ${DART_SASS_VERSION} ..."
curl -LJO "https://github.com/sass/dart-sass-embedded/releases/download/${DART_SASS_VERSION}/sass_embedded-${DART_SASS_VERSION}-macos-x64.tar.gz";
echo "${DART_SASS_SHA_MACOS} sass_embedded-${DART_SASS_VERSION}-macos-x64.tar.gz" | shasum -a 256 -c;
tar -xvf "sass_embedded-${DART_SASS_VERSION}-macos-x64.tar.gz";
echo "$GITHUB_WORKSPACE/sass_embedded/" >> $GITHUB_PATH
echo "Install Dart Sass version ${SASS_VERSION} ..."
curl -LJO "https://github.com/sass/dart-sass/releases/download/${SASS_VERSION}/dart-sass-${SASS_VERSION}-macos-x64.tar.gz";
echo "${DART_SASS_SHA_MACOS} dart-sass-${SASS_VERSION}-macos-x64.tar.gz" | shasum -a 256 -c;
tar -xvf "dart-sass-${SASS_VERSION}-macos-x64.tar.gz";
echo "$GITHUB_WORKSPACE/dart-sass/" >> $GITHUB_PATH
- if: matrix.os == 'windows-latest'
name: Install dart-sass-embedded Windows
run: |
echo "Install Dart Sass version ${env:DART_SASS_VERSION} ..."
curl -LJO "https://github.com/sass/dart-sass-embedded/releases/download/${env:DART_SASS_VERSION}/sass_embedded-${env:DART_SASS_VERSION}-windows-x64.zip";
Expand-Archive -Path "sass_embedded-${env:DART_SASS_VERSION}-windows-x64.zip" -DestinationPath .;
echo "$env:GITHUB_WORKSPACE/sass_embedded/" | Out-File -FilePath $Env:GITHUB_PATH -Encoding utf-8 -Append
- name: Check
echo "Install Dart Sass version ${env:SASS_VERSION} ..."
curl -LJO "https://github.com/sass/dart-sass/releases/download/${env:SASS_VERSION}/dart-sass-${env:SASS_VERSION}-windows-x64.zip";
Expand-Archive -Path "dart-sass-${env:SASS_VERSION}-windows-x64.zip" -DestinationPath .;
echo "$env:GITHUB_WORKSPACE/dart-sass/" | Out-File -FilePath $Env:GITHUB_PATH -Encoding utf-8 -Append
- if: matrix.os != 'windows-latest'
name: Check
run: |
sass --version;
mage -v check;
env:
HUGO_BUILD_TAGS: extended
- if: matrix.os == 'windows-latest'
# See issue #11052. We limit the build to regular test (no -race flag) on Windows for now.
name: Test
run: |
mage -v test;
env:
HUGO_BUILD_TAGS: extended
- name: Build tags
run: |
go install -tags extended,nodeploy
- if: matrix.os == 'ubuntu-latest'
name: Build for dragonfly
run: |
go install
env:
GOARCH: amd64
GOOS: dragonfly
+194 -147
View File
@@ -1,243 +1,290 @@
[bep]: https://github.com/spf13
[bugs]: https://github.com/gohugoio/hugo/issues?q=is%3Aopen+is%3Aissue+label%3ABug
[contributing]: CONTRIBUTING.md
[create a proposal]: https://github.com/gohugoio/hugo/issues/new?labels=Proposal%2C+NeedsTriage&template=feature_request.md
[documentation repository]: https://github.com/gohugoio/hugoDocs
[documentation]: https://gohugo.io/documentation
[dragonfly bsd, freebsd, netbsd, and openbsd]: https://gohugo.io/installation/bsd
[forum]: https://discourse.gohugo.io
[friends]: https://github.com/gohugoio/hugo/graphs/contributors
[go]: https://go.dev/
[hugo modules]: https://gohugo.io/hugo-modules/
[installation]: https://gohugo.io/installation
[issue queue]: https://github.com/gohugoio/hugo/issues
[linux]: https://gohugo.io/installation/linux
[macos]: https://gohugo.io/installation/macos
[prebuilt binary]: https://github.com/gohugoio/hugo/releases/latest
[requesting help]: https://discourse.gohugo.io/t/requesting-help/9132
[spf13]: https://github.com/spf13
[static site generator]: https://en.wikipedia.org/wiki/Static_site_generator
[support]: https://discourse.gohugo.io
[themes]: https://themes.gohugo.io/
[twitter]: https://twitter.com/gohugoio
[website]: https://gohugo.io
[windows]: https://gohugo.io/installation/windows
<a href="https://gohugo.io/"><img src="https://raw.githubusercontent.com/gohugoio/gohugoioTheme/master/static/images/hugo-logo-wide.svg?sanitize=true" alt="Hugo" width="565"></a>
A Fast and Flexible Static Site Generator built with love by [bep](https://github.com/bep), [spf13](https://spf13.com/) and [friends](https://github.com/gohugoio/hugo/graphs/contributors) in [Go](https://go.dev/).
A fast and flexible static site generator built with love by [bep], [spf13], and [friends] in [Go].
[Website](https://gohugo.io) |
[Forum](https://discourse.gohugo.io) |
[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)
[![Tests on Linux, MacOS and Windows](https://github.com/gohugoio/hugo/workflows/Test/badge.svg)](https://github.com/gohugoio/hugo/actions?query=workflow%3ATest)
[![Go Report Card](https://goreportcard.com/badge/github.com/gohugoio/hugo)](https://goreportcard.com/report/github.com/gohugoio/hugo)
* [Overview](#overview)
* [Banner Sponsors](#banner-sponsors)
* [Supported Architectures](#supported-architectures)
* [Choose How to Install](#choose-how-to-install)
* [Install Hugo as Your Site Generator (Binary Install)](#install-hugo-as-your-site-generator-binary-install)
* [Build and Install the Binary from Source (Using the Go toolchain)](#build-and-install-the-binary-from-source-using-the-go-toolchain)
* [The Hugo Documentation](#the-hugo-documentation)
* [Contributing to Hugo](#contributing-code-to-hugo)
* [Dependencies](#dependencies)
[Website] | [Installation] | [Documentation] | [Support] | [Contributing] | [Twitter]
## Overview
Hugo is a static HTML and CSS website generator written in [Go](https://go.dev/).
It is optimized for speed, ease of use, and configurability.
Hugo takes a directory with content and templates and renders them into a full HTML website.
Hugo is a [static site generator] written in [Go], optimized for speed and designed for flexibility. With its advanced templating system and fast asset pipelines, Hugo renders a complete site in seconds, often less.
Hugo relies on Markdown files with front matter for metadata, and you can run Hugo from any directory.
This works well for shared hosts and other systems where you dont have a privileged account.
Due to its flexible framework, multilingual support, and powerful taxonomy system, Hugo is widely used to create:
Hugo renders a typical website of moderate size in a fraction of a second.
A good rule of thumb is that each piece of content renders in around 1 millisecond.
- Corporate, government, nonprofit, education, news, event, and project sites
- Documentation sites
- Image portfolios
- Landing pages
- Business, professional, and personal blogs
- Resumes and CVs
Hugo is designed to work well for any kind of website including blogs, tumbles, and docs.
Use Hugo's embedded web server during development to instantly see changes to content, structure, behavior, and presentation. Then deploy the site to your host, or push changes to your Git provider for automated builds and deployment.
Hugo's fast asset pipelines include:
- CSS bundling &ndash; transpilation (Sass), tree shaking, minification, source maps, SRI hashing, and PostCSS integration
- JavaScript bundling &ndash; transpilation (TypeScript, JSX), tree shaking, minification, source maps, and SRI hashing
- Image processing &ndash; convert, resize, crop, rotate, adjust colors, apply filters, overlay text and images, and extract EXIF data
And with [Hugo Modules], you can share content, assets, data, translations, themes, templates, and configuration with other projects via public or private Git repositories.
## Sponsors
## Banner Sponsors
<p>&nbsp;</p>
<p float="left">
<a href="https://www.linode.com/?utm_campaign=hugosponsor&utm_medium=banner&utm_source=hugogithub" target="_blank"><img src="https://raw.githubusercontent.com/gohugoio/gohugoioTheme/master/assets/images/sponsors/linode-logo_standard_light_medium.png" width="200" alt="Linode"></a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<a href="https://cloudcannon.com/hugo-cms/?utm_campaign=HugoSponsorship&utm_source=sponsor&utm_content=gohugo" target="_blank"><img src="https://raw.githubusercontent.com/gohugoio/gohugoioTheme/master/assets/images/sponsors/cloudcannon-blue.svg" width="220" alt="CloudCannon"></a>
<p>&nbsp;</p>
## Supported Architectures
## Installation
Currently, we provide pre-built Hugo binaries for Windows, Linux, FreeBSD, NetBSD, DragonFly BSD, OpenBSD, macOS (Darwin), and [Android](https://gist.github.com/bep/a0d8a26cf6b4f8bc992729b8e50b480b) for x64, i386 and ARM architectures.
Install Hugo from a [prebuilt binary], package manager, or package repository. Please see the installation instructions for your operating system:
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.
- [macOS]
- [Linux]
- [Windows]
- [DragonFly BSD, FreeBSD, NetBSD, and OpenBSD]
**Complete documentation is available at [Hugo Documentation](https://gohugo.io/getting-started/).**
## Build from source
## Choose How to Install
Hugo is available in two editions: standard and extended. With the extended edition you can:
If you want to use Hugo as your site generator, simply install the Hugo binaries.
- Encode to the WebP format when processing images. You can decode WebP images with either edition.
- Transpile Sass to CSS using the embedded LibSass transpiler. The extended edition is not required to use the Dart Sass transpiler.
To contribute to the Hugo source code or documentation, you should [fork the Hugo GitHub project](https://github.com/gohugoio/hugo#fork-destination-box) and clone it to your local machine.
Prerequisites to build Hugo from source:
Finally, you can install the Hugo source code with `go`, build the binaries yourself, and run Hugo that way.
Building the binaries is an easy task for an experienced `go` getter.
- Standard edition: Go 1.19 or later
- Extended edition: Go 1.19 or later, and GCC
### Install Hugo as Your Site Generator (Binary Install)
Build the standard edition:
Use the [installation instructions in the Hugo documentation](https://gohugo.io/getting-started/installing/).
### Build and Install the Binary from Source (Using the Go toolchain)
#### Prerequisite Tools
* [Go (we test it with the last 2 major versions; but note that Hugo 0.95.0 only builds with >= Go 1.18.)](https://golang.org/dl/)
#### Fetch from GitHub
To fetch, build and install from the Github source:
```bash
```text
go install github.com/gohugoio/hugo@latest
```
If you want to compile with Sass/SCSS support use `-tags extended` and make sure `CGO_ENABLED=1` is set in your go environment. If you don't want to have CGO enabled, you may use the following command to temporarily enable CGO only for hugo compilation:
Build the extended edition:
```bash
```text
CGO_ENABLED=1 go install -tags extended github.com/gohugoio/hugo@latest
```
## The Hugo Documentation
## Documentation
The Hugo documentation now lives in its own repository, see https://github.com/gohugoio/hugoDocs. But we do keep a version of that documentation as a `git subtree` in this repository. To build the sub folder `/docs` as a Hugo site, you need to clone this repo:
Hugo's [documentation] includes installation instructions, a quick start guide, conceptual explanations, reference information, and examples.
```bash
git clone git@github.com:gohugoio/hugo.git
```
## Contributing code to Hugo
Please submit documentation issues and pull requests to the [documentation repository].
## Support
Please **do not use the issue queue** for questions or troubleshooting. Unless you are certain that your issue is a software defect, use the [forum].
Hugos [forum] is an active community of users and developers who answer questions, share knowledge, and provide examples. A quick search of over 20,000 topics will often answer your question. Please be sure to read about [requesting help] before asking your first question.
## Contributing
You can contribute to the Hugo project by:
- Answering questions on the [forum]
- Improving the [documentation]
- Monitoring the [issue queue]
- Creating or improving [themes]
- Squashing [bugs]
Please submit documentation issues and pull requests to the [documentation repository].
If you have an idea for an enhancement or new feature, create a new topic on the [forum] in the "Feature" category. This will help you to:
- Determine if the capability already exists
- Measure interest
- Refine the concept
If there is sufficient interest, [create a proposal]. Do not submit a pull request until the project lead accepts the proposal.
For a complete guide to contributing to Hugo, see the [Contribution Guide](CONTRIBUTING.md).
We welcome contributions to Hugo of any kind including documentation, themes,
organization, tutorials, blog posts, bug reports, issues, feature requests,
feature implementations, pull requests, answering questions on the forum,
helping to manage issues, etc.
The Hugo community and maintainers are [very active](https://github.com/gohugoio/hugo/pulse/monthly) and helpful, and the project benefits greatly from this activity.
## Asking Support Questions
We have an active [discussion forum](https://discourse.gohugo.io) where users and developers can ask questions.
Please don't use the GitHub issue tracker to ask questions.
## Reporting Issues
If you believe you have found a defect in Hugo or its documentation, use
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`).
## Dependencies
Hugo stands on the shoulder of many great open source libraries.
Hugo stands on the shoulders of great open source libraries. Run `hugo env --logLevel info` to display a list of dependencies.
If you run `hugo env -v` you will get a complete and up to date list.
<details>
<summary>See current dependencies</summary>
In Hugo 0.111.2 that list is, in lexical order:
```
cloud.google.com/go/compute="v1.6.1"
cloud.google.com/go/iam="v0.3.0"
cloud.google.com/go/storage="v1.22.0"
cloud.google.com/go="v0.101.0"
github.com/Azure/azure-pipeline-go="v0.2.3"
github.com/Azure/azure-storage-blob-go="v0.14.0"
github.com/Azure/go-autorest/autorest/adal="v0.9.15"
github.com/Azure/go-autorest/autorest/date="v0.3.0"
github.com/Azure/go-autorest/autorest="v0.11.20"
github.com/Azure/go-autorest/logger="v0.2.1"
github.com/Azure/go-autorest/tracing="v0.6.0"
```text
cloud.google.com/go/compute/metadata="v0.2.3"
cloud.google.com/go/iam="v1.1.0"
cloud.google.com/go/storage="v1.30.1"
cloud.google.com/go="v0.110.2"
github.com/Azure/azure-sdk-for-go/sdk/azcore="v1.6.1"
github.com/Azure/azure-sdk-for-go/sdk/azidentity="v1.3.0"
github.com/Azure/azure-sdk-for-go/sdk/internal="v1.3.0"
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob="v1.0.0"
github.com/Azure/go-autorest/autorest/to="v0.4.0"
github.com/AzureAD/microsoft-authentication-library-for-go="v1.0.0"
github.com/BurntSushi/locker="v0.0.0-20171006230638-a6e239ea1c69"
github.com/PuerkitoBio/purell="v1.1.1"
github.com/PuerkitoBio/urlesc="v0.0.0-20170810143723-de5bf2ad4578"
github.com/alecthomas/chroma/v2="v2.5.0"
github.com/alecthomas/chroma/v2="v2.7.0"
github.com/armon/go-radix="v1.0.0"
github.com/aws/aws-sdk-go-v2/config="v1.7.0"
github.com/aws/aws-sdk-go-v2/credentials="v1.4.0"
github.com/aws/aws-sdk-go-v2/feature/ec2/imds="v1.5.0"
github.com/aws/aws-sdk-go-v2/internal/ini="v1.2.2"
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url="v1.3.0"
github.com/aws/aws-sdk-go-v2/service/sso="v1.4.0"
github.com/aws/aws-sdk-go-v2/service/sts="v1.7.0"
github.com/aws/aws-sdk-go-v2="v1.9.0"
github.com/aws/aws-sdk-go="v1.43.5"
github.com/aws/smithy-go="v1.8.0"
github.com/bep/clock="v0.3.0"
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream="v1.4.10"
github.com/aws/aws-sdk-go-v2/config="v1.18.27"
github.com/aws/aws-sdk-go-v2/credentials="v1.13.26"
github.com/aws/aws-sdk-go-v2/feature/ec2/imds="v1.13.4"
github.com/aws/aws-sdk-go-v2/feature/s3/manager="v1.11.70"
github.com/aws/aws-sdk-go-v2/internal/configsources="v1.1.34"
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2="v2.4.28"
github.com/aws/aws-sdk-go-v2/internal/ini="v1.3.35"
github.com/aws/aws-sdk-go-v2/internal/v4a="v1.0.26"
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding="v1.9.11"
github.com/aws/aws-sdk-go-v2/service/internal/checksum="v1.1.29"
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url="v1.9.28"
github.com/aws/aws-sdk-go-v2/service/internal/s3shared="v1.14.3"
github.com/aws/aws-sdk-go-v2/service/s3="v1.35.0"
github.com/aws/aws-sdk-go-v2/service/sso="v1.12.12"
github.com/aws/aws-sdk-go-v2/service/ssooidc="v1.14.12"
github.com/aws/aws-sdk-go-v2/service/sts="v1.19.2"
github.com/aws/aws-sdk-go-v2="v1.18.1"
github.com/aws/aws-sdk-go="v1.44.284"
github.com/aws/smithy-go="v1.13.5"
github.com/bep/clocks="v0.5.0"
github.com/bep/debounce="v1.2.0"
github.com/bep/gitmap="v1.1.2"
github.com/bep/goat="v0.5.0"
github.com/bep/godartsass="v0.16.0"
github.com/bep/golibsass="v1.1.0"
github.com/bep/godartsass/v2="v2.0.0"
github.com/bep/godartsass="v1.2.0"
github.com/bep/golibsass="v1.1.1"
github.com/bep/gowebp="v0.2.0"
github.com/bep/lazycache="v0.2.0"
github.com/bep/logg="v0.2.0"
github.com/bep/mclib="v1.20400.20402"
github.com/bep/overlayfs="v0.6.0"
github.com/bep/simplecobra="v0.3.2"
github.com/bep/tmc="v0.5.1"
github.com/clbanning/mxj/v2="v2.5.7"
github.com/cli/safeexec="v1.0.0"
github.com/cli/safeexec="v1.0.1"
github.com/cpuguy83/go-md2man/v2="v2.0.2"
github.com/disintegration/gift="v1.2.1"
github.com/dlclark/regexp2="v1.7.0"
github.com/dustin/go-humanize="v1.0.0"
github.com/evanw/esbuild="v0.17.0"
github.com/frankban/quicktest="v1.14.4"
github.com/dlclark/regexp2="v1.10.0"
github.com/dustin/go-humanize="v1.0.1"
github.com/evanw/esbuild="v0.18.5"
github.com/fatih/color="v1.15.0"
github.com/frankban/quicktest="v1.14.5"
github.com/fsnotify/fsnotify="v1.6.0"
github.com/getkin/kin-openapi="v0.110.0"
github.com/getkin/kin-openapi="v0.118.0"
github.com/ghodss/yaml="v1.0.0"
github.com/go-openapi/jsonpointer="v0.19.5"
github.com/go-openapi/swag="v0.19.5"
github.com/gobuffalo/flect="v0.3.0"
github.com/go-openapi/jsonpointer="v0.19.6"
github.com/go-openapi/swag="v0.22.3"
github.com/gobuffalo/flect="v1.0.2"
github.com/gobwas/glob="v0.2.3"
github.com/gohugoio/go-i18n/v2="v2.1.3-0.20210430103248-4c28c89f8013"
github.com/gohugoio/locales="v0.14.0"
github.com/gohugoio/localescompressed="v1.0.1"
github.com/golang-jwt/jwt/v4="v4.0.0"
github.com/golang-jwt/jwt/v4="v4.5.0"
github.com/golang/groupcache="v0.0.0-20210331224755-41bb18bfe9da"
github.com/golang/protobuf="v1.5.2"
github.com/golang/protobuf="v1.5.3"
github.com/google/go-cmp="v0.5.9"
github.com/google/s2a-go="v0.1.4"
github.com/google/uuid="v1.3.0"
github.com/google/wire="v0.5.0"
github.com/googleapis/gax-go/v2="v2.3.0"
github.com/googleapis/go-type-adapters="v1.0.0"
github.com/googleapis/enterprise-certificate-proxy="v0.2.5"
github.com/googleapis/gax-go/v2="v2.11.0"
github.com/gorilla/websocket="v1.5.0"
github.com/hairyhenderson/go-codeowners="v0.2.3-0.20201026200250-cdc7c0759690"
github.com/hairyhenderson/go-codeowners="v0.3.0"
github.com/hashicorp/golang-lru/v2="v2.0.1"
github.com/invopop/yaml="v0.1.0"
github.com/jdkato/prose="v1.2.1"
github.com/jmespath/go-jmespath="v0.4.0"
github.com/josharian/intern="v1.0.0"
github.com/kr/pretty="v0.3.1"
github.com/kr/text="v0.2.0"
github.com/kyokomi/emoji/v2="v2.2.11"
github.com/mailru/easyjson="v0.0.0-20190626092158-b2ccc519800e"
github.com/kylelemons/godebug="v1.1.0"
github.com/kyokomi/emoji/v2="v2.2.12"
github.com/mailru/easyjson="v0.7.7"
github.com/marekm4/color-extractor="v1.2.0"
github.com/mattn/go-ieproxy="v0.0.1"
github.com/mattn/go-isatty="v0.0.17"
github.com/mattn/go-colorable="v0.1.13"
github.com/mattn/go-isatty="v0.0.19"
github.com/mattn/go-runewidth="v0.0.9"
github.com/mitchellh/hashstructure="v1.1.0"
github.com/mitchellh/mapstructure="v1.5.0"
github.com/mohae/deepcopy="v0.0.0-20170929034955-c48cc78d4826"
github.com/muesli/smartcrop="v0.3.0"
github.com/niklasfasching/go-org="v1.6.5"
github.com/niklasfasching/go-org="v1.7.0"
github.com/olekukonko/tablewriter="v0.0.5"
github.com/pelletier/go-toml/v2="v2.0.6"
github.com/rogpeppe/go-internal="v1.9.0"
github.com/pelletier/go-toml/v2="v2.0.8"
github.com/perimeterx/marshmallow="v1.1.4"
github.com/pkg/browser="v0.0.0-20210911075715-681adbf594b8"
github.com/pkg/errors="v0.9.1"
github.com/rogpeppe/go-internal="v1.10.1-0.20230508101108-a4f6fabd84c5"
github.com/russross/blackfriday/v2="v2.1.0"
github.com/rwcarlsen/goexif="v0.0.0-20190401172101-9e8deecbddbd"
github.com/sanity-io/litter="v1.5.5"
github.com/sass/dart-sass/compiler="1.63.6"
github.com/sass/dart-sass/implementation="1.63.6"
github.com/sass/dart-sass/protocol="2.1.0"
github.com/sass/libsass="3.6.5"
github.com/spf13/afero="v1.9.3"
github.com/spf13/cast="v1.5.0"
github.com/spf13/cobra="v1.6.1"
github.com/spf13/afero="v1.9.5"
github.com/spf13/cast="v1.5.1"
github.com/spf13/cobra="v1.7.0"
github.com/spf13/fsync="v0.9.0"
github.com/spf13/jwalterweatherman="v1.1.0"
github.com/spf13/pflag="v1.0.5"
github.com/tdewolff/minify/v2="v2.12.4"
github.com/tdewolff/parse/v2="v2.6.5"
github.com/tdewolff/minify/v2="v2.12.7"
github.com/tdewolff/parse/v2="v2.6.6"
github.com/webmproject/libwebp="v1.2.4"
github.com/yuin/goldmark="v1.5.4"
go.opencensus.io="v0.24.0"
go.uber.org/atomic="v1.10.0"
gocloud.dev="v0.24.0"
golang.org/x/crypto="v0.3.0"
golang.org/x/exp="v0.0.0-20221031165847-c99f073a8326"
golang.org/x/image="v0.5.0"
golang.org/x/net="v0.7.0"
golang.org/x/oauth2="v0.2.0"
golang.org/x/sync="v0.1.0"
golang.org/x/sys="v0.5.0"
golang.org/x/text="v0.7.0"
golang.org/x/tools="v0.4.0"
go.uber.org/atomic="v1.11.0"
go.uber.org/automaxprocs="v1.5.2"
gocloud.dev="v0.30.0"
golang.org/x/crypto="v0.10.0"
golang.org/x/exp="v0.0.0-20230321023759-10a507213a29"
golang.org/x/image="v0.8.0"
golang.org/x/mod="v0.10.0"
golang.org/x/net="v0.11.0"
golang.org/x/oauth2="v0.9.0"
golang.org/x/sync="v0.3.0"
golang.org/x/sys="v0.9.0"
golang.org/x/text="v0.10.0"
golang.org/x/tools="v0.9.3"
golang.org/x/xerrors="v0.0.0-20220907171357-04be3eba64a2"
google.golang.org/api="v0.76.0"
google.golang.org/genproto="v0.0.0-20220426171045-31bebdecfb46"
google.golang.org/grpc="v1.46.0"
google.golang.org/protobuf="v1.28.1"
google.golang.org/api="v0.128.0"
google.golang.org/appengine="v1.6.7"
google.golang.org/genproto/googleapis/api="v0.0.0-20230530153820-e85fd2cbaebc"
google.golang.org/genproto/googleapis/rpc="v0.0.0-20230530153820-e85fd2cbaebc"
google.golang.org/genproto="v0.0.0-20230530153820-e85fd2cbaebc"
google.golang.org/grpc="v1.56.0"
google.golang.org/protobuf="v1.30.0"
gopkg.in/yaml.v2="v2.4.0"
gopkg.in/yaml.v3="v3.0.1"
software.sslmate.com/src/go-pkcs12="v0.2.0"
```
</details>
+1 -1
View File
@@ -1,2 +1,2 @@
// Package cache contains the differenct cache implementations.
// Package cache contains the different cache implementations.
package cache
+1 -1
View File
@@ -81,7 +81,7 @@ type FileCacheConfig 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.
// Hugo is leninent with what types it accepts here, but we recommend using
// Hugo is lenient with what types it accepts here, but we recommend using
// a duration string, a sequence of decimal numbers, each with optional fraction and a unit suffix,
// such as "300ms", "1.5h" or "2h45m".
// Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
+2 -3
View File
@@ -16,11 +16,10 @@ package filecache_test
import (
"path/filepath"
jww "github.com/spf13/jwalterweatherman"
"testing"
"time"
"github.com/bep/logg"
qt "github.com/frankban/quicktest"
"github.com/gohugoio/hugo/htesting"
"github.com/gohugoio/hugo/hugolib"
@@ -80,7 +79,7 @@ iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAA
`
b := hugolib.NewIntegrationTestBuilder(
hugolib.IntegrationTestConfig{T: t, TxtarString: files, Running: true, RunGC: true, NeedsOsFS: true, LogLevel: jww.LevelInfo},
hugolib.IntegrationTestConfig{T: t, TxtarString: files, Running: true, RunGC: true, NeedsOsFS: true, LogLevel: logg.LevelInfo},
).Build()
b.Assert(b.GCCount, qt.Equals, 0)
+85 -92
View File
@@ -18,20 +18,21 @@ import (
"errors"
"fmt"
"io"
"log"
"os"
"os/signal"
"path/filepath"
"strings"
"sync"
"sync/atomic"
"syscall"
"time"
jww "github.com/spf13/jwalterweatherman"
"go.uber.org/automaxprocs/maxprocs"
"github.com/bep/clock"
"github.com/bep/clocks"
"github.com/bep/lazycache"
"github.com/bep/logg"
"github.com/bep/overlayfs"
"github.com/bep/simplecobra"
@@ -108,17 +109,11 @@ type rootCommand struct {
buildWatch bool
environment string
// File format to read or write (TOML, YAML, JSON).
format string
// Common build flags.
baseURL string
gc bool
poll string
panicOnWarning bool
forceSyncStatic bool
printPathWarnings bool
printUnusedTemplates bool
baseURL string
gc bool
poll string
forceSyncStatic bool
// Profile flags (for debugging of performance problems)
cpuprofile string
@@ -127,17 +122,20 @@ type rootCommand struct {
traceprofile string
printm bool
// TODO(bep) var vs string
logging bool
verbose bool
verboseLog bool
debug bool
quiet bool
logLevel string
verbose bool
debug bool
quiet bool
renderToMemory bool
cfgFile string
cfgDir string
logFile string
}
func (r *rootCommand) isVerbose() bool {
return r.logger.Level() <= logg.LevelInfo
}
func (r *rootCommand) Build(cd *simplecobra.Commandeer, bcfg hugolib.BuildCfg, cfg config.Provider) (*hugolib.HugoSites, error) {
@@ -175,7 +173,7 @@ func (r *rootCommand) ConfigFromConfig(key int32, oldConf *commonConfig) (*commo
if !configs.Base.C.Clock.IsZero() {
// TODO(bep) find a better place for this.
htime.Clock = clock.Start(configs.Base.C.Clock)
htime.Clock = clocks.Start(configs.Base.C.Clock)
}
return &commonConfig{
@@ -242,11 +240,11 @@ func (r *rootCommand) ConfigFromProvider(key int32, cfg config.Provider) (*commo
renderStaticToDisk := cfg.GetBool("renderStaticToDisk")
sourceFs := hugofs.Os
var desinationFs afero.Fs
var destinationFs afero.Fs
if cfg.GetBool("renderToDisk") {
desinationFs = hugofs.Os
destinationFs = hugofs.Os
} else {
desinationFs = afero.NewMemMapFs()
destinationFs = afero.NewMemMapFs()
if renderStaticToDisk {
// Hybrid, render dynamic content to Root.
cfg.Set("publishDirDynamic", "/")
@@ -257,7 +255,7 @@ func (r *rootCommand) ConfigFromProvider(key int32, cfg config.Provider) (*commo
}
}
fs := hugofs.NewFromSourceAndDestination(sourceFs, desinationFs, cfg)
fs := hugofs.NewFromSourceAndDestination(sourceFs, destinationFs, cfg)
if renderStaticToDisk {
dynamicFs := fs.PublishDir
@@ -285,10 +283,10 @@ func (r *rootCommand) ConfigFromProvider(key int32, cfg config.Provider) (*commo
if !base.C.Clock.IsZero() {
// TODO(bep) find a better place for this.
htime.Clock = clock.Start(configs.Base.C.Clock)
htime.Clock = clocks.Start(configs.Base.C.Clock)
}
if base.LogPathWarnings {
if base.PrintPathWarnings {
// Note that we only care about the "dynamic creates" here,
// so skip the static fs.
fs.PublishDir = hugofs.NewCreateCountingFs(fs.PublishDir)
@@ -310,7 +308,7 @@ func (r *rootCommand) ConfigFromProvider(key int32, cfg config.Provider) (*commo
func (r *rootCommand) HugFromConfig(conf *commonConfig) (*hugolib.HugoSites, error) {
h, _, err := r.hugoSites.GetOrCreate(r.configVersionID.Load(), func(key int32) (*hugolib.HugoSites, error) {
depsCfg := deps.DepsCfg{Configs: conf.configs, Fs: conf.fs, Logger: r.logger}
depsCfg := deps.DepsCfg{Configs: conf.configs, Fs: conf.fs, LogOut: r.logger.Out(), LogLevel: r.logger.Level()}
return hugolib.NewHugoSites(depsCfg)
})
return h, err
@@ -322,7 +320,7 @@ func (r *rootCommand) Hugo(cfg config.Provider) (*hugolib.HugoSites, error) {
if err != nil {
return nil, err
}
depsCfg := deps.DepsCfg{Configs: conf.configs, Fs: conf.fs, Logger: r.logger}
depsCfg := deps.DepsCfg{Configs: conf.configs, Fs: conf.fs, LogOut: r.logger.Out(), LogLevel: r.logger.Level()}
return hugolib.NewHugoSites(depsCfg)
})
return h, err
@@ -339,7 +337,7 @@ func (r *rootCommand) Run(ctx context.Context, cd *simplecobra.Commandeer, args
b := newHugoBuilder(r, nil)
if err := b.loadConfig(cd, true); err != nil {
if err := b.loadConfig(cd, false); err != nil {
return err
}
@@ -392,6 +390,9 @@ func (r *rootCommand) PreRun(cd, runner *simplecobra.Commandeer) error {
if r.quiet {
r.Out = io.Discard
}
// Used by mkcert (server).
log.SetOutput(r.Out)
r.Printf = func(format string, v ...interface{}) {
if !r.quiet {
fmt.Fprintf(r.Out, format, v...)
@@ -408,14 +409,7 @@ func (r *rootCommand) PreRun(cd, runner *simplecobra.Commandeer) error {
if err != nil {
return err
}
switch r.format {
case "json", "toml", "yaml":
// OK
default:
return fmt.Errorf("unsupported format %q; must be one of json, toml or yaml", r.format)
}
loggers.PanicOnWarning.Store(r.panicOnWarning)
r.commonConfigs = lazycache.New[int32, *commonConfig](lazycache.Options{MaxEntries: 5})
r.hugoSites = lazycache.New[int32, *hugolib.HugoSites](lazycache.Options{MaxEntries: 5})
@@ -423,48 +417,48 @@ func (r *rootCommand) PreRun(cd, runner *simplecobra.Commandeer) error {
}
func (r *rootCommand) createLogger(running bool) (loggers.Logger, error) {
var (
logHandle = io.Discard
logThreshold = jww.LevelWarn
outHandle = r.Out
stdoutThreshold = jww.LevelWarn
)
level := logg.LevelWarn
if r.verboseLog || r.logging || (r.logFile != "") {
var err error
if r.logFile != "" {
logHandle, err = os.OpenFile(r.logFile, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0666)
if err != nil {
return nil, fmt.Errorf("Failed to open log file %q: %s", r.logFile, err)
}
} else {
logHandle, err = os.CreateTemp("", "hugo")
if err != nil {
return nil, err
}
if r.logLevel != "" {
switch strings.ToLower(r.logLevel) {
case "debug":
level = logg.LevelDebug
case "info":
level = logg.LevelInfo
case "warn", "warning":
level = logg.LevelWarn
case "error":
level = logg.LevelError
default:
return nil, fmt.Errorf("invalid log level: %q, must be one of debug, warn, info or error", r.logLevel)
}
} else {
if r.verbose {
helpers.Deprecated("--verbose", "use --logLevel info", false)
level = logg.LevelInfo
}
} else if r.verbose {
stdoutThreshold = jww.LevelInfo
}
if r.debug {
stdoutThreshold = jww.LevelDebug
}
if r.verboseLog {
logThreshold = jww.LevelInfo
if r.debug {
logThreshold = jww.LevelDebug
helpers.Deprecated("--debug", "use --logLevel debug", false)
level = logg.LevelDebug
}
}
loggers.InitGlobalLogger(stdoutThreshold, logThreshold, outHandle, logHandle)
helpers.InitLoggers()
return loggers.NewLogger(stdoutThreshold, logThreshold, outHandle, logHandle, running), nil
optsLogger := loggers.Options{
Distinct: true,
Level: level,
Stdout: r.Out,
Stderr: r.Out,
StoreErrors: running,
}
return loggers.New(optsLogger), nil
}
func (r *rootCommand) Reset() {
r.logger.Reset()
loggers.Log().Reset()
}
// IsTestRun reports whether the command is running as a test.
@@ -485,7 +479,6 @@ Complete documentation is available at https://gohugo.io/.`
// Configure persistent flags
cmd.PersistentFlags().StringVarP(&r.source, "source", "s", "", "filesystem path to read files relative from")
cmd.PersistentFlags().StringVar(&r.format, "format", "toml", "preferred file format (toml, yaml or json)")
cmd.PersistentFlags().SetAnnotation("source", cobra.BashCompSubdirsInDir, []string{})
cmd.PersistentFlags().StringP("destination", "d", "", "filesystem path to write files to")
cmd.PersistentFlags().SetAnnotation("destination", cobra.BashCompSubdirsInDir, []string{})
@@ -504,17 +497,12 @@ Complete documentation is available at https://gohugo.io/.`
cmd.PersistentFlags().BoolVarP(&r.verbose, "verbose", "v", false, "verbose output")
cmd.PersistentFlags().BoolVarP(&r.debug, "debug", "", false, "debug output")
cmd.PersistentFlags().BoolVar(&r.logging, "log", false, "enable Logging")
cmd.PersistentFlags().StringVar(&r.logFile, "logFile", "", "log File path (if set, logging enabled automatically)")
cmd.PersistentFlags().BoolVar(&r.verboseLog, "verboseLog", false, "verbose logging")
cmd.PersistentFlags().StringVar(&r.logLevel, "logLevel", "", "log level (debug|info|warn|error)")
cmd.Flags().BoolVarP(&r.buildWatch, "watch", "w", false, "watch filesystem for changes and recreate as needed")
cmd.Flags().BoolVar(&r.renderToMemory, "renderToMemory", false, "render to memory (only useful for benchmark testing)")
// Set bash-completion
_ = cmd.PersistentFlags().SetAnnotation("logFile", cobra.BashCompFilenameExt, []string{})
// Configure local flags
applyLocalBuildFlags(cmd, r)
applyLocalFlagsBuild(cmd, r)
// Set bash-completion.
// Each flag must first be defined before using the SetAnnotation() call.
@@ -523,21 +511,30 @@ Complete documentation is available at https://gohugo.io/.`
return nil
}
func applyLocalBuildFlags(cmd *cobra.Command, r *rootCommand) {
// A sub set of the complete build flags. These flags are used by new and mod.
func applyLocalFlagsBuildConfig(cmd *cobra.Command, r *rootCommand) {
cmd.Flags().StringSliceP("theme", "t", []string{}, "themes to use (located in /themes/THEMENAME/)")
cmd.Flags().StringVarP(&r.baseURL, "baseURL", "b", "", "hostname (and path) to the root, e.g. https://spf13.com/")
cmd.Flags().StringP("cacheDir", "", "", "filesystem path to cache directory. Defaults: $TMPDIR/hugo_cache_$USER/")
_ = cmd.Flags().SetAnnotation("cacheDir", cobra.BashCompSubdirsInDir, []string{})
cmd.Flags().StringP("contentDir", "c", "", "filesystem path to content directory")
_ = cmd.Flags().SetAnnotation("theme", cobra.BashCompSubdirsInDir, []string{"themes"})
}
// Flags needed to do a build (used by hugo and hugo server commands)
func applyLocalFlagsBuild(cmd *cobra.Command, r *rootCommand) {
applyLocalFlagsBuildConfig(cmd, r)
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().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().StringSliceP("theme", "t", []string{}, "themes to use (located in /themes/THEMENAME/)")
cmd.Flags().StringVarP(&r.baseURL, "baseURL", "b", "", "hostname (and path) to the root, e.g. https://spf13.com/")
cmd.Flags().Bool("enableGitInfo", false, "add Git revision, date, author, and CODEOWNERS info to the pages")
cmd.Flags().StringP("layoutDir", "l", "", "filesystem path to layout directory")
cmd.Flags().BoolVar(&r.gc, "gc", false, "enable to run some cleanup tasks (remove unused cache files) after the build")
cmd.Flags().StringVar(&r.poll, "poll", "", "set this to a poll interval, e.g --poll 700ms, to use a poll based approach to watch for file system changes")
cmd.Flags().BoolVar(&r.panicOnWarning, "panicOnWarning", false, "panic on first WARNING log")
cmd.Flags().Bool("panicOnWarning", false, "panic on first WARNING log")
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().BoolVar(&r.forceSyncStatic, "forceSyncStatic", false, "copy all files when static is changed.")
@@ -545,8 +542,8 @@ func applyLocalBuildFlags(cmd *cobra.Command, r *rootCommand) {
cmd.Flags().BoolP("noChmod", "", false, "don't sync permission mode of files")
cmd.Flags().BoolP("noBuildLock", "", false, "don't create .hugo_build.lock file")
cmd.Flags().BoolP("printI18nWarnings", "", false, "print missing translations")
cmd.Flags().BoolVarP(&r.printPathWarnings, "printPathWarnings", "", false, "print warnings on duplicate target paths etc.")
cmd.Flags().BoolVarP(&r.printUnusedTemplates, "printUnusedTemplates", "", false, "print warnings on unused templates.")
cmd.Flags().BoolP("printPathWarnings", "", false, "print warnings on duplicate target paths etc.")
cmd.Flags().BoolP("printUnusedTemplates", "", false, "print warnings on unused templates.")
cmd.Flags().StringVarP(&r.cpuprofile, "profile-cpu", "", "", "write cpu profile to `file`")
cmd.Flags().StringVarP(&r.memprofile, "profile-mem", "", "", "write memory profile to `file`")
cmd.Flags().BoolVarP(&r.printm, "printMemoryUsage", "", false, "print memory usage to screen at intervals")
@@ -559,12 +556,8 @@ func applyLocalBuildFlags(cmd *cobra.Command, r *rootCommand) {
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.)")
_ = cmd.Flags().SetAnnotation("cacheDir", cobra.BashCompSubdirsInDir, []string{})
_ = cmd.Flags().SetAnnotation("destination", cobra.BashCompSubdirsInDir, []string{})
_ = cmd.Flags().SetAnnotation("theme", cobra.BashCompSubdirsInDir, []string{"themes"})
}
@@ -579,7 +572,7 @@ type simpleCommand struct {
short string
long string
run func(ctx context.Context, cd *simplecobra.Commandeer, rootCmd *rootCommand, args []string) error
withc func(cmd *cobra.Command)
withc func(cmd *cobra.Command, r *rootCommand)
initc func(cd *simplecobra.Commandeer) error
commands []simplecobra.Commander
@@ -603,6 +596,7 @@ func (c *simpleCommand) Run(ctx context.Context, cd *simplecobra.Commandeer, arg
}
func (c *simpleCommand) Init(cd *simplecobra.Commandeer) error {
c.rootCmd = cd.Root.Command.(*rootCommand)
cmd := cd.CobraCommand
cmd.Short = c.short
cmd.Long = c.long
@@ -610,13 +604,12 @@ func (c *simpleCommand) Init(cd *simplecobra.Commandeer) error {
cmd.Use = c.use
}
if c.withc != nil {
c.withc(cmd)
c.withc(cmd, c.rootCmd)
}
return nil
}
func (c *simpleCommand) PreRun(cd, runner *simplecobra.Commandeer) error {
c.rootCmd = cd.Root.Command.(*rootCommand)
if c.initc != nil {
return c.initc(cd)
}
+27 -4
View File
@@ -17,11 +17,13 @@ import (
"bytes"
"context"
"encoding/json"
"fmt"
"os"
"strings"
"time"
"github.com/bep/simplecobra"
"github.com/gohugoio/hugo/config/allconfig"
"github.com/gohugoio/hugo/modules"
"github.com/gohugoio/hugo/parser"
"github.com/gohugoio/hugo/parser/metadecoders"
@@ -40,6 +42,9 @@ func newConfigCommand() *configCommand {
type configCommand struct {
r *rootCommand
format string
lang string
commands []simplecobra.Commander
}
@@ -56,7 +61,16 @@ func (c *configCommand) Run(ctx context.Context, cd *simplecobra.Commandeer, arg
if err != nil {
return err
}
config := conf.configs.Base
var config *allconfig.Config
if c.lang != "" {
var found bool
config, found = conf.configs.LanguageConfigMap[c.lang]
if !found {
return fmt.Errorf("language %q not found", c.lang)
}
} else {
config = conf.configs.LanguageConfigSlice[0]
}
var buf bytes.Buffer
dec := json.NewEncoder(&buf)
@@ -67,7 +81,7 @@ func (c *configCommand) Run(ctx context.Context, cd *simplecobra.Commandeer, arg
return err
}
format := strings.ToLower(c.r.format)
format := strings.ToLower(c.format)
switch format {
case "json":
@@ -83,6 +97,8 @@ func (c *configCommand) Run(ctx context.Context, cd *simplecobra.Commandeer, arg
return parser.InterfaceToConfig(m, metadecoders.YAML, os.Stdout)
case "toml":
return parser.InterfaceToConfig(m, metadecoders.TOML, os.Stdout)
default:
return fmt.Errorf("unsupported format: %q", format)
}
}
@@ -90,14 +106,18 @@ func (c *configCommand) Run(ctx context.Context, cd *simplecobra.Commandeer, arg
}
func (c *configCommand) Init(cd *simplecobra.Commandeer) error {
c.r = cd.Root.Command.(*rootCommand)
cmd := cd.CobraCommand
cmd.Short = "Print the site configuration"
cmd.Long = `Print the site configuration, both default and custom settings.`
cmd.Flags().StringVar(&c.format, "format", "toml", "preferred file format (toml, yaml or json)")
cmd.Flags().StringVar(&c.lang, "lang", "", "the language to display config for. Defaults to the first language defined.")
applyLocalFlagsBuildConfig(cmd, c.r)
return nil
}
func (c *configCommand) PreRun(cd, runner *simplecobra.Commandeer) error {
c.r = cd.Root.Command.(*rootCommand)
return nil
}
@@ -172,6 +192,7 @@ func (m *configModMounts) MarshalJSON() ([]byte, error) {
}
type configMountsCommand struct {
r *rootCommand
configCmd *configCommand
}
@@ -191,7 +212,7 @@ func (c *configMountsCommand) Run(ctx context.Context, cd *simplecobra.Commandee
}
for _, m := range conf.configs.Modules {
if err := parser.InterfaceToConfig(&configModMounts{m: m, verbose: r.verbose}, metadecoders.JSON, os.Stdout); err != nil {
if err := parser.InterfaceToConfig(&configModMounts{m: m, verbose: r.isVerbose()}, metadecoders.JSON, os.Stdout); err != nil {
return err
}
}
@@ -199,8 +220,10 @@ func (c *configMountsCommand) Run(ctx context.Context, cd *simplecobra.Commandee
}
func (c *configMountsCommand) Init(cd *simplecobra.Commandeer) error {
c.r = cd.Root.Command.(*rootCommand)
cmd := cd.CobraCommand
cmd.Short = "Print the configured file mounts"
applyLocalFlagsBuildConfig(cmd, c.r)
return nil
}
+6 -5
View File
@@ -45,7 +45,7 @@ to use JSON for the front matter.`,
run: func(ctx context.Context, cd *simplecobra.Commandeer, r *rootCommand, args []string) error {
return c.convertContents(metadecoders.JSON)
},
withc: func(cmd *cobra.Command) {
withc: func(cmd *cobra.Command, r *rootCommand) {
},
},
&simpleCommand{
@@ -56,7 +56,7 @@ to use TOML for the front matter.`,
run: func(ctx context.Context, cd *simplecobra.Commandeer, r *rootCommand, args []string) error {
return c.convertContents(metadecoders.TOML)
},
withc: func(cmd *cobra.Command) {
withc: func(cmd *cobra.Command, r *rootCommand) {
},
},
&simpleCommand{
@@ -67,7 +67,7 @@ to use YAML for the front matter.`,
run: func(ctx context.Context, cd *simplecobra.Commandeer, r *rootCommand, args []string) error {
return c.convertContents(metadecoders.YAML)
},
withc: func(cmd *cobra.Command) {
withc: func(cmd *cobra.Command, r *rootCommand) {
},
},
},
@@ -84,7 +84,7 @@ type convertCommand struct {
r *rootCommand
h *hugolib.HugoSites
// Commmands.
// Commands.
commands []simplecobra.Commander
}
@@ -110,6 +110,7 @@ See convert's subcommands toJSON, toTOML and toYAML for more information.`
cmd.PersistentFlags().StringVarP(&c.outputDir, "output", "o", "", "filesystem path to write files to")
cmd.PersistentFlags().BoolVar(&c.unsafe, "unsafe", false, "enable less safe operations, please backup first")
cmd.RunE = nil
return nil
}
@@ -140,7 +141,7 @@ func (c *convertCommand) convertAndSavePage(p page.Page, site *hugolib.Site, tar
errMsg := fmt.Errorf("error processing file %q", p.File().Path())
site.Log.Infoln("ttempting to convert", p.File().Filename())
site.Log.Infoln("attempting to convert", p.File().Filename())
f := p.File()
file, err := f.FileInfo().Meta().Open()
+5 -5
View File
@@ -52,20 +52,20 @@ documentation.
if err != nil {
return err
}
deployer, err := deploy.New(h.Configs.GetFirstLanguageConfig(), h.PathSpec.PublishFs)
deployer, err := deploy.New(h.Configs.GetFirstLanguageConfig(), h.Log, h.PathSpec.PublishFs)
if err != nil {
return err
}
return deployer.Deploy(ctx)
},
withc: func(cmd *cobra.Command) {
withc: func(cmd *cobra.Command, r *rootCommand) {
cmd.Flags().String("target", "", "target deployment from deployments section in config file; defaults to the first one")
cmd.Flags().Bool("confirm", false, "ask for confirmation before making changes to the target")
cmd.Flags().Bool("dryRun", false, "dry run")
cmd.Flags().Bool("force", false, "force upload of all files")
cmd.Flags().Bool("invalidateCDN", true, "invalidate the CDN cache listed in the deployment target")
cmd.Flags().Int("maxDeletes", 256, "maximum # of files to delete, or -1 to disable")
cmd.Flags().Int("workers", 10, "number of workers to transfer files. defaults to 10")
cmd.Flags().Bool("invalidateCDN", deploy.DefaultConfig.InvalidateCDN, "invalidate the CDN cache listed in the deployment target")
cmd.Flags().Int("maxDeletes", deploy.DefaultConfig.MaxDeletes, "maximum # of files to delete, or -1 to disable")
cmd.Flags().Int("workers", deploy.DefaultConfig.Workers, "number of workers to transfer files. defaults to 10")
},
}
}
+3 -2
View File
@@ -30,8 +30,9 @@
package commands
import (
"errors"
"context"
"github.com/bep/simplecobra"
"github.com/spf13/cobra"
)
@@ -41,7 +42,7 @@ func newDeployCommand() simplecobra.Commander {
run: func(ctx context.Context, cd *simplecobra.Commandeer, r *rootCommand, args []string) error {
return nil
},
withc: func(cmd *cobra.Command) {
withc: func(cmd *cobra.Command, r *rootCommand) {
cmd.Hidden = true
},
}
+1 -1
View File
@@ -32,7 +32,7 @@ func newEnvCommand() simplecobra.Commander {
r.Printf("GOARCH=%q\n", runtime.GOARCH)
r.Printf("GOVERSION=%q\n", runtime.Version())
if r.verbose {
if r.isVerbose() {
deps := hugo.GetDependencyList()
for _, dep := range deps {
r.Printf("%s\n", dep)
+6 -4
View File
@@ -70,7 +70,7 @@ See https://xyproto.github.io/splash/docs/all.html for a preview of the availabl
formatter.WriteCSS(os.Stdout, style)
return nil
},
withc: func(cmd *cobra.Command) {
withc: func(cmd *cobra.Command, r *rootCommand) {
cmd.PersistentFlags().StringVar(&style, "style", "friendly", "highlighter style (see https://xyproto.github.io/splash/docs/)")
cmd.PersistentFlags().StringVar(&highlightStyle, "highlightStyle", "bg:#ffffcc", "style used for highlighting lines (see https://github.com/alecthomas/chroma)")
cmd.PersistentFlags().StringVar(&linesStyle, "linesStyle", "", "style used for line numbers (see https://github.com/alecthomas/chroma)")
@@ -110,7 +110,7 @@ See https://xyproto.github.io/splash/docs/all.html for a preview of the availabl
return nil
},
withc: func(cmd *cobra.Command) {
withc: func(cmd *cobra.Command, r *rootCommand) {
cmd.PersistentFlags().StringVar(&genmandir, "dir", "man/", "the directory to write the man pages.")
// For bash-completion
cmd.PersistentFlags().SetAnnotation("dir", cobra.BashCompSubdirsInDir, []string{})
@@ -167,7 +167,7 @@ url: %s
return nil
},
withc: func(cmd *cobra.Command) {
withc: func(cmd *cobra.Command, r *rootCommand) {
cmd.PersistentFlags().StringVar(&gendocdir, "dir", "/tmp/hugodoc/", "the directory to write the doc.")
// For bash-completion
cmd.PersistentFlags().SetAnnotation("dir", cobra.BashCompSubdirsInDir, []string{})
@@ -204,7 +204,7 @@ url: %s
r.Println("Done!")
return nil
},
withc: func(cmd *cobra.Command) {
withc: func(cmd *cobra.Command, r *rootCommand) {
cmd.Hidden = true
cmd.PersistentFlags().StringVarP(&docsHelperTarget, "dir", "", "docs/data", "data dir")
},
@@ -243,6 +243,8 @@ func (c *genCommand) Run(ctx context.Context, cd *simplecobra.Commandeer, args [
func (c *genCommand) Init(cd *simplecobra.Commandeer) error {
cmd := cd.CobraCommand
cmd.Short = "A collection of several useful generators."
cmd.RunE = nil
return nil
}
+3 -5
View File
@@ -79,11 +79,9 @@ func flagsToCfgWithAdditionalConfigBase(cd *simplecobra.Commandeer, cfg config.P
// Flags with a different name in the config.
keyMap := map[string]string{
"minify": "minifyOutput",
"destination": "publishDir",
"printI18nWarnings": "logI18nWarnings",
"printPathWarnings": "logPathWarnings",
"editor": "newContentEditor",
"minify": "minifyOutput",
"destination": "publishDir",
"editor": "newContentEditor",
}
// Flags that we for some reason don't want to expose in the site config.
+37 -39
View File
@@ -26,11 +26,13 @@ import (
"sync"
"time"
"github.com/bep/logg"
"github.com/bep/simplecobra"
"github.com/fsnotify/fsnotify"
"github.com/gohugoio/hugo/common/herrors"
"github.com/gohugoio/hugo/common/htime"
"github.com/gohugoio/hugo/common/hugo"
"github.com/gohugoio/hugo/common/loggers"
"github.com/gohugoio/hugo/common/maps"
"github.com/gohugoio/hugo/common/terminal"
"github.com/gohugoio/hugo/common/types"
@@ -41,9 +43,7 @@ import (
"github.com/gohugoio/hugo/hugolib/filesystems"
"github.com/gohugoio/hugo/livereload"
"github.com/gohugoio/hugo/resources/page"
"github.com/gohugoio/hugo/tpl"
"github.com/gohugoio/hugo/watcher"
"github.com/spf13/afero"
"github.com/spf13/fsync"
"golang.org/x/sync/errgroup"
"golang.org/x/sync/semaphore"
@@ -68,7 +68,6 @@ type hugoBuilder struct {
onConfigLoaded func(reloaded bool) error
fastRenderMode bool
buildWatch bool
showErrorInBrowser bool
errState hugoBuilderErrState
@@ -131,7 +130,7 @@ func (e *hugoBuilderErrState) wasErr() bool {
}
func (c *hugoBuilder) errCount() int {
return int(c.r.logger.LogCounters().ErrorCounter.Count())
return c.r.logger.LoggCount(logg.LevelError) + loggers.Log().LoggCount(logg.LevelError)
}
// getDirList provides NewWatcher() with a list of directories to watch for changes.
@@ -363,7 +362,7 @@ func (c *hugoBuilder) newWatcher(pollIntervalStr string, dirList ...string) (*wa
configFiles = conf.configs.LoadingInfo.ConfigFiles
})
c.r.logger.Println("Watching for config changes in", strings.Join(configFiles, ", "))
c.r.Println("Watching for config changes in", strings.Join(configFiles, ", "))
for _, configFile := range configFiles {
watcher.Add(configFile)
configSet[configFile] = true
@@ -418,25 +417,6 @@ func (c *hugoBuilder) build() error {
return err
}
if c.r.printPathWarnings {
hugofs.WalkFilesystems(h.Fs.PublishDir, func(fs afero.Fs) bool {
if dfs, ok := fs.(hugofs.DuplicatesReporter); ok {
dupes := dfs.ReportDuplicates()
if dupes != "" {
c.r.logger.Warnln("Duplicate target paths:", dupes)
}
}
return false
})
}
if c.r.printUnusedTemplates {
unusedTemplates := h.Tmpl().(tpl.UnusedTemplatesProvider).UnusedTemplates()
for _, unusedTemplate := range unusedTemplates {
c.r.logger.Warnf("Template %s is unused, source file %s", unusedTemplate.Name(), unusedTemplate.Filename())
}
}
h.PrintProcessingStats(os.Stdout)
c.r.Println()
}
@@ -461,6 +441,7 @@ func (c *hugoBuilder) copyStatic() (map[string]uint64, error) {
}
func (c *hugoBuilder) copyStaticTo(sourceFs *filesystems.SourceFilesystem) (uint64, error) {
infol := c.r.logger.InfoCommand("copy static")
publishDir := helpers.FilePathSeparator
if sourceFs.PublishFolder != "" {
@@ -484,13 +465,13 @@ func (c *hugoBuilder) copyStaticTo(sourceFs *filesystems.SourceFilesystem) (uint
syncer.SrcFs = fs
if syncer.Delete {
c.r.logger.Infoln("removing all files from destination that don't exist in static dirs")
infol.Logf("removing all files from destination that don't exist in static dirs")
syncer.DeleteFilter = func(f os.FileInfo) bool {
return f.IsDir() && strings.HasPrefix(f.Name(), ".")
}
}
c.r.logger.Infoln("syncing static files to", publishDir)
infol.Logf("syncing static files to %s", publishDir)
// because we are using a baseFs (to get the union right).
// set sync src to root
@@ -545,14 +526,13 @@ func (c *hugoBuilder) fullBuild(noBuildLock bool) error {
langCount map[string]uint64
)
if !c.r.quiet {
fmt.Println("Start building sites … ")
fmt.Println(hugo.BuildVersionString())
if terminal.IsTerminal(os.Stdout) {
defer func() {
fmt.Print(showCursor + clearLine)
}()
}
c.r.logger.Println("Start building sites … ")
c.r.logger.Println(hugo.BuildVersionString())
c.r.logger.Println()
if terminal.IsTerminal(os.Stdout) {
defer func() {
fmt.Print(showCursor + clearLine)
}()
}
copyStaticFunc := func() error {
@@ -990,14 +970,28 @@ func (c *hugoBuilder) loadConfig(cd *simplecobra.Commandeer, running bool) error
cfg := config.New()
cfg.Set("renderToDisk", (c.s == nil && !c.r.renderToMemory) || (c.s != nil && c.s.renderToDisk))
watch := c.r.buildWatch || (c.s != nil && c.s.serverWatch)
if c.r.environment != "" {
cfg.Set("environment", c.r.environment)
if c.r.environment == "" {
// We need to set the environment as early as possible because we need it to load the correct config.
// Check if the user has set it in env.
if env := os.Getenv("HUGO_ENVIRONMENT"); env != "" {
c.r.environment = env
} else if env := os.Getenv("HUGO_ENV"); env != "" {
c.r.environment = env
} else {
if c.s != nil {
// The server defaults to development.
c.r.environment = hugo.EnvironmentDevelopment
} else {
c.r.environment = hugo.EnvironmentProduction
}
}
}
cfg.Set("environment", c.r.environment)
cfg.Set("internal", maps.Params{
"running": running,
"watch": watch,
"verbose": c.r.verbose,
"verbose": c.r.isVerbose(),
})
conf, err := c.r.ConfigFromProvider(c.r.configVersionID.Load(), flagsToCfg(cd, cfg))
@@ -1005,6 +999,10 @@ func (c *hugoBuilder) loadConfig(cd *simplecobra.Commandeer, running bool) error
return err
}
if len(conf.configs.LoadingInfo.ConfigFiles) == 0 {
return errors.New("Unable to locate config file or config directory. Perhaps you need to create a new site.\nRun `hugo help new` for details.")
}
c.conf = conf
if c.onConfigLoaded != nil {
if err := c.onConfigLoaded(false); err != nil {
@@ -1044,8 +1042,8 @@ func (c *hugoBuilder) rebuildSites(events []fsnotify.Event) error {
if c.fastRenderMode {
c.withConf(func(conf *commonConfig) {
// Make sure we always render the home pages
for _, l := range conf.configs.Languages {
langPath := h.GetLangSubDir(l.Lang)
for _, l := range conf.configs.ConfigLangs() {
langPath := l.LanguagePrefix()
if langPath != "" {
langPath = langPath + "/"
}
+13 -10
View File
@@ -19,12 +19,11 @@ import (
"errors"
"fmt"
"io"
"log"
"os"
"path/filepath"
"regexp"
jww "github.com/spf13/jwalterweatherman"
"strconv"
"strings"
"time"
@@ -59,7 +58,7 @@ Import from Jekyll requires two paths, e.g. ` + "`hugo import jekyll jekyll_root
}
return c.importFromJekyll(args)
},
withc: func(cmd *cobra.Command) {
withc: func(cmd *cobra.Command, r *rootCommand) {
cmd.Flags().BoolVar(&c.force, "force", false, "allow import into non-empty target directory")
},
},
@@ -97,6 +96,7 @@ func (c *importCommand) Init(cd *simplecobra.Commandeer) error {
Import requires a subcommand, e.g. ` + "`hugo import jekyll jekyll_root_path target_path`."
cmd.RunE = nil
return nil
}
@@ -299,7 +299,7 @@ func (c *importCommand) convertJekyllMetaData(m any, postName string, postDate t
}
func (c *importCommand) convertJekyllPost(path, relPath, targetDir string, draft bool) error {
jww.TRACE.Println("Converting", path)
log.Println("Converting", path)
filename := filepath.Base(path)
postDate, postName, err := c.parseJekyllFilename(filename)
@@ -308,7 +308,7 @@ func (c *importCommand) convertJekyllPost(path, relPath, targetDir string, draft
return nil
}
jww.TRACE.Println(filename, postDate, postName)
log.Println(filename, postDate, postName)
targetFile := filepath.Join(targetDir, relPath)
targetParentDir := filepath.Dir(targetFile)
@@ -367,7 +367,7 @@ func (c *importCommand) copyJekyllFilesAndFolders(jekyllRoot, dest string, jekyl
if _, ok := jekyllPostDirs[entry.Name()]; !ok {
err = hugio.CopyDir(fs, sfp, dfp, nil)
if err != nil {
jww.ERROR.Println(err)
c.r.logger.Errorln(err)
}
}
}
@@ -388,7 +388,7 @@ func (c *importCommand) copyJekyllFilesAndFolders(jekyllRoot, dest string, jekyl
if !isExcept && entry.Name()[0] != '.' && entry.Name()[0] != '_' {
err = hugio.CopyFile(fs, sfp, dfp)
if err != nil {
jww.ERROR.Println(err)
c.r.logger.Errorln(err)
}
}
}
@@ -469,9 +469,12 @@ func (c *importCommand) importFromJekyll(args []string) error {
}
c.r.Println("Congratulations!", fileCount, "post(s) imported!")
c.r.Println("Now, start Hugo by yourself:\n" +
"$ git clone https://github.com/spf13/herring-cove.git " + args[1] + "/themes/herring-cove")
c.r.Println("$ cd " + args[1] + "\n$ hugo server --theme=herring-cove")
c.r.Println("Now, start Hugo by yourself:\n")
c.r.Println("cd " + args[1])
c.r.Println("git init")
c.r.Println("git submodule add https://github.com/theNewDynamic/gohugo-theme-ananke themes/ananke")
c.r.Println("echo \"theme = 'ananke'\" > hugo.toml")
c.r.Println("hugo server")
return nil
}
+1
View File
@@ -182,6 +182,7 @@ func (c *listCommand) Init(cd *simplecobra.Commandeer) error {
List requires a subcommand, e.g. hugo list drafts`
cmd.RunE = nil
return nil
}
+20 -5
View File
@@ -61,6 +61,9 @@ This command is marked as 'Experimental'. We think it's a great idea, so it's no
removed from Hugo, but we need to test this out in "real life" to get a feel of it,
so this may/will change in future versions of Hugo.
`,
withc: func(cmd *cobra.Command, r *rootCommand) {
applyLocalFlagsBuildConfig(cmd, r)
},
run: func(ctx context.Context, cd *simplecobra.Commandeer, r *rootCommand, args []string) error {
h, err := r.Hugo(flagsToCfg(cd, nil))
if err != nil {
@@ -85,6 +88,9 @@ so this may/will change in future versions of Hugo.
Note that Hugo Modules supports multi-module projects, so you can initialize a Hugo Module
inside a subfolder on GitHub, as one example.
`,
withc: func(cmd *cobra.Command, r *rootCommand) {
applyLocalFlagsBuildConfig(cmd, r)
},
run: func(ctx context.Context, cd *simplecobra.Commandeer, r *rootCommand, args []string) error {
h, err := r.Hugo(flagsToCfg(cd, nil))
if err != nil {
@@ -101,7 +107,8 @@ so this may/will change in future versions of Hugo.
name: "verify",
short: "Verify dependencies.",
long: `Verify checks that the dependencies of the current module, which are stored in a local downloaded source cache, have not been modified since being downloaded.`,
withc: func(cmd *cobra.Command) {
withc: func(cmd *cobra.Command, r *rootCommand) {
applyLocalFlagsBuildConfig(cmd, r)
cmd.Flags().BoolVarP(&clean, "clean", "", false, "delete module cache for dependencies that fail verification")
},
run: func(ctx context.Context, cd *simplecobra.Commandeer, r *rootCommand, args []string) error {
@@ -119,7 +126,8 @@ so this may/will change in future versions of Hugo.
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.
`,
withc: func(cmd *cobra.Command) {
withc: func(cmd *cobra.Command, r *rootCommand) {
applyLocalFlagsBuildConfig(cmd, r)
cmd.Flags().BoolVarP(&clean, "clean", "", false, "delete module cache for dependencies that fail verification")
},
run: func(ctx context.Context, cd *simplecobra.Commandeer, r *rootCommand, args []string) error {
@@ -135,7 +143,8 @@ Note that for vendored modules, that is the version listed and not the one from
name: "clean",
short: "Delete the Hugo Module cache for the current project.",
long: `Delete the Hugo Module cache for the current project.`,
withc: func(cmd *cobra.Command) {
withc: func(cmd *cobra.Command, r *rootCommand) {
applyLocalFlagsBuildConfig(cmd, r)
cmd.Flags().StringVarP(&pattern, "pattern", "", "", `pattern matching module paths to clean (all if not set), e.g. "**hugo*"`)
cmd.Flags().BoolVarP(&all, "all", "", false, "clean entire module cache")
},
@@ -157,6 +166,9 @@ Note that for vendored modules, that is the version listed and not the one from
&simpleCommand{
name: "tidy",
short: "Remove unused entries in go.mod and go.sum.",
withc: func(cmd *cobra.Command, r *rootCommand) {
applyLocalFlagsBuildConfig(cmd, r)
},
run: func(ctx context.Context, cd *simplecobra.Commandeer, r *rootCommand, args []string) error {
h, err := r.Hugo(flagsToCfg(cd, nil))
if err != nil {
@@ -171,6 +183,9 @@ Note that for vendored modules, that is the version listed and not the one from
long: `Vendor all module dependencies into the _vendor directory.
If a module is vendored, that is where Hugo will look for it's dependencies.
`,
withc: func(cmd *cobra.Command, r *rootCommand) {
applyLocalFlagsBuildConfig(cmd, r)
},
run: func(ctx context.Context, cd *simplecobra.Commandeer, r *rootCommand, args []string) error {
h, err := r.Hugo(flagsToCfg(cd, nil))
if err != nil {
@@ -203,13 +218,13 @@ Install the latest versions of all module dependencies:
Run "go help get" for more information. All flags available for "go get" is also relevant here.
` + commonUsageMod,
withc: func(cmd *cobra.Command) {
withc: func(cmd *cobra.Command, r *rootCommand) {
cmd.DisableFlagParsing = true
},
run: func(ctx context.Context, cd *simplecobra.Commandeer, r *rootCommand, args []string) error {
// We currently just pass on the flags we get to Go and
// need to do the flag handling manually.
if len(args) == 1 && args[0] == "-h" {
if len(args) == 1 && (args[0] == "-h" || args[0] == "--help") {
return errHelp
}
+31 -20
View File
@@ -36,6 +36,7 @@ func newNewCommand() *newCommand {
var (
force bool
contentType string
format string
)
var c *newCommand
@@ -46,16 +47,16 @@ func newNewCommand() *newCommand {
use: "content [path]",
short: "Create new content for your site",
long: `Create a new content file and automatically set the date and title.
It will guess which kind of file to create based on the path provided.
You can also specify the kind with ` + "`-k KIND`" + `.
If archetypes are provided in your theme or site, they will be used.
Ensure you run this within the root directory of your site.`,
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.
Ensure you run this within the root directory of your site.`,
run: func(ctx context.Context, cd *simplecobra.Commandeer, r *rootCommand, args []string) error {
if len(args) < 1 {
return errors.New("path needs to be provided")
return newUserError("path needs to be provided")
}
h, err := r.Hugo(flagsToCfg(cd, nil))
if err != nil {
@@ -63,10 +64,13 @@ func newNewCommand() *newCommand {
}
return create.NewContent(h, contentType, args[0], force)
},
withc: func(cmd *cobra.Command) {
withc: func(cmd *cobra.Command, r *rootCommand) {
cmd.Flags().StringVarP(&contentType, "kind", "k", "", "content type to create")
cmd.Flags().String("editor", "", "edit new content with this editor, if provided")
cmd.Flags().BoolVarP(&force, "force", "f", false, "overwrite file if it already exists")
cmd.Flags().StringVar(&format, "format", "toml", "preferred file format (toml, yaml or json)")
applyLocalFlagsBuildConfig(cmd, r)
},
},
&simpleCommand{
@@ -78,7 +82,7 @@ The new site will have the correct structure, but no content or theme yet.
Use ` + "`hugo new [contentPath]`" + ` to create new content.`,
run: func(ctx context.Context, cd *simplecobra.Commandeer, r *rootCommand, args []string) error {
if len(args) < 1 {
return errors.New("path needs to be provided")
return newUserError("path needs to be provided")
}
createpath, err := filepath.Abs(filepath.Clean(args[0]))
if err != nil {
@@ -118,7 +122,7 @@ Use ` + "`hugo new [contentPath]`" + ` to create new content.`,
return errors.New(createpath + " already exists and is not empty. See --force.")
case !isEmpty && force:
all := append(dirs, filepath.Join(createpath, "hugo."+r.format))
all := append(dirs, filepath.Join(createpath, "hugo."+format))
for _, path := range all {
if exists, _ := helpers.Exists(path, sourceFs); exists {
return errors.New(path + " already exists")
@@ -133,7 +137,7 @@ Use ` + "`hugo new [contentPath]`" + ` to create new content.`,
}
}
c.newSiteCreateConfig(sourceFs, createpath, r.format)
c.newSiteCreateConfig(sourceFs, createpath, format)
// Create a default archetype file.
helpers.SafeWriteToDisk(filepath.Join(archeTypePath, "default.md"),
@@ -144,18 +148,23 @@ Use ` + "`hugo new [contentPath]`" + ` to create new content.`,
return nil
},
withc: func(cmd *cobra.Command) {
cmd.Flags().BoolVar(&force, "force", false, "init inside non-empty directory")
withc: func(cmd *cobra.Command, r *rootCommand) {
cmd.Flags().BoolVarP(&force, "force", "f", false, "init inside non-empty directory")
cmd.Flags().StringVar(&format, "format", "toml", "preferred file format (toml, yaml or json)")
},
},
&simpleCommand{
name: "theme",
use: "theme [path]",
short: "Create a new site (skeleton)",
long: `Create a new site in the provided directory.
The new site will have the correct structure, but no content or theme yet.
Use ` + "`hugo new [contentPath]`" + ` to create new content.`,
use: "theme [name]",
short: "Create a new theme (skeleton)",
long: `Create a new theme (skeleton) called [name] in ./themes.
New theme is a skeleton. Please add content to the touched files. Add your
name to the copyright line in the license and adjust the theme.toml file
according to your needs.`,
run: func(ctx context.Context, cd *simplecobra.Commandeer, r *rootCommand, args []string) error {
if len(args) < 1 {
return newUserError("theme name needs to be provided")
}
h, err := r.Hugo(flagsToCfg(cd, nil))
if err != nil {
return err
@@ -280,6 +289,8 @@ You can also specify the kind with ` + "`-k KIND`" + `.
If archetypes are provided in your theme or site, they will be used.
Ensure you run this within the root directory of your site.`
cmd.RunE = nil
return nil
}
@@ -337,7 +348,7 @@ description = ""
homepage = "http://example.com/"
tags = []
features = []
min_version = "0.112.1"
min_version = "0.115.0"
[author]
name = ""
+1 -1
View File
@@ -42,7 +42,7 @@ func newReleaseCommand() simplecobra.Commander {
return rel.Run()
},
withc: func(cmd *cobra.Command) {
withc: func(cmd *cobra.Command, r *rootCommand) {
cmd.Hidden = true
cmd.PersistentFlags().BoolVarP(&skipPush, "skip-push", "", false, "skip pushing to remote")
cmd.PersistentFlags().BoolVarP(&try, "try", "", false, "no changes")
+165 -38
View File
@@ -16,7 +16,10 @@ package commands
import (
"bytes"
"context"
"crypto/tls"
"crypto/x509"
"encoding/json"
"encoding/pem"
"errors"
"fmt"
"io"
@@ -28,6 +31,8 @@ import (
"sync"
"sync/atomic"
"github.com/bep/mclib"
"os/signal"
"path"
"path/filepath"
@@ -55,13 +60,13 @@ import (
"github.com/gohugoio/hugo/transform"
"github.com/gohugoio/hugo/transform/livereloadinject"
"github.com/spf13/afero"
"github.com/spf13/cobra"
"github.com/spf13/fsync"
"golang.org/x/sync/errgroup"
"golang.org/x/sync/semaphore"
)
var (
logErrorRe = regexp.MustCompile(`(?s)ERROR \d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} `)
logDuplicateTemplateExecuteRe = regexp.MustCompile(`: template: .*?:\d+:\d+: executing ".*?"`)
logDuplicateTemplateParseRe = regexp.MustCompile(`: template: .*?:\d+:\d*`)
)
@@ -97,13 +102,38 @@ func newHugoBuilder(r *rootCommand, s *serverCommand, onConfigLoaded ...func(rel
}
func newServerCommand() *serverCommand {
var c *serverCommand
c = &serverCommand{
// Flags.
var uninstall bool
c := &serverCommand{
quit: make(chan bool),
commands: []simplecobra.Commander{
&simpleCommand{
name: "trust",
short: "Install the local CA in the system trust store.",
run: func(ctx context.Context, cd *simplecobra.Commandeer, r *rootCommand, args []string) error {
action := "-install"
if uninstall {
action = "-uninstall"
}
os.Args = []string{action}
return mclib.RunMain()
},
withc: func(cmd *cobra.Command, r *rootCommand) {
cmd.Flags().BoolVar(&uninstall, "uninstall", false, "Uninstall the local CA (but do not delete it).")
},
},
},
}
return c
}
func (c *serverCommand) Commands() []simplecobra.Commander {
return c.commands
}
type countingStatFs struct {
afero.Fs
statCounter uint64
@@ -204,7 +234,7 @@ func (f *fileServer) createEndpoint(i int) (*http.ServeMux, net.Listener, string
listener := f.c.serverPorts[i].ln
logger := f.c.r.logger
r.Printf("Environment: %q", f.c.hugoTry().Deps.Site.Hugo().Environment)
r.Printf("Environment: %q\n", f.c.hugoTry().Deps.Site.Hugo().Environment)
if i == 0 {
if f.c.renderToDisk {
@@ -288,7 +318,7 @@ func (f *fileServer) createEndpoint(i int) (*http.ServeMux, net.Listener, string
}
var fs afero.Fs
f.c.withConf(func(conf *commonConfig) {
fs = conf.fs.PublishDir
fs = conf.fs.PublishDirServer
})
fi, err := fs.Stat(path)
@@ -423,6 +453,9 @@ type serverCommand struct {
navigateToChanged bool
serverAppend bool
serverInterface string
tlsCertFile string
tlsKeyFile string
tlsAuto bool
serverPort int
liveReloadPort int
serverWatch bool
@@ -432,10 +465,6 @@ type serverCommand struct {
disableBrowserError bool
}
func (c *serverCommand) Commands() []simplecobra.Commander {
return c.commands
}
func (c *serverCommand) Name() string {
return "server"
}
@@ -480,8 +509,6 @@ func (c *serverCommand) Init(cd *simplecobra.Commandeer) error {
cmd.Short = "A high performance webserver"
cmd.Long = `Hugo provides its own webserver which builds and serves the site.
While hugo server is high performance, it is a webserver with limited options.
Many run it in production, but the standard behavior is for people to use it
in development and use a more full featured server such as Nginx or Caddy.
'hugo server' will avoid writing the rendered and served content to disk,
preferring to store it in memory.
@@ -495,6 +522,9 @@ of a second, you will be able to save and see your changes nearly instantly.`
cmd.Flags().IntVarP(&c.serverPort, "port", "p", 1313, "port on which the server will listen")
cmd.Flags().IntVar(&c.liveReloadPort, "liveReloadPort", -1, "port for live reloading (i.e. 443 in HTTPS proxy situations)")
cmd.Flags().StringVarP(&c.serverInterface, "bind", "", "127.0.0.1", "interface to which the server will bind")
cmd.Flags().StringVarP(&c.tlsCertFile, "tlsCertFile", "", "", "path to TLS certificate file")
cmd.Flags().StringVarP(&c.tlsKeyFile, "tlsKeyFile", "", "", "path to TLS key file")
cmd.Flags().BoolVar(&c.tlsAuto, "tlsAuto", false, "generate and use locally-trusted certificates.")
cmd.Flags().BoolVarP(&c.serverWatch, "watch", "w", true, "watch filesystem for changes and recreate as needed")
cmd.Flags().BoolVar(&c.noHTTPCache, "noHTTPCache", false, "prevent HTTP caching")
cmd.Flags().BoolVarP(&c.serverAppend, "appendPort", "", true, "append port to baseURL")
@@ -508,8 +538,11 @@ of a second, you will be able to save and see your changes nearly instantly.`
cmd.Flags().String("memstats", "", "log memory usage to this file")
cmd.Flags().String("meminterval", "100ms", "interval to poll memory usage (requires --memstats), valid time units are \"ns\", \"us\" (or \"µs\"), \"ms\", \"s\", \"m\", \"h\".")
cmd.Flags().SetAnnotation("tlsCertFile", cobra.BashCompSubdirsInDir, []string{})
cmd.Flags().SetAnnotation("tlsKeyFile", cobra.BashCompSubdirsInDir, []string{})
r := cd.Root.Command.(*rootCommand)
applyLocalBuildFlags(cmd, r)
applyLocalFlagsBuild(cmd, r)
return nil
}
@@ -525,7 +558,14 @@ func (c *serverCommand) PreRun(cd, runner *simplecobra.Commandeer) error {
if err := c.createServerPorts(cd); err != nil {
return err
}
if (c.tlsCertFile == "" || c.tlsKeyFile == "") && c.tlsAuto {
c.withConfE(func(conf *commonConfig) error {
return c.createCertificates(conf)
})
}
}
if err := c.setBaseURLsInConfig(); err != nil {
return err
}
@@ -546,9 +586,6 @@ func (c *serverCommand) PreRun(cd, runner *simplecobra.Commandeer) error {
c.doLiveReload = !c.disableLiveReload
c.fastRenderMode = !c.disableFastRender
c.showErrorInBrowser = c.doLiveReload && !c.disableBrowserError
if c.r.environment == "" {
c.r.environment = hugo.EnvironmentDevelopment
}
if c.fastRenderMode {
// For now, fast render mode only. It should, however, be fast enough
@@ -614,8 +651,8 @@ func (c *serverCommand) getErrorWithContext() any {
m := make(map[string]any)
//xwm["Error"] = errors.New(cleanErrorLog(removeErrorPrefixFromLog(c.r.logger.Errors())))
m["Error"] = errors.New(cleanErrorLog(removeErrorPrefixFromLog(c.r.logger.Errors())))
m["Error"] = cleanErrorLog(c.r.logger.Errors())
m["Version"] = hugo.BuildVersionString()
ferrors := herrors.UnwrapFileErrorsWithErrorContext(c.errState.buildErr())
m["Files"] = ferrors
@@ -623,6 +660,78 @@ func (c *serverCommand) getErrorWithContext() any {
return m
}
func (c *serverCommand) createCertificates(conf *commonConfig) error {
hostname := "localhost"
if c.r.baseURL != "" {
u, err := url.Parse(c.r.baseURL)
if err != nil {
return err
}
hostname = u.Hostname()
}
// For now, store these in the Hugo cache dir.
// Hugo should probably introduce some concept of a less temporary application directory.
keyDir := filepath.Join(conf.configs.LoadingInfo.BaseConfig.CacheDir, "_mkcerts")
// Create the directory if it doesn't exist.
if _, err := os.Stat(keyDir); os.IsNotExist(err) {
if err := os.MkdirAll(keyDir, 0777); err != nil {
return err
}
}
c.tlsCertFile = filepath.Join(keyDir, fmt.Sprintf("%s.pem", hostname))
c.tlsKeyFile = filepath.Join(keyDir, fmt.Sprintf("%s-key.pem", hostname))
// Check if the certificate already exists and is valid.
certPEM, err := ioutil.ReadFile(c.tlsCertFile)
if err == nil {
rootPem, err := ioutil.ReadFile(filepath.Join(mclib.GetCAROOT(), "rootCA.pem"))
if err == nil {
if err := c.verifyCert(rootPem, certPEM, hostname); err == nil {
c.r.Println("Using existing", c.tlsCertFile, "and", c.tlsKeyFile)
return nil
}
}
}
c.r.Println("Creating TLS certificates in", keyDir)
// Yes, this is unfortunate, but it's currently the only way to use Mkcert as a library.
os.Args = []string{"-cert-file", c.tlsCertFile, "-key-file", c.tlsKeyFile, hostname}
return mclib.RunMain()
}
func (c *serverCommand) verifyCert(rootPEM, certPEM []byte, name string) error {
roots := x509.NewCertPool()
ok := roots.AppendCertsFromPEM(rootPEM)
if !ok {
return fmt.Errorf("failed to parse root certificate")
}
block, _ := pem.Decode(certPEM)
if block == nil {
return fmt.Errorf("failed to parse certificate PEM")
}
cert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
return fmt.Errorf("failed to parse certificate: %v", err.Error())
}
opts := x509.VerifyOptions{
DNSName: name,
Roots: roots,
}
if _, err := cert.Verify(opts); err != nil {
return fmt.Errorf("failed to verify certificate: %v", err.Error())
}
return nil
}
func (c *serverCommand) createServerPorts(cd *simplecobra.Commandeer) error {
flags := cd.CobraCommand.Flags()
var cerr error
@@ -665,36 +774,40 @@ func (c *serverCommand) createServerPorts(cd *simplecobra.Commandeer) error {
// fixURL massages the baseURL into a form needed for serving
// all pages correctly.
func (c *serverCommand) fixURL(baseURL, s string, port int) (string, error) {
func (c *serverCommand) fixURL(baseURLFromConfig, baseURLFromFlag string, port int) (string, error) {
certsSet := (c.tlsCertFile != "" && c.tlsKeyFile != "") || c.tlsAuto
useLocalhost := false
if s == "" {
s = baseURL
baseURL := baseURLFromFlag
if baseURL == "" {
baseURL = baseURLFromConfig
useLocalhost = true
}
if !strings.HasSuffix(s, "/") {
s = s + "/"
if !strings.HasSuffix(baseURL, "/") {
baseURL = baseURL + "/"
}
// do an initial parse of the input string
u, err := url.Parse(s)
u, err := url.Parse(baseURL)
if err != nil {
return "", err
}
// if no Host is defined, then assume that no schema or double-slash were
// present in the url. Add a double-slash and make a best effort attempt.
if u.Host == "" && s != "/" {
s = "//" + s
if u.Host == "" && baseURL != "/" {
baseURL = "//" + baseURL
u, err = url.Parse(s)
u, err = url.Parse(baseURL)
if err != nil {
return "", err
}
}
if useLocalhost {
if u.Scheme == "https" {
if certsSet {
u.Scheme = "https"
} else if u.Scheme == "https" {
u.Scheme = "http"
}
u.Host = "localhost"
@@ -745,6 +858,9 @@ func (c *serverCommand) serve() error {
return err
}
// We need the server to share the same logger as the Hugo build (for error counts etc.)
c.r.logger = h.Log
if isMultiHost {
for _, l := range conf.configs.ConfigLangs() {
baseURLs = append(baseURLs, l.BaseURL().String())
@@ -811,10 +927,22 @@ func (c *serverCommand) serve() error {
for i := range baseURLs {
mu, listener, serverURL, endpoint, err := srv.createEndpoint(i)
srv := &http.Server{
Addr: endpoint,
Handler: mu,
var srv *http.Server
if c.tlsCertFile != "" && c.tlsKeyFile != "" {
srv = &http.Server{
Addr: endpoint,
Handler: mu,
TLSConfig: &tls.Config{
MinVersion: tls.VersionTLS12,
},
}
} else {
srv = &http.Server{
Addr: endpoint,
Handler: mu,
}
}
servers = append(servers, srv)
if doLiveReload {
@@ -828,7 +956,11 @@ func (c *serverCommand) serve() error {
}
c.r.Printf("Web Server is available at %s (bind address %s)\n", serverURL, c.serverInterface)
wg1.Go(func() error {
err = srv.Serve(listener)
if c.tlsCertFile != "" && c.tlsKeyFile != "" {
err = srv.ServeTLS(listener, c.tlsCertFile, c.tlsKeyFile)
} else {
err = srv.Serve(listener)
}
if err != nil && err != http.ErrServerClosed {
return err
}
@@ -851,7 +983,7 @@ func (c *serverCommand) serve() error {
if err != nil {
return err
}
err = ioutil.WriteFile(readyFile, b, 0777)
err = os.WriteFile(readyFile, b, 0777)
if err != nil {
return err
}
@@ -934,8 +1066,7 @@ func (s *staticSyncer) syncsStaticEvents(staticEvents []fsnotify.Event) error {
}
})
// prevent spamming the log on changes
logger := helpers.NewDistinctErrorLogger()
logger := s.c.r.logger
for _, ev := range staticEvents {
// Due to our approach of layering both directories and the content's rendered output
@@ -1074,10 +1205,6 @@ func pickOneWriteOrCreatePath(events []fsnotify.Event) string {
return name
}
func removeErrorPrefixFromLog(content string) string {
return logErrorRe.ReplaceAllLiteralString(content, "")
}
func formatByteCount(b uint64) string {
const unit = 1000
if b < unit {
-79
View File
@@ -1,79 +0,0 @@
// Copyright 2023 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"
"fmt"
"github.com/bep/simplecobra"
"github.com/spf13/cobra"
)
func newSimpleTemplateCommand() simplecobra.Commander {
return &simpleCommand{
name: "template",
run: func(ctx context.Context, cd *simplecobra.Commandeer, r *rootCommand, args []string) error {
return nil
},
withc: func(cmd *cobra.Command) {
},
}
}
func newTemplateCommand() *templateCommand {
return &templateCommand{
commands: []simplecobra.Commander{},
}
}
type templateCommand struct {
r *rootCommand
commands []simplecobra.Commander
}
func (c *templateCommand) Commands() []simplecobra.Commander {
return c.commands
}
func (c *templateCommand) Name() string {
return "template"
}
func (c *templateCommand) Run(ctx context.Context, cd *simplecobra.Commandeer, args []string) error {
conf, err := c.r.ConfigFromProvider(c.r.configVersionID.Load(), flagsToCfg(cd, nil))
if err != nil {
return err
}
fmt.Println("templateCommand.Run", conf)
return nil
}
func (c *templateCommand) Init(cd *simplecobra.Commandeer) error {
cmd := cd.CobraCommand
cmd.Short = "Print the site configuration"
cmd.Long = `Print the site configuration, both default and custom settings.`
return nil
}
func (c *templateCommand) PreRun(cd, runner *simplecobra.Commandeer) error {
c.r = cd.Root.Command.(*rootCommand)
return nil
}
+43 -3
View File
@@ -22,29 +22,64 @@ import (
// 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 any, from ...any) (any, error) {
if len(from) == 0 {
return to, nil
}
tov, toIsNil := indirect(reflect.ValueOf(to))
toIsNil = toIsNil || to == nil
var tot reflect.Type
if !toIsNil {
if tov.Kind() == reflect.Slice {
// Create a copy of tov, so we don't modify the original.
c := reflect.MakeSlice(tov.Type(), tov.Len(), tov.Len()+len(from))
reflect.Copy(c, tov)
tov = c
}
if tov.Kind() != reflect.Slice {
return nil, fmt.Errorf("expected a slice, got %T", to)
}
tot = tov.Type().Elem()
if tot.Kind() == reflect.Slice {
totvt := tot.Elem()
fromvs := make([]reflect.Value, len(from))
for i, f := range from {
fromv := reflect.ValueOf(f)
fromt := fromv.Type()
if fromt.Kind() == reflect.Slice {
fromt = fromt.Elem()
}
if totvt != fromt {
return nil, fmt.Errorf("cannot append slice of %s to slice of %s", fromt, totvt)
} else {
fromvs[i] = fromv
}
}
return reflect.Append(tov, fromvs...).Interface(), nil
}
toIsNil = tov.Len() == 0
if len(from) == 1 {
fromv := reflect.ValueOf(from[0])
if !fromv.IsValid() {
// from[0] is nil
return appendToInterfaceSliceFromValues(tov, fromv)
}
fromt := fromv.Type()
if fromt.Kind() == reflect.Slice {
fromt = fromt.Elem()
}
if fromv.Kind() == reflect.Slice {
if toIsNil {
// If we get nil []string, we just return the []string
return from[0], nil
}
fromt := reflect.TypeOf(from[0]).Elem()
// If we get []string []string, we append the from slice to to
if tot == fromt {
return reflect.AppendSlice(tov, fromv).Interface(), nil
@@ -52,6 +87,7 @@ func Append(to any, from ...any) (any, error) {
// Fall back to a []interface{} slice.
return appendToInterfaceSliceFromValues(tov, fromv)
}
}
}
}
@@ -62,7 +98,7 @@ func Append(to any, from ...any) (any, error) {
for _, f := range from {
fv := reflect.ValueOf(f)
if !fv.Type().AssignableTo(tot) {
if !fv.IsValid() || !fv.Type().AssignableTo(tot) {
// Fall back to a []interface{} slice.
tov, _ := indirect(reflect.ValueOf(to))
return appendToInterfaceSlice(tov, from...)
@@ -77,6 +113,10 @@ func appendToInterfaceSliceFromValues(slice1, slice2 reflect.Value) ([]any, erro
var tos []any
for _, slice := range []reflect.Value{slice1, slice2} {
if !slice.IsValid() {
tos = append(tos, nil)
continue
}
for i := 0; i < slice.Len(); i++ {
tos = append(tos, slice.Index(i).Interface())
}
+58 -2
View File
@@ -24,7 +24,7 @@ func TestAppend(t *testing.T) {
t.Parallel()
c := qt.New(t)
for _, test := range []struct {
for i, test := range []struct {
start any
addend []any
expected any
@@ -74,6 +74,9 @@ func TestAppend(t *testing.T) {
[]any{"c"},
false,
},
{[]string{"a", "b"}, []any{nil}, []any{"a", "b", nil}},
{[]string{"a", "b"}, []any{nil, "d", nil}, []any{"a", "b", nil, "d", nil}},
{[]any{"a", nil, "c"}, []any{"d", nil, "f"}, []any{"a", nil, "c", "d", nil, "f"}},
} {
result, err := Append(test.start, test.addend...)
@@ -85,6 +88,59 @@ func TestAppend(t *testing.T) {
}
c.Assert(err, qt.IsNil)
c.Assert(result, qt.DeepEquals, test.expected)
c.Assert(result, qt.DeepEquals, test.expected, qt.Commentf("test: [%d] %v", i, test))
}
}
// #11093
func TestAppendToMultiDimensionalSlice(t *testing.T) {
t.Parallel()
c := qt.New(t)
for _, test := range []struct {
to any
from []any
expected any
}{
{[][]string{{"a", "b"}},
[]any{[]string{"c", "d"}},
[][]string{
{"a", "b"},
{"c", "d"},
},
},
{[][]string{{"a", "b"}},
[]any{[]string{"c", "d"}, []string{"e", "f"}},
[][]string{
{"a", "b"},
{"c", "d"},
{"e", "f"},
},
},
{[][]string{{"a", "b"}},
[]any{[]int{1, 2}},
false,
},
} {
result, err := Append(test.to, test.from...)
if b, ok := test.expected.(bool); ok && !b {
c.Assert(err, qt.Not(qt.IsNil))
} else {
c.Assert(err, qt.IsNil)
c.Assert(result, qt.DeepEquals, test.expected)
}
}
}
func TestAppendShouldMakeACopyOfTheInputSlice(t *testing.T) {
t.Parallel()
c := qt.New(t)
slice := make([]string, 0, 100)
slice = append(slice, "a", "b")
result, err := Append(slice, "c")
c.Assert(err, qt.IsNil)
slice[0] = "d"
c.Assert(result, qt.DeepEquals, []string{"a", "b", "c"})
c.Assert(slice, qt.DeepEquals, []string{"d", "b"})
}
+1 -1
View File
@@ -33,7 +33,7 @@ type LineMatcher struct {
}
// LineMatcherFn is used to match a line with an error.
// It returns the column number or 0 if the line was found, but column could not be determinde. Returns -1 if no line match.
// It returns the column number or 0 if the line was found, but column could not be determined. Returns -1 if no line match.
type LineMatcherFn func(m LineMatcher) int
// SimpleLineMatcher simply matches by line number.
+24 -1
View File
@@ -59,11 +59,34 @@ func GetGID() uint64 {
return n
}
// IsFeatureNotAvailableError returns true if the given error is or contains a FeatureNotAvailableError.
func IsFeatureNotAvailableError(err error) bool {
return errors.Is(err, &FeatureNotAvailableError{})
}
// 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")
var ErrFeatureNotAvailable = &FeatureNotAvailableError{Cause: errors.New("this feature is not available in your current Hugo version, see https://goo.gl/YMrWcn for more information")}
// FeatureNotAvailableError is an error type used to signal that a feature is not available.
type FeatureNotAvailableError struct {
Cause error
}
func (e *FeatureNotAvailableError) Unwrap() error {
return e.Cause
}
func (e *FeatureNotAvailableError) Error() string {
return e.Cause.Error()
}
func (e *FeatureNotAvailableError) Is(target error) bool {
_, ok := target.(*FeatureNotAvailableError)
return ok
}
// Must panics if err != nil.
func Must(err error) {
+10
View File
@@ -14,6 +14,7 @@
package herrors
import (
"errors"
"fmt"
"testing"
@@ -34,3 +35,12 @@ func TestIsNotExist(t *testing.T) {
// os.IsNotExist returns false for wrapped errors.
c.Assert(IsNotExist(fmt.Errorf("foo: %w", afero.ErrFileNotFound)), qt.Equals, true)
}
func TestIsFeatureNotAvailableError(t *testing.T) {
c := qt.New(t)
c.Assert(IsFeatureNotAvailableError(ErrFeatureNotAvailable), qt.Equals, true)
c.Assert(IsFeatureNotAvailableError(&FeatureNotAvailableError{}), qt.Equals, true)
c.Assert(IsFeatureNotAvailableError(errors.New("asdf")), qt.Equals, false)
}
+15 -3
View File
@@ -15,11 +15,14 @@ package herrors
import (
"encoding/json"
godartsassv1 "github.com/bep/godartsass"
"fmt"
"io"
"path/filepath"
"github.com/bep/godartsass"
"github.com/bep/godartsass/v2"
"github.com/bep/golibsass/libsass/libsasserrors"
"github.com/gohugoio/hugo/common/paths"
"github.com/gohugoio/hugo/common/text"
@@ -145,6 +148,8 @@ func (e *fileError) causeString() string {
// Avoid repeating the file info in the error message.
case godartsass.SassError:
return v.Message
case godartsassv1.SassError:
return v.Message
case libsasserrors.Error:
return v.Message
default:
@@ -292,7 +297,7 @@ func extractFileTypePos(err error) (string, text.Position) {
}
// The error type from the minifier contains line number and column number.
if line, col := exctractLineNumberAndColumnNumber(err); line >= 0 {
if line, col := extractLineNumberAndColumnNumber(err); line >= 0 {
pos.LineNumber = line
pos.ColumnNumber = col
return fileType, pos
@@ -364,7 +369,7 @@ func extractOffsetAndType(e error) (int, string) {
}
}
func exctractLineNumberAndColumnNumber(e error) (int, int) {
func extractLineNumberAndColumnNumber(e error) (int, int) {
switch v := e.(type) {
case *parse.Error:
return v.Line, v.Column
@@ -385,6 +390,13 @@ func extractPosition(e error) (pos text.Position) {
pos.Filename = filename
pos.Offset = start.Offset
pos.ColumnNumber = start.Column
case godartsassv1.SassError:
span := v.Span
start := span.Start
filename, _ := paths.UrlToFilename(span.Url)
pos.Filename = filename
pos.Offset = start.Offset
pos.ColumnNumber = start.Column
case libsasserrors.Error:
pos.Filename = v.File
pos.LineNumber = v.Line
+1 -1
View File
@@ -118,7 +118,7 @@ func SafeCommand(name string, arg ...string) (*exec.Cmd, error) {
return exec.Command(bin, arg...), nil
}
// Exec encorces a security policy for commands run via os/exec.
// Exec enforces a security policy for commands run via os/exec.
type Exec struct {
sc security.Config
+2 -2
View File
@@ -18,7 +18,7 @@ import (
"strings"
"time"
"github.com/bep/clock"
"github.com/bep/clocks"
"github.com/spf13/cast"
"github.com/gohugoio/locales"
@@ -75,7 +75,7 @@ var (
"December",
}
Clock = clock.System()
Clock = clocks.System()
)
func NewTimeFormatter(ltr locales.Translator) TimeFormatter {
+49 -7
View File
@@ -22,9 +22,13 @@ import (
"sort"
"strings"
"sync"
godartsassv1 "github.com/bep/godartsass"
"github.com/mitchellh/mapstructure"
"time"
"github.com/bep/godartsass"
"github.com/bep/godartsass/v2"
"github.com/gohugoio/hugo/common/hexec"
"github.com/gohugoio/hugo/hugofs/files"
@@ -238,7 +242,10 @@ func GetDependencyListNonGo() []string {
}
if dartSass := dartSassVersion(); dartSass.ProtocolVersion != "" {
const dartSassPath = "github.com/sass/dart-sass-embedded"
var dartSassPath = "github.com/sass/dart-sass-embedded"
if IsDartSassV2() {
dartSassPath = "github.com/sass/dart-sass"
}
deps = append(deps,
formatDep(dartSassPath+"/protocol", dartSass.ProtocolVersion),
formatDep(dartSassPath+"/compiler", dartSass.CompilerVersion),
@@ -283,11 +290,46 @@ type Dependency struct {
}
func dartSassVersion() godartsass.DartSassVersion {
// This is also duplicated in the dartsass package.
const dartSassEmbeddedBinaryName = "dart-sass-embedded"
if !hexec.InPath(dartSassEmbeddedBinaryName) {
if DartSassBinaryName == "" {
return godartsass.DartSassVersion{}
}
v, _ := godartsass.Version(dartSassEmbeddedBinaryName)
return v
if IsDartSassV2() {
v, _ := godartsass.Version(DartSassBinaryName)
return v
}
v, _ := godartsassv1.Version(DartSassBinaryName)
var vv godartsass.DartSassVersion
mapstructure.WeakDecode(v, &vv)
return vv
}
// DartSassBinaryName is the name of the Dart Sass binary to use.
// TODO(beop) find a better place for this.
var DartSassBinaryName string
func init() {
DartSassBinaryName = os.Getenv("DART_SASS_BINARY")
if DartSassBinaryName == "" {
for _, name := range dartSassBinaryNamesV2 {
if hexec.InPath(name) {
DartSassBinaryName = name
break
}
}
if DartSassBinaryName == "" {
if hexec.InPath(dartSassBinaryNameV1) {
DartSassBinaryName = dartSassBinaryNameV1
}
}
}
}
var (
dartSassBinaryNameV1 = "dart-sass-embedded"
dartSassBinaryNamesV2 = []string{"dart-sass", "sass"}
)
func IsDartSassV2() bool {
return !strings.Contains(DartSassBinaryName, "embedded")
}
+3 -3
View File
@@ -17,7 +17,7 @@ package hugo
// This should be the only one.
var CurrentVersion = Version{
Major: 0,
Minor: 112,
PatchLevel: 1,
Suffix: "",
Minor: 116,
PatchLevel: 0,
Suffix: "-DEV",
}
+106
View File
@@ -0,0 +1,106 @@
// Copyright 2023 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 loggers contains some basic logging setup.
package loggers
import (
"fmt"
"io"
"strings"
"sync"
"github.com/bep/logg"
"github.com/fatih/color"
)
var bold = color.New(color.Bold)
// levelColor mapping.
var levelColor = [...]*color.Color{
logg.LevelDebug: color.New(color.FgWhite),
logg.LevelInfo: color.New(color.FgBlue),
logg.LevelWarn: color.New(color.FgYellow),
logg.LevelError: color.New(color.FgRed),
}
// levelString mapping.
var levelString = [...]string{
logg.LevelDebug: "DEBUG",
logg.LevelInfo: "INFO ",
logg.LevelWarn: "WARN ",
logg.LevelError: "ERROR",
}
// newDefaultHandler handler.
func newDefaultHandler(outWriter, errWriter io.Writer) logg.Handler {
return &defaultHandler{
outWriter: outWriter,
errWriter: errWriter,
Padding: 0,
}
}
// Default Handler implementation.
// Based on https://github.com/apex/log/blob/master/handlers/cli/cli.go
type defaultHandler struct {
mu sync.Mutex
outWriter io.Writer // Defaults to os.Stdout.
errWriter io.Writer // Defaults to os.Stderr.
Padding int
}
// HandleLog implements logg.Handler.
func (h *defaultHandler) HandleLog(e *logg.Entry) error {
color := levelColor[e.Level]
level := levelString[e.Level]
h.mu.Lock()
defer h.mu.Unlock()
var w io.Writer
if e.Level > logg.LevelInfo {
w = h.errWriter
} else {
w = h.outWriter
}
var prefix string
for _, field := range e.Fields {
if field.Name == FieldNameCmd {
prefix = fmt.Sprint(field.Value)
break
}
}
if prefix != "" {
prefix = prefix + ": "
}
color.Fprintf(w, "%s %s%s", fmt.Sprintf("%*s", h.Padding+1, level), color.Sprint(prefix), e.Message)
for _, field := range e.Fields {
if strings.HasPrefix(field.Name, reservedFieldNamePrefix) {
continue
}
fmt.Fprintf(w, " %s %v", color.Sprint(field.Name), field.Value)
}
fmt.Fprintln(w)
return nil
}
+158
View File
@@ -0,0 +1,158 @@
// Copyright 2023 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 loggers
import (
"fmt"
"strings"
"sync"
"github.com/bep/logg"
"github.com/gohugoio/hugo/identity"
)
// PanicOnWarningHook panics on warnings.
var PanicOnWarningHook = func(e *logg.Entry) error {
if e.Level != logg.LevelWarn {
return nil
}
panic(e.Message)
}
func newLogLevelCounter() *logLevelCounter {
return &logLevelCounter{
counters: make(map[logg.Level]int),
}
}
func newLogOnceHandler(threshold logg.Level) *logOnceHandler {
return &logOnceHandler{
threshold: threshold,
seen: make(map[uint64]bool),
}
}
func newStopHandler(h ...logg.Handler) *stopHandler {
return &stopHandler{
handlers: h,
}
}
func newSuppressStatementsHandler(statements map[string]bool) *suppressStatementsHandler {
return &suppressStatementsHandler{
statements: statements,
}
}
type logLevelCounter struct {
mu sync.RWMutex
counters map[logg.Level]int
}
func (h *logLevelCounter) HandleLog(e *logg.Entry) error {
h.mu.Lock()
defer h.mu.Unlock()
h.counters[e.Level]++
return nil
}
var stopError = fmt.Errorf("stop")
type logOnceHandler struct {
threshold logg.Level
mu sync.Mutex
seen map[uint64]bool
}
func (h *logOnceHandler) HandleLog(e *logg.Entry) error {
if e.Level < h.threshold {
// We typically only want to enable this for warnings and above.
// The common use case is that many go routines may log the same error.
return nil
}
h.mu.Lock()
defer h.mu.Unlock()
hash := identity.HashUint64(e.Level, e.Message, e.Fields)
if h.seen[hash] {
return stopError
}
h.seen[hash] = true
return nil
}
func (h *logOnceHandler) reset() {
h.mu.Lock()
defer h.mu.Unlock()
h.seen = make(map[uint64]bool)
}
type stopHandler struct {
handlers []logg.Handler
}
// HandleLog implements logg.Handler.
func (h *stopHandler) HandleLog(e *logg.Entry) error {
for _, handler := range h.handlers {
if err := handler.HandleLog(e); err != nil {
if err == stopError {
return nil
}
return err
}
}
return nil
}
type suppressStatementsHandler struct {
statements map[string]bool
}
func (h *suppressStatementsHandler) HandleLog(e *logg.Entry) error {
for _, field := range e.Fields {
if field.Name == FieldNameStatementID {
if h.statements[field.Value.(string)] {
return stopError
}
}
}
return nil
}
// replacer creates a new log handler that does string replacement in log messages.
func replacer(repl *strings.Replacer) logg.Handler {
return logg.HandlerFunc(func(e *logg.Entry) error {
e.Message = repl.Replace(e.Message)
for i, field := range e.Fields {
if s, ok := field.Value.(string); ok {
e.Fields[i].Value = repl.Replace(s)
}
}
return nil
})
}
// whiteSpaceTrimmer creates a new log handler that trims whitespace from log messages and string fields.
func whiteSpaceTrimmer() logg.Handler {
return logg.HandlerFunc(func(e *logg.Entry) error {
e.Message = strings.TrimSpace(e.Message)
for i, field := range e.Fields {
if s, ok := field.Value.(string); ok {
e.Fields[i].Value = strings.TrimSpace(s)
}
}
return nil
})
}
+90
View File
@@ -0,0 +1,90 @@
// Copyright 2023 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 loggers
import (
"fmt"
"io"
"strings"
"sync"
"github.com/bep/logg"
)
// newNoColoursHandler creates a new NoColoursHandler
func newNoColoursHandler(outWriter, errWriter io.Writer, noLevelPrefix bool, predicate func(*logg.Entry) bool) *noColoursHandler {
if predicate == nil {
predicate = func(e *logg.Entry) bool { return true }
}
return &noColoursHandler{
noLevelPrefix: noLevelPrefix,
outWriter: outWriter,
errWriter: errWriter,
predicate: predicate,
}
}
type noColoursHandler struct {
mu sync.Mutex
outWriter io.Writer // Defaults to os.Stdout.
errWriter io.Writer // Defaults to os.Stderr.
predicate func(*logg.Entry) bool
noLevelPrefix bool
}
func (h *noColoursHandler) HandleLog(e *logg.Entry) error {
if !h.predicate(e) {
return nil
}
h.mu.Lock()
defer h.mu.Unlock()
var w io.Writer
if e.Level > logg.LevelInfo {
w = h.errWriter
} else {
w = h.outWriter
}
var prefix string
for _, field := range e.Fields {
if field.Name == FieldNameCmd {
prefix = fmt.Sprint(field.Value)
break
}
}
if prefix != "" {
prefix = prefix + ": "
}
if h.noLevelPrefix {
fmt.Fprintf(w, "%s%s", prefix, e.Message)
} else {
fmt.Fprintf(w, "%s %s%s", levelString[e.Level], prefix, e.Message)
}
for _, field := range e.Fields {
if strings.HasPrefix(field.Name, reservedFieldNamePrefix) {
continue
}
fmt.Fprintf(w, " %s %q", field.Name, field.Value)
}
fmt.Fprintln(w)
return nil
}
-63
View File
@@ -1,63 +0,0 @@
// Copyright 2020 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package loggers
import (
"fmt"
)
// IgnorableLogger is a logger that ignores certain log statements.
type IgnorableLogger interface {
Logger
Errorsf(statementID, format string, v ...any)
Apply(logger Logger) IgnorableLogger
}
type ignorableLogger struct {
Logger
statements map[string]bool
}
// NewIgnorableLogger wraps the given logger and ignores the log statement IDs given.
func NewIgnorableLogger(logger Logger, statements map[string]bool) IgnorableLogger {
if statements == nil {
statements = make(map[string]bool)
}
return ignorableLogger{
Logger: logger,
statements: statements,
}
}
// Errorsf logs statementID as an ERROR if not configured as ignoreable.
func (l ignorableLogger) Errorsf(statementID, format string, v ...any) {
if l.statements[statementID] {
// Ignore.
return
}
ignoreMsg := fmt.Sprintf(`
If you feel that this should not be logged as an ERROR, you can ignore it by adding this to your site config:
ignoreErrors = [%q]`, statementID)
format += ignoreMsg
l.Errorf(format, v...)
}
func (l ignorableLogger) Apply(logger Logger) IgnorableLogger {
return ignorableLogger{
Logger: logger,
statements: l.statements,
}
}
+307
View File
@@ -0,0 +1,307 @@
// Copyright 2023 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 loggers
import (
"fmt"
"io"
"os"
"strings"
"time"
"github.com/bep/logg"
"github.com/bep/logg/handlers/multi"
"github.com/gohugoio/hugo/common/terminal"
)
var (
reservedFieldNamePrefix = "__h_field_"
// FieldNameCmd is the name of the field that holds the command name.
FieldNameCmd = reservedFieldNamePrefix + "_cmd"
// Used to suppress statements.
FieldNameStatementID = reservedFieldNamePrefix + "__h_field_statement_id"
)
// Options defines options for the logger.
type Options struct {
Level logg.Level
Stdout io.Writer
Stderr io.Writer
Distinct bool
StoreErrors bool
HandlerPost func(e *logg.Entry) error
SuppresssStatements map[string]bool
}
// New creates a new logger with the given options.
func New(opts Options) Logger {
if opts.Stdout == nil {
opts.Stdout = os.Stdout
}
if opts.Stderr == nil {
opts.Stderr = os.Stdout
}
if opts.Level == 0 {
opts.Level = logg.LevelWarn
}
var logHandler logg.Handler
if terminal.PrintANSIColors(os.Stdout) {
logHandler = newDefaultHandler(opts.Stdout, opts.Stderr)
} else {
logHandler = newNoColoursHandler(opts.Stdout, opts.Stderr, false, nil)
}
errorsw := &strings.Builder{}
logCounters := newLogLevelCounter()
handlers := []logg.Handler{
whiteSpaceTrimmer(),
logHandler,
logCounters,
}
if opts.HandlerPost != nil {
var hookHandler logg.HandlerFunc = func(e *logg.Entry) error {
opts.HandlerPost(e)
return nil
}
handlers = append(handlers, hookHandler)
}
if opts.StoreErrors {
h := newNoColoursHandler(io.Discard, errorsw, true, func(e *logg.Entry) bool {
return e.Level >= logg.LevelError
})
handlers = append(handlers, h)
}
logHandler = multi.New(handlers...)
var logOnce *logOnceHandler
if opts.Distinct {
logOnce = newLogOnceHandler(logg.LevelWarn)
logHandler = newStopHandler(logOnce, logHandler)
}
if opts.SuppresssStatements != nil && len(opts.SuppresssStatements) > 0 {
logHandler = newStopHandler(newSuppressStatementsHandler(opts.SuppresssStatements), logHandler)
}
logger := logg.New(
logg.Options{
Level: opts.Level,
Handler: logHandler,
},
)
l := logger.WithLevel(opts.Level)
reset := func() {
logCounters.mu.Lock()
defer logCounters.mu.Unlock()
logCounters.counters = make(map[logg.Level]int)
errorsw.Reset()
if logOnce != nil {
logOnce.reset()
}
}
return &logAdapter{
logCounters: logCounters,
errors: errorsw,
reset: reset,
out: opts.Stdout,
level: opts.Level,
logger: logger,
debugl: l.WithLevel(logg.LevelDebug),
infol: l.WithLevel(logg.LevelInfo),
warnl: l.WithLevel(logg.LevelWarn),
errorl: l.WithLevel(logg.LevelError),
}
}
// NewDefault creates a new logger with the default options.
func NewDefault() Logger {
opts := Options{
Distinct: true,
Level: logg.LevelWarn,
Stdout: os.Stdout,
Stderr: os.Stdout,
}
return New(opts)
}
func LevelLoggerToWriter(l logg.LevelLogger) io.Writer {
return logWriter{l: l}
}
type Logger interface {
Debugf(format string, v ...any)
Debugln(v ...any)
Error() logg.LevelLogger
Errorf(format string, v ...any)
Errorln(v ...any)
Errors() string
Errorsf(id, format string, v ...any)
Info() logg.LevelLogger
InfoCommand(command string) logg.LevelLogger
Infof(format string, v ...any)
Infoln(v ...any)
Level() logg.Level
LoggCount(logg.Level) int
Logger() logg.Logger
Out() io.Writer
Printf(format string, v ...any)
Println(v ...any)
PrintTimerIfDelayed(start time.Time, name string)
Reset()
Warn() logg.LevelLogger
WarnCommand(command string) logg.LevelLogger
Warnf(format string, v ...any)
Warnln(v ...any)
}
type logAdapter struct {
logCounters *logLevelCounter
errors *strings.Builder
reset func()
out io.Writer
level logg.Level
logger logg.Logger
debugl logg.LevelLogger
infol logg.LevelLogger
warnl logg.LevelLogger
errorl logg.LevelLogger
}
func (l *logAdapter) Debugf(format string, v ...any) {
l.debugl.Logf(format, v...)
}
func (l *logAdapter) Debugln(v ...any) {
l.debugl.Logf(l.sprint(v...))
}
func (l *logAdapter) Info() logg.LevelLogger {
return l.infol
}
func (l *logAdapter) InfoCommand(command string) logg.LevelLogger {
return l.infol.WithField(FieldNameCmd, command)
}
func (l *logAdapter) Infof(format string, v ...any) {
l.infol.Logf(format, v...)
}
func (l *logAdapter) Infoln(v ...any) {
l.infol.Logf(l.sprint(v...))
}
func (l *logAdapter) Level() logg.Level {
return l.level
}
func (l *logAdapter) LoggCount(level logg.Level) int {
l.logCounters.mu.RLock()
defer l.logCounters.mu.RUnlock()
return l.logCounters.counters[level]
}
func (l *logAdapter) Logger() logg.Logger {
return l.logger
}
func (l *logAdapter) Out() io.Writer {
return l.out
}
// PrintTimerIfDelayed prints a time statement to the FEEDBACK logger
// if considerable time is spent.
func (l *logAdapter) PrintTimerIfDelayed(start time.Time, name string) {
elapsed := time.Since(start)
milli := int(1000 * elapsed.Seconds())
if milli < 500 {
return
}
l.Printf("%s in %v ms", name, milli)
}
func (l *logAdapter) Printf(format string, v ...any) {
// Add trailing newline if not present.
if !strings.HasSuffix(format, "\n") {
format += "\n"
}
fmt.Fprintf(l.out, format, v...)
}
func (l *logAdapter) Println(v ...any) {
fmt.Fprintln(l.out, v...)
}
func (l *logAdapter) Reset() {
l.reset()
}
func (l *logAdapter) Warn() logg.LevelLogger {
return l.warnl
}
func (l *logAdapter) Warnf(format string, v ...any) {
l.warnl.Logf(format, v...)
}
func (l *logAdapter) WarnCommand(command string) logg.LevelLogger {
return l.warnl.WithField(FieldNameCmd, command)
}
func (l *logAdapter) Warnln(v ...any) {
l.warnl.Logf(l.sprint(v...))
}
func (l *logAdapter) Error() logg.LevelLogger {
return l.errorl
}
func (l *logAdapter) Errorf(format string, v ...any) {
l.errorl.Logf(format, v...)
}
func (l *logAdapter) Errorln(v ...any) {
l.errorl.Logf(l.sprint(v...))
}
func (l *logAdapter) Errors() string {
return l.errors.String()
}
func (l *logAdapter) Errorsf(id, format string, v ...any) {
l.errorl.WithField(FieldNameStatementID, id).Logf(format, v...)
}
func (l *logAdapter) sprint(v ...any) string {
return strings.TrimRight(fmt.Sprintln(v...), "\n")
}
type logWriter struct {
l logg.LevelLogger
}
func (w logWriter) Write(p []byte) (n int, err error) {
w.l.Log(logg.String(string(p)))
return len(p), nil
}
+156
View File
@@ -0,0 +1,156 @@
// Copyright 2023 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 loggers_test
import (
"io"
"strings"
"testing"
"github.com/bep/logg"
qt "github.com/frankban/quicktest"
"github.com/gohugoio/hugo/common/loggers"
)
func TestLogDistinct(t *testing.T) {
c := qt.New(t)
opts := loggers.Options{
Distinct: true,
StoreErrors: true,
Stdout: io.Discard,
Stderr: io.Discard,
}
l := loggers.New(opts)
for i := 0; i < 10; i++ {
l.Errorln("error 1")
l.Errorln("error 2")
l.Warnln("warn 1")
}
c.Assert(strings.Count(l.Errors(), "error 1"), qt.Equals, 1)
c.Assert(l.LoggCount(logg.LevelError), qt.Equals, 2)
c.Assert(l.LoggCount(logg.LevelWarn), qt.Equals, 1)
}
func TestHookLast(t *testing.T) {
c := qt.New(t)
opts := loggers.Options{
HandlerPost: func(e *logg.Entry) error {
panic(e.Message)
},
Stdout: io.Discard,
Stderr: io.Discard,
}
l := loggers.New(opts)
c.Assert(func() { l.Warnln("warn 1") }, qt.PanicMatches, "warn 1")
}
func TestOptionStoreErrors(t *testing.T) {
c := qt.New(t)
var sb strings.Builder
opts := loggers.Options{
StoreErrors: true,
Stderr: &sb,
Stdout: &sb,
}
l := loggers.New(opts)
l.Errorln("error 1")
l.Errorln("error 2")
errorsStr := l.Errors()
c.Assert(errorsStr, qt.Contains, "error 1")
c.Assert(errorsStr, qt.Not(qt.Contains), "ERROR")
c.Assert(sb.String(), qt.Contains, "error 1")
c.Assert(sb.String(), qt.Contains, "ERROR")
}
func TestLogCount(t *testing.T) {
c := qt.New(t)
opts := loggers.Options{
StoreErrors: true,
}
l := loggers.New(opts)
l.Errorln("error 1")
l.Errorln("error 2")
l.Warnln("warn 1")
c.Assert(l.LoggCount(logg.LevelError), qt.Equals, 2)
c.Assert(l.LoggCount(logg.LevelWarn), qt.Equals, 1)
c.Assert(l.LoggCount(logg.LevelInfo), qt.Equals, 0)
}
func TestSuppressStatements(t *testing.T) {
c := qt.New(t)
opts := loggers.Options{
StoreErrors: true,
SuppresssStatements: map[string]bool{
"error-1": true,
},
}
l := loggers.New(opts)
l.Error().WithField(loggers.FieldNameStatementID, "error-1").Logf("error 1")
l.Errorln("error 2")
errorsStr := l.Errors()
c.Assert(errorsStr, qt.Not(qt.Contains), "error 1")
c.Assert(errorsStr, qt.Contains, "error 2")
c.Assert(l.LoggCount(logg.LevelError), qt.Equals, 1)
}
func TestReset(t *testing.T) {
c := qt.New(t)
opts := loggers.Options{
StoreErrors: true,
Distinct: true,
Stdout: io.Discard,
Stderr: io.Discard,
}
l := loggers.New(opts)
for i := 0; i < 3; i++ {
l.Errorln("error 1")
l.Errorln("error 2")
l.Errorln("error 1")
c.Assert(l.LoggCount(logg.LevelError), qt.Equals, 2)
l.Reset()
errorsStr := l.Errors()
c.Assert(errorsStr, qt.Equals, "")
c.Assert(l.LoggCount(logg.LevelError), qt.Equals, 0)
}
}
+53
View File
@@ -0,0 +1,53 @@
// Copyright 2023 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 loggers
import (
"sync"
"github.com/bep/logg"
)
func InitGlobalLogger(panicOnWarnings bool) {
logMu.Lock()
defer logMu.Unlock()
var logHookLast func(e *logg.Entry) error
if panicOnWarnings {
logHookLast = PanicOnWarningHook
}
log = New(
Options{
Distinct: true,
HandlerPost: logHookLast,
},
)
}
var logMu sync.Mutex
func Log() Logger {
logMu.Lock()
defer logMu.Unlock()
return log
}
// The global logger.
var log Logger
func init() {
InitGlobalLogger(false)
}
-355
View File
@@ -1,355 +0,0 @@
// Copyright 2020 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package loggers
import (
"bytes"
"fmt"
"io"
"log"
"os"
"regexp"
"runtime"
"sync/atomic"
"time"
"github.com/gohugoio/hugo/common/terminal"
jww "github.com/spf13/jwalterweatherman"
)
var (
// Counts ERROR logs to the global jww logger.
GlobalErrorCounter *jww.Counter
PanicOnWarning atomic.Bool
)
func init() {
GlobalErrorCounter = &jww.Counter{}
jww.SetLogListeners(jww.LogCounter(GlobalErrorCounter, jww.LevelError))
}
func LoggerToWriterWithPrefix(logger *log.Logger, prefix string) io.Writer {
return prefixWriter{
logger: logger,
prefix: prefix,
}
}
type prefixWriter struct {
logger *log.Logger
prefix string
}
func (w prefixWriter) Write(p []byte) (n int, err error) {
w.logger.Printf("%s: %s", w.prefix, p)
return len(p), nil
}
type Logger interface {
Printf(format string, v ...any)
Println(v ...any)
PrintTimerIfDelayed(start time.Time, name string)
Debug() *log.Logger
Debugf(format string, v ...any)
Debugln(v ...any)
Info() *log.Logger
Infof(format string, v ...any)
Infoln(v ...any)
Warn() *log.Logger
Warnf(format string, v ...any)
Warnln(v ...any)
Error() *log.Logger
Errorf(format string, v ...any)
Errorln(v ...any)
Errors() string
Out() io.Writer
Reset()
// Used in tests.
LogCounters() *LogCounters
}
type LogCounters struct {
ErrorCounter *jww.Counter
WarnCounter *jww.Counter
}
type logger struct {
*jww.Notepad
// The writer that represents stdout.
// Will be io.Discard when in quiet mode.
out io.Writer
logCounters *LogCounters
// This is only set in server mode.
errors *bytes.Buffer
}
func (l *logger) Printf(format string, v ...any) {
l.FEEDBACK.Printf(format, v...)
}
func (l *logger) Println(v ...any) {
l.FEEDBACK.Println(v...)
}
func (l *logger) Debug() *log.Logger {
return l.DEBUG
}
func (l *logger) Debugf(format string, v ...any) {
l.DEBUG.Printf(format, v...)
}
func (l *logger) Debugln(v ...any) {
l.DEBUG.Println(v...)
}
func (l *logger) Infof(format string, v ...any) {
l.INFO.Printf(format, v...)
}
func (l *logger) Infoln(v ...any) {
l.INFO.Println(v...)
}
func (l *logger) Info() *log.Logger {
return l.INFO
}
const panicOnWarningMessage = "Warning trapped. Remove the --panicOnWarning flag to continue."
func (l *logger) Warnf(format string, v ...any) {
l.WARN.Printf(format, v...)
if PanicOnWarning.Load() {
panic(panicOnWarningMessage)
}
}
func (l *logger) Warnln(v ...any) {
l.WARN.Println(v...)
if PanicOnWarning.Load() {
panic(panicOnWarningMessage)
}
}
func (l *logger) Warn() *log.Logger {
return l.WARN
}
func (l *logger) Errorf(format string, v ...any) {
l.ERROR.Printf(format, v...)
}
func (l *logger) Errorln(v ...any) {
l.ERROR.Println(v...)
}
func (l *logger) Error() *log.Logger {
return l.ERROR
}
func (l *logger) LogCounters() *LogCounters {
return l.logCounters
}
func (l *logger) Out() io.Writer {
return l.out
}
// PrintTimerIfDelayed prints a time statement to the FEEDBACK logger
// if considerable time is spent.
func (l *logger) PrintTimerIfDelayed(start time.Time, name string) {
elapsed := time.Since(start)
milli := int(1000 * elapsed.Seconds())
if milli < 500 {
return
}
l.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.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.logCounters.ErrorCounter.Reset()
if l.errors != nil {
l.errors.Reset()
}
}
// NewLogger creates a new Logger for the given thresholds
func NewLogger(stdoutThreshold, logThreshold jww.Threshold, outHandle, logHandle io.Writer, saveErrors bool) Logger {
return newLogger(stdoutThreshold, logThreshold, outHandle, logHandle, saveErrors)
}
// NewDebugLogger is a convenience function to create a debug logger.
func NewDebugLogger() Logger {
return NewBasicLogger(jww.LevelDebug)
}
// NewWarningLogger is a convenience function to create a warning logger.
func NewWarningLogger() Logger {
return NewBasicLogger(jww.LevelWarn)
}
// NewInfoLogger is a convenience function to create a info logger.
func NewInfoLogger() Logger {
return NewBasicLogger(jww.LevelInfo)
}
// NewErrorLogger is a convenience function to create an error logger.
func NewErrorLogger() Logger {
return NewBasicLogger(jww.LevelError)
}
// NewBasicLogger creates a new basic logger writing to Stdout.
func NewBasicLogger(t jww.Threshold) Logger {
return newLogger(t, jww.LevelError, os.Stdout, io.Discard, false)
}
// NewBasicLoggerForWriter creates a new basic logger writing to w.
func NewBasicLoggerForWriter(t jww.Threshold, w io.Writer) Logger {
return newLogger(t, jww.LevelError, w, io.Discard, false)
}
// RemoveANSIColours removes all ANSI colours from the given string.
func RemoveANSIColours(s string) string {
return ansiColorRe.ReplaceAllString(s, "")
}
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.PrintANSIColors(os.Stdout)
if logHandle != io.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,
logCounters: &LogCounters{
ErrorCounter: errorCounter,
WarnCounter: warnCounter,
},
errors: errorBuff,
}
}
-60
View File
@@ -1,60 +0,0 @@
// Copyright 2018 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package loggers
import (
"bytes"
"fmt"
"log"
"testing"
qt "github.com/frankban/quicktest"
)
func TestLogger(t *testing.T) {
c := qt.New(t)
l := NewWarningLogger()
l.Errorln("One error")
l.Errorln("Two error")
l.Warnln("A warning")
c.Assert(l.LogCounters().ErrorCounter.Count(), qt.Equals, uint64(2))
}
func TestLoggerToWriterWithPrefix(t *testing.T) {
c := qt.New(t)
var b bytes.Buffer
logger := log.New(&b, "", 0)
w := LoggerToWriterWithPrefix(logger, "myprefix")
fmt.Fprint(w, "Hello Hugo!")
c.Assert(b.String(), qt.Equals, "myprefix: Hello Hugo!\n")
}
func TestRemoveANSIColours(t *testing.T) {
c := qt.New(t)
c.Assert(RemoveANSIColours(""), qt.Equals, "")
c.Assert(RemoveANSIColours("\033[31m"), qt.Equals, "")
c.Assert(RemoveANSIColours("\033[31mHello"), qt.Equals, "Hello")
c.Assert(RemoveANSIColours("\033[31mHello\033[0m"), qt.Equals, "Hello")
c.Assert(RemoveANSIColours("\033[31mHello\033[0m World"), qt.Equals, "Hello World")
c.Assert(RemoveANSIColours("\033[31mHello\033[0m World\033[31m!"), qt.Equals, "Hello World!")
c.Assert(RemoveANSIColours("\x1b[90m 5 |"), qt.Equals, " 5 |")
}
+1 -1
View File
@@ -209,7 +209,7 @@ func extractFilename(in, ext, base, pathSeparator string) (name string) {
// return the filename minus the extension (and the ".")
name = base[:strings.LastIndex(base, ".")]
} else {
// no extension case so just return base, which willi
// no extension case so just return base, which will
// be the filename
name = base
}
+60 -11
View File
@@ -150,7 +150,7 @@ type Config struct {
Minify minifiers.MinifyConfig `mapstructure:"-"`
// Permalink configuration.
Permalinks map[string]string `mapstructure:"-"`
Permalinks map[string]map[string]string `mapstructure:"-"`
// Taxonomy configuration.
Taxonomies map[string]string `mapstructure:"-"`
@@ -191,6 +191,22 @@ type configCompiler interface {
func (c Config) cloneForLang() *Config {
x := c
x.C = nil
copyStringSlice := func(in []string) []string {
if in == nil {
return nil
}
out := make([]string, len(in))
copy(out, in)
return out
}
// Copy all the slices to avoid sharing.
x.DisableKinds = copyStringSlice(x.DisableKinds)
x.DisableLanguages = copyStringSlice(x.DisableLanguages)
x.MainSections = copyStringSlice(x.MainSections)
x.IgnoreErrors = copyStringSlice(x.IgnoreErrors)
x.IgnoreFiles = copyStringSlice(x.IgnoreFiles)
x.Theme = copyStringSlice(x.Theme)
// Collapse all static dirs to one.
x.StaticDir = x.staticDirs()
@@ -258,6 +274,14 @@ func (c *Config) CompileConfig(logger loggers.Logger) error {
}
disabledLangs[lang] = true
}
for lang, language := range c.Languages {
if language.Disabled {
disabledLangs[lang] = true
if lang == c.DefaultContentLanguage {
return fmt.Errorf("cannot disable default content language %q", lang)
}
}
}
ignoredErrors := make(map[string]bool)
for _, err := range c.IgnoreErrors {
@@ -408,10 +432,10 @@ type RootConfig struct {
// Copyright information.
Copyright string
// The language to apply to content without any Clolanguage indicator.
// The language to apply to content without any language indicator.
DefaultContentLanguage string
// By defefault, we put the default content language in the root and the others below their language ID, e.g. /no/.
// By default, we put the default content language in the root and the others below their language ID, e.g. /no/.
// Set this to true to put all languages below their language ID.
DefaultContentLanguageInSubdir bool
@@ -468,11 +492,8 @@ type RootConfig struct {
// Enable to print greppable placeholders (on the form "[i18n] TRANSLATIONID") for missing translation strings.
EnableMissingTranslationPlaceholders bool
// Enable to print warnings for missing translation strings.
LogI18nWarnings bool
// ENable to print warnings for multiple files published to the same destination.
LogPathWarnings bool
// Enable to panic on warning log entries. This may make it easier to detect the source.
PanicOnWarning bool
// The configured environment. Default is "development" for server and "production" for build.
Environment string
@@ -506,6 +527,12 @@ type RootConfig struct {
// Whether to track and print unused templates during the build.
PrintUnusedTemplates bool
// Enable to print warnings for missing translation strings.
PrintI18nWarnings bool
// ENable to print warnings for multiple files published to the same destination.
PrintPathWarnings bool
// URL to be used as a placeholder when a page reference cannot be found in ref or relref. Is used as-is.
RefLinksNotFoundURL string
@@ -526,7 +553,7 @@ type RootConfig struct {
// See Modules for more a more flexible way to load themes.
Theme []string
// Timeout for generating page contents, specified as a duration or in milliseconds.
// Timeout for generating page contents, specified as a duration or in seconds.
Timeout string
// The time zone (or location), e.g. Europe/Oslo, used to parse front matter dates without such information and in the time function.
@@ -649,6 +676,26 @@ func (c *Configs) Init() error {
return err
}
// We should consolidate this, but to get a full view of the mounts in e.g. "hugo config" we need to
// transfer any default mounts added above to the config used to print the config.
for _, m := range c.Modules[0].Mounts() {
var found bool
for _, cm := range c.Base.Module.Mounts {
if cm.Source == m.Source && cm.Target == m.Target && cm.Lang == m.Lang {
found = true
break
}
}
if !found {
c.Base.Module.Mounts = append(c.Base.Module.Mounts, m)
}
}
// Transfer the changed mounts to the language versions (all share the same mount set, but can be displayed in different languages).
for _, l := range c.LanguageConfigSlice {
l.Module.Mounts = c.Base.Module.Mounts
}
return nil
}
@@ -729,8 +776,8 @@ func fromLoadConfigResult(fs afero.Fs, logger loggers.Logger, res config.LoadCon
isMultiHost = true
}
mergedConfig.Set(kk, vv)
if cfg.IsSet(kk) {
rootv := cfg.Get(kk)
rootv := cfg.Get(kk)
if rootv != nil && cfg.IsSet(kk) {
// This overrides a root key and potentially needs a merge.
if !reflect.DeepEqual(rootv, vv) {
switch vvv := vv.(type) {
@@ -767,12 +814,14 @@ func fromLoadConfigResult(fs afero.Fs, logger loggers.Logger, res config.LoadCon
// Create a copy of the complete config and replace the root keys with the language specific ones.
clone := all.cloneForLang()
if err := decodeConfigFromParams(fs, bcfg, mergedConfig, clone, differentRootKeys); err != nil {
return nil, fmt.Errorf("failed to decode config for language %q: %w", k, err)
}
if err := clone.CompileConfig(logger); err != nil {
return nil, err
}
langConfigMap[k] = clone
case maps.ParamsMergeStrategy:
default:
+69 -12
View File
@@ -60,7 +60,14 @@ var allDecoderSetups = map[string]decodeWeight{
key: "",
weight: -100, // Always first.
decode: func(d decodeWeight, p decodeConfig) error {
return mapstructure.WeakDecode(p.p.Get(""), &p.c.RootConfig)
if err := mapstructure.WeakDecode(p.p.Get(""), &p.c.RootConfig); err != nil {
return err
}
// This need to match with Lang which is always lower case.
p.c.RootConfig.DefaultContentLanguage = strings.ToLower(p.c.RootConfig.DefaultContentLanguage)
return nil
},
},
"imaging": {
@@ -131,8 +138,8 @@ var allDecoderSetups = map[string]decodeWeight{
return err
},
},
"mediaTypes": {
key: "mediaTypes",
"mediatypes": {
key: "mediatypes",
decode: func(d decodeWeight, p decodeConfig) error {
var err error
p.c.MediaTypes, err = media.DecodeTypes(p.p.GetStringMap(d.key))
@@ -143,7 +150,7 @@ var allDecoderSetups = map[string]decodeWeight{
key: "outputs",
decode: func(d decodeWeight, p decodeConfig) error {
defaults := createDefaultOutputFormats(p.c.OutputFormats.Config)
m := p.p.GetStringMap("outputs")
m := maps.CleanConfigStringMap(p.p.GetStringMap("outputs"))
p.c.Outputs = make(map[string][]string)
for k, v := range m {
s := types.ToStringSlicePreserveString(v)
@@ -161,8 +168,8 @@ var allDecoderSetups = map[string]decodeWeight{
return nil
},
},
"outputFormats": {
key: "outputFormats",
"outputformats": {
key: "outputformats",
decode: func(d decodeWeight, p decodeConfig) error {
var err error
p.c.OutputFormats, err = output.DecodeConfig(p.c.MediaTypes.Config, p.p.Get(d.key))
@@ -199,8 +206,9 @@ var allDecoderSetups = map[string]decodeWeight{
"permalinks": {
key: "permalinks",
decode: func(d decodeWeight, p decodeConfig) error {
p.c.Permalinks = maps.CleanConfigStringMapString(p.p.GetStringMapString(d.key))
return nil
var err error
p.c.Permalinks, err = page.DecodePermalinksConfig(p.p.GetStringMap(d.key))
return err
},
},
"sitemap": {
@@ -241,8 +249,41 @@ var allDecoderSetups = map[string]decodeWeight{
key: "languages",
decode: func(d decodeWeight, p decodeConfig) error {
var err error
p.c.Languages, err = langs.DecodeConfig(p.p.GetStringMap(d.key))
return err
m := p.p.GetStringMap(d.key)
if len(m) == 1 {
// In v0.112.4 we moved this to the language config, but it's very commmon for mono language sites to have this at the top level.
var first maps.Params
var ok bool
for _, v := range m {
first, ok = v.(maps.Params)
if ok {
break
}
}
if first != nil {
if _, found := first["languagecode"]; !found {
first["languagecode"] = p.p.GetString("languagecode")
}
}
}
p.c.Languages, err = langs.DecodeConfig(m)
if err != nil {
return err
}
// Validate defaultContentLanguage.
var found bool
for lang := range p.c.Languages {
if lang == p.c.DefaultContentLanguage {
found = true
break
}
}
if !found {
return fmt.Errorf("config value %q for defaultContentLanguage does not match any language definition", p.c.DefaultContentLanguage)
}
return nil
},
},
"cascade": {
@@ -296,14 +337,14 @@ var allDecoderSetups = map[string]decodeWeight{
"author": {
key: "author",
decode: func(d decodeWeight, p decodeConfig) error {
p.c.Author = p.p.GetStringMap(d.key)
p.c.Author = maps.CleanConfigStringMap(p.p.GetStringMap(d.key))
return nil
},
},
"social": {
key: "social",
decode: func(d decodeWeight, p decodeConfig) error {
p.c.Social = p.p.GetStringMapString(d.key)
p.c.Social = maps.CleanConfigStringMapString(p.p.GetStringMapString(d.key))
return nil
},
},
@@ -329,3 +370,19 @@ var allDecoderSetups = map[string]decodeWeight{
},
},
}
func init() {
for k, v := range allDecoderSetups {
// Verify that k and v.key is all lower case.
if k != strings.ToLower(k) {
panic(fmt.Sprintf("key %q is not lower case", k))
}
if v.key != strings.ToLower(v.key) {
panic(fmt.Sprintf("key %q is not lower case", v.key))
}
if k != v.key {
panic(fmt.Sprintf("key %q is not the same as the map key %q", k, v.key))
}
}
}
+12 -2
View File
@@ -41,6 +41,16 @@ func (c ConfigLanguage) LanguagesDefaultFirst() langs.Languages {
return c.m.LanguagesDefaultFirst
}
func (c ConfigLanguage) LanguagePrefix() string {
if c.DefaultContentLanguageInSubdir() && c.DefaultContentLanguage() == c.Language().Lang {
return c.Language().Lang
}
if !c.IsMultiLingual() || c.DefaultContentLanguage() == c.Language().Lang {
return ""
}
return c.Language().Lang
}
func (c ConfigLanguage) BaseURL() urls.BaseURL {
return c.config.C.BaseURL
}
@@ -199,8 +209,8 @@ func (c ConfigLanguage) EnableMissingTranslationPlaceholders() bool {
return c.config.EnableMissingTranslationPlaceholders
}
func (c ConfigLanguage) LogI18nWarnings() bool {
return c.config.LogI18nWarnings
func (c ConfigLanguage) PrintI18nWarnings() bool {
return c.config.PrintI18nWarnings
}
func (c ConfigLanguage) CreateTitle(s string) string {
+19 -1
View File
@@ -60,7 +60,7 @@ Title: {{ .Title }}
b.Assert(enConcp.BaseURL().String(), qt.Equals, "https://example.com")
modConf := enConf.Module
b.Assert(modConf.Mounts, qt.HasLen, 2)
b.Assert(modConf.Mounts, qt.HasLen, 8)
b.Assert(modConf.Mounts[0].Source, qt.Equals, filepath.FromSlash("content/en"))
b.Assert(modConf.Mounts[0].Target, qt.Equals, "content")
b.Assert(modConf.Mounts[0].Lang, qt.Equals, "en")
@@ -69,3 +69,21 @@ Title: {{ .Title }}
b.Assert(modConf.Mounts[1].Lang, qt.Equals, "sv")
}
func TestConfigAliases(t *testing.T) {
files := `
-- hugo.toml --
baseURL = "https://example.com"
logI18nWarnings = true
logPathWarnings = true
`
b := hugolib.NewIntegrationTestBuilder(
hugolib.IntegrationTestConfig{T: t, TxtarString: files},
).Build()
conf := b.H.Configs.Base
b.Assert(conf.PrintI18nWarnings, qt.Equals, true)
b.Assert(conf.PrintPathWarnings, qt.Equals, true)
}
+23 -6
View File
@@ -34,6 +34,7 @@ import (
hglob "github.com/gohugoio/hugo/hugofs/glob"
"github.com/gohugoio/hugo/modules"
"github.com/gohugoio/hugo/parser/metadecoders"
"github.com/gohugoio/hugo/tpl"
"github.com/spf13/afero"
)
@@ -45,7 +46,7 @@ func LoadConfig(d ConfigSourceDescriptor) (*Configs, error) {
}
if d.Logger == nil {
d.Logger = loggers.NewErrorLogger()
d.Logger = loggers.NewDefault()
}
l := &configLoader{ConfigSourceDescriptor: d, cfg: config.New()}
@@ -89,6 +90,10 @@ func LoadConfig(d ConfigSourceDescriptor) (*Configs, error) {
return nil, fmt.Errorf("failed to init config: %w", err)
}
// This is unfortunate, but these are global settings.
tpl.SetSecurityAllowActionJSTmpl(configs.Base.Security.GoTemplates.AllowActionJSTmpl)
loggers.InitGlobalLogger(configs.Base.PanicOnWarning)
return configs, nil
}
@@ -134,7 +139,11 @@ type configLoader struct {
// Handle some legacy values.
func (l configLoader) applyConfigAliases() error {
aliases := []types.KeyValueStr{{Key: "taxonomies", Value: "indexes"}}
aliases := []types.KeyValueStr{
{Key: "indexes", Value: "taxonomies"},
{Key: "logI18nWarnings", Value: "printI18nWarnings"},
{Key: "logPathWarnings", Value: "printPathWarnings"},
}
for _, alias := range aliases {
if l.cfg.IsSet(alias.Key) {
@@ -284,11 +293,19 @@ func (l configLoader) applyOsEnvOverrides(environ []string) error {
} else {
l.cfg.Set(env.Key, val)
}
} else if nestedKey != "" {
owner[nestedKey] = env.Value
} else {
// The container does not exist yet.
l.cfg.Set(strings.ReplaceAll(env.Key, delim, "."), env.Value)
if nestedKey != "" {
owner[nestedKey] = env.Value
} else {
var val any = env.Value
if _, ok := allDecoderSetups[env.Key]; ok {
// A map.
val, err = metadecoders.Default.UnmarshalStringTo(env.Value, map[string]interface{}{})
}
if err == nil {
l.cfg.Set(strings.ReplaceAll(env.Key, delim, "."), val)
}
}
}
}
+36 -8
View File
@@ -19,6 +19,7 @@ import (
"sort"
"strings"
"github.com/bep/logg"
"github.com/gobwas/glob"
"github.com/gohugoio/hugo/common/loggers"
"github.com/gohugoio/hugo/common/types"
@@ -81,7 +82,7 @@ type LoadConfigResult struct {
var defaultBuild = BuildConfig{
UseResourceCacheWhen: "fallback",
WriteStats: false,
BuildStats: BuildStats{},
CacheBusters: []CacheBuster{
{
@@ -96,7 +97,7 @@ var defaultBuild = BuildConfig{
Source: `(postcss|tailwind)\.config\.js`,
Target: cssTargetCachebusterRe,
},
// This is deliberatly coarse grained; it will cache bust resources with "json" in the cache key when js files changes, which is good.
// This is deliberately coarse grained; it will cache bust resources with "json" in the cache key when js files changes, which is good.
{
Source: `assets/.*\.(.*)$`,
Target: `$1`,
@@ -110,9 +111,10 @@ type BuildConfig struct {
// When enabled, will collect and write a hugo_stats.json with some build
// related aggregated data (e.g. CSS class names).
WriteStats bool
// Note that this was a bool <= v0.115.0.
BuildStats BuildStats
// Can be used to toggle off writing of the intellinsense /assets/jsconfig.js
// Can be used to toggle off writing of the IntelliSense /assets/jsconfig.js
// file.
NoJSConfigInAssets bool
@@ -120,6 +122,21 @@ type BuildConfig struct {
CacheBusters []CacheBuster
}
// BuildStats configures if and what to write to the hugo_stats.json file.
type BuildStats struct {
Enable bool
DisableTags bool
DisableClasses bool
DisableIDs bool
}
func (w BuildStats) Enabled() bool {
if !w.Enable {
return false
}
return !w.DisableTags || !w.DisableClasses || !w.DisableIDs
}
func (b BuildConfig) clone() BuildConfig {
b.CacheBusters = append([]CacheBuster{}, b.CacheBusters...)
return b
@@ -131,7 +148,7 @@ func (b BuildConfig) UseResourceCache(err error) bool {
}
if b.UseResourceCacheWhen == "fallback" {
return err == herrors.ErrFeatureNotAvailable
return herrors.IsFeatureNotAvailableError(err)
}
return true
@@ -170,14 +187,22 @@ func (b *BuildConfig) CompileConfig(logger loggers.Logger) error {
func DecodeBuildConfig(cfg Provider) BuildConfig {
m := cfg.GetStringMap("build")
b := defaultBuild.clone()
if m == nil {
return b
}
// writeStats was a bool <= v0.115.0.
if writeStats, ok := m["writestats"]; ok {
if bb, ok := writeStats.(bool); ok {
m["buildstats"] = BuildStats{Enable: bb}
}
}
err := mapstructure.WeakDecode(m, &b)
if err != nil {
return defaultBuild
return b
}
b.UseResourceCacheWhen = strings.ToLower(b.UseResourceCacheWhen)
@@ -306,6 +331,7 @@ func (c *CacheBuster) CompileConfig(logger loggers.Logger) error {
if c.compiledSource != nil {
return nil
}
source := c.Source
target := c.Target
sourceRe, err := regexp.Compile(source)
@@ -313,6 +339,8 @@ func (c *CacheBuster) CompileConfig(logger loggers.Logger) error {
return fmt.Errorf("failed to compile cache buster source %q: %w", c.Source, err)
}
var compileErr error
debugl := logger.Logger().WithLevel(logg.LevelDebug).WithField(loggers.FieldNameCmd, "cachebuster")
c.compiledSource = func(s string) func(string) bool {
m := sourceRe.FindStringSubmatch(s)
matchString := "no match"
@@ -320,7 +348,7 @@ func (c *CacheBuster) CompileConfig(logger loggers.Logger) error {
if match {
matchString = "match!"
}
logger.Debugf("cachebuster: Matching %q with source %q: %s\n", s, source, matchString)
debugl.Logf("Matching %q with source %q: %s", s, source, matchString)
if !match {
return nil
}
@@ -341,7 +369,7 @@ func (c *CacheBuster) CompileConfig(logger loggers.Logger) error {
if match {
matchString = "match!"
}
logger.Debugf("cachebuster: Matching %q with target %q: %s\n", s, target, matchString)
logger.Debugf("Matching %q with target %q: %s", s, target, matchString)
return match
}
+2 -2
View File
@@ -92,7 +92,7 @@ status = 301
s, err := DecodeServer(cfg)
c.Assert(err, qt.IsNil)
c.Assert(s.CompileConfig(loggers.NewErrorLogger()), qt.IsNil)
c.Assert(s.CompileConfig(loggers.NewDefault()), qt.IsNil)
c.Assert(s.MatchHeaders("/foo.jpg"), qt.DeepEquals, []types.KeyValueStr{
{Key: "X-Content-Type-Options", Value: "nosniff"},
@@ -145,7 +145,7 @@ func TestBuildConfigCacheBusters(t *testing.T) {
c := qt.New(t)
cfg := New()
conf := DecodeBuildConfig(cfg)
l := loggers.NewInfoLogger()
l := loggers.NewDefault()
c.Assert(conf.CompileConfig(l), qt.IsNil)
m, err := conf.MatchCacheBuster(l, "assets/foo/main.js")
+1 -1
View File
@@ -157,7 +157,7 @@ func LoadConfigFromDir(sourceFs afero.Fs, configDir, environment string) (Provid
if err != nil {
// This will be used in error reporting, use the most specific value.
dirnames = []string{path}
return fmt.Errorf("failed to unmarshl config for path %q: %w", path, err)
return fmt.Errorf("failed to unmarshal config for path %q: %w", path, err)
}
var keyPath []string
+2 -1
View File
@@ -27,6 +27,7 @@ type AllProvider interface {
Language() *langs.Language
Languages() langs.Languages
LanguagesDefaultFirst() langs.Languages
LanguagePrefix() string
BaseURL() urls.BaseURL
BaseURLLiveReload() urls.BaseURL
Environment() string
@@ -57,7 +58,7 @@ type AllProvider interface {
EnableMissingTranslationPlaceholders() bool
TemplateMetrics() bool
TemplateMetricsHints() bool
LogI18nWarnings() bool
PrintI18nWarnings() bool
CreateTitle(s string) string
IgnoreFile(s string) bool
NewContentEditor() string
+21 -9
View File
@@ -34,22 +34,22 @@ const securityConfigKey = "security"
// DefaultConfig holds the default security policy.
var DefaultConfig = Config{
Exec: Exec{
Allow: NewWhitelist(
"^dart-sass-embedded$",
"^go$", // for Go Modules
"^npx$", // used by all Node tools (Babel, PostCSS).
Allow: MustNewWhitelist(
"^(dart-)?sass(-embedded)?$", // sass, dart-sass, dart-sass-embedded.
"^go$", // for Go Modules
"^npx$", // used by all Node tools (Babel, PostCSS).
"^postcss$",
),
// These have been tested to work with Hugo's external programs
// on Windows, Linux and MacOS.
OsEnv: NewWhitelist(`(?i)^((HTTPS?|NO)_PROXY|PATH(EXT)?|APPDATA|TE?MP|TERM|GO\w+)$`),
OsEnv: MustNewWhitelist(`(?i)^((HTTPS?|NO)_PROXY|PATH(EXT)?|APPDATA|TE?MP|TERM|GO\w+|(XDG_CONFIG_)?HOME|USERPROFILE|SSH_AUTH_SOCK|DISPLAY|LANG)$`),
},
Funcs: Funcs{
Getenv: NewWhitelist("^HUGO_", "^CI$"),
Getenv: MustNewWhitelist("^HUGO_", "^CI$"),
},
HTTP: HTTP{
URLs: NewWhitelist(".*"),
Methods: NewWhitelist("(?i)GET|POST"),
URLs: MustNewWhitelist(".*"),
Methods: MustNewWhitelist("(?i)GET|POST"),
},
}
@@ -68,6 +68,9 @@ type Config struct {
// Allow inline shortcodes
EnableInlineShortcodes bool `json:"enableInlineShortcodes"`
// Go templates related security config.
GoTemplates GoTemplates `json:"goTemplates"`
}
// Exec holds os/exec policies.
@@ -93,6 +96,15 @@ type HTTP struct {
MediaTypes Whitelist `json:"mediaTypes"`
}
type GoTemplates struct {
// Enable to allow template actions inside bakcticks in ES6 template literals.
// This was blocked in Hugo 0.114.0 for security reasons and you now get errors on the form
// "... appears in a JS template literal" if you have this in your templates.
// See https://github.com/golang/go/issues/59234
AllowActionJSTmpl bool
}
// ToTOML converts c to TOML with [security] as the root.
func (c Config) ToTOML() string {
sec := c.ToSecurityMap()
@@ -209,7 +221,7 @@ func stringSliceToWhitelistHook() mapstructure.DecodeHookFuncType {
wl := types.ToStringSlicePreserveString(data)
return NewWhitelist(wl...), nil
return NewWhitelist(wl...)
}
}
+5 -4
View File
@@ -140,7 +140,7 @@ func TestToTOML(t *testing.T) {
got := DefaultConfig.ToTOML()
c.Assert(got, qt.Equals,
"[security]\n enableInlineShortcodes = false\n\n [security.exec]\n allow = ['^dart-sass-embedded$', '^go$', '^npx$', '^postcss$']\n osEnv = ['(?i)^((HTTPS?|NO)_PROXY|PATH(EXT)?|APPDATA|TE?MP|TERM|GO\\w+)$']\n\n [security.funcs]\n getenv = ['^HUGO_', '^CI$']\n\n [security.http]\n methods = ['(?i)GET|POST']\n urls = ['.*']",
"[security]\n enableInlineShortcodes = false\n\n [security.exec]\n allow = ['^(dart-)?sass(-embedded)?$', '^go$', '^npx$', '^postcss$']\n osEnv = ['(?i)^((HTTPS?|NO)_PROXY|PATH(EXT)?|APPDATA|TE?MP|TERM|GO\\w+|(XDG_CONFIG_)?HOME|USERPROFILE|SSH_AUTH_SOCK|DISPLAY|LANG)$']\n\n [security.funcs]\n getenv = ['^HUGO_', '^CI$']\n\n [security.goTemplates]\n AllowActionJSTmpl = false\n\n [security.http]\n methods = ['(?i)GET|POST']\n urls = ['.*']",
)
}
@@ -154,9 +154,6 @@ func TestDecodeConfigDefault(t *testing.T) {
c.Assert(pc.Exec.Allow.Accept("a"), qt.IsFalse)
c.Assert(pc.Exec.Allow.Accept("npx"), qt.IsTrue)
c.Assert(pc.Exec.Allow.Accept("Npx"), qt.IsFalse)
c.Assert(pc.Exec.OsEnv.Accept("a"), qt.IsFalse)
c.Assert(pc.Exec.OsEnv.Accept("PATH"), qt.IsTrue)
c.Assert(pc.Exec.OsEnv.Accept("e"), qt.IsFalse)
c.Assert(pc.HTTP.URLs.Accept("https://example.org"), qt.IsTrue)
c.Assert(pc.HTTP.Methods.Accept("POST"), qt.IsTrue)
@@ -167,6 +164,10 @@ func TestDecodeConfigDefault(t *testing.T) {
c.Assert(pc.Exec.OsEnv.Accept("PATH"), qt.IsTrue)
c.Assert(pc.Exec.OsEnv.Accept("GOROOT"), qt.IsTrue)
c.Assert(pc.Exec.OsEnv.Accept("HOME"), qt.IsTrue)
c.Assert(pc.Exec.OsEnv.Accept("SSH_AUTH_SOCK"), qt.IsTrue)
c.Assert(pc.Exec.OsEnv.Accept("a"), qt.IsFalse)
c.Assert(pc.Exec.OsEnv.Accept("e"), qt.IsFalse)
c.Assert(pc.Exec.OsEnv.Accept("MYSECRET"), qt.IsFalse)
}
+18 -5
View File
@@ -45,9 +45,9 @@ func (w Whitelist) MarshalJSON() ([]byte, error) {
// NewWhitelist creates a new Whitelist from zero or more patterns.
// An empty patterns list or a pattern with the value 'none' will create
// a whitelist that will Accept none.
func NewWhitelist(patterns ...string) Whitelist {
func NewWhitelist(patterns ...string) (Whitelist, error) {
if len(patterns) == 0 {
return Whitelist{acceptNone: true}
return Whitelist{acceptNone: true}, nil
}
var acceptSome bool
@@ -68,7 +68,7 @@ func NewWhitelist(patterns ...string) Whitelist {
if !acceptSome {
return Whitelist{
acceptNone: true,
}
}, nil
}
var patternsr []*regexp.Regexp
@@ -78,10 +78,23 @@ func NewWhitelist(patterns ...string) Whitelist {
if p == "" {
continue
}
patternsr = append(patternsr, regexp.MustCompile(p))
re, err := regexp.Compile(p)
if err != nil {
return Whitelist{}, fmt.Errorf("failed to compile whitelist pattern %q: %w", p, err)
}
patternsr = append(patternsr, re)
}
return Whitelist{patterns: patternsr, patternsStrings: patternsStrings}
return Whitelist{patterns: patternsr, patternsStrings: patternsStrings}, nil
}
// MustNewWhitelist creates a new Whitelist from zero or more patterns and panics on error.
func MustNewWhitelist(patterns ...string) Whitelist {
w, err := NewWhitelist(patterns...)
if err != nil {
panic(err)
}
return w
}
// Accept reports whether name is whitelisted.
+6 -6
View File
@@ -24,21 +24,21 @@ func TestWhitelist(t *testing.T) {
c := qt.New(t)
c.Run("none", func(c *qt.C) {
c.Assert(NewWhitelist("none", "foo").Accept("foo"), qt.IsFalse)
c.Assert(NewWhitelist().Accept("foo"), qt.IsFalse)
c.Assert(NewWhitelist("").Accept("foo"), qt.IsFalse)
c.Assert(NewWhitelist(" ", " ").Accept("foo"), qt.IsFalse)
c.Assert(MustNewWhitelist("none", "foo").Accept("foo"), qt.IsFalse)
c.Assert(MustNewWhitelist().Accept("foo"), qt.IsFalse)
c.Assert(MustNewWhitelist("").Accept("foo"), qt.IsFalse)
c.Assert(MustNewWhitelist(" ", " ").Accept("foo"), qt.IsFalse)
c.Assert(Whitelist{}.Accept("foo"), qt.IsFalse)
})
c.Run("One", func(c *qt.C) {
w := NewWhitelist("^foo.*")
w := MustNewWhitelist("^foo.*")
c.Assert(w.Accept("foo"), qt.IsTrue)
c.Assert(w.Accept("mfoo"), qt.IsFalse)
})
c.Run("Multiple", func(c *qt.C) {
w := NewWhitelist("^foo.*", "^bar.*")
w := MustNewWhitelist("^foo.*", "^bar.*")
c.Assert(w.Accept("foo"), qt.IsTrue)
c.Assert(w.Accept("bar"), qt.IsTrue)
c.Assert(w.Accept("mbar"), qt.IsFalse)
+1 -1
View File
@@ -41,7 +41,7 @@ func GetTestConfigs(fs afero.Fs, cfg config.Provider) *allconfig.Configs {
}
}
configs, err := allconfig.LoadConfig(allconfig.ConfigSourceDescriptor{Fs: fs, Flags: cfg})
configs, err := allconfig.LoadConfig(allconfig.ConfigSourceDescriptor{Fs: fs, Flags: cfg, Environ: []string{"EMPTY_TEST_ENVIRONMENT"}})
if err != nil {
panic(err)
}
+43 -38
View File
@@ -37,10 +37,10 @@ import (
"github.com/dustin/go-humanize"
"github.com/gobwas/glob"
"github.com/gohugoio/hugo/common/loggers"
"github.com/gohugoio/hugo/config"
"github.com/gohugoio/hugo/media"
"github.com/spf13/afero"
jww "github.com/spf13/jwalterweatherman"
"golang.org/x/text/unicode/norm"
"gocloud.dev/blob"
@@ -56,9 +56,10 @@ type Deployer struct {
bucket *blob.Bucket
mediaTypes media.Types // Hugo's MediaType to guess ContentType
quiet bool // true reduces STDOUT
quiet bool // true reduces STDOUT // TODO(bep) remove, this is a global feature.
cfg DeployConfig
cfg DeployConfig
logger loggers.Logger
target *Target // the target to deploy to
@@ -73,7 +74,7 @@ type deploySummary struct {
const metaMD5Hash = "md5chksum" // the meta key to store md5hash in
// New constructs a new *Deployer.
func New(cfg config.AllProvider, localFs afero.Fs) (*Deployer, error) {
func New(cfg config.AllProvider, logger loggers.Logger, localFs afero.Fs) (*Deployer, error) {
dcfg := cfg.GetConfigSection(deploymentConfigKey).(DeployConfig)
targetName := dcfg.Target
@@ -112,12 +113,16 @@ func (d *Deployer) openBucket(ctx context.Context) (*blob.Bucket, error) {
if d.bucket != nil {
return d.bucket, nil
}
jww.FEEDBACK.Printf("Deploying to target %q (%s)\n", d.target.Name, d.target.URL)
d.logger.Printf("Deploying to target %q (%s)\n", d.target.Name, d.target.URL)
return blob.OpenBucket(ctx, d.target.URL)
}
// Deploy deploys the site to a target.
func (d *Deployer) Deploy(ctx context.Context) error {
if d.logger == nil {
d.logger = loggers.NewDefault()
}
bucket, err := d.openBucket(ctx)
if err != nil {
return err
@@ -132,33 +137,33 @@ func (d *Deployer) Deploy(ctx context.Context) error {
if d.target != nil {
include, exclude = d.target.includeGlob, d.target.excludeGlob
}
local, err := walkLocal(d.localFs, d.cfg.Matchers, include, exclude, d.mediaTypes)
local, err := d.walkLocal(d.localFs, d.cfg.Matchers, include, exclude, d.mediaTypes)
if err != nil {
return err
}
jww.INFO.Printf("Found %d local files.\n", len(local))
d.logger.Infof("Found %d local files.\n", len(local))
d.summary.NumLocal = len(local)
// Load remote files from the target.
remote, err := walkRemote(ctx, bucket, include, exclude)
remote, err := d.walkRemote(ctx, bucket, include, exclude)
if err != nil {
return err
}
jww.INFO.Printf("Found %d remote files.\n", len(remote))
d.logger.Infof("Found %d remote files.\n", len(remote))
d.summary.NumRemote = len(remote)
// Diff local vs remote to see what changes need to be applied.
uploads, deletes := findDiffs(local, remote, d.cfg.Force)
uploads, deletes := d.findDiffs(local, remote, d.cfg.Force)
d.summary.NumUploads = len(uploads)
d.summary.NumDeletes = len(deletes)
if len(uploads)+len(deletes) == 0 {
if !d.quiet {
jww.FEEDBACK.Println("No changes required.")
d.logger.Println("No changes required.")
}
return nil
}
if !d.quiet {
jww.FEEDBACK.Println(summarizeChanges(uploads, deletes))
d.logger.Println(summarizeChanges(uploads, deletes))
}
// Ask for confirmation before proceeding.
@@ -192,14 +197,14 @@ func (d *Deployer) Deploy(ctx context.Context) error {
for _, upload := range uploads {
if d.cfg.DryRun {
if !d.quiet {
jww.FEEDBACK.Printf("[DRY RUN] Would upload: %v\n", upload)
d.logger.Printf("[DRY RUN] Would upload: %v\n", upload)
}
continue
}
sem <- struct{}{}
go func(upload *fileToUpload) {
if err := doSingleUpload(ctx, bucket, upload); err != nil {
if err := d.doSingleUpload(ctx, bucket, upload); err != nil {
errMu.Lock()
defer errMu.Unlock()
errs = append(errs, err)
@@ -214,7 +219,7 @@ func (d *Deployer) Deploy(ctx context.Context) error {
}
if d.cfg.MaxDeletes != -1 && len(deletes) > d.cfg.MaxDeletes {
jww.WARN.Printf("Skipping %d deletes because it is more than --maxDeletes (%d). If this is expected, set --maxDeletes to a larger number, or -1 to disable this check.\n", len(deletes), d.cfg.MaxDeletes)
d.logger.Warnf("Skipping %d deletes because it is more than --maxDeletes (%d). If this is expected, set --maxDeletes to a larger number, or -1 to disable this check.\n", len(deletes), d.cfg.MaxDeletes)
d.summary.NumDeletes = 0
} else {
// Apply deletes in parallel.
@@ -223,16 +228,16 @@ func (d *Deployer) Deploy(ctx context.Context) error {
for _, del := range deletes {
if d.cfg.DryRun {
if !d.quiet {
jww.FEEDBACK.Printf("[DRY RUN] Would delete %s\n", del)
d.logger.Printf("[DRY RUN] Would delete %s\n", del)
}
continue
}
sem <- struct{}{}
go func(del string) {
jww.INFO.Printf("Deleting %s...\n", del)
d.logger.Infof("Deleting %s...\n", del)
if err := bucket.Delete(ctx, del); err != nil {
if gcerrors.Code(err) == gcerrors.NotFound {
jww.WARN.Printf("Failed to delete %q because it wasn't found: %v", del, err)
d.logger.Warnf("Failed to delete %q because it wasn't found: %v", del, err)
} else {
errMu.Lock()
defer errMu.Unlock()
@@ -250,24 +255,24 @@ func (d *Deployer) Deploy(ctx context.Context) error {
if len(errs) > 0 {
if !d.quiet {
jww.FEEDBACK.Printf("Encountered %d errors.\n", len(errs))
d.logger.Printf("Encountered %d errors.\n", len(errs))
}
return errs[0]
}
if !d.quiet {
jww.FEEDBACK.Println("Success!")
d.logger.Println("Success!")
}
if d.cfg.InvalidateCDN {
if d.target.CloudFrontDistributionID != "" {
if d.cfg.DryRun {
if !d.quiet {
jww.FEEDBACK.Printf("[DRY RUN] Would invalidate CloudFront CDN with ID %s\n", d.target.CloudFrontDistributionID)
d.logger.Printf("[DRY RUN] Would invalidate CloudFront CDN with ID %s\n", d.target.CloudFrontDistributionID)
}
} else {
jww.FEEDBACK.Println("Invalidating CloudFront CDN...")
d.logger.Println("Invalidating CloudFront CDN...")
if err := InvalidateCloudFront(ctx, d.target.CloudFrontDistributionID); err != nil {
jww.FEEDBACK.Printf("Failed to invalidate CloudFront CDN: %v\n", err)
d.logger.Printf("Failed to invalidate CloudFront CDN: %v\n", err)
return err
}
}
@@ -275,17 +280,17 @@ func (d *Deployer) Deploy(ctx context.Context) error {
if d.target.GoogleCloudCDNOrigin != "" {
if d.cfg.DryRun {
if !d.quiet {
jww.FEEDBACK.Printf("[DRY RUN] Would invalidate Google Cloud CDN with origin %s\n", d.target.GoogleCloudCDNOrigin)
d.logger.Printf("[DRY RUN] Would invalidate Google Cloud CDN with origin %s\n", d.target.GoogleCloudCDNOrigin)
}
} else {
jww.FEEDBACK.Println("Invalidating Google Cloud CDN...")
d.logger.Println("Invalidating Google Cloud CDN...")
if err := InvalidateGoogleCloudCDN(ctx, d.target.GoogleCloudCDNOrigin); err != nil {
jww.FEEDBACK.Printf("Failed to invalidate Google Cloud CDN: %v\n", err)
d.logger.Printf("Failed to invalidate Google Cloud CDN: %v\n", err)
return err
}
}
}
jww.FEEDBACK.Println("Success!")
d.logger.Println("Success!")
}
return nil
}
@@ -300,8 +305,8 @@ func summarizeChanges(uploads []*fileToUpload, deletes []string) string {
}
// doSingleUpload executes a single file upload.
func doSingleUpload(ctx context.Context, bucket *blob.Bucket, upload *fileToUpload) error {
jww.INFO.Printf("Uploading %v...\n", upload)
func (d *Deployer) doSingleUpload(ctx context.Context, bucket *blob.Bucket, upload *fileToUpload) error {
d.logger.Infof("Uploading %v...\n", upload)
opts := &blob.WriterOptions{
CacheControl: upload.Local.CacheControl(),
ContentEncoding: upload.Local.ContentEncoding(),
@@ -479,7 +484,7 @@ func knownHiddenDirectory(name string) bool {
// walkLocal walks the source directory and returns a flat list of files,
// using localFile.SlashPath as the map keys.
func walkLocal(fs afero.Fs, matchers []*Matcher, include, exclude glob.Glob, mediaTypes media.Types) (map[string]*localFile, error) {
func (d *Deployer) walkLocal(fs afero.Fs, matchers []*Matcher, include, exclude glob.Glob, mediaTypes media.Types) (map[string]*localFile, error) {
retval := map[string]*localFile{}
err := afero.Walk(fs, "", func(path string, info os.FileInfo, err error) error {
if err != nil {
@@ -509,11 +514,11 @@ func walkLocal(fs afero.Fs, matchers []*Matcher, include, exclude glob.Glob, med
// Check include/exclude matchers.
slashpath := filepath.ToSlash(path)
if include != nil && !include.Match(slashpath) {
jww.INFO.Printf(" dropping %q due to include\n", slashpath)
d.logger.Infof(" dropping %q due to include\n", slashpath)
return nil
}
if exclude != nil && exclude.Match(slashpath) {
jww.INFO.Printf(" dropping %q due to exclude\n", slashpath)
d.logger.Infof(" dropping %q due to exclude\n", slashpath)
return nil
}
@@ -539,7 +544,7 @@ func walkLocal(fs afero.Fs, matchers []*Matcher, include, exclude glob.Glob, med
}
// walkRemote walks the target bucket and returns a flat list.
func walkRemote(ctx context.Context, bucket *blob.Bucket, include, exclude glob.Glob) (map[string]*blob.ListObject, error) {
func (d *Deployer) walkRemote(ctx context.Context, bucket *blob.Bucket, include, exclude glob.Glob) (map[string]*blob.ListObject, error) {
retval := map[string]*blob.ListObject{}
iter := bucket.List(nil)
for {
@@ -552,11 +557,11 @@ func walkRemote(ctx context.Context, bucket *blob.Bucket, include, exclude glob.
}
// Check include/exclude matchers.
if include != nil && !include.Match(obj.Key) {
jww.INFO.Printf(" remote dropping %q due to include\n", obj.Key)
d.logger.Infof(" remote dropping %q due to include\n", obj.Key)
continue
}
if exclude != nil && exclude.Match(obj.Key) {
jww.INFO.Printf(" remote dropping %q due to exclude\n", obj.Key)
d.logger.Infof(" remote dropping %q due to exclude\n", obj.Key)
continue
}
// If the remote didn't give us an MD5, use remote attributes MD5, if that doesn't exist compute one.
@@ -629,7 +634,7 @@ func (u *fileToUpload) String() string {
// findDiffs diffs localFiles vs remoteFiles to see what changes should be
// applied to the remote target. It returns a slice of *fileToUpload and a
// slice of paths for files to delete.
func findDiffs(localFiles map[string]*localFile, remoteFiles map[string]*blob.ListObject, force bool) ([]*fileToUpload, []string) {
func (d *Deployer) findDiffs(localFiles map[string]*localFile, remoteFiles map[string]*blob.ListObject, force bool) ([]*fileToUpload, []string) {
var uploads []*fileToUpload
var deletes []string
@@ -680,10 +685,10 @@ func findDiffs(localFiles map[string]*localFile, remoteFiles map[string]*blob.Li
reason = reasonNotFound
}
if upload {
jww.DEBUG.Printf("%s needs to be uploaded: %v\n", path, reason)
d.logger.Debugf("%s needs to be uploaded: %v\n", path, reason)
uploads = append(uploads, &fileToUpload{lf, reason})
} else {
jww.DEBUG.Printf("%s exists at target and does not need to be uploaded", path)
d.logger.Debugf("%s exists at target and does not need to be uploaded", path)
}
}
+8 -6
View File
@@ -11,9 +11,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//go:build !nodeploy
// +build !nodeploy
package deploy
import (
@@ -127,11 +124,16 @@ func (m *Matcher) Matches(path string) bool {
return m.re.MatchString(path)
}
var DefaultConfig = DeployConfig{
Workers: 10,
InvalidateCDN: true,
MaxDeletes: 256,
}
// DecodeConfig creates a config from a given Hugo configuration.
func DecodeConfig(cfg config.Provider) (DeployConfig, error) {
var (
dcfg DeployConfig
)
dcfg := DefaultConfig
if !cfg.IsSet(deploymentConfigKey) {
return dcfg, nil
+11 -2
View File
@@ -30,6 +30,7 @@ import (
"sort"
"testing"
"github.com/gohugoio/hugo/common/loggers"
"github.com/gohugoio/hugo/media"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
@@ -197,7 +198,8 @@ func TestFindDiffs(t *testing.T) {
for _, r := range tc.Remote {
remote[r.Key] = r
}
gotUpdates, gotDeletes := findDiffs(local, remote, tc.Force)
d := newDeployer()
gotUpdates, gotDeletes := d.findDiffs(local, remote, tc.Force)
gotUpdates = applyOrdering(nil, gotUpdates)[0]
sort.Slice(gotDeletes, func(i, j int) bool { return gotDeletes[i] < gotDeletes[j] })
if diff := cmp.Diff(gotUpdates, tc.WantUpdates, cmpopts.IgnoreUnexported(localFile{})); diff != "" {
@@ -249,7 +251,8 @@ func TestWalkLocal(t *testing.T) {
fd.Close()
}
}
if got, err := walkLocal(fs, nil, nil, nil, media.DefaultTypes); err != nil {
d := newDeployer()
if got, err := d.walkLocal(fs, nil, nil, nil, media.DefaultTypes); err != nil {
t.Fatal(err)
} else {
expect := map[string]any{}
@@ -1026,3 +1029,9 @@ func verifyRemote(ctx context.Context, bucket *blob.Bucket, local []*fileData) (
}
return diff, nil
}
func newDeployer() *Deployer {
return &Deployer{
logger: loggers.NewDefault(),
}
}
+22 -15
View File
@@ -3,12 +3,14 @@ package deps
import (
"context"
"fmt"
"io"
"path/filepath"
"sort"
"strings"
"sync"
"sync/atomic"
"github.com/bep/logg"
"github.com/gohugoio/hugo/common/hexec"
"github.com/gohugoio/hugo/common/loggers"
"github.com/gohugoio/hugo/config"
@@ -25,7 +27,6 @@ import (
"github.com/gohugoio/hugo/source"
"github.com/gohugoio/hugo/tpl"
"github.com/spf13/afero"
jww "github.com/spf13/jwalterweatherman"
)
// Deps holds dependencies used by many.
@@ -36,9 +37,6 @@ type Deps struct {
// The logger to use.
Log loggers.Logger `json:"-"`
// Used to log errors that may repeat itself many times.
LogDistinct loggers.Logger
ExecHelper *hexec.Exec
// The templates to use. This will usually implement the full tpl.TemplateManager.
@@ -117,15 +115,13 @@ func (d *Deps) Init() error {
}
if d.Log == nil {
d.Log = loggers.NewErrorLogger()
}
if d.LogDistinct == nil {
d.LogDistinct = helpers.NewDistinctLogger(d.Log)
d.Log = loggers.NewDefault()
}
if d.globalErrHandler == nil {
d.globalErrHandler = &globalErrHandler{}
d.globalErrHandler = &globalErrHandler{
logger: d.Log,
}
}
if d.BuildState == nil {
@@ -189,10 +185,13 @@ func (d *Deps) Init() error {
}
var common *resources.SpecCommon
var imageCache *resources.ImageCache
if d.ResourceSpec != nil {
common = d.ResourceSpec.SpecCommon
imageCache = d.ResourceSpec.ImageCache
}
resourceSpec, err := resources.NewSpec(d.PathSpec, common, d.BuildState, d.Log, d, d.ExecHelper)
resourceSpec, err := resources.NewSpec(d.PathSpec, common, imageCache, d.BuildState, d.Log, d, d.ExecHelper)
if err != nil {
return fmt.Errorf("failed to create resource spec: %w", err)
}
@@ -225,6 +224,8 @@ func (d *Deps) Compile(prototype *Deps) error {
}
type globalErrHandler struct {
logger loggers.Logger
// Channel for some "hard to get to" build errors
buildErrors chan error
// Used to signal that the build is done.
@@ -243,8 +244,7 @@ func (e *globalErrHandler) SendError(err error) {
}
return
}
jww.ERROR.Println(err)
e.logger.Errorln(err)
}
func (e *globalErrHandler) StartErrorCollector() chan error {
@@ -309,9 +309,16 @@ func (d *Deps) Close() error {
// on a global level, i.e. logging etc.
// Nil values will be given default values.
type DepsCfg struct {
// The logger to use. Only set in some tests.
// TODO(bep) get rid of this.
TestLogger loggers.Logger
// The Logger to use.
Logger loggers.Logger
// The logging level to use.
LogLevel logg.Level
// Where to write the logs.
// Currently we typically write everything to stdout.
LogOut io.Writer
// The file systems to use
Fs *hugofs.Fs
@@ -3,6 +3,3 @@
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
Referrer-Policy: origin-when-cross-origin
/*
Link: <{{ "dist/app.bundle.js" | relURL }}>; rel=preload; as=script
Link: <{{ "dist/main.css" | relURL }}>; rel=preload; as=style
+1 -1
View File
@@ -1 +1 @@
# github.com/gohugoio/gohugoioTheme v0.0.0-20230418063032-99f9185b8e11
# github.com/gohugoio/gohugoioTheme v0.0.0-20230527124826-78bc315d7b8a
+5 -5
View File
@@ -27,9 +27,9 @@ toc: true
## All Privacy Settings
Below are all privacy settings and their default value. These settings need to be put in your site config (e.g. `config.toml`).
Below are all privacy settings and their default value. These settings need to be put in your site config (e.g. `hugo.toml`).
{{< code-toggle file="config">}}
{{< code-toggle file="hugo" >}}
[privacy]
[privacy.disqus]
disable = false
@@ -58,7 +58,7 @@ privacyEnhanced = false
An example Privacy Config that disables all the relevant services in Hugo. With this configuration, the other settings will not matter.
{{< code-toggle file="config">}}
{{< code-toggle file="hugo" >}}
[privacy]
[privacy.disqus]
disable = true
@@ -98,7 +98,7 @@ simple
**Note:** If you use the _simple mode_ for Instagram and a site styled with Bootstrap 4, you may want to disable the inline styles provided by Hugo:
{{< code-toggle file="config">}}
{{< code-toggle file="hugo" >}}
[services]
[services.instagram]
disableInlineCSS = true
@@ -114,7 +114,7 @@ simple
**Note:** If you use the _simple mode_ for Twitter, you may want to disable the inline styles provided by Hugo:
{{< code-toggle file="config">}}
{{< code-toggle file="hugo" >}}
[services]
[services.twitter]
disableInlineCSS = true
+2 -4
View File
@@ -27,7 +27,7 @@ hugo [flags]
-D, --buildDrafts include content marked as draft
-E, --buildExpired include expired content
-F, --buildFuture include content with publishdate in the future
--cacheDir string filesystem path to cache directory. Defaults: $TMPDIR/hugo_cache/
--cacheDir string filesystem path to cache directory. Defaults: $TMPDIR/hugo_cache_$USER/
--cleanDestinationDir remove files from destination not found in static directories
--clock string set the clock used by Hugo, e.g. --clock 2021-11-06T22:30:00.00+09:00
--config string config file (default is hugo.yaml|json|toml)
@@ -44,8 +44,7 @@ hugo [flags]
--ignoreCache ignores the cache directory
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
-l, --layoutDir string filesystem path to layout directory
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--logLevel string log level (debug|info|warn|error)
--minify minify any supported output format (HTML, XML etc.)
--noBuildLock don't create .hugo_build.lock file
--noChmod don't sync permission mode of files
@@ -65,7 +64,6 @@ hugo [flags]
--themesDir string filesystem path to themes directory
--trace file write trace to file (not useful in general)
-v, --verbose verbose output
--verboseLog verbose logging
-w, --watch watch filesystem for changes and recreate as needed
```
+1 -3
View File
@@ -29,13 +29,11 @@ See each sub-command's help for details on how to use the generated script.
-d, --destination string filesystem path to write files to
-e, --environment string build environment
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode
-s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory
-v, --verbose verbose output
--verboseLog verbose logging
```
### SEE ALSO
@@ -52,13 +52,11 @@ hugo completion bash
-d, --destination string filesystem path to write files to
-e, --environment string build environment
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode
-s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory
-v, --verbose verbose output
--verboseLog verbose logging
```
### SEE ALSO
@@ -43,13 +43,11 @@ hugo completion fish [flags]
-d, --destination string filesystem path to write files to
-e, --environment string build environment
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode
-s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory
-v, --verbose verbose output
--verboseLog verbose logging
```
### SEE ALSO
@@ -40,13 +40,11 @@ hugo completion powershell [flags]
-d, --destination string filesystem path to write files to
-e, --environment string build environment
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode
-s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory
-v, --verbose verbose output
--verboseLog verbose logging
```
### SEE ALSO
@@ -54,13 +54,11 @@ hugo completion zsh [flags]
-d, --destination string filesystem path to write files to
-e, --environment string build environment
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode
-s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory
-v, --verbose verbose output
--verboseLog verbose logging
```
### SEE ALSO
+8 -4
View File
@@ -18,7 +18,13 @@ hugo config [command] [flags]
### Options
```
-h, --help help for config
-b, --baseURL string hostname (and path) to the root, e.g. https://spf13.com/
--cacheDir string filesystem path to cache directory. Defaults: $TMPDIR/hugo_cache_$USER/
-c, --contentDir string filesystem path to content directory
--format string preferred file format (toml, yaml or json) (default "toml")
-h, --help help for config
--lang string the language to display config for. Defaults to the first language defined.
-t, --theme strings themes to use (located in /themes/THEMENAME/)
```
### Options inherited from parent commands
@@ -31,13 +37,11 @@ hugo config [command] [flags]
-d, --destination string filesystem path to write files to
-e, --environment string build environment
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode
-s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory
-v, --verbose verbose output
--verboseLog verbose logging
```
### SEE ALSO
@@ -14,7 +14,11 @@ hugo config mounts [flags] [args]
### Options
```
-h, --help help for mounts
-b, --baseURL string hostname (and path) to the root, e.g. https://spf13.com/
--cacheDir string filesystem path to cache directory. Defaults: $TMPDIR/hugo_cache_$USER/
-c, --contentDir string filesystem path to content directory
-h, --help help for mounts
-t, --theme strings themes to use (located in /themes/THEMENAME/)
```
### Options inherited from parent commands
@@ -27,13 +31,11 @@ hugo config mounts [flags] [args]
-d, --destination string filesystem path to write files to
-e, --environment string build environment
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode
-s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory
-v, --verbose verbose output
--verboseLog verbose logging
```
### SEE ALSO
+1 -3
View File
@@ -35,13 +35,11 @@ hugo convert [command] [flags]
-d, --destination string filesystem path to write files to
-e, --environment string build environment
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode
-s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory
-v, --verbose verbose output
--verboseLog verbose logging
```
### SEE ALSO
@@ -32,15 +32,13 @@ hugo convert toJSON [flags] [args]
-d, --destination string filesystem path to write files to
-e, --environment string build environment
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--logLevel string log level (debug|info|warn|error)
-o, --output string filesystem path to write files to
--quiet build in quiet mode
-s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory
--unsafe enable less safe operations, please backup first
-v, --verbose verbose output
--verboseLog verbose logging
```
### SEE ALSO
@@ -32,15 +32,13 @@ hugo convert toTOML [flags] [args]
-d, --destination string filesystem path to write files to
-e, --environment string build environment
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--logLevel string log level (debug|info|warn|error)
-o, --output string filesystem path to write files to
--quiet build in quiet mode
-s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory
--unsafe enable less safe operations, please backup first
-v, --verbose verbose output
--verboseLog verbose logging
```
### SEE ALSO
@@ -32,15 +32,13 @@ hugo convert toYAML [flags] [args]
-d, --destination string filesystem path to write files to
-e, --environment string build environment
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--logLevel string log level (debug|info|warn|error)
-o, --output string filesystem path to write files to
--quiet build in quiet mode
-s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory
--unsafe enable less safe operations, please backup first
-v, --verbose verbose output
--verboseLog verbose logging
```
### SEE ALSO
+1 -3
View File
@@ -42,13 +42,11 @@ hugo deploy [flags] [args]
-d, --destination string filesystem path to write files to
-e, --environment string build environment
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode
-s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory
-v, --verbose verbose output
--verboseLog verbose logging
```
### SEE ALSO
+1 -3
View File
@@ -31,13 +31,11 @@ hugo env [flags] [args]
-d, --destination string filesystem path to write files to
-e, --environment string build environment
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode
-s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory
-v, --verbose verbose output
--verboseLog verbose logging
```
### SEE ALSO
+1 -3
View File
@@ -27,13 +27,11 @@ hugo gen [command] [flags]
-d, --destination string filesystem path to write files to
-e, --environment string build environment
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode
-s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory
-v, --verbose verbose output
--verboseLog verbose logging
```
### SEE ALSO
@@ -36,13 +36,11 @@ hugo gen chromastyles [flags] [args]
-d, --destination string filesystem path to write files to
-e, --environment string build environment
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode
-s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory
-v, --verbose verbose output
--verboseLog verbose logging
```
### SEE ALSO
+1 -3
View File
@@ -37,13 +37,11 @@ hugo gen doc [flags] [args]
-d, --destination string filesystem path to write files to
-e, --environment string build environment
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode
-s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory
-v, --verbose verbose output
--verboseLog verbose logging
```
### SEE ALSO
+1 -3
View File
@@ -34,13 +34,11 @@ hugo gen man [flags] [args]
-d, --destination string filesystem path to write files to
-e, --environment string build environment
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode
-s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory
-v, --verbose verbose output
--verboseLog verbose logging
```
### SEE ALSO
+1 -3
View File
@@ -33,13 +33,11 @@ hugo import [command] [flags]
-d, --destination string filesystem path to write files to
-e, --environment string build environment
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode
-s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory
-v, --verbose verbose output
--verboseLog verbose logging
```
### SEE ALSO
@@ -34,13 +34,11 @@ hugo import jekyll [flags] [args]
-d, --destination string filesystem path to write files to
-e, --environment string build environment
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode
-s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory
-v, --verbose verbose output
--verboseLog verbose logging
```
### SEE ALSO
+1 -3
View File
@@ -33,13 +33,11 @@ hugo list [command] [flags]
-d, --destination string filesystem path to write files to
-e, --environment string build environment
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode
-s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory
-v, --verbose verbose output
--verboseLog verbose logging
```
### SEE ALSO
+1 -3
View File
@@ -31,13 +31,11 @@ hugo list all [flags] [args]
-d, --destination string filesystem path to write files to
-e, --environment string build environment
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode
-s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory
-v, --verbose verbose output
--verboseLog verbose logging
```
### SEE ALSO
+1 -3
View File
@@ -31,13 +31,11 @@ hugo list drafts [flags] [args]
-d, --destination string filesystem path to write files to
-e, --environment string build environment
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode
-s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory
-v, --verbose verbose output
--verboseLog verbose logging
```
### SEE ALSO
@@ -31,13 +31,11 @@ hugo list expired [flags] [args]
-d, --destination string filesystem path to write files to
-e, --environment string build environment
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode
-s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory
-v, --verbose verbose output
--verboseLog verbose logging
```
### SEE ALSO
+1 -3
View File
@@ -31,13 +31,11 @@ hugo list future [flags] [args]
-d, --destination string filesystem path to write files to
-e, --environment string build environment
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode
-s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory
-v, --verbose verbose output
--verboseLog verbose logging
```
### SEE ALSO
+1 -3
View File
@@ -38,13 +38,11 @@ See https://gohugo.io/hugo-modules/ for more information.
-d, --destination string filesystem path to write files to
-e, --environment string build environment
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode
-s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory
-v, --verbose verbose output
--verboseLog verbose logging
```
### SEE ALSO
+8 -6
View File
@@ -18,9 +18,13 @@ hugo mod clean [flags] [args]
### Options
```
--all clean entire module cache
-h, --help help for clean
--pattern string pattern matching module paths to clean (all if not set), e.g. "**hugo*"
--all clean entire module cache
-b, --baseURL string hostname (and path) to the root, e.g. https://spf13.com/
--cacheDir string filesystem path to cache directory. Defaults: $TMPDIR/hugo_cache_$USER/
-c, --contentDir string filesystem path to content directory
-h, --help help for clean
--pattern string pattern matching module paths to clean (all if not set), e.g. "**hugo*"
-t, --theme strings themes to use (located in /themes/THEMENAME/)
```
### Options inherited from parent commands
@@ -33,13 +37,11 @@ hugo mod clean [flags] [args]
-d, --destination string filesystem path to write files to
-e, --environment string build environment
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode
-s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory
-v, --verbose verbose output
--verboseLog verbose logging
```
### SEE ALSO
+1 -3
View File
@@ -57,13 +57,11 @@ hugo mod get [flags] [args]
-d, --destination string filesystem path to write files to
-e, --environment string build environment
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode
-s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory
-v, --verbose verbose output
--verboseLog verbose logging
```
### SEE ALSO
+7 -5
View File
@@ -20,8 +20,12 @@ hugo mod graph [flags] [args]
### Options
```
--clean delete module cache for dependencies that fail verification
-h, --help help for graph
-b, --baseURL string hostname (and path) to the root, e.g. https://spf13.com/
--cacheDir string filesystem path to cache directory. Defaults: $TMPDIR/hugo_cache_$USER/
--clean delete module cache for dependencies that fail verification
-c, --contentDir string filesystem path to content directory
-h, --help help for graph
-t, --theme strings themes to use (located in /themes/THEMENAME/)
```
### Options inherited from parent commands
@@ -34,13 +38,11 @@ hugo mod graph [flags] [args]
-d, --destination string filesystem path to write files to
-e, --environment string build environment
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode
-s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory
-v, --verbose verbose output
--verboseLog verbose logging
```
### SEE ALSO
+6 -4
View File
@@ -25,7 +25,11 @@ hugo mod init [flags] [args]
### Options
```
-h, --help help for init
-b, --baseURL string hostname (and path) to the root, e.g. https://spf13.com/
--cacheDir string filesystem path to cache directory. Defaults: $TMPDIR/hugo_cache_$USER/
-c, --contentDir string filesystem path to content directory
-h, --help help for init
-t, --theme strings themes to use (located in /themes/THEMENAME/)
```
### Options inherited from parent commands
@@ -38,13 +42,11 @@ hugo mod init [flags] [args]
-d, --destination string filesystem path to write files to
-e, --environment string build environment
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode
-s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory
-v, --verbose verbose output
--verboseLog verbose logging
```
### SEE ALSO
+1 -3
View File
@@ -31,13 +31,11 @@ hugo mod npm [command] [flags]
-d, --destination string filesystem path to write files to
-e, --environment string build environment
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode
-s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory
-v, --verbose verbose output
--verboseLog verbose logging
```
### SEE ALSO
@@ -28,7 +28,11 @@ hugo mod npm pack [flags] [args]
### Options
```
-h, --help help for pack
-b, --baseURL string hostname (and path) to the root, e.g. https://spf13.com/
--cacheDir string filesystem path to cache directory. Defaults: $TMPDIR/hugo_cache_$USER/
-c, --contentDir string filesystem path to content directory
-h, --help help for pack
-t, --theme strings themes to use (located in /themes/THEMENAME/)
```
### Options inherited from parent commands
@@ -41,13 +45,11 @@ hugo mod npm pack [flags] [args]
-d, --destination string filesystem path to write files to
-e, --environment string build environment
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode
-s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory
-v, --verbose verbose output
--verboseLog verbose logging
```
### SEE ALSO
+6 -4
View File
@@ -14,7 +14,11 @@ hugo mod tidy [flags] [args]
### Options
```
-h, --help help for tidy
-b, --baseURL string hostname (and path) to the root, e.g. https://spf13.com/
--cacheDir string filesystem path to cache directory. Defaults: $TMPDIR/hugo_cache_$USER/
-c, --contentDir string filesystem path to content directory
-h, --help help for tidy
-t, --theme strings themes to use (located in /themes/THEMENAME/)
```
### Options inherited from parent commands
@@ -27,13 +31,11 @@ hugo mod tidy [flags] [args]
-d, --destination string filesystem path to write files to
-e, --environment string build environment
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode
-s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory
-v, --verbose verbose output
--verboseLog verbose logging
```
### SEE ALSO
+6 -4
View File
@@ -20,7 +20,11 @@ hugo mod vendor [flags] [args]
### Options
```
-h, --help help for vendor
-b, --baseURL string hostname (and path) to the root, e.g. https://spf13.com/
--cacheDir string filesystem path to cache directory. Defaults: $TMPDIR/hugo_cache_$USER/
-c, --contentDir string filesystem path to content directory
-h, --help help for vendor
-t, --theme strings themes to use (located in /themes/THEMENAME/)
```
### Options inherited from parent commands
@@ -33,13 +37,11 @@ hugo mod vendor [flags] [args]
-d, --destination string filesystem path to write files to
-e, --environment string build environment
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode
-s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory
-v, --verbose verbose output
--verboseLog verbose logging
```
### SEE ALSO
+7 -5
View File
@@ -18,8 +18,12 @@ hugo mod verify [flags] [args]
### Options
```
--clean delete module cache for dependencies that fail verification
-h, --help help for verify
-b, --baseURL string hostname (and path) to the root, e.g. https://spf13.com/
--cacheDir string filesystem path to cache directory. Defaults: $TMPDIR/hugo_cache_$USER/
--clean delete module cache for dependencies that fail verification
-c, --contentDir string filesystem path to content directory
-h, --help help for verify
-t, --theme strings themes to use (located in /themes/THEMENAME/)
```
### Options inherited from parent commands
@@ -32,13 +36,11 @@ hugo mod verify [flags] [args]
-d, --destination string filesystem path to write files to
-e, --environment string build environment
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode
-s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory
-v, --verbose verbose output
--verboseLog verbose logging
```
### SEE ALSO
+1 -3
View File
@@ -38,13 +38,11 @@ hugo new [command] [flags]
-d, --destination string filesystem path to write files to
-e, --environment string build environment
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode
-s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory
-v, --verbose verbose output
--verboseLog verbose logging
```
### SEE ALSO
+10 -7
View File
@@ -25,10 +25,15 @@ hugo new content [path] [flags]
### Options
```
--editor string edit new content with this editor, if provided
-f, --force overwrite file if it already exists
-h, --help help for content
-k, --kind string content type to create
-b, --baseURL string hostname (and path) to the root, e.g. https://spf13.com/
--cacheDir string filesystem path to cache directory. Defaults: $TMPDIR/hugo_cache_$USER/
-c, --contentDir string filesystem path to content directory
--editor string edit new content with this editor, if provided
-f, --force overwrite file if it already exists
--format string preferred file format (toml, yaml or json) (default "toml")
-h, --help help for content
-k, --kind string content type to create
-t, --theme strings themes to use (located in /themes/THEMENAME/)
```
### Options inherited from parent commands
@@ -41,13 +46,11 @@ hugo new content [path] [flags]
-d, --destination string filesystem path to write files to
-e, --environment string build environment
--ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--logLevel string log level (debug|info|warn|error)
--quiet build in quiet mode
-s, --source string filesystem path to read files relative from
--themesDir string filesystem path to themes directory
-v, --verbose verbose output
--verboseLog verbose logging
```
### SEE ALSO

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