mirror of
https://github.com/gohugoio/hugo.git
synced 2026-08-31 18:52:38 +00:00
Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9f9695cf7b | |||
| 0831d8ccaf | |||
| 1d4ff024ca | |||
| 521e63ac7c | |||
| 47d38628ec | |||
| 0024dcfe3e | |||
| beec1fc98e | |||
| 306573def0 | |||
| 80c8f3b81a | |||
| 6b6dcb44a0 | |||
| d96f2a460f | |||
| ac53035030 | |||
| b874a1ba7a | |||
| 4108705934 | |||
| 9c1e82085e | |||
| 2b73e89d6d | |||
| febf0aec8b | |||
| a4fad5be6b | |||
| 6084f0433c |
@@ -3,3 +3,6 @@
|
||||
|
||||
# Go source files always have LF line endings
|
||||
*.go text eol=lf
|
||||
|
||||
# SVG files should not be modified
|
||||
*.svg -text
|
||||
|
||||
Generated
+209
-25
@@ -3,35 +3,46 @@
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:f6a10073544cc0bd1eb9fd9f8d9bf4644971910a0f8393d51b5b4d286e554849"
|
||||
name = "github.com/BurntSushi/locker"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "a6e239ea1c69bff1cfdb20c4b73dadf52f784b6a"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:af3600b068c8dd0e004122f154de7ece06b0b13376f79e976701aab4834c860a"
|
||||
name = "github.com/BurntSushi/toml"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "a368813c5e648fee92e5f6c30e3944ff9d5e8895"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:1080c443bebc98b1c25665b46b321dc02f8a4d384fe544379dcba1e651f59321"
|
||||
name = "github.com/PuerkitoBio/purell"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "0bcb03f4b4d0a9428594752bd2a3b9aa0a9d4bd4"
|
||||
version = "v1.1.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:331a419049c2be691e5ba1d24342fc77c7e767a80c666a18fd8a9f7b82419c1c"
|
||||
name = "github.com/PuerkitoBio/urlesc"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "de5bf2ad457846296e2031421a34e2568e304e35"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:60d5ffa86fb76749180841154b3714cde4771723b7e52329fb97ec916a6a68a6"
|
||||
name = "github.com/alecthomas/assert"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "405dbfeb8e38effee6e723317226e93fff912d06"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:2d78d7ffff1988e613e4946d6a6914190db0b38d533e392208797d2f557c92b6"
|
||||
name = "github.com/alecthomas/chroma"
|
||||
packages = [
|
||||
".",
|
||||
@@ -64,111 +75,135 @@
|
||||
"lexers/w",
|
||||
"lexers/x",
|
||||
"lexers/y",
|
||||
"styles"
|
||||
"styles",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "1b755a90bd109f170385cb3964f0abdfd3451145"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:ba0a389824c3c3d378f5f334370524b7d04b5a5ccedce7dd2da05ae8d3868609"
|
||||
name = "github.com/alecthomas/colour"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "60882d9e27213e8552dcff6328914fe4c2b44bc9"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:5723237c9114bb92b4571532d9580dd0ed885ec3eb371d58085c074895c04a51"
|
||||
name = "github.com/alecthomas/repr"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "f49988b46e025398b9f834f7c726afe001ec481f"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:05d0e4ae6b8d0273647964fe26762e3345d5d196aaeb858838e75336703451ba"
|
||||
name = "github.com/bep/debounce"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "844797fa1dd9ba969d71b62797ff19d1e49d4eac"
|
||||
version = "v1.1.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:88b2a2ccfbcf8aa697ec140e196c524f40bbdc8e6f6d03ff79354bc694cb677d"
|
||||
name = "github.com/bep/gitmap"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "012701e8669671499fc43e9792335a1dcbfe2afb"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:7337271448975bc9cf3deae77bb2d7f7fc937c60c59b606ffcd25bfc754dd2ec"
|
||||
name = "github.com/bep/go-tocss"
|
||||
packages = [
|
||||
"scss",
|
||||
"scss/libsass",
|
||||
"tocss"
|
||||
"tocss",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "2abb118dc8688b6c7df44e12f4152c2bded9b19c"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:e5ad472b763adca2591568384b8f07974d2da4a98b55ffb360e2cecc2a216bae"
|
||||
name = "github.com/chaseadamsio/goorgeous"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "dcf1ef873b8987bf12596fe6951c48347986eb2f"
|
||||
version = "v1.1.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:f30036d9c6eb2b9262edac69b5f6b59e25b25310ffee3035ab0e7c4b722a8552"
|
||||
name = "github.com/cpuguy83/go-md2man"
|
||||
packages = ["md2man"]
|
||||
pruneopts = ""
|
||||
revision = "a65d4d2de4d5f7c74868dfa9b202a3c8be315aaa"
|
||||
version = "v1.0.6"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:8f6c36ee73ded871996ada894e20dfecde56557d08b4d1849d5489076679971f"
|
||||
name = "github.com/danwakefield/fnmatch"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "cbb64ac3d964b81592e64f957ad53df015803288"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:0a39ec8bf5629610a4bc7873a92039ee509246da3cef1a0ea60f1ed7e5f9cea5"
|
||||
name = "github.com/davecgh/go-spew"
|
||||
packages = ["spew"]
|
||||
pruneopts = ""
|
||||
revision = "346938d642f2ec3594ed81d874461961cd0faa76"
|
||||
version = "v1.1.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:8dc164acd41f84c9f704362d061f90cf45014c3b7eb3fead126efb7d152e2efc"
|
||||
name = "github.com/disintegration/imaging"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "dd50a3ee9985ccd313a2f03c398fcaedc96dc707"
|
||||
version = "v1.2.4"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:536d2bdf1cdef7ec49e1cb4a8a083ae639159f0fd11a5829fe4d35ecb8cc3a1a"
|
||||
name = "github.com/dlclark/regexp2"
|
||||
packages = [
|
||||
".",
|
||||
"syntax"
|
||||
"syntax",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "487489b64fb796de2e55f4e8a4ad1e145f80e957"
|
||||
version = "v1.1.6"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/dsnet/golib"
|
||||
packages = ["memfile"]
|
||||
revision = "1ea1667757804fdcccc5a1810e09aba618885ac2"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:fbbae68d476d61afb78178dd4c5532dbfff154e2fea72d1312138bf35c613ec1"
|
||||
name = "github.com/eknkc/amber"
|
||||
packages = [
|
||||
".",
|
||||
"parser"
|
||||
"parser",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "cdade1c073850f4ffc70a829e31235ea6892853b"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:e5c807ac3b60699ccec9263f6eec756251b17e78582eb149f90ac345d9e58327"
|
||||
name = "github.com/fortytw2/leaktest"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "a5ef70473c97b71626b9abeda80ee92ba2a7de9e"
|
||||
version = "v1.2.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:b2106f1668ea5efc1ecc480f7e922a093adb9563fd9ce58585292871f0d0f229"
|
||||
name = "github.com/fsnotify/fsnotify"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "c2828203cd70a50dcccfb2761f8b1f8ceef9a8e9"
|
||||
version = "v1.4.7"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:b7a7e17513aeee6492d93015c7bf29c86a0c1c91210ea56b21e36c1a40958cba"
|
||||
name = "github.com/gobwas/glob"
|
||||
packages = [
|
||||
".",
|
||||
@@ -178,31 +213,39 @@
|
||||
"syntax/ast",
|
||||
"syntax/lexer",
|
||||
"util/runes",
|
||||
"util/strings"
|
||||
"util/strings",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "5ccd90ef52e1e632236f7326478d4faa74f99438"
|
||||
version = "v0.2.3"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:fe1b4d4cbe48c0d55507c55f8663aa4185576cc58fa0c8be03bb8f19dfe17a9c"
|
||||
name = "github.com/gorilla/websocket"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "ea4d1f681babbce9545c9c5f3d5194a789c89f5b"
|
||||
version = "v1.2.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:4423ee95d6ee30bb22f680445c58889bb5b91e1b955405bf34374a053784a8a2"
|
||||
name = "github.com/hashicorp/go-immutable-radix"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "7f3cd4390caab3250a57f30efdb2a65dd7649ecf"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:9c776d7d9c54b7ed89f119e449983c3f24c0023e75001d6092442412ebca6b94"
|
||||
name = "github.com/hashicorp/golang-lru"
|
||||
packages = ["simplelru"]
|
||||
pruneopts = ""
|
||||
revision = "0fb14efe8c47ae851c0034ed7a448854d3d34cf3"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:ccfc44438ba7fc24effffbe9c7b75bbbb51e7a275e361e62a4dbffbc9e8e43d9"
|
||||
name = "github.com/hashicorp/hcl"
|
||||
packages = [
|
||||
".",
|
||||
@@ -214,206 +257,266 @@
|
||||
"hcl/token",
|
||||
"json/parser",
|
||||
"json/scanner",
|
||||
"json/token"
|
||||
"json/token",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "ef8a98b0bbce4a65b5aa4c368430a80ddc533168"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:870d441fe217b8e689d7949fef6e43efbc787e50f200cb1e70dbca9204a1d6be"
|
||||
name = "github.com/inconshreveable/mousetrap"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75"
|
||||
version = "v1.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:3b82a4308adc7319d0c7efbad106e966cbbf70e47f16fb5f7aca131b01f6f9b1"
|
||||
name = "github.com/jdkato/prose"
|
||||
packages = [
|
||||
"internal/util",
|
||||
"transform"
|
||||
"transform",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "20d3663d4bc9dd10d75abcde9d92e04b4861c674"
|
||||
version = "v1.1.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:f72872791669f287262777a6a635c7aaebbdd9919cffacea802f8f9c1dc2e6f6"
|
||||
name = "github.com/kyokomi/emoji"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "7e06b236c489543f53868841f188a294e3383eab"
|
||||
version = "v1.5"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:3ee69edc976a8e66debd179073163cbbef426faa7c0ef2d8ff8e3be159699d2e"
|
||||
name = "github.com/magefile/mage"
|
||||
packages = [
|
||||
"mg",
|
||||
"sh"
|
||||
"sh",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "2f974307b636f59c13b88704cf350a4772fef271"
|
||||
version = "v1.0.2"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:093cd7ebfdecf5692c66f0b0f7a1877d796c89d9940f5769439c53dc65264036"
|
||||
name = "github.com/magiconair/properties"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "c3beff4c2358b44d0493c7dda585e7db7ff28ae6"
|
||||
version = "v1.7.6"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:fd46423a2fe75d52968baf37471b99e6f05cea3ac29c756128ead26af34e1c35"
|
||||
name = "github.com/markbates/inflect"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "a12c3aec81a6a938bf584a4bac567afed9256586"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:78229b46ddb7434f881390029bd1af7661294af31f6802e0e1bedaad4ab0af3c"
|
||||
name = "github.com/mattn/go-isatty"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39"
|
||||
version = "v0.0.3"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:81e673df85e765593a863f67cba4544cf40e8919590f04d67664940786c2b61a"
|
||||
name = "github.com/mattn/go-runewidth"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "9e777a8366cce605130a531d2cd6363d07ad7317"
|
||||
version = "v0.0.2"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:6066f4c384723dd468c96adc13bfe4d977f182c2305e1a82c94bb50e1507d528"
|
||||
name = "github.com/miekg/mmark"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "fd2f6c1403b37925bd7fe13af05853b8ae58ee5f"
|
||||
version = "v1.3.6"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:0de0f377aeccd41384e883c59c6f184c9db01c96db33a2724a1eaadd60f92629"
|
||||
name = "github.com/mitchellh/hashstructure"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "2bca23e0e452137f789efbc8610126fd8b94f73b"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:59fa50d593e5673a0dfffa1852b66fd700c05b35e368680b4b89a68fdb2c1379"
|
||||
name = "github.com/mitchellh/mapstructure"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "00c29f56e2386353d58c599509e8dc3801b0d716"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:08b8db6381176e5472815f67f29b2b8b21d5bf3adaba4de3e5416faaf26f3689"
|
||||
name = "github.com/muesli/smartcrop"
|
||||
packages = [
|
||||
".",
|
||||
"options"
|
||||
"options",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "f6ebaa786a12a0fdb2d7c6dee72808e68c296464"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:34afc91b88b56c71639e275ff3ea8179a8f094ddc86df96e26074000cade42fe"
|
||||
name = "github.com/nicksnyder/go-i18n"
|
||||
packages = [
|
||||
"i18n/bundle",
|
||||
"i18n/language",
|
||||
"i18n/translation"
|
||||
"i18n/translation",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "0dc1626d56435e9d605a29875701721c54bc9bbd"
|
||||
version = "v1.10.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:2656200f82783893859c77903afc794d97c1f5054e2b57f7021e33a6047e7b1e"
|
||||
name = "github.com/olekukonko/tablewriter"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "b8a9be070da40449e501c3c4730a889e42d87a9e"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:fef37519c971ab3c464318a0c9da6a7fb9c21439aa587e61bf10af651e6119b9"
|
||||
name = "github.com/pelletier/go-toml"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "acdc4509485b587f5e675510c4f2c63e90ff68a8"
|
||||
version = "v1.1.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:256484dbbcd271f9ecebc6795b2df8cad4c458dd0f5fd82a8c2fa0c29f233411"
|
||||
name = "github.com/pmezard/go-difflib"
|
||||
packages = ["difflib"]
|
||||
pruneopts = ""
|
||||
revision = "792786c7400a136282c1664665ae0a8db921c6c2"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:10bc894f31df5ca3366a50122ee2ade6b56f3f5531c523a8a551748a0663aa1b"
|
||||
name = "github.com/russross/blackfriday"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "11635eb403ff09dbc3a6b5a007ab5ab09151c229"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:afa9b7bb3d9e633ef32e46ab4b6a87b5376271e3d86b09a379029bbb10e26fa0"
|
||||
name = "github.com/sanity-io/litter"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "ae543b7ba8fd6af63e4976198f146e1348ae53c1"
|
||||
version = "v1.1.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:1ebe873a8dc99e3316c30fea2e211038c4d1fcb605eee17e00a5e91b8817925e"
|
||||
name = "github.com/sergi/go-diff"
|
||||
packages = ["diffmatchpatch"]
|
||||
pruneopts = ""
|
||||
revision = "1744e2970ca51c86172c8190fadad617561ed6e7"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:606fa779c7a80ab6a9ec5836cd12759f86cd6e1d82d5d60cf7ec5133e78c6cf8"
|
||||
name = "github.com/shurcooL/sanitized_anchor_name"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "86672fcb3f950f35f2e675df2240550f2a50762f"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:3d6c88f060fdaac3291f3d18f58eb542fe3a2b330609b269962d26d0c99104be"
|
||||
name = "github.com/spf13/afero"
|
||||
packages = [
|
||||
".",
|
||||
"mem"
|
||||
"mem",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "787d034dfe70e44075ccc060d346146ef53270ad"
|
||||
version = "v1.1.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:d0b38ba6da419a6d4380700218eeec8623841d44a856bb57369c172fbf692ab4"
|
||||
name = "github.com/spf13/cast"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "8965335b8c7107321228e3e3702cab9832751bac"
|
||||
version = "v1.2.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:9e14345bfb9aa30952b41ffceaa2acd559933cfe3d17bd87b7f6e54b6c618492"
|
||||
name = "github.com/spf13/cobra"
|
||||
packages = [
|
||||
".",
|
||||
"doc"
|
||||
"doc",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "a1f051bc3eba734da4772d60e2d677f47cf93ef4"
|
||||
version = "v0.0.2"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:7c00f445c89f468abd5ab86546ba1fa11bac66e63325ade8ca05aa7220791fc7"
|
||||
name = "github.com/spf13/fsync"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "12a01e648f05a938100a26858d2d59a120307a18"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:104517520aab91164020ab6524a5d6b7cafc641b2e42ac6236f6ac1deac4f66a"
|
||||
name = "github.com/spf13/jwalterweatherman"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "7c0cea34c8ece3fbeb2b27ab9b59511d360fb394"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:5082c0d57a199dabc0868010784039249af0932fad2990b51ad9404c9a6b6e5d"
|
||||
name = "github.com/spf13/nitro"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "24d7ef30a12da0bdc5e2eb370a79c659ddccf0e8"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:261bc565833ef4f02121450d74eb88d5ae4bd74bfe5d0e862cddb8550ec35000"
|
||||
name = "github.com/spf13/pflag"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "e57e3eeb33f795204c1ca35f56c44f83227c6e66"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:79af66c513727a0ed32fb4137ad7d0613b01e8e2f5ce9479724e26e2c9068011"
|
||||
name = "github.com/spf13/viper"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "b5e8006cbee93ec955a89ab31e0e3ce3204f3736"
|
||||
version = "v1.0.2"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:a70d585d45f695f2e8e6782569bdf181419667a35e6035ceb086706b495aa21a"
|
||||
name = "github.com/stretchr/testify"
|
||||
packages = [
|
||||
"assert",
|
||||
"require"
|
||||
"require",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "12b6f73e6084dad08a7c6e575284b177ecafbc71"
|
||||
version = "v1.2.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:54b1c3f97e0d74b571055cc17af4a978b6160e6ccfda73608aba048e404319c1"
|
||||
name = "github.com/tdewolff/minify"
|
||||
packages = [
|
||||
".",
|
||||
@@ -422,12 +525,14 @@
|
||||
"js",
|
||||
"json",
|
||||
"svg",
|
||||
"xml"
|
||||
"xml",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "8d72a4127ae33b755e95bffede9b92e396267ce2"
|
||||
version = "v2.3.5"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:33d327ae34260328b00ed15f89961446d805797a96de8643a983020825bb51ae"
|
||||
name = "github.com/tdewolff/parse"
|
||||
packages = [
|
||||
".",
|
||||
@@ -438,25 +543,31 @@
|
||||
"json",
|
||||
"strconv",
|
||||
"svg",
|
||||
"xml"
|
||||
"xml",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "d739d6fccb0971177e06352fea02d3552625efb1"
|
||||
version = "v2.3.3"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:12e69a2969bdcdf2928607e51966a868482c2a450f1c97c5dde004257c8369ff"
|
||||
name = "github.com/wellington/go-libsass"
|
||||
packages = ["libs"]
|
||||
pruneopts = ""
|
||||
revision = "615eaa47ef794d037c1906a0eb7bf85375a5decf"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:b1e5dc66cd8ad9712eb8fd4dfaecac6ae45cbcde94476c5b64d905c5d789eef7"
|
||||
name = "github.com/yosssi/ace"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "ea038f4770b6746c3f8f84f14fa60d9fe1205b56"
|
||||
version = "v0.0.5"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:4525c51a65e4974007814da8e2621343840d769d80b2b2ab79e6958342726587"
|
||||
name = "golang.org/x/image"
|
||||
packages = [
|
||||
"bmp",
|
||||
@@ -467,33 +578,41 @@
|
||||
"tiff/lzw",
|
||||
"vp8",
|
||||
"vp8l",
|
||||
"webp"
|
||||
"webp",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "f315e440302883054d0c2bd85486878cb4f8572c"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:8bb19e8d6e1321626d3f58ffee75699e86940c79d959b30fcf632883d7c4d303"
|
||||
name = "golang.org/x/net"
|
||||
packages = [
|
||||
"context",
|
||||
"idna"
|
||||
"idna",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "61147c48b25b599e5b561d2e9c4f3e1ef489ca41"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:d84d0f563cc649de4c9a8272a0395f75b11952202d18d4d927e933cc91493062"
|
||||
name = "golang.org/x/sync"
|
||||
packages = ["errgroup"]
|
||||
pruneopts = ""
|
||||
revision = "1d60e4601c6fd243af51cc01ddf169918a5407ca"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:137a530894d869c2fb09e135e6bb7a5d701347ba273471eaa2483053f8fbeb35"
|
||||
name = "golang.org/x/sys"
|
||||
packages = ["unix"]
|
||||
pruneopts = ""
|
||||
revision = "3b87a42e500a6dc65dae1a55d0b641295971163e"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:4cf01dae652ef4428cf9d354bdec79467e436ecfa92d943b1ada8184e1a938b6"
|
||||
name = "golang.org/x/text"
|
||||
packages = [
|
||||
"collate",
|
||||
@@ -512,19 +631,84 @@
|
||||
"unicode/cldr",
|
||||
"unicode/norm",
|
||||
"unicode/rangetable",
|
||||
"width"
|
||||
"width",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "2cb43934f0eece38629746959acc633cba083fe4"
|
||||
|
||||
[[projects]]
|
||||
branch = "v2"
|
||||
digest = "1:f0620375dd1f6251d9973b5f2596228cc8042e887cd7f827e4220bc1ce8c30e2"
|
||||
name = "gopkg.in/yaml.v2"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "993acf46c3937e5cebef4f39a2733150aad7cbf96913a017e56cd03c8241a56e"
|
||||
input-imports = [
|
||||
"github.com/BurntSushi/locker",
|
||||
"github.com/BurntSushi/toml",
|
||||
"github.com/PuerkitoBio/purell",
|
||||
"github.com/alecthomas/assert",
|
||||
"github.com/alecthomas/chroma",
|
||||
"github.com/alecthomas/chroma/formatters",
|
||||
"github.com/alecthomas/chroma/formatters/html",
|
||||
"github.com/alecthomas/chroma/lexers",
|
||||
"github.com/alecthomas/chroma/styles",
|
||||
"github.com/bep/debounce",
|
||||
"github.com/bep/gitmap",
|
||||
"github.com/bep/go-tocss/scss",
|
||||
"github.com/bep/go-tocss/scss/libsass",
|
||||
"github.com/bep/go-tocss/tocss",
|
||||
"github.com/chaseadamsio/goorgeous",
|
||||
"github.com/disintegration/imaging",
|
||||
"github.com/eknkc/amber",
|
||||
"github.com/fortytw2/leaktest",
|
||||
"github.com/fsnotify/fsnotify",
|
||||
"github.com/gobwas/glob",
|
||||
"github.com/gorilla/websocket",
|
||||
"github.com/hashicorp/go-immutable-radix",
|
||||
"github.com/jdkato/prose/transform",
|
||||
"github.com/kyokomi/emoji",
|
||||
"github.com/magefile/mage/mg",
|
||||
"github.com/magefile/mage/sh",
|
||||
"github.com/markbates/inflect",
|
||||
"github.com/miekg/mmark",
|
||||
"github.com/mitchellh/hashstructure",
|
||||
"github.com/mitchellh/mapstructure",
|
||||
"github.com/muesli/smartcrop",
|
||||
"github.com/nicksnyder/go-i18n/i18n/bundle",
|
||||
"github.com/nicksnyder/go-i18n/i18n/language",
|
||||
"github.com/olekukonko/tablewriter",
|
||||
"github.com/russross/blackfriday",
|
||||
"github.com/sanity-io/litter",
|
||||
"github.com/spf13/afero",
|
||||
"github.com/spf13/cast",
|
||||
"github.com/spf13/cobra",
|
||||
"github.com/spf13/cobra/doc",
|
||||
"github.com/spf13/fsync",
|
||||
"github.com/spf13/jwalterweatherman",
|
||||
"github.com/spf13/nitro",
|
||||
"github.com/spf13/pflag",
|
||||
"github.com/spf13/viper",
|
||||
"github.com/stretchr/testify/assert",
|
||||
"github.com/stretchr/testify/require",
|
||||
"github.com/tdewolff/minify",
|
||||
"github.com/tdewolff/minify/css",
|
||||
"github.com/tdewolff/minify/html",
|
||||
"github.com/tdewolff/minify/js",
|
||||
"github.com/tdewolff/minify/json",
|
||||
"github.com/tdewolff/minify/svg",
|
||||
"github.com/tdewolff/minify/xml",
|
||||
"github.com/yosssi/ace",
|
||||
"golang.org/x/image/webp",
|
||||
"golang.org/x/net/context",
|
||||
"golang.org/x/sync/errgroup",
|
||||
"golang.org/x/text/transform",
|
||||
"golang.org/x/text/unicode/norm",
|
||||
"gopkg.in/yaml.v2",
|
||||
]
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
|
||||
Vendored
+29
@@ -1,6 +1,7 @@
|
||||
package deps
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/gohugoio/hugo/common/loggers"
|
||||
@@ -22,6 +23,7 @@ import (
|
||||
// There will be normally only one instance of deps in play
|
||||
// at a given time, i.e. one per Site built.
|
||||
type Deps struct {
|
||||
|
||||
// The logger to use.
|
||||
Log *jww.Notepad `json:"-"`
|
||||
|
||||
@@ -69,6 +71,30 @@ type Deps struct {
|
||||
|
||||
// Timeout is configurable in site config.
|
||||
Timeout time.Duration
|
||||
|
||||
// BuildStartListeners will be notified before a build starts.
|
||||
BuildStartListeners *Listeners
|
||||
}
|
||||
|
||||
type Listeners struct {
|
||||
sync.Mutex
|
||||
|
||||
// A list of funcs to be notified about an event.
|
||||
listeners []func()
|
||||
}
|
||||
|
||||
func (b *Listeners) Add(f func()) {
|
||||
b.Lock()
|
||||
defer b.Unlock()
|
||||
b.listeners = append(b.listeners, f)
|
||||
}
|
||||
|
||||
func (b *Listeners) Notify() {
|
||||
b.Lock()
|
||||
defer b.Unlock()
|
||||
for _, notify := range b.listeners {
|
||||
notify()
|
||||
}
|
||||
}
|
||||
|
||||
// ResourceProvider is used to create and refresh, and clone resources needed.
|
||||
@@ -168,6 +194,7 @@ func New(cfg DepsCfg) (*Deps, error) {
|
||||
ResourceSpec: resourceSpec,
|
||||
Cfg: cfg.Language,
|
||||
Language: cfg.Language,
|
||||
BuildStartListeners: &Listeners{},
|
||||
Timeout: time.Duration(timeoutms) * time.Millisecond,
|
||||
}
|
||||
|
||||
@@ -210,6 +237,8 @@ func (d Deps) ForLanguage(cfg DepsCfg) (*Deps, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
d.BuildStartListeners = &Listeners{}
|
||||
|
||||
return &d, nil
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -70,7 +70,7 @@ twitter = "GoHugoIO"
|
||||
[params]
|
||||
description = "The world’s fastest framework for building websites"
|
||||
## Used for views in rendered HTML (i.e., rather than using the .Hugo variable)
|
||||
release = "0.43"
|
||||
release = "0.44"
|
||||
## Setting this to true will add a "noindex" to *EVERY* page on the site
|
||||
removefromexternalsearch = false
|
||||
## Gh repo for site footer (include trailing slash)
|
||||
|
||||
@@ -8,8 +8,6 @@ categories: ["Releases"]
|
||||
|
||||
Hugo `0.43` adds a powerful and very simple to use **Assets Pipeline** with **SASS and SCSS** with source map support, **PostCSS** and **minification** and **fingerprinting** and **Subresource Integrity** and ... much more. Oh, did we mention that you can now do **ad-hoc image processing** and execute text resources as Go templates?
|
||||
|
||||
I, [@bep](https://github.com/bep), implemented this in [dea71670](https://github.com/gohugoio/hugo/commit/dea71670c059ab4d5a42bd22503f18c087dd22d4) [#4381]. We will work hard to get the documentation up to date, but follow the links above for details, and also see this [demo project](https://github.com/bep/hugo-sass-test).
|
||||
|
||||
An example pipeline:
|
||||
|
||||
```go-html-template
|
||||
@@ -19,6 +17,24 @@ An example pipeline:
|
||||
|
||||
To me, the above is beautiful in its speed and simplicity. It could be printed on a t-shirt. I wrote in the [Hugo Birthday Post](https://gohugo.io/news/lets-celebrate-hugos-5th-birthday/) some days ago about the value of a single binary with native and fast implementations. I should have added _simplicity_ as a keyword. There seem to be a misconception that all of this needs to be hard and painful.
|
||||
|
||||
New functions to create `Resource` objects:
|
||||
|
||||
* `resources.Get`
|
||||
* `resources.FromString`: Create a Resource from a string.
|
||||
|
||||
New `Resource` transformation funcs:
|
||||
|
||||
* `resources.ToCSS`: Compile `SCSS` or `SASS` into `CSS`.
|
||||
* `resources.PostCSS`: Process your CSS with PostCSS. Config file support (project or theme or passed as an option).
|
||||
* `resources.Minify`: Currently supports `css`, `js`, `json`, `html`, `svg`, `xml`.
|
||||
* `resources.Fingerprint`: Creates a fingerprinted version of the given Resource with Subresource Integrity.
|
||||
* `resources.Concat`: Concatenates a list of Resource objects. Think of this as a poor man's bundler.
|
||||
* `resources.ExecuteAsTemplate`: Parses and executes the given Resource and data context (e.g. .Site) as a Go template.
|
||||
|
||||
|
||||
I, [@bep](https://github.com/bep), implemented this in [dea71670](https://github.com/gohugoio/hugo/commit/dea71670c059ab4d5a42bd22503f18c087dd22d4). We will work hard to get the documentation up to date, but follow the links above for details, and also see this [demo project](https://github.com/bep/hugo-sass-test).
|
||||
|
||||
|
||||
This release represents **35 contributions by 7 contributors** to the main Hugo code base.
|
||||
[@bep](https://github.com/bep) leads the Hugo development with a significant amount of contributions, but also a big shoutout to [@anthonyfok](https://github.com/anthonyfok), [@openscript](https://github.com/openscript), and [@caarlos0](https://github.com/caarlos0) for their ongoing contributions.
|
||||
And a big thanks to [@digitalcraftsman](https://github.com/digitalcraftsman) for his relentless work on keeping the themes site in pristine condition and to [@kaushalmodi](https://github.com/kaushalmodi) for his great work on the documentation site.
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
|
||||
---
|
||||
date: 2018-07-13
|
||||
title: "0.44"
|
||||
description: "0.44"
|
||||
categories: ["Releases"]
|
||||
---
|
||||
|
||||
|
||||
Hugo `0.44` is the follow-up release, or **The Sequel**, of the very well received `0.43` only days ago. That release added **Hugo Pipes**, with SCSS/SASS support, assets bundling and minification, ad-hoc image processing and much more.
|
||||
|
||||
This is mostly a bug-fix release, but it also includes several important improvements.
|
||||
|
||||
Many complained that their SVG images vanished when browsed from the `hugo server`. With **Hugo Pipes** MIME types suddenly got really important, but Hugo's use of `Suffix` was ambiguous. This became visible when we redefined the `image/svg+xml` to work with **Hugo Pipes**. We have now added a `Suffixes` field on the MIME type definition in Hugo, which is a list of one or more filename suffixes the MIME type is identified with. If you need to add a custom MIME type definition, this means that you also need to specify the full MIME type as the key, e.g. `image/svg+xml`.
|
||||
|
||||
Hugo now has:
|
||||
|
||||
* 27120+ [stars](https://github.com/gohugoio/hugo/stargazers)
|
||||
* 443+ [contributors](https://github.com/gohugoio/hugo/graphs/contributors)
|
||||
* 239+ [themes](http://themes.gohugo.io/)
|
||||
|
||||
## Notes
|
||||
* `MediaType.Suffix` is deprecated and replaced with a plural version, `MediaType.Suffixes`, with a more specific definition. You will get a detailed WARNING in the console if you need to do anything.
|
||||
|
||||
## Enhancements
|
||||
* Allow multiple file suffixes per media type [b874a1ba](https://github.com/gohugoio/hugo/commit/b874a1ba7ab8394dc741c8c70303a30a35b63e43) [@bep](https://github.com/bep) [#4920](https://github.com/gohugoio/hugo/issues/4920)
|
||||
* Clean up the in-memory Resource reader usage [47d38628](https://github.com/gohugoio/hugo/commit/47d38628ec0f4e72ff17661f13456b2a1511fe13) [@bep](https://github.com/bep) [#4936](https://github.com/gohugoio/hugo/issues/4936)
|
||||
* Move opening of the transformed resources after cache check [0024dcfe](https://github.com/gohugoio/hugo/commit/0024dcfe3e016c67046de06d1dac5e7f5235f9e1) [@bep](https://github.com/bep)
|
||||
* Improve type support in `resources.Concat` [306573de](https://github.com/gohugoio/hugo/commit/306573def0e20ec16ee5c447981cc09ed8bb7ec7) [@bep](https://github.com/bep) [#4934](https://github.com/gohugoio/hugo/issues/4934)
|
||||
* Flush `partialCached` cache on rebuilds [6b6dcb44](https://github.com/gohugoio/hugo/commit/6b6dcb44a014699c289bf32fe57d4c4216777be0) [@bep](https://github.com/bep) [#4931](https://github.com/gohugoio/hugo/issues/4931)
|
||||
* Include the transformation step in the error message [d96f2a46](https://github.com/gohugoio/hugo/commit/d96f2a460f58e91d8f6253a489d4879acfec6916) [@bep](https://github.com/bep) [#4924](https://github.com/gohugoio/hugo/issues/4924)
|
||||
* Exclude *.svg from CRLF/LF conversion [9c1e8208](https://github.com/gohugoio/hugo/commit/9c1e82085eb07d5b4dcdacbe82d5bafd26e08631) [@anthonyfok](https://github.com/anthonyfok)
|
||||
|
||||
## Fixes
|
||||
|
||||
* Fix `resources.Concat` for transformed resources [beec1fc9](https://github.com/gohugoio/hugo/commit/beec1fc98e5d37bba742d6bc2a0ff7c344b469f8) [@bep](https://github.com/bep) [#4936](https://github.com/gohugoio/hugo/issues/4936)
|
||||
* Fix static filesystem for themed multihost sites [80c8f3b8](https://github.com/gohugoio/hugo/commit/80c8f3b81a9849080e64bf877288ede28d960d3f) [@bep](https://github.com/bep) [#4929](https://github.com/gohugoio/hugo/issues/4929)
|
||||
* Set permission of embedded templates to 0644 [2b73e89d](https://github.com/gohugoio/hugo/commit/2b73e89d6d2822e86360a6c92c87f539677c119b) [@anthonyfok](https://github.com/anthonyfok)
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
project_name: hugo_extended
|
||||
builds:
|
||||
- binary: hugo
|
||||
ldflags: -s -w -X github.com/gohugoio/hugo/hugolib.BuildDate={{.Date}}
|
||||
ldflags:
|
||||
- -s -w -X github.com/gohugoio/hugo/hugolib.BuildDate={{.Date}}
|
||||
- "-extldflags '-static'"
|
||||
env:
|
||||
- CGO_ENABLED=1
|
||||
- CC=x86_64-w64-mingw32-gcc
|
||||
- CXX=x86_64-w64-mingw32-g++
|
||||
- CGO_LDFLAGS="-static"
|
||||
flags:
|
||||
- -tags
|
||||
- extended
|
||||
|
||||
+1
-1
@@ -123,7 +123,7 @@ func (v HugoVersion) NextPatchLevel(level int) HugoVersion {
|
||||
// CurrentHugoVersion represents the current build version.
|
||||
// This should be the only one.
|
||||
var CurrentHugoVersion = HugoVersion{
|
||||
Number: 0.43,
|
||||
Number: 0.44,
|
||||
PatchLevel: 0,
|
||||
Suffix: "",
|
||||
}
|
||||
|
||||
@@ -219,8 +219,11 @@ map[string]interface {}{
|
||||
"mediatype": Type{
|
||||
MainType: "text",
|
||||
SubType: "m1",
|
||||
Suffix: "m1main",
|
||||
OldSuffix: "m1main",
|
||||
Delimiter: ".",
|
||||
Suffixes: []string{
|
||||
"m1main",
|
||||
},
|
||||
},
|
||||
},
|
||||
"o2": map[string]interface {}{
|
||||
@@ -228,8 +231,11 @@ map[string]interface {}{
|
||||
"mediatype": Type{
|
||||
MainType: "text",
|
||||
SubType: "m2",
|
||||
Suffix: "m2theme",
|
||||
OldSuffix: "m2theme",
|
||||
Delimiter: ".",
|
||||
Suffixes: []string{
|
||||
"m2theme",
|
||||
},
|
||||
},
|
||||
},
|
||||
}`, got["outputformats"])
|
||||
|
||||
@@ -499,7 +499,6 @@ func (b *sourceFilesystemsBuilder) createRootMappingFs(dirKey, themeFolder strin
|
||||
s.Fs = afero.NewReadOnlyFs(fs)
|
||||
|
||||
return s, nil
|
||||
|
||||
}
|
||||
|
||||
func (b *sourceFilesystemsBuilder) existsInSource(abspath string) bool {
|
||||
@@ -536,6 +535,14 @@ func (b *sourceFilesystemsBuilder) createStaticFs() error {
|
||||
return err
|
||||
}
|
||||
|
||||
if b.hasTheme {
|
||||
themeFolder := "static"
|
||||
fs = afero.NewCopyOnWriteFs(newRealBase(afero.NewBasePathFs(b.themeFs, themeFolder)), fs)
|
||||
for _, absThemeDir := range b.absThemeDirs {
|
||||
s.Dirnames = append(s.Dirnames, filepath.Join(absThemeDir, themeFolder))
|
||||
}
|
||||
}
|
||||
|
||||
s.Fs = fs
|
||||
ms[l.Lang] = s
|
||||
|
||||
|
||||
@@ -20,6 +20,8 @@ import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/gohugoio/hugo/langs"
|
||||
|
||||
"github.com/spf13/afero"
|
||||
|
||||
"github.com/gohugoio/hugo/hugofs"
|
||||
@@ -167,9 +169,6 @@ func TestRealDirs(t *testing.T) {
|
||||
}()
|
||||
|
||||
v.Set("workingDir", root)
|
||||
v.Set("contentDir", "content")
|
||||
v.Set("resourceDir", "resources")
|
||||
v.Set("publishDir", "public")
|
||||
v.Set("themesDir", themesDir)
|
||||
v.Set("theme", "mytheme")
|
||||
|
||||
@@ -211,12 +210,94 @@ func TestRealDirs(t *testing.T) {
|
||||
|
||||
}
|
||||
|
||||
func TestStaticFs(t *testing.T) {
|
||||
assert := require.New(t)
|
||||
v := createConfig()
|
||||
workDir := "mywork"
|
||||
v.Set("workingDir", workDir)
|
||||
v.Set("themesDir", "themes")
|
||||
v.Set("theme", "t1")
|
||||
|
||||
fs := hugofs.NewMem(v)
|
||||
|
||||
themeStaticDir := filepath.Join(workDir, "themes", "t1", "static")
|
||||
|
||||
afero.WriteFile(fs.Source, filepath.Join(workDir, "mystatic", "f1.txt"), []byte("Hugo Rocks!"), 0755)
|
||||
afero.WriteFile(fs.Source, filepath.Join(themeStaticDir, "f1.txt"), []byte("Hugo Themes Rocks!"), 0755)
|
||||
afero.WriteFile(fs.Source, filepath.Join(themeStaticDir, "f2.txt"), []byte("Hugo Themes Still Rocks!"), 0755)
|
||||
|
||||
p, err := paths.New(fs, v)
|
||||
assert.NoError(err)
|
||||
bfs, err := NewBase(p)
|
||||
sfs := bfs.StaticFs("en")
|
||||
checkFileContent(sfs, "f1.txt", assert, "Hugo Rocks!")
|
||||
checkFileContent(sfs, "f2.txt", assert, "Hugo Themes Still Rocks!")
|
||||
|
||||
}
|
||||
|
||||
func TestStaticFsMultiHost(t *testing.T) {
|
||||
assert := require.New(t)
|
||||
v := createConfig()
|
||||
workDir := "mywork"
|
||||
v.Set("workingDir", workDir)
|
||||
v.Set("themesDir", "themes")
|
||||
v.Set("theme", "t1")
|
||||
v.Set("multihost", true)
|
||||
|
||||
vn := viper.New()
|
||||
vn.Set("staticDir", "nn_static")
|
||||
|
||||
en := langs.NewLanguage("en", v)
|
||||
no := langs.NewLanguage("no", v)
|
||||
no.Set("staticDir", "static_no")
|
||||
|
||||
languages := langs.Languages{
|
||||
en,
|
||||
no,
|
||||
}
|
||||
|
||||
v.Set("languagesSorted", languages)
|
||||
|
||||
fs := hugofs.NewMem(v)
|
||||
|
||||
themeStaticDir := filepath.Join(workDir, "themes", "t1", "static")
|
||||
|
||||
afero.WriteFile(fs.Source, filepath.Join(workDir, "mystatic", "f1.txt"), []byte("Hugo Rocks!"), 0755)
|
||||
afero.WriteFile(fs.Source, filepath.Join(workDir, "static_no", "f1.txt"), []byte("Hugo Rocks in Norway!"), 0755)
|
||||
|
||||
afero.WriteFile(fs.Source, filepath.Join(themeStaticDir, "f1.txt"), []byte("Hugo Themes Rocks!"), 0755)
|
||||
afero.WriteFile(fs.Source, filepath.Join(themeStaticDir, "f2.txt"), []byte("Hugo Themes Still Rocks!"), 0755)
|
||||
|
||||
p, err := paths.New(fs, v)
|
||||
assert.NoError(err)
|
||||
bfs, err := NewBase(p)
|
||||
enFs := bfs.StaticFs("en")
|
||||
checkFileContent(enFs, "f1.txt", assert, "Hugo Rocks!")
|
||||
checkFileContent(enFs, "f2.txt", assert, "Hugo Themes Still Rocks!")
|
||||
|
||||
noFs := bfs.StaticFs("no")
|
||||
checkFileContent(noFs, "f1.txt", assert, "Hugo Rocks in Norway!")
|
||||
checkFileContent(noFs, "f2.txt", assert, "Hugo Themes Still Rocks!")
|
||||
}
|
||||
|
||||
func checkFileCount(fs afero.Fs, dirname string, assert *require.Assertions, expected int) {
|
||||
count, _, err := countFileaAndGetDirs(fs, dirname)
|
||||
assert.NoError(err)
|
||||
assert.Equal(expected, count)
|
||||
}
|
||||
|
||||
func checkFileContent(fs afero.Fs, filename string, assert *require.Assertions, expected ...string) {
|
||||
|
||||
b, err := afero.ReadFile(fs, filename)
|
||||
assert.NoError(err)
|
||||
|
||||
content := string(b)
|
||||
|
||||
for _, e := range expected {
|
||||
assert.Contains(content, e)
|
||||
}
|
||||
}
|
||||
|
||||
func countFileaAndGetDirs(fs afero.Fs, dirname string) (int, []string, error) {
|
||||
if fs == nil {
|
||||
return 0, nil, errors.New("no fs")
|
||||
|
||||
@@ -28,6 +28,7 @@ import (
|
||||
// Build builds all sites. If filesystem events are provided,
|
||||
// this is considered to be a potential partial rebuild.
|
||||
func (h *HugoSites) Build(config BuildCfg, events ...fsnotify.Event) error {
|
||||
|
||||
if h.Metrics != nil {
|
||||
h.Metrics.Reset()
|
||||
}
|
||||
@@ -42,6 +43,10 @@ func (h *HugoSites) Build(config BuildCfg, events ...fsnotify.Event) error {
|
||||
conf.whatChanged = &whatChanged{source: true, other: true}
|
||||
}
|
||||
|
||||
for _, s := range h.Sites {
|
||||
s.Deps.BuildStartListeners.Notify()
|
||||
}
|
||||
|
||||
if len(events) > 0 {
|
||||
// Rebuild
|
||||
if err := h.initRebuild(conf); err != nil {
|
||||
|
||||
@@ -218,7 +218,7 @@ func newOutputFormat(p *Page, f output.Format) *OutputFormat {
|
||||
func (p *PageOutput) AlternativeOutputFormats() (OutputFormats, error) {
|
||||
var o OutputFormats
|
||||
for _, of := range p.OutputFormats() {
|
||||
if of.f.NotAlternative || of.f == p.outputFormat {
|
||||
if of.f.NotAlternative || of.f.Name == p.outputFormat.Name {
|
||||
continue
|
||||
}
|
||||
o = append(o, of)
|
||||
|
||||
@@ -239,7 +239,7 @@ func createTargetPath(d targetPathDescriptor) string {
|
||||
}
|
||||
|
||||
if isUgly {
|
||||
pagePath += d.Type.MediaType.Delimiter + d.Type.MediaType.Suffix
|
||||
pagePath += d.Type.MediaType.FullSuffix()
|
||||
} else {
|
||||
pagePath = filepath.Join(pagePath, d.Type.BaseName+d.Type.MediaType.FullSuffix())
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ func TestPageTargetPath(t *testing.T) {
|
||||
pathSpec := newTestDefaultPathSpec(t)
|
||||
|
||||
noExtNoDelimMediaType := media.TextType
|
||||
noExtNoDelimMediaType.Suffix = ""
|
||||
noExtNoDelimMediaType.Suffixes = []string{}
|
||||
noExtNoDelimMediaType.Delimiter = ""
|
||||
|
||||
// Netlify style _redirects
|
||||
@@ -169,8 +169,8 @@ func TestPageTargetPath(t *testing.T) {
|
||||
} else if test.d.Kind == KindHome && test.d.Type.Path != "" {
|
||||
} else if (!strings.HasPrefix(expected, "/index") || test.d.Addends != "") && test.d.URL == "" && isUgly {
|
||||
expected = strings.Replace(expected,
|
||||
"/"+test.d.Type.BaseName+"."+test.d.Type.MediaType.Suffix,
|
||||
"."+test.d.Type.MediaType.Suffix, -1)
|
||||
"/"+test.d.Type.BaseName+"."+test.d.Type.MediaType.Suffix(),
|
||||
"."+test.d.Type.MediaType.Suffix(), -1)
|
||||
}
|
||||
|
||||
if test.d.LangPrefix != "" && !(test.d.Kind == KindPage && test.d.URL != "") {
|
||||
|
||||
@@ -239,7 +239,7 @@ func TestPaginationURLFactory(t *testing.T) {
|
||||
}
|
||||
|
||||
if uglyURLs {
|
||||
expected = expected[:len(expected)-1] + "." + test.d.Type.MediaType.Suffix
|
||||
expected = expected[:len(expected)-1] + "." + test.d.Type.MediaType.Suffix()
|
||||
}
|
||||
|
||||
pathSpec := newTestPathSpec(fs, cfg)
|
||||
|
||||
@@ -36,12 +36,15 @@ func TestResourceChain(t *testing.T) {
|
||||
{{ $sass := resources.Get "sass/styles3.sass" | toCSS }}
|
||||
{{ $scssCustomTarget := resources.Get "scss/styles2.scss" | toCSS (dict "targetPath" "styles/main.css") }}
|
||||
{{ $scssCustomTargetString := resources.Get "scss/styles2.scss" | toCSS "styles/main.css" }}
|
||||
{{ $scssMin := resources.Get "scss/styles2.scss" | toCSS | minify }}
|
||||
{{ $scssMin := resources.Get "scss/styles2.scss" | toCSS | minify }}
|
||||
{{ $scssFromTempl := ".{{ .Kind }} { color: blue; }" | resources.FromString "kindofblue.templ" | resources.ExecuteAsTemplate "kindofblue.scss" . | toCSS (dict "targetPath" "styles/templ.css") | minify }}
|
||||
{{ $bundle1 := slice $scssFromTempl $scssMin | resources.Concat "styles/bundle1.css" }}
|
||||
T1: Len Content: {{ len $scss.Content }}|RelPermalink: {{ $scss.RelPermalink }}|Permalink: {{ $scss.Permalink }}|MediaType: {{ $scss.MediaType.Type }}
|
||||
T2: Content: {{ $scssMin.Content }}|RelPermalink: {{ $scssMin.RelPermalink }}
|
||||
T3: Content: {{ len $scssCustomTarget.Content }}|RelPermalink: {{ $scssCustomTarget.RelPermalink }}|MediaType: {{ $scssCustomTarget.MediaType.Type }}
|
||||
T4: Content: {{ len $scssCustomTargetString.Content }}|RelPermalink: {{ $scssCustomTargetString.RelPermalink }}|MediaType: {{ $scssCustomTargetString.MediaType.Type }}
|
||||
T5: Content: {{ $sass.Content }}|T5 RelPermalink: {{ $sass.RelPermalink }}|
|
||||
T6: {{ $bundle1.Permalink }}
|
||||
`)
|
||||
}, func(b *sitesBuilder) {
|
||||
b.AssertFileContent("public/index.html", `T1: Len Content: 24|RelPermalink: /scss/styles2.css|Permalink: http://example.com/scss/styles2.css|MediaType: text/css`)
|
||||
@@ -50,6 +53,10 @@ T5: Content: {{ $sass.Content }}|T5 RelPermalink: {{ $sass.RelPermalink }}|
|
||||
b.AssertFileContent("public/index.html", `T4: Content: 24|RelPermalink: /styles/main.css|MediaType: text/css`)
|
||||
b.AssertFileContent("public/index.html", `T5: Content: .content-navigation {`)
|
||||
b.AssertFileContent("public/index.html", `T5 RelPermalink: /sass/styles3.css|`)
|
||||
b.AssertFileContent("public/index.html", `T6: http://example.com/styles/bundle1.css`)
|
||||
|
||||
b.AssertFileContent("public/styles/templ.min.css", `.home{color:blue}`)
|
||||
b.AssertFileContent("public/styles/bundle1.css", `.home{color:blue}body{color:#333}`)
|
||||
|
||||
}},
|
||||
|
||||
@@ -80,14 +87,21 @@ Min HTML: {{ ( resources.Get "mydata/html1.html" | resources.Minify ).Content |
|
||||
{{ $a := "A" | resources.FromString "a.txt"}}
|
||||
{{ $b := "B" | resources.FromString "b.txt"}}
|
||||
{{ $c := "C" | resources.FromString "c.txt"}}
|
||||
{{ $textResources := .Resources.Match "*.txt" }}
|
||||
{{ $combined := slice $a $b $c | resources.Concat "bundle/concat.txt" }}
|
||||
T: Content: {{ $combined.Content }}|RelPermalink: {{ $combined.RelPermalink }}|Permalink: {{ $combined.Permalink }}|MediaType: {{ $combined.MediaType.Type }}
|
||||
T1: Content: {{ $combined.Content }}|RelPermalink: {{ $combined.RelPermalink }}|Permalink: {{ $combined.Permalink }}|MediaType: {{ $combined.MediaType.Type }}
|
||||
{{ with $textResources }}
|
||||
{{ $combinedText := . | resources.Concat "bundle/concattxt.txt" }}
|
||||
T2: Content: {{ $combinedText.Content }}|{{ $combinedText.RelPermalink }}
|
||||
{{ end }}
|
||||
`)
|
||||
}, func(b *sitesBuilder) {
|
||||
b.AssertFileContent("public/index.html", `T: Content: ABC|RelPermalink: /bundle/concat.txt|Permalink: http://example.com/bundle/concat.txt|MediaType: text/plain`)
|
||||
b.AssertFileContent("public/index.html", `T1: Content: ABC|RelPermalink: /bundle/concat.txt|Permalink: http://example.com/bundle/concat.txt|MediaType: text/plain`)
|
||||
b.AssertFileContent("public/bundle/concat.txt", "ABC")
|
||||
}},
|
||||
|
||||
b.AssertFileContent("public/index.html", `T2: Content: t1t|t2t|`)
|
||||
b.AssertFileContent("public/bundle/concattxt.txt", "t1t|t2t|")
|
||||
}},
|
||||
{"fromstring", func() bool { return true }, func(b *sitesBuilder) {
|
||||
b.WithTemplates("home.html", `
|
||||
{{ $r := "Hugo Rocks!" | resources.FromString "rocks/hugo.txt" }}
|
||||
@@ -137,12 +151,31 @@ T3: {{ $resultMD5.Content }}|{{ $resultMD5.RelPermalink}}|{{$resultMD5.MediaType
|
||||
|
||||
b := newTestSitesBuilder(t).WithLogger(loggers.NewWarningLogger())
|
||||
b.WithSimpleConfigFile()
|
||||
b.WithContent("page.md", `
|
||||
b.WithContent("_index.md", `
|
||||
---
|
||||
title: Hello
|
||||
title: Home
|
||||
---
|
||||
|
||||
`)
|
||||
Home.
|
||||
|
||||
`,
|
||||
"page1.md", `
|
||||
---
|
||||
title: Hello1
|
||||
---
|
||||
|
||||
Hello1
|
||||
`,
|
||||
"page2.md", `
|
||||
---
|
||||
title: Hello2
|
||||
---
|
||||
|
||||
Hello2
|
||||
`,
|
||||
"t1.txt", "t1t|",
|
||||
"t2.txt", "t2t|",
|
||||
)
|
||||
|
||||
b.WithSourceFile(filepath.Join("assets", "css", "styles1.css"), `
|
||||
h1 {
|
||||
|
||||
@@ -173,11 +173,11 @@ type scKey struct {
|
||||
}
|
||||
|
||||
func newScKey(m media.Type, shortcodeplaceholder string) scKey {
|
||||
return scKey{Suffix: m.Suffix, ShortcodePlaceholder: shortcodeplaceholder}
|
||||
return scKey{Suffix: m.Suffix(), ShortcodePlaceholder: shortcodeplaceholder}
|
||||
}
|
||||
|
||||
func newScKeyFromLangAndOutputFormat(lang string, o output.Format, shortcodeplaceholder string) scKey {
|
||||
return scKey{Lang: lang, Suffix: o.MediaType.Suffix, OutputFormat: o.Name, ShortcodePlaceholder: shortcodeplaceholder}
|
||||
return scKey{Lang: lang, Suffix: o.MediaType.Suffix(), OutputFormat: o.Name, ShortcodePlaceholder: shortcodeplaceholder}
|
||||
}
|
||||
|
||||
func newDefaultScKey(shortcodeplaceholder string) scKey {
|
||||
|
||||
+3
-2
@@ -586,8 +586,9 @@ type whatChanged struct {
|
||||
// package, so it will behave correctly with Hugo's built-in server.
|
||||
func (s *Site) RegisterMediaTypes() {
|
||||
for _, mt := range s.mediaTypesConfig {
|
||||
// The last one will win if there are any duplicates.
|
||||
_ = mime.AddExtensionType("."+mt.Suffix, mt.Type()+"; charset=utf-8")
|
||||
for _, suffix := range mt.Suffixes {
|
||||
_ = mime.AddExtensionType(mt.Delimiter+suffix, mt.Type()+"; charset=utf-8")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -179,7 +179,7 @@ Len Pages: {{ .Kind }} {{ len .Site.RegularPages }} Page Number: {{ .Paginator.P
|
||||
th.assertFileContent("public/index.html",
|
||||
// The HTML entity is a deliberate part of this test: The HTML templates are
|
||||
// parsed with html/template.
|
||||
`List HTML|JSON Home|<atom:link href=http://example.com/blog/ rel="self" type="text/html+html" />`,
|
||||
`List HTML|JSON Home|<atom:link href=http://example.com/blog/ rel="self" type="text/html" />`,
|
||||
"en: Elbow",
|
||||
"ShortHTML",
|
||||
"OtherShort: <h1>Hi!</h1>",
|
||||
@@ -195,7 +195,7 @@ Len Pages: {{ .Kind }} {{ len .Site.RegularPages }} Page Number: {{ .Paginator.P
|
||||
th.assertFileContent("public/index.json",
|
||||
"Output/Rel: JSON/canonical|",
|
||||
// JSON is plain text, so no need to safeHTML this and that
|
||||
`<atom:link href=http://example.com/blog/index.json rel="self" type="application/json+json" />`,
|
||||
`<atom:link href=http://example.com/blog/index.json rel="self" type="application/json" />`,
|
||||
"ShortJSON",
|
||||
"OtherShort: <h1>Hi!</h1>",
|
||||
)
|
||||
|
||||
@@ -69,7 +69,7 @@ func headlessPagesPublisher(s *Site, wg *sync.WaitGroup) {
|
||||
defer wg.Done()
|
||||
for _, page := range s.headlessPages {
|
||||
outFormat := page.outputFormats[0] // There is only one
|
||||
if outFormat != s.rc.Format {
|
||||
if outFormat.Name != s.rc.Format.Name {
|
||||
// Avoid double work.
|
||||
continue
|
||||
}
|
||||
@@ -92,7 +92,7 @@ func pageRenderer(s *Site, pages <-chan *Page, results chan<- error, wg *sync.Wa
|
||||
|
||||
for i, outFormat := range page.outputFormats {
|
||||
|
||||
if outFormat != page.s.rc.Format {
|
||||
if outFormat.Name != page.s.rc.Format.Name {
|
||||
// Will be rendered ... later.
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ package hugolib
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -359,6 +360,7 @@ func doTestShouldAlwaysHaveUglyURLs(t *testing.T, uglyURLs bool) {
|
||||
|
||||
func TestNewSiteDefaultLang(t *testing.T) {
|
||||
t.Parallel()
|
||||
defer os.Remove("resources")
|
||||
s, err := NewSiteDefaultLang()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, hugofs.Os, s.Fs.Source)
|
||||
|
||||
+192
-61
@@ -19,6 +19,7 @@ import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/gohugoio/hugo/helpers"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
)
|
||||
|
||||
@@ -29,19 +30,39 @@ const (
|
||||
// Type (also known as MIME type and content type) is a two-part identifier for
|
||||
// file formats and format contents transmitted on the Internet.
|
||||
// For Hugo's use case, we use the top-level type name / subtype name + suffix.
|
||||
// One example would be image/jpeg+jpg
|
||||
// One example would be application/svg+xml
|
||||
// If suffix is not provided, the sub type will be used.
|
||||
// See // https://en.wikipedia.org/wiki/Media_type
|
||||
type Type struct {
|
||||
MainType string `json:"mainType"` // i.e. text
|
||||
SubType string `json:"subType"` // i.e. html
|
||||
Suffix string `json:"suffix"` // i.e html
|
||||
Delimiter string `json:"delimiter"` // defaults to "."
|
||||
MainType string `json:"mainType"` // i.e. text
|
||||
SubType string `json:"subType"` // i.e. html
|
||||
|
||||
// Deprecated in Hugo 0.44. To be renamed and unexported.
|
||||
// Was earlier used both to set file suffix and to augment the MIME type.
|
||||
// This had its limitations and issues.
|
||||
OldSuffix string `json:"-" mapstructure:"suffix"`
|
||||
|
||||
Delimiter string `json:"delimiter"` // e.g. "."
|
||||
|
||||
Suffixes []string `json:"suffixes"`
|
||||
|
||||
// Set when doing lookup by suffix.
|
||||
fileSuffix string
|
||||
}
|
||||
|
||||
// FromString creates a new Type given a type sring on the form MainType/SubType and
|
||||
// FromStringAndExt is same as FromString, but adds the file extension to the type.
|
||||
func FromStringAndExt(t, ext string) (Type, error) {
|
||||
tp, err := fromString(t)
|
||||
if err != nil {
|
||||
return tp, err
|
||||
}
|
||||
tp.Suffixes = []string{strings.TrimPrefix(ext, ".")}
|
||||
return tp, nil
|
||||
}
|
||||
|
||||
// FromString creates a new Type given a type string on the form MainType/SubType and
|
||||
// an optional suffix, e.g. "text/html" or "text/html+html".
|
||||
func FromString(t string) (Type, error) {
|
||||
func fromString(t string) (Type, error) {
|
||||
t = strings.ToLower(t)
|
||||
parts := strings.Split(t, "/")
|
||||
if len(parts) != 2 {
|
||||
@@ -54,54 +75,67 @@ func FromString(t string) (Type, error) {
|
||||
|
||||
var suffix string
|
||||
|
||||
if len(subParts) == 1 {
|
||||
suffix = subType
|
||||
} else {
|
||||
if len(subParts) > 1 {
|
||||
suffix = subParts[1]
|
||||
}
|
||||
|
||||
return Type{MainType: mainType, SubType: subType, Suffix: suffix, Delimiter: defaultDelimiter}, nil
|
||||
return Type{MainType: mainType, SubType: subType, OldSuffix: suffix}, nil
|
||||
}
|
||||
|
||||
// Type returns a string representing the main- and sub-type of a media type, i.e. "text/css".
|
||||
// Type returns a string representing the main- and sub-type of a media type, e.g. "text/css".
|
||||
// A suffix identifier will be appended after a "+" if set, e.g. "image/svg+xml".
|
||||
// Hugo will register a set of default media types.
|
||||
// These can be overridden by the user in the configuration,
|
||||
// by defining a media type with the same Type.
|
||||
func (m Type) Type() string {
|
||||
// Examples are
|
||||
// image/svg+xml
|
||||
// text/css
|
||||
if m.OldSuffix != "" {
|
||||
return fmt.Sprintf("%s/%s+%s", m.MainType, m.SubType, m.OldSuffix)
|
||||
}
|
||||
return fmt.Sprintf("%s/%s", m.MainType, m.SubType)
|
||||
|
||||
}
|
||||
|
||||
func (m Type) String() string {
|
||||
if m.Suffix != "" {
|
||||
return fmt.Sprintf("%s/%s+%s", m.MainType, m.SubType, m.Suffix)
|
||||
}
|
||||
return fmt.Sprintf("%s/%s", m.MainType, m.SubType)
|
||||
return m.Type()
|
||||
}
|
||||
|
||||
// FullSuffix returns the file suffix with any delimiter prepended.
|
||||
func (m Type) FullSuffix() string {
|
||||
return m.Delimiter + m.Suffix
|
||||
return m.Delimiter + m.Suffix()
|
||||
}
|
||||
|
||||
// Suffix returns the file suffix without any delmiter prepended.
|
||||
func (m Type) Suffix() string {
|
||||
if m.fileSuffix != "" {
|
||||
return m.fileSuffix
|
||||
}
|
||||
if len(m.Suffixes) > 0 {
|
||||
return m.Suffixes[0]
|
||||
}
|
||||
// There are MIME types without file suffixes.
|
||||
return ""
|
||||
}
|
||||
|
||||
var (
|
||||
CalendarType = Type{"text", "calendar", "ics", defaultDelimiter}
|
||||
CSSType = Type{"text", "css", "css", defaultDelimiter}
|
||||
SCSSType = Type{"text", "x-scss", "scss", defaultDelimiter}
|
||||
SASSType = Type{"text", "x-sass", "sass", defaultDelimiter}
|
||||
CSVType = Type{"text", "csv", "csv", defaultDelimiter}
|
||||
HTMLType = Type{"text", "html", "html", defaultDelimiter}
|
||||
JavascriptType = Type{"application", "javascript", "js", defaultDelimiter}
|
||||
JSONType = Type{"application", "json", "json", defaultDelimiter}
|
||||
RSSType = Type{"application", "rss", "xml", defaultDelimiter}
|
||||
XMLType = Type{"application", "xml", "xml", defaultDelimiter}
|
||||
// The official MIME type of SVG is image/svg+xml. We currently only support one extension
|
||||
// per mime type. The workaround in projects is to create multiple media type definitions,
|
||||
// but we need to improve this to take other known suffixes into account.
|
||||
// But until then, svg has an svg extension, which is very common. TODO(bep)
|
||||
SVGType = Type{"image", "svg", "svg", defaultDelimiter}
|
||||
TextType = Type{"text", "plain", "txt", defaultDelimiter}
|
||||
// Definitions from https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types etc.
|
||||
// Note that from Hugo 0.44 we only set Suffix if it is part of the MIME type.
|
||||
CalendarType = Type{MainType: "text", SubType: "calendar", Suffixes: []string{"ics"}, Delimiter: defaultDelimiter}
|
||||
CSSType = Type{MainType: "text", SubType: "css", Suffixes: []string{"css"}, Delimiter: defaultDelimiter}
|
||||
SCSSType = Type{MainType: "text", SubType: "x-scss", Suffixes: []string{"scss"}, Delimiter: defaultDelimiter}
|
||||
SASSType = Type{MainType: "text", SubType: "x-sass", Suffixes: []string{"sass"}, Delimiter: defaultDelimiter}
|
||||
CSVType = Type{MainType: "text", SubType: "csv", Suffixes: []string{"csv"}, Delimiter: defaultDelimiter}
|
||||
HTMLType = Type{MainType: "text", SubType: "html", Suffixes: []string{"html"}, Delimiter: defaultDelimiter}
|
||||
JavascriptType = Type{MainType: "application", SubType: "javascript", Suffixes: []string{"js"}, Delimiter: defaultDelimiter}
|
||||
JSONType = Type{MainType: "application", SubType: "json", Suffixes: []string{"json"}, Delimiter: defaultDelimiter}
|
||||
RSSType = Type{MainType: "application", SubType: "rss", OldSuffix: "xml", Suffixes: []string{"xml"}, Delimiter: defaultDelimiter}
|
||||
XMLType = Type{MainType: "application", SubType: "xml", Suffixes: []string{"xml"}, Delimiter: defaultDelimiter}
|
||||
SVGType = Type{MainType: "image", SubType: "svg", OldSuffix: "xml", Suffixes: []string{"svg"}, Delimiter: defaultDelimiter}
|
||||
TextType = Type{MainType: "text", SubType: "plain", Suffixes: []string{"txt"}, Delimiter: defaultDelimiter}
|
||||
|
||||
OctetType = Type{"application", "octet-stream", "", ""}
|
||||
OctetType = Type{MainType: "application", SubType: "octet-stream"}
|
||||
)
|
||||
|
||||
var DefaultTypes = Types{
|
||||
@@ -136,13 +170,23 @@ func (t Types) GetByType(tp string) (Type, bool) {
|
||||
return tt, true
|
||||
}
|
||||
}
|
||||
|
||||
if !strings.Contains(tp, "+") {
|
||||
// Try with the main and sub type
|
||||
parts := strings.Split(tp, "/")
|
||||
if len(parts) == 2 {
|
||||
return t.GetByMainSubType(parts[0], parts[1])
|
||||
}
|
||||
}
|
||||
|
||||
return Type{}, false
|
||||
}
|
||||
|
||||
// GetFirstBySuffix will return the first media type matching the given suffix.
|
||||
func (t Types) GetFirstBySuffix(suffix string) (Type, bool) {
|
||||
for _, tt := range t {
|
||||
if strings.EqualFold(suffix, tt.Suffix) {
|
||||
if match := tt.matchSuffix(suffix); match != "" {
|
||||
tt.fileSuffix = match
|
||||
return tt, true
|
||||
}
|
||||
}
|
||||
@@ -155,12 +199,46 @@ func (t Types) GetFirstBySuffix(suffix string) (Type, bool) {
|
||||
// The lookup is case insensitive.
|
||||
func (t Types) GetBySuffix(suffix string) (tp Type, found bool) {
|
||||
for _, tt := range t {
|
||||
if strings.EqualFold(suffix, tt.Suffix) {
|
||||
if match := tt.matchSuffix(suffix); match != "" {
|
||||
if found {
|
||||
// ambiguous
|
||||
found = false
|
||||
return
|
||||
}
|
||||
tp = tt
|
||||
tp.fileSuffix = match
|
||||
found = true
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (t Type) matchSuffix(suffix string) string {
|
||||
if strings.EqualFold(suffix, t.OldSuffix) {
|
||||
return t.OldSuffix
|
||||
}
|
||||
for _, s := range t.Suffixes {
|
||||
if strings.EqualFold(suffix, s) {
|
||||
return s
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
// GetMainSubType gets a media type given a main and a sub type e.g. "text" and "plain".
|
||||
// It will return false if no format could be found, or if the combination given
|
||||
// is ambiguous.
|
||||
// The lookup is case insensitive.
|
||||
func (t Types) GetByMainSubType(mainType, subType string) (tp Type, found bool) {
|
||||
for _, tt := range t {
|
||||
if strings.EqualFold(mainType, tt.MainType) && strings.EqualFold(subType, tt.SubType) {
|
||||
if found {
|
||||
// ambiguous
|
||||
found = false
|
||||
return
|
||||
}
|
||||
|
||||
tp = tt
|
||||
found = true
|
||||
}
|
||||
@@ -168,46 +246,99 @@ func (t Types) GetBySuffix(suffix string) (tp Type, found bool) {
|
||||
return
|
||||
}
|
||||
|
||||
func suffixIsDeprecated() {
|
||||
helpers.Deprecated("MediaType", "Suffix in config.toml", `
|
||||
Before Hugo 0.44 this was used both to set a custom file suffix and as way
|
||||
to augment the mediatype definition (what you see after the "+", e.g. "image/svg+xml").
|
||||
|
||||
This had its limitations. For one, it was only possible with one file extension per MIME type.
|
||||
|
||||
Now you can specify multiple file suffixes using "suffixes", but you need to specify the full MIME type
|
||||
identifier:
|
||||
|
||||
[mediaTypes]
|
||||
[mediaTypes."image/svg+xml"]
|
||||
suffixes = ["svg", "abc" ]
|
||||
|
||||
In most cases, it will be enough to just change:
|
||||
|
||||
[mediaTypes]
|
||||
[mediaTypes."my/custom-mediatype"]
|
||||
suffix = "txt"
|
||||
|
||||
To:
|
||||
|
||||
[mediaTypes]
|
||||
[mediaTypes."my/custom-mediatype"]
|
||||
suffixes = ["txt"]
|
||||
|
||||
Hugo will still respect values set in "suffix" if no value for "suffixes" is provided, but this will be removed
|
||||
in a future release.
|
||||
|
||||
Note that you can still get the Media Type's suffix from a template: {{ $mediaType.Suffix }}. But this will now map to the MIME type filename.
|
||||
`, false)
|
||||
}
|
||||
|
||||
// DecodeTypes takes a list of media type configurations and merges those,
|
||||
// in the order given, with the Hugo defaults as the last resort.
|
||||
func DecodeTypes(maps ...map[string]interface{}) (Types, error) {
|
||||
m := make(Types, len(DefaultTypes))
|
||||
copy(m, DefaultTypes)
|
||||
var m Types
|
||||
|
||||
// Maps type string to Type. Type string is the full application/svg+xml.
|
||||
mmm := make(map[string]Type)
|
||||
for _, dt := range DefaultTypes {
|
||||
suffixes := make([]string, len(dt.Suffixes))
|
||||
copy(suffixes, dt.Suffixes)
|
||||
dt.Suffixes = suffixes
|
||||
mmm[dt.Type()] = dt
|
||||
}
|
||||
|
||||
for _, mm := range maps {
|
||||
for k, v := range mm {
|
||||
// It may be tempting to put the full media type in the key, e.g.
|
||||
// "text/css+css", but that will break the logic below.
|
||||
if strings.Contains(k, "+") {
|
||||
return Types{}, fmt.Errorf("media type keys cannot contain any '+' chars. Valid example is %q", "text/css")
|
||||
}
|
||||
var mediaType Type
|
||||
|
||||
found := false
|
||||
for i, vv := range m {
|
||||
// Match by type, i.e. "text/css"
|
||||
if strings.EqualFold(k, vv.Type()) {
|
||||
// Merge it with the existing
|
||||
if err := mapstructure.WeakDecode(v, &m[i]); err != nil {
|
||||
return m, err
|
||||
}
|
||||
found = true
|
||||
}
|
||||
}
|
||||
mediaType, found := mmm[k]
|
||||
if !found {
|
||||
mediaType, err := FromString(k)
|
||||
var err error
|
||||
mediaType, err = fromString(k)
|
||||
if err != nil {
|
||||
return m, err
|
||||
}
|
||||
|
||||
if err := mapstructure.WeakDecode(v, &mediaType); err != nil {
|
||||
return m, err
|
||||
}
|
||||
|
||||
m = append(m, mediaType)
|
||||
}
|
||||
|
||||
if err := mapstructure.WeakDecode(v, &mediaType); err != nil {
|
||||
return m, err
|
||||
}
|
||||
|
||||
vm := v.(map[string]interface{})
|
||||
_, delimiterSet := vm["delimiter"]
|
||||
_, suffixSet := vm["suffix"]
|
||||
|
||||
if suffixSet {
|
||||
suffixIsDeprecated()
|
||||
}
|
||||
|
||||
// Before Hugo 0.44 we had a non-standard use of the Suffix
|
||||
// attribute, and this is now deprecated (use Suffixes for file suffixes).
|
||||
// But we need to keep old configurations working for a while.
|
||||
if len(mediaType.Suffixes) == 0 && mediaType.OldSuffix != "" {
|
||||
mediaType.Suffixes = []string{mediaType.OldSuffix}
|
||||
}
|
||||
// The user may set the delimiter as an empty string.
|
||||
if !delimiterSet && len(mediaType.Suffixes) != 0 {
|
||||
mediaType.Delimiter = defaultDelimiter
|
||||
} else if suffixSet && !delimiterSet {
|
||||
mediaType.Delimiter = defaultDelimiter
|
||||
}
|
||||
|
||||
mmm[k] = mediaType
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
for _, v := range mmm {
|
||||
m = append(m, v)
|
||||
}
|
||||
sort.Sort(m)
|
||||
|
||||
return m, nil
|
||||
|
||||
+87
-34
@@ -28,21 +28,21 @@ func TestDefaultTypes(t *testing.T) {
|
||||
expectedType string
|
||||
expectedString string
|
||||
}{
|
||||
{CalendarType, "text", "calendar", "ics", "text/calendar", "text/calendar+ics"},
|
||||
{CSSType, "text", "css", "css", "text/css", "text/css+css"},
|
||||
{SCSSType, "text", "x-scss", "scss", "text/x-scss", "text/x-scss+scss"},
|
||||
{CSVType, "text", "csv", "csv", "text/csv", "text/csv+csv"},
|
||||
{HTMLType, "text", "html", "html", "text/html", "text/html+html"},
|
||||
{JavascriptType, "application", "javascript", "js", "application/javascript", "application/javascript+js"},
|
||||
{JSONType, "application", "json", "json", "application/json", "application/json+json"},
|
||||
{RSSType, "application", "rss", "xml", "application/rss", "application/rss+xml"},
|
||||
{SVGType, "image", "svg", "svg", "image/svg", "image/svg+svg"},
|
||||
{TextType, "text", "plain", "txt", "text/plain", "text/plain+txt"},
|
||||
{XMLType, "application", "xml", "xml", "application/xml", "application/xml+xml"},
|
||||
{CalendarType, "text", "calendar", "ics", "text/calendar", "text/calendar"},
|
||||
{CSSType, "text", "css", "css", "text/css", "text/css"},
|
||||
{SCSSType, "text", "x-scss", "scss", "text/x-scss", "text/x-scss"},
|
||||
{CSVType, "text", "csv", "csv", "text/csv", "text/csv"},
|
||||
{HTMLType, "text", "html", "html", "text/html", "text/html"},
|
||||
{JavascriptType, "application", "javascript", "js", "application/javascript", "application/javascript"},
|
||||
{JSONType, "application", "json", "json", "application/json", "application/json"},
|
||||
{RSSType, "application", "rss", "xml", "application/rss+xml", "application/rss+xml"},
|
||||
{SVGType, "image", "svg", "svg", "image/svg+xml", "image/svg+xml"},
|
||||
{TextType, "text", "plain", "txt", "text/plain", "text/plain"},
|
||||
{XMLType, "application", "xml", "xml", "application/xml", "application/xml"},
|
||||
} {
|
||||
require.Equal(t, test.expectedMainType, test.tp.MainType)
|
||||
require.Equal(t, test.expectedSubType, test.tp.SubType)
|
||||
require.Equal(t, test.expectedSuffix, test.tp.Suffix)
|
||||
require.Equal(t, test.expectedSuffix, test.tp.Suffix(), test.tp.String())
|
||||
require.Equal(t, defaultDelimiter, test.tp.Delimiter)
|
||||
|
||||
require.Equal(t, test.expectedType, test.tp.Type())
|
||||
@@ -61,34 +61,68 @@ func TestGetByType(t *testing.T) {
|
||||
|
||||
_, found = types.GetByType("text/nono")
|
||||
require.False(t, found)
|
||||
|
||||
mt, found = types.GetByType("application/rss+xml")
|
||||
require.True(t, found)
|
||||
require.Equal(t, mt, RSSType)
|
||||
|
||||
mt, found = types.GetByType("application/rss")
|
||||
require.True(t, found)
|
||||
require.Equal(t, mt, RSSType)
|
||||
}
|
||||
|
||||
func TestGetByMainSubType(t *testing.T) {
|
||||
assert := require.New(t)
|
||||
f, found := DefaultTypes.GetByMainSubType("text", "plain")
|
||||
assert.True(found)
|
||||
assert.Equal(f, TextType)
|
||||
_, found = DefaultTypes.GetByMainSubType("foo", "plain")
|
||||
assert.False(found)
|
||||
}
|
||||
|
||||
func TestGetFirstBySuffix(t *testing.T) {
|
||||
assert := require.New(t)
|
||||
f, found := DefaultTypes.GetFirstBySuffix("xml")
|
||||
assert.True(found)
|
||||
assert.Equal(Type{MainType: "application", SubType: "rss", Suffix: "xml", Delimiter: "."}, f)
|
||||
assert.Equal(Type{MainType: "application", SubType: "rss", OldSuffix: "xml", Delimiter: ".", Suffixes: []string{"xml"}, fileSuffix: "xml"}, f)
|
||||
}
|
||||
|
||||
func TestFromTypeString(t *testing.T) {
|
||||
f, err := FromString("text/html")
|
||||
f, err := fromString("text/html")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, HTMLType, f)
|
||||
require.Equal(t, HTMLType.Type(), f.Type())
|
||||
|
||||
f, err = FromString("application/custom")
|
||||
f, err = fromString("application/custom")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, Type{MainType: "application", SubType: "custom", Suffix: "custom", Delimiter: defaultDelimiter}, f)
|
||||
require.Equal(t, Type{MainType: "application", SubType: "custom", OldSuffix: "", fileSuffix: ""}, f)
|
||||
|
||||
f, err = FromString("application/custom+pdf")
|
||||
f, err = fromString("application/custom+sfx")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, Type{MainType: "application", SubType: "custom", Suffix: "pdf", Delimiter: defaultDelimiter}, f)
|
||||
require.Equal(t, Type{MainType: "application", SubType: "custom", OldSuffix: "sfx"}, f)
|
||||
|
||||
_, err = FromString("noslash")
|
||||
_, err = fromString("noslash")
|
||||
require.Error(t, err)
|
||||
|
||||
f, err = FromString("text/xml; charset=utf-8")
|
||||
f, err = fromString("text/xml; charset=utf-8")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, Type{MainType: "text", SubType: "xml", Suffix: "xml", Delimiter: "."}, f)
|
||||
require.Equal(t, Type{MainType: "text", SubType: "xml", OldSuffix: ""}, f)
|
||||
require.Equal(t, "", f.Suffix())
|
||||
}
|
||||
|
||||
// Add a test for the SVG case
|
||||
// https://github.com/gohugoio/hugo/issues/4920
|
||||
func TestFromExtensionMultipleSuffixes(t *testing.T) {
|
||||
assert := require.New(t)
|
||||
tp, found := DefaultTypes.GetBySuffix("svg")
|
||||
assert.True(found)
|
||||
assert.Equal("image/svg+xml", tp.String())
|
||||
assert.Equal("svg", tp.fileSuffix)
|
||||
assert.Equal(".svg", tp.FullSuffix())
|
||||
tp, found = DefaultTypes.GetByType("image/svg+xml")
|
||||
assert.True(found)
|
||||
assert.Equal("image/svg+xml", tp.String())
|
||||
assert.True(found)
|
||||
assert.Equal(".svg", tp.FullSuffix())
|
||||
|
||||
}
|
||||
|
||||
@@ -105,13 +139,40 @@ func TestDecodeTypes(t *testing.T) {
|
||||
[]map[string]interface{}{
|
||||
{
|
||||
"application/json": map[string]interface{}{
|
||||
"suffix": "jsn"}}},
|
||||
"suffixes": []string{"jasn"}}}},
|
||||
false,
|
||||
func(t *testing.T, name string, tt Types) {
|
||||
require.Len(t, tt, len(DefaultTypes))
|
||||
json, found := tt.GetBySuffix("jsn")
|
||||
json, found := tt.GetBySuffix("jasn")
|
||||
require.True(t, found)
|
||||
require.Equal(t, "application/json+jsn", json.String(), name)
|
||||
require.Equal(t, "application/json", json.String(), name)
|
||||
}},
|
||||
{
|
||||
"Suffix from key, multiple file suffixes",
|
||||
[]map[string]interface{}{
|
||||
{
|
||||
"application/hugo+hg": map[string]interface{}{
|
||||
"Suffixes": []string{"hg1", "hg2"},
|
||||
}}},
|
||||
false,
|
||||
func(t *testing.T, name string, tt Types) {
|
||||
require.Len(t, tt, len(DefaultTypes)+1)
|
||||
hg, found := tt.GetBySuffix("hg")
|
||||
require.True(t, found)
|
||||
require.Equal(t, "hg", hg.OldSuffix)
|
||||
require.Equal(t, "hg", hg.Suffix())
|
||||
require.Equal(t, ".hg", hg.FullSuffix())
|
||||
require.Equal(t, "application/hugo+hg", hg.String(), name)
|
||||
hg, found = tt.GetBySuffix("hg2")
|
||||
require.True(t, found)
|
||||
require.Equal(t, "hg", hg.OldSuffix)
|
||||
require.Equal(t, "hg2", hg.Suffix())
|
||||
require.Equal(t, ".hg2", hg.FullSuffix())
|
||||
require.Equal(t, "application/hugo+hg", hg.String(), name)
|
||||
|
||||
hg, found = tt.GetByType("application/hugo+hg")
|
||||
require.True(t, found)
|
||||
|
||||
}},
|
||||
{
|
||||
"Add custom media type",
|
||||
@@ -123,6 +184,7 @@ func TestDecodeTypes(t *testing.T) {
|
||||
func(t *testing.T, name string, tt Types) {
|
||||
require.Len(t, tt, len(DefaultTypes)+1)
|
||||
// Make sure we have not broken the default config.
|
||||
|
||||
_, found := tt.GetBySuffix("json")
|
||||
require.True(t, found)
|
||||
|
||||
@@ -130,15 +192,6 @@ func TestDecodeTypes(t *testing.T) {
|
||||
require.True(t, found)
|
||||
require.Equal(t, "text/hugo+hgo", hugo.String(), name)
|
||||
}},
|
||||
{
|
||||
"Add media type invalid key",
|
||||
[]map[string]interface{}{
|
||||
{
|
||||
"text/hugo+hgo": map[string]interface{}{}}},
|
||||
true,
|
||||
func(t *testing.T, name string, tt Types) {
|
||||
|
||||
}},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
|
||||
@@ -72,7 +72,7 @@ func createLayoutExamples() interface{} {
|
||||
Example: example.name,
|
||||
Kind: example.d.Kind,
|
||||
OutputFormat: example.f.Name,
|
||||
Suffix: example.f.MediaType.Suffix,
|
||||
Suffix: example.f.MediaType.Suffix(),
|
||||
Layouts: makeLayoutsPresentable(layouts)})
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -47,7 +47,7 @@ type LayoutHandler struct {
|
||||
|
||||
type layoutCacheKey struct {
|
||||
d LayoutDescriptor
|
||||
f Format
|
||||
f string
|
||||
}
|
||||
|
||||
// NewLayoutHandler creates a new LayoutHandler.
|
||||
@@ -60,7 +60,7 @@ func NewLayoutHandler() *LayoutHandler {
|
||||
func (l *LayoutHandler) For(d LayoutDescriptor, f Format) ([]string, error) {
|
||||
|
||||
// We will get lots of requests for the same layouts, so avoid recalculations.
|
||||
key := layoutCacheKey{d, f}
|
||||
key := layoutCacheKey{d, f.Name}
|
||||
l.mu.RLock()
|
||||
if cacheVal, found := l.cache[key]; found {
|
||||
l.mu.RUnlock()
|
||||
@@ -209,7 +209,7 @@ func (l *layoutBuilder) resolveVariations() []string {
|
||||
"TYPE", typeVar,
|
||||
"LAYOUT", layoutVar,
|
||||
"VARIATIONS", variation,
|
||||
"EXTENSION", l.f.MediaType.Suffix,
|
||||
"EXTENSION", l.f.MediaType.Suffix(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,11 +27,11 @@ import (
|
||||
func TestLayout(t *testing.T) {
|
||||
|
||||
noExtNoDelimMediaType := media.TextType
|
||||
noExtNoDelimMediaType.Suffix = ""
|
||||
noExtNoDelimMediaType.Suffixes = nil
|
||||
noExtNoDelimMediaType.Delimiter = ""
|
||||
|
||||
noExtMediaType := media.TextType
|
||||
noExtMediaType.Suffix = ""
|
||||
noExtMediaType.Suffixes = nil
|
||||
|
||||
var (
|
||||
ampType = Format{
|
||||
@@ -47,6 +47,7 @@ func TestLayout(t *testing.T) {
|
||||
MediaType: noExtNoDelimMediaType,
|
||||
BaseName: "_redirects",
|
||||
}
|
||||
|
||||
noExt = Format{
|
||||
Name: "NEX",
|
||||
MediaType: noExtMediaType,
|
||||
|
||||
@@ -178,7 +178,7 @@ func (formats Formats) Less(i, j int) bool { return formats[i].Name < formats[j]
|
||||
// The lookup is case insensitive.
|
||||
func (formats Formats) GetBySuffix(suffix string) (f Format, found bool) {
|
||||
for _, ff := range formats {
|
||||
if strings.EqualFold(suffix, ff.MediaType.Suffix) {
|
||||
if strings.EqualFold(suffix, ff.MediaType.Suffix()) {
|
||||
if found {
|
||||
// ambiguous
|
||||
found = false
|
||||
@@ -331,7 +331,7 @@ func decode(mediaTypes media.Types, input, output interface{}) error {
|
||||
}
|
||||
|
||||
func (formats Format) BaseFilename() string {
|
||||
return formats.BaseName + "." + formats.MediaType.Suffix
|
||||
return formats.BaseName + formats.MediaType.FullSuffix()
|
||||
}
|
||||
|
||||
func (formats Format) MarshalJSON() ([]byte, error) {
|
||||
|
||||
@@ -93,11 +93,11 @@ func TestGetFormatByExt(t *testing.T) {
|
||||
|
||||
func TestGetFormatByFilename(t *testing.T) {
|
||||
noExtNoDelimMediaType := media.TextType
|
||||
noExtNoDelimMediaType.Suffix = ""
|
||||
noExtNoDelimMediaType.OldSuffix = ""
|
||||
noExtNoDelimMediaType.Delimiter = ""
|
||||
|
||||
noExtMediaType := media.TextType
|
||||
noExtMediaType.Suffix = ""
|
||||
noExtMediaType.OldSuffix = ""
|
||||
|
||||
var (
|
||||
noExtDelimFormat = Format{
|
||||
|
||||
@@ -62,7 +62,7 @@ func (r *multiReadSeekCloser) Close() error {
|
||||
}
|
||||
|
||||
// Concat concatenates the list of Resource objects.
|
||||
func (c *Client) Concat(targetPath string, resources []resource.Resource) (resource.Resource, error) {
|
||||
func (c *Client) Concat(targetPath string, resources resource.Resources) (resource.Resource, error) {
|
||||
// The CACHE_OTHER will make sure this will be re-created and published on rebuilds.
|
||||
return c.rs.ResourceCache.GetOrCreate(resource.CACHE_OTHER, targetPath, func() (resource.Resource, error) {
|
||||
var resolvedm media.Type
|
||||
@@ -70,7 +70,7 @@ func (c *Client) Concat(targetPath string, resources []resource.Resource) (resou
|
||||
// The given set of resources must be of the same Media Type.
|
||||
// We may improve on that in the future, but then we need to know more.
|
||||
for i, r := range resources {
|
||||
if i > 0 && r.MediaType() != resolvedm {
|
||||
if i > 0 && r.MediaType().Type() != resolvedm.Type() {
|
||||
return nil, errors.New("resources in Concat must be of the same Media Type")
|
||||
}
|
||||
resolvedm = r.MediaType()
|
||||
|
||||
@@ -16,12 +16,10 @@
|
||||
package create
|
||||
|
||||
import (
|
||||
"io"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/spf13/afero"
|
||||
|
||||
"github.com/dsnet/golib/memfile"
|
||||
"github.com/gohugoio/hugo/resource"
|
||||
)
|
||||
|
||||
@@ -36,15 +34,6 @@ func New(rs *resource.Spec) *Client {
|
||||
return &Client{rs: rs}
|
||||
}
|
||||
|
||||
type memFileCloser struct {
|
||||
*memfile.File
|
||||
io.Closer
|
||||
}
|
||||
|
||||
func (m *memFileCloser) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get creates a new Resource by opening the given filename in the given filesystem.
|
||||
func (c *Client) Get(fs afero.Fs, filename string) (resource.Resource, error) {
|
||||
filename = filepath.Clean(filename)
|
||||
@@ -53,7 +42,6 @@ func (c *Client) Get(fs afero.Fs, filename string) (resource.Resource, error) {
|
||||
resource.ResourceSourceDescriptor{
|
||||
LazyPublish: true,
|
||||
SourceFilename: filename})
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
@@ -66,9 +54,7 @@ func (c *Client) FromString(targetPath, content string) (resource.Resource, erro
|
||||
resource.ResourceSourceDescriptor{
|
||||
LazyPublish: true,
|
||||
OpenReadSeekCloser: func() (resource.ReadSeekCloser, error) {
|
||||
return &memFileCloser{
|
||||
File: memfile.New([]byte(content)),
|
||||
}, nil
|
||||
return resource.NewReadSeekerNoOpCloserFromString(content), nil
|
||||
},
|
||||
RelTargetFilename: filepath.Clean(targetPath)})
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ func New(rs *resource.Spec) *Client {
|
||||
addMinifierFunc(m, mt, "text/html", "html", html.Minify)
|
||||
addMinifierFunc(m, mt, "application/javascript", "js", js.Minify)
|
||||
addMinifierFunc(m, mt, "application/json", "json", json.Minify)
|
||||
addMinifierFunc(m, mt, "image/svg", "xml", svg.Minify)
|
||||
addMinifierFunc(m, mt, "image/svg+xml", "svg", svg.Minify)
|
||||
addMinifierFunc(m, mt, "application/xml", "xml", xml.Minify)
|
||||
addMinifierFunc(m, mt, "application/rss", "xml", xml.Minify)
|
||||
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
// 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 resource
|
||||
|
||||
import (
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ReadSeeker wraps io.Reader and io.Seeker.
|
||||
type ReadSeeker interface {
|
||||
io.Reader
|
||||
io.Seeker
|
||||
}
|
||||
|
||||
// ReadSeekCloser is implemented by afero.File. We use this as the common type for
|
||||
// content in Resource objects, even for strings.
|
||||
type ReadSeekCloser interface {
|
||||
ReadSeeker
|
||||
io.Closer
|
||||
}
|
||||
|
||||
// ReadSeekerNoOpCloser implements ReadSeekCloser by doing nothing in Close.
|
||||
type ReadSeekerNoOpCloser struct {
|
||||
ReadSeeker
|
||||
}
|
||||
|
||||
// Close does nothing.
|
||||
func (r ReadSeekerNoOpCloser) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewReadSeekerNoOpCloser creates a new ReadSeekerNoOpCloser with the given ReadSeeker.
|
||||
func NewReadSeekerNoOpCloser(r ReadSeeker) ReadSeekerNoOpCloser {
|
||||
return ReadSeekerNoOpCloser{r}
|
||||
}
|
||||
|
||||
// NewReadSeekerNoOpCloserFromString uses strings.NewReader to create a new ReadSeekerNoOpCloser
|
||||
// from the given string.
|
||||
func NewReadSeekerNoOpCloserFromString(content string) ReadSeekerNoOpCloser {
|
||||
return ReadSeekerNoOpCloser{strings.NewReader(content)}
|
||||
}
|
||||
+2
-12
@@ -16,7 +16,6 @@ package resource
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"mime"
|
||||
"os"
|
||||
@@ -134,14 +133,6 @@ type ContentResource interface {
|
||||
Content() (interface{}, error)
|
||||
}
|
||||
|
||||
// ReadSeekCloser is implemented by afero.File. We use this as the common type for
|
||||
// content in Resource objects, even for strings.
|
||||
type ReadSeekCloser interface {
|
||||
io.Reader
|
||||
io.Seeker
|
||||
io.Closer
|
||||
}
|
||||
|
||||
// OpenReadSeekeCloser allows setting some other way (than reading from a filesystem)
|
||||
// to open or create a ReadSeekCloser.
|
||||
type OpenReadSeekCloser func() (ReadSeekCloser, error)
|
||||
@@ -416,16 +407,15 @@ func (r *Spec) newResource(sourceFs afero.Fs, fd ResourceSourceDescriptor) (Reso
|
||||
mimeType, found := r.MediaTypes.GetFirstBySuffix(strings.TrimPrefix(ext, "."))
|
||||
// TODO(bep) we need to handle these ambigous types better, but in this context
|
||||
// we most likely want the application/xml type.
|
||||
if mimeType.Suffix == "xml" && mimeType.SubType == "rss" {
|
||||
if mimeType.Suffix() == "xml" && mimeType.SubType == "rss" {
|
||||
mimeType, found = r.MediaTypes.GetByType("application/xml")
|
||||
}
|
||||
|
||||
if !found {
|
||||
mimeStr := mime.TypeByExtension(ext)
|
||||
if mimeStr != "" {
|
||||
mimeType, _ = media.FromString(mimeStr)
|
||||
mimeType, _ = media.FromStringAndExt(mimeStr, ext)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
gr := r.newGenericResourceWithBase(
|
||||
|
||||
@@ -97,7 +97,7 @@ func TestNewResourceFromFilenameSubPathInBaseURL(t *testing.T) {
|
||||
|
||||
}
|
||||
|
||||
var pngType, _ = media.FromString("image/png")
|
||||
var pngType, _ = media.FromStringAndExt("image/png", "png")
|
||||
|
||||
func TestResourcesByType(t *testing.T) {
|
||||
assert := require.New(t)
|
||||
|
||||
+13
-11
@@ -17,6 +17,7 @@ import (
|
||||
"bytes"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/gohugoio/hugo/common/errors"
|
||||
"github.com/gohugoio/hugo/helpers"
|
||||
@@ -188,11 +189,10 @@ type transformedResource struct {
|
||||
}
|
||||
|
||||
func (r *transformedResource) ReadSeekCloser() (ReadSeekCloser, error) {
|
||||
rc, ok := r.Resource.(ReadSeekCloserResource)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("resource %T is not a ReadSeekerCloserResource", rc)
|
||||
if err := r.initContent(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return rc.ReadSeekCloser()
|
||||
return NewReadSeekerNoOpCloserFromString(r.content), nil
|
||||
}
|
||||
|
||||
func (r *transformedResource) transferTransformedValues(another *transformedResource) {
|
||||
@@ -289,12 +289,6 @@ func (r *transformedResource) transform(setContent bool) (err error) {
|
||||
|
||||
first := chain[0]
|
||||
|
||||
contentrc, err := contentReadSeekerCloser(first)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer contentrc.Close()
|
||||
|
||||
// Files with a suffix will be stored in cache (both on disk and in memory)
|
||||
// partitioned by their suffix. There will be other files below /other.
|
||||
// This partition is also how we determine what to delete on server reloads.
|
||||
@@ -333,6 +327,7 @@ func (r *transformedResource) transform(setContent bool) (err error) {
|
||||
r.cache.nlocker.Unlock(key)
|
||||
return
|
||||
}
|
||||
|
||||
defer r.cache.nlocker.Unlock(key)
|
||||
defer r.cache.set(key, r)
|
||||
|
||||
@@ -348,6 +343,13 @@ func (r *transformedResource) transform(setContent bool) (err error) {
|
||||
|
||||
tctx.InMediaType = first.MediaType()
|
||||
tctx.OutMediaType = first.MediaType()
|
||||
|
||||
contentrc, err := contentReadSeekerCloser(first)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer contentrc.Close()
|
||||
|
||||
tctx.From = contentrc
|
||||
tctx.To = b1
|
||||
|
||||
@@ -389,7 +391,7 @@ func (r *transformedResource) transform(setContent bool) (err error) {
|
||||
// If a prepared bundle for this transformation chain is available, use that.
|
||||
f := r.tryTransformedFileCache(key)
|
||||
if f == nil {
|
||||
return fmt.Errorf("failed to transform %q (%s): %s", tctx.InPath, tctx.InMediaType.Type(), err)
|
||||
return fmt.Errorf("%s: failed to transform %q (%s): %s", strings.ToUpper(tr.transformation.Key().name), tctx.InPath, tctx.InMediaType.Type(), err)
|
||||
}
|
||||
transformedContentr = f
|
||||
defer f.Close()
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
name: hugo
|
||||
version: "0.43"
|
||||
version: "0.44"
|
||||
summary: Fast and Flexible Static Site Generator
|
||||
description: |
|
||||
Hugo is a static HTML and CSS website generator written in Go. It is
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
Hugo `0.43` adds a powerful and very simple to use **Assets Pipeline** with **SASS and SCSS** with source map support, **PostCSS** and **minification** and **fingerprinting** and **Subresource Integrity** and ... much more. Oh, did we mention that you can now do **ad-hoc image processing** and execute text resources as Go templates?
|
||||
|
||||
I, [@bep](https://github.com/bep), implemented this in [dea71670](https://github.com/gohugoio/hugo/commit/dea71670c059ab4d5a42bd22503f18c087dd22d4) [#4381]. We will work hard to get the documentation up to date, but follow the links above for details, and also see this [demo project](https://github.com/bep/hugo-sass-test).
|
||||
|
||||
An example pipeline:
|
||||
|
||||
```go-html-template
|
||||
{{ $styles := resources.Get "scss/main.scss" | toCSS | postCSS | minify | fingerprint }}
|
||||
<link rel="stylesheet" href="{{ $styles.Permalink }}" integrity="{{ $styles.Data.Integrity }}" media="screen">
|
||||
```
|
||||
|
||||
To me, the above is beautiful in its speed and simplicity. It could be printed on a t-shirt. I wrote in the [Hugo Birthday Post](https://gohugo.io/news/lets-celebrate-hugos-5th-birthday/) some days ago about the value of a single binary with native and fast implementations. I should have added _simplicity_ as a keyword. There seem to be a misconception that all of this needs to be hard and painful.
|
||||
|
||||
This release represents **35 contributions by 7 contributors** to the main Hugo code base.
|
||||
[@bep](https://github.com/bep) leads the Hugo development with a significant amount of contributions, but also a big shoutout to [@anthonyfok](https://github.com/anthonyfok), [@openscript](https://github.com/openscript), and [@caarlos0](https://github.com/caarlos0) for their ongoing contributions.
|
||||
And a big thanks to [@digitalcraftsman](https://github.com/digitalcraftsman) for his relentless work on keeping the themes site in pristine condition and to [@kaushalmodi](https://github.com/kaushalmodi) for his great work on the documentation site.
|
||||
|
||||
Many have also been busy writing and fixing the documentation in [hugoDocs](https://github.com/gohugoio/hugoDocs),
|
||||
which has received **11 contributions by 5 contributors**. A special thanks to [@bep](https://github.com/bep), [@danrl](https://github.com/danrl), [@regisphilibert](https://github.com/regisphilibert), and [@digitalcraftsman](https://github.com/digitalcraftsman) for their work on the documentation site.
|
||||
|
||||
Hugo now has:
|
||||
|
||||
* 26968+ [stars](https://github.com/gohugoio/hugo/stargazers)
|
||||
* 443+ [contributors](https://github.com/gohugoio/hugo/graphs/contributors)
|
||||
* 238+ [themes](http://themes.gohugo.io/)
|
||||
|
||||
## Notes
|
||||
|
||||
* Replace deprecated {Get,}ByPrefix with {Get,}Match [42ed6025](https://github.com/gohugoio/hugo/commit/42ed602580a672e420e1d860384e812f4871ff67) [@anthonyfok](https://github.com/anthonyfok)
|
||||
* Hugo is now released with two binary version: One with and one without SCSS/SASS support. At the time of writing, this is only available in the binaries on the GitHub release page. Brew, Snap builds etc. will come. But note that you **only need the extended version if you want to edit SCSS**. For your CI server, or if you don't use SCSS, you will most likely want the non-extended version.
|
||||
|
||||
## Enhancements
|
||||
|
||||
### Templates
|
||||
|
||||
* Return en empty slice in `after` instead of error [f8212d20](https://github.com/gohugoio/hugo/commit/f8212d20009c4b5cc6e1ec733d09531eb6525d9f) [@bep](https://github.com/bep) [#4894](https://github.com/gohugoio/hugo/issues/4894)
|
||||
* Update internal pagination template to support Bootstrap 4 [ca1e46ef](https://github.com/gohugoio/hugo/commit/ca1e46efb94e3f3d2c8482cb9434d2f38ffd2683) [@bep](https://github.com/bep) [#4881](https://github.com/gohugoio/hugo/issues/4881)
|
||||
* Support text/template/parse API change in go1.11 [9f27091e](https://github.com/gohugoio/hugo/commit/9f27091e1067875e2577c331acc60adaef5bb234) [@anthonyfok](https://github.com/anthonyfok) [#4784](https://github.com/gohugoio/hugo/issues/4784)
|
||||
|
||||
### Core
|
||||
|
||||
* Allow forward slash in shortcode names [de37455e](https://github.com/gohugoio/hugo/commit/de37455ec73cffd039b44e8f6c62d2884b1d6bbd) [@bep](https://github.com/bep) [#4886](https://github.com/gohugoio/hugo/issues/4886)
|
||||
* Reset the global pages cache on server rebuilds [128f14ef](https://github.com/gohugoio/hugo/commit/128f14efad90886ffef37c01ac1e20436a732f97) [@bep](https://github.com/bep) [#4845](https://github.com/gohugoio/hugo/issues/4845)
|
||||
|
||||
### Other
|
||||
|
||||
* Bump CircleCI image [e3df6478](https://github.com/gohugoio/hugo/commit/e3df6478f09a7a5fed96aced791fa94fd2c35d1a) [@bep](https://github.com/bep)
|
||||
* Add Goreleaser extended config [626afc98](https://github.com/gohugoio/hugo/commit/626afc98254421f5a5edc97c541b10bd81d5bbbb) [@bep](https://github.com/bep) [#4908](https://github.com/gohugoio/hugo/issues/4908)
|
||||
* Build both hugo and hugo.extended for 0.43 [e1027c58](https://github.com/gohugoio/hugo/commit/e1027c5846b48c4ad450f6cc27e2654c9e0dae39) [@anthonyfok](https://github.com/anthonyfok) [#4908](https://github.com/gohugoio/hugo/issues/4908)
|
||||
* Add temporary build script [bfc3488b](https://github.com/gohugoio/hugo/commit/bfc3488b8e8b3dc1ffc6a339ee2dac8dcbdb55a9) [@bep](https://github.com/bep)
|
||||
* Add "extended" to "hugo version" [ce84b524](https://github.com/gohugoio/hugo/commit/ce84b524f4e94299b5b66afe7ce1a9bd4a9959fc) [@anthonyfok](https://github.com/anthonyfok) [#4913](https://github.com/gohugoio/hugo/issues/4913)
|
||||
* Add a newScratch template func [2b8d907a](https://github.com/gohugoio/hugo/commit/2b8d907ab731627f4e2a30442cd729064516c8bb) [@bep](https://github.com/bep) [#4685](https://github.com/gohugoio/hugo/issues/4685)
|
||||
* Add Hugo Piper with SCSS support and much more [dea71670](https://github.com/gohugoio/hugo/commit/dea71670c059ab4d5a42bd22503f18c087dd22d4) [@bep](https://github.com/bep) [#4381](https://github.com/gohugoio/hugo/issues/4381)[#4903](https://github.com/gohugoio/hugo/issues/4903)[#4858](https://github.com/gohugoio/hugo/issues/4858)
|
||||
* Consider root and current section's content type if set in front matter [c790029e](https://github.com/gohugoio/hugo/commit/c790029e1dbb0b66af18d05764bd6045deb2e180) [@bep](https://github.com/bep) [#4891](https://github.com/gohugoio/hugo/issues/4891)
|
||||
* Update docker image [554553c0](https://github.com/gohugoio/hugo/commit/554553c09c7657d28681e1fa0638806a452737a0) [@bep](https://github.com/bep)
|
||||
* Merge branch 'release-0.42.2' [282f6035](https://github.com/gohugoio/hugo/commit/282f6035e7c36f8550d91033e3a66718468c6c8b) [@bep](https://github.com/bep)
|
||||
* Release 0.42.2 [1637d12e](https://github.com/gohugoio/hugo/commit/1637d12e3762fc1ebab4cd675f75afaf25f59cdb) [@bep](https://github.com/bep)
|
||||
* Update GoReleaser config [1f0c4e1f](https://github.com/gohugoio/hugo/commit/1f0c4e1fb347bb233f3312c424fbf5a013c03604) [@caarlos0](https://github.com/caarlos0)
|
||||
* Create missing head.html partial on new theme generation [fd71fa89](https://github.com/gohugoio/hugo/commit/fd71fa89bd6c197402582c87b2b76d4b96d562bf) [@openscript](https://github.com/openscript)
|
||||
* Add html doctype to baseof.html template for new themes [b5a3aa70](https://github.com/gohugoio/hugo/commit/b5a3aa7082135d0a573f4fbb00f798e26b67b902) [@openscript](https://github.com/openscript)
|
||||
* Adds .gitattributes to force Go files to LF [6a2968fd](https://github.com/gohugoio/hugo/commit/6a2968fd5c0116d93de0f379ac615e9076821899) [@neurocline](https://github.com/neurocline)
|
||||
* Update to Go 1.9.7 and Go 1.10.3 [23d5fc82](https://github.com/gohugoio/hugo/commit/23d5fc82ee01d56440d0991c899acd31e9b63e27) [@anthonyfok](https://github.com/anthonyfok)
|
||||
* Update Dockerfile to a multi-stage build [8531ec7c](https://github.com/gohugoio/hugo/commit/8531ec7ca36fd35a57fba06bbb06a65c94dfd3ed) [@skoblenick](https://github.com/skoblenick) [#4154](https://github.com/gohugoio/hugo/issues/4154)
|
||||
* Release 0.42.1 [d67e843c](https://github.com/gohugoio/hugo/commit/d67e843c1212e1f53933556b5f946c8541188d9a) [@bep](https://github.com/bep)
|
||||
* Do not fail server build when /static is missing [34ee27a7](https://github.com/gohugoio/hugo/commit/34ee27a78b9e2b5f475d44253ae234067b76cc6e) [@bep](https://github.com/bep) [#4846](https://github.com/gohugoio/hugo/issues/4846)
|
||||
|
||||
## Fixes
|
||||
|
||||
* Do not create paginator pages for the other output formats [43338c3a](https://github.com/gohugoio/hugo/commit/43338c3a99769eb7d0df0c12559b8b3d42b67dba) [@bep](https://github.com/bep) [#4890](https://github.com/gohugoio/hugo/issues/4890)
|
||||
* Fix the shortcodes/partials vs base template detection [a5d0a57e](https://github.com/gohugoio/hugo/commit/a5d0a57e6bdab583134a68c035aac9b3007f006a) [@bep](https://github.com/bep) [#4897](https://github.com/gohugoio/hugo/issues/4897)
|
||||
* nfpm replacements [e1a052ec](https://github.com/gohugoio/hugo/commit/e1a052ecb823c688406a8af97dfaaf52a75231da) [@caarlos0](https://github.com/caarlos0)
|
||||
* Fix typos [3cea2932](https://github.com/gohugoio/hugo/commit/3cea2932e17a08ebc19cd05f3079d9379bc8fba5) [@idealhack](https://github.com/idealhack)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
|
||||
Hugo `0.44` is the follow-up release, or **The Sequel**, of the very well received `0.43` only days ago. That release added **Hugo Pipes**, with SCSS/SASS support, assets bundling and minification, ad-hoc image processing and much more.
|
||||
|
||||
This is mostly a bug-fix release, but it also includes several important improvements.
|
||||
|
||||
Many complained that their SVG images vanished when browsed from the `hugo server`. With **Hugo Pipes** MIME types suddenly got really important, but Hugo's use of `Suffix` was ambiguous. This became visible when we redefined the `image/svg+xml` to work with **Hugo Pipes**. We have now added a `Suffixes` field on the MIME type definition in Hugo, which is a list of one or more filename suffixes the MIME type is identified with. If you need to add a custom MIME type definition, this means that you also need to specify the full MIME type as the key, e.g. `image/svg+xml`.
|
||||
|
||||
Hugo now has:
|
||||
|
||||
* 27120+ [stars](https://github.com/gohugoio/hugo/stargazers)
|
||||
* 443+ [contributors](https://github.com/gohugoio/hugo/graphs/contributors)
|
||||
* 239+ [themes](http://themes.gohugo.io/)
|
||||
|
||||
## Notes
|
||||
* `MediaType.Suffix` is deprecated and replaced with a plural version, `MediaType.Suffixes`, with a more specific definition. You will get a detailed WARNING in the console if you need to do anything.
|
||||
|
||||
## Enhancements
|
||||
* Allow multiple file suffixes per media type [b874a1ba](https://github.com/gohugoio/hugo/commit/b874a1ba7ab8394dc741c8c70303a30a35b63e43) [@bep](https://github.com/bep) [#4920](https://github.com/gohugoio/hugo/issues/4920)
|
||||
* Clean up the in-memory Resource reader usage [47d38628](https://github.com/gohugoio/hugo/commit/47d38628ec0f4e72ff17661f13456b2a1511fe13) [@bep](https://github.com/bep) [#4936](https://github.com/gohugoio/hugo/issues/4936)
|
||||
* Move opening of the transformed resources after cache check [0024dcfe](https://github.com/gohugoio/hugo/commit/0024dcfe3e016c67046de06d1dac5e7f5235f9e1) [@bep](https://github.com/bep)
|
||||
* Improve type support in `resources.Concat` [306573de](https://github.com/gohugoio/hugo/commit/306573def0e20ec16ee5c447981cc09ed8bb7ec7) [@bep](https://github.com/bep) [#4934](https://github.com/gohugoio/hugo/issues/4934)
|
||||
* Flush `partialCached` cache on rebuilds [6b6dcb44](https://github.com/gohugoio/hugo/commit/6b6dcb44a014699c289bf32fe57d4c4216777be0) [@bep](https://github.com/bep) [#4931](https://github.com/gohugoio/hugo/issues/4931)
|
||||
* Include the transformation step in the error message [d96f2a46](https://github.com/gohugoio/hugo/commit/d96f2a460f58e91d8f6253a489d4879acfec6916) [@bep](https://github.com/bep) [#4924](https://github.com/gohugoio/hugo/issues/4924)
|
||||
* Exclude *.svg from CRLF/LF conversion [9c1e8208](https://github.com/gohugoio/hugo/commit/9c1e82085eb07d5b4dcdacbe82d5bafd26e08631) [@anthonyfok](https://github.com/anthonyfok)
|
||||
|
||||
## Fixes
|
||||
|
||||
* Fix `resources.Concat` for transformed resources [beec1fc9](https://github.com/gohugoio/hugo/commit/beec1fc98e5d37bba742d6bc2a0ff7c344b469f8) [@bep](https://github.com/bep) [#4936](https://github.com/gohugoio/hugo/issues/4936)
|
||||
* Fix static filesystem for themed multihost sites [80c8f3b8](https://github.com/gohugoio/hugo/commit/80c8f3b81a9849080e64bf877288ede28d960d3f) [@bep](https://github.com/bep) [#4929](https://github.com/gohugoio/hugo/issues/4929)
|
||||
* Set permission of embedded templates to 0644 [2b73e89d](https://github.com/gohugoio/hugo/commit/2b73e89d6d2822e86360a6c92c87f539677c119b) [@anthonyfok](https://github.com/anthonyfok)
|
||||
|
||||
@@ -26,7 +26,9 @@ func TestInit(t *testing.T) {
|
||||
var ns *internal.TemplateFuncsNamespace
|
||||
|
||||
for _, nsf := range internal.TemplateFuncsNamespaceRegistry {
|
||||
ns = nsf(&deps.Deps{})
|
||||
ns = nsf(&deps.Deps{
|
||||
BuildStartListeners: &deps.Listeners{},
|
||||
})
|
||||
if ns.Name == name {
|
||||
found = true
|
||||
break
|
||||
|
||||
@@ -34,18 +34,30 @@ type partialCache struct {
|
||||
p map[string]interface{}
|
||||
}
|
||||
|
||||
func (p *partialCache) clear() {
|
||||
p.Lock()
|
||||
defer p.Unlock()
|
||||
p.p = make(map[string]interface{})
|
||||
}
|
||||
|
||||
// New returns a new instance of the templates-namespaced template functions.
|
||||
func New(deps *deps.Deps) *Namespace {
|
||||
cache := &partialCache{p: make(map[string]interface{})}
|
||||
deps.BuildStartListeners.Add(
|
||||
func() {
|
||||
cache.clear()
|
||||
})
|
||||
|
||||
return &Namespace{
|
||||
deps: deps,
|
||||
cachedPartials: partialCache{p: make(map[string]interface{})},
|
||||
cachedPartials: cache,
|
||||
}
|
||||
}
|
||||
|
||||
// Namespace provides template functions for the "templates" namespace.
|
||||
type Namespace struct {
|
||||
deps *deps.Deps
|
||||
cachedPartials partialCache
|
||||
cachedPartials *partialCache
|
||||
}
|
||||
|
||||
// Include executes the named partial and returns either a string,
|
||||
|
||||
@@ -79,19 +79,38 @@ func (ns *Namespace) Get(filename interface{}) (resource.Resource, error) {
|
||||
|
||||
// Concat concatenates a slice of Resource objects. These resources must
|
||||
// (currently) be of the same Media Type.
|
||||
func (ns *Namespace) Concat(targetPathIn interface{}, r []interface{}) (resource.Resource, error) {
|
||||
func (ns *Namespace) Concat(targetPathIn interface{}, r interface{}) (resource.Resource, error) {
|
||||
targetPath, err := cast.ToStringE(targetPathIn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rr := make([]resource.Resource, len(r))
|
||||
for i := 0; i < len(r); i++ {
|
||||
rv, ok := r[i].(resource.Resource)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("cannot concat type %T", rv)
|
||||
|
||||
var rr resource.Resources
|
||||
|
||||
switch v := r.(type) {
|
||||
// This is what we get from the slice func.
|
||||
case []interface{}:
|
||||
rr = make([]resource.Resource, len(v))
|
||||
for i := 0; i < len(v); i++ {
|
||||
rv, ok := v[i].(resource.Resource)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("cannot concat type %T", v[i])
|
||||
}
|
||||
rr[i] = rv
|
||||
}
|
||||
rr[i] = rv
|
||||
// This is what we get from .Resources.Match etc.
|
||||
case resource.Resources:
|
||||
rr = v
|
||||
default:
|
||||
// We may support Page collections at one point, but we need to think about ...
|
||||
// what to acutually concatenate.
|
||||
return nil, fmt.Errorf("slice %T not supported in concat", r)
|
||||
}
|
||||
|
||||
if len(rr) == 0 {
|
||||
return nil, errors.New("must provide one or more Resource objects to concat")
|
||||
}
|
||||
|
||||
return ns.bundlerClient.Concat(targetPath, rr)
|
||||
}
|
||||
|
||||
|
||||
Executable → Regular
Executable → Regular
Executable → Regular
Executable → Regular
Executable → Regular
Executable → Regular
Executable → Regular
Executable → Regular
Executable → Regular
Executable → Regular
Executable → Regular
Executable → Regular
Executable → Regular
Executable → Regular
Executable → Regular
Executable → Regular
Executable → Regular
Executable → Regular
Executable → Regular
Executable → Regular
Executable → Regular
Reference in New Issue
Block a user