Browse Source

Custom taxonomies (#330)

index-subcmd
Vincent Prouillet GitHub 5 years ago
parent
commit
1ae0702494
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 684 additions and 604 deletions
  1. +7
    -0
      CHANGELOG.md
  2. +139
    -135
      Cargo.lock
  3. +37
    -6
      components/config/src/lib.rs
  4. +2
    -3
      components/content/src/page.rs
  5. +20
    -45
      components/front_matter/src/page.rs
  6. +9
    -0
      components/imageproc/src/lib.rs
  7. +1
    -0
      components/pagination/Cargo.toml
  8. +119
    -25
      components/pagination/src/lib.rs
  9. +24
    -45
      components/rebuild/src/lib.rs
  10. +77
    -81
      components/site/src/lib.rs
  11. +10
    -61
      components/site/tests/site.rs
  12. +98
    -81
      components/taxonomies/src/lib.rs
  13. +4
    -4
      components/templates/src/builtins/rss.xml
  14. +4
    -7
      components/templates/src/builtins/sitemap.xml
  15. +22
    -34
      components/templates/src/global_fns.rs
  16. +0
    -1
      components/templates/src/lib.rs
  17. +2
    -2
      components/utils/src/templates.rs
  18. +4
    -5
      docs/content/documentation/content/page.md
  19. +0
    -23
      docs/content/documentation/content/tags-categories.md
  20. +27
    -0
      docs/content/documentation/content/taxonomies.md
  21. +8
    -7
      docs/content/documentation/getting-started/configuration.md
  22. +7
    -2
      docs/content/documentation/templates/pagination.md
  23. +0
    -31
      docs/content/documentation/templates/tags-categories.md
  24. +53
    -0
      docs/content/documentation/templates/taxonomies.md
  25. +4
    -0
      test_site/config.toml
  26. +0
    -3
      test_site/templates/categories.html
  27. +3
    -0
      test_site/templates/categories/list.html
  28. +1
    -1
      test_site/templates/categories/single.html
  29. +2
    -2
      test_site/themes/sample/templates/categories/single.html

+ 7
- 0
CHANGELOG.md View File

@@ -2,6 +2,13 @@

## 0.4.0 (unreleased)

### Breaking

- Taxonomies have been rewritten from scratch to allow custom ones with RSS and pagination
- `get_taxonomy_url` has been renamed to `get_taxonomy` and will now return the full taxonomy
instead of just the URL

### Others
- Fix `serve` not working with the config flag
- Websocket port on `live` will not get the first available port instead of a fixed one
- Rewrite markdown rendering to fix all known issues with shortcodes


+ 139
- 135
Cargo.lock View File

@@ -8,7 +8,7 @@ dependencies = [
"bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam-channel 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"skeptic 0.13.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -22,7 +22,7 @@ dependencies = [

[[package]]
name = "actix-web"
version = "0.6.14"
version = "0.6.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"actix 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -33,25 +33,25 @@ dependencies = [
"cookie 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
"encoding 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"h2 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"http 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"http-range 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"httparse 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"mime 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"mime_guess 2.0.0-alpha.5 (registry+https://github.com/rust-lang/crates.io-index)",
"mime_guess 2.0.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)",
"net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_urlencoded 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
"sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -60,8 +60,8 @@ dependencies = [
"time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"version_check 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
@@ -72,7 +72,7 @@ dependencies = [
"quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
"version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"version_check 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
@@ -82,7 +82,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "aho-corasick"
version = "0.6.5"
version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -94,11 +94,11 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"html5ever 0.22.3 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"maplit 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"tendril 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
@@ -158,7 +158,7 @@ name = "backtrace-sys"
version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cc 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
"cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
]

@@ -186,7 +186,7 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
@@ -240,14 +240,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "cc"
version = "1.0.17"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
@@ -284,7 +284,7 @@ name = "cmake"
version = "0.1.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cc 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
"cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
@@ -300,8 +300,8 @@ dependencies = [
"errors 0.1.0",
"globset 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"highlighting 0.1.0",
"serde 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
]

@@ -316,7 +316,7 @@ dependencies = [
"globset 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rendering 0.1.0",
"serde 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"slug 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"tempfile 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"tera 0.11.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -330,7 +330,7 @@ version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
@@ -369,7 +369,7 @@ dependencies = [
"arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
"scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -383,7 +383,7 @@ dependencies = [
"arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam-utils 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -433,7 +433,7 @@ dependencies = [

[[package]]
name = "dtoa"
version = "0.4.2"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
@@ -457,11 +457,11 @@ name = "elasticlunr-rs"
version = "2.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rust-stemmers 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)",
"strum 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"strum_macros 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -607,10 +607,10 @@ version = "0.1.0"
dependencies = [
"chrono 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"errors 0.1.0",
"lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"tera 0.11.8 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -663,7 +663,7 @@ dependencies = [

[[package]]
name = "futures"
version = "0.1.21"
version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
@@ -671,7 +671,7 @@ name = "futures-cpupool"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
]

@@ -682,8 +682,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "getopts"
version = "0.2.17"
version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "gif"
@@ -704,7 +707,7 @@ name = "globset"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"aho-corasick 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
"aho-corasick 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
"fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -716,7 +719,7 @@ name = "gutenberg"
version = "0.4.0"
dependencies = [
"actix 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
"actix-web 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)",
"actix-web 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)",
"chrono 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
"content 0.1.0",
@@ -728,7 +731,7 @@ dependencies = [
"site 0.1.0",
"term-painter 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"utils 0.1.0",
"ws 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -741,12 +744,12 @@ dependencies = [
"byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
"http 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"indexmap 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"string 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"string 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
]

@@ -754,7 +757,7 @@ dependencies = [
name = "highlighting"
version = "0.1.0"
dependencies = [
"lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syntect 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]

@@ -787,7 +790,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"itoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"itoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
@@ -807,7 +810,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "idna"
version = "0.1.4"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -838,7 +841,7 @@ version = "0.1.0"
dependencies = [
"errors 0.1.0",
"image 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"tera 0.11.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -889,7 +892,7 @@ dependencies = [

[[package]]
name = "itoa"
version = "0.4.1"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
@@ -917,7 +920,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "lazy_static"
version = "1.0.1"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
@@ -986,8 +989,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"phf 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)",
"phf_codegen 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)",
"string_cache 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
"string_cache_codegen 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1022,7 +1025,7 @@ dependencies = [

[[package]]
name = "mime_guess"
version = "2.0.0-alpha.5"
version = "2.0.0-alpha.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"mime 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1036,7 +1039,7 @@ name = "miniz-sys"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cc 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
"cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
]

@@ -1152,7 +1155,7 @@ version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"cc 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
"cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1236,7 +1239,7 @@ version = "3.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
"onig_sys 68.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -1277,8 +1280,9 @@ dependencies = [
"content 0.1.0",
"errors 0.1.0",
"front_matter 0.1.0",
"serde 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"taxonomies 0.1.0",
"tera 0.11.8 (registry+https://github.com/rust-lang/crates.io-index)",
"utils 0.1.0",
]
@@ -1371,7 +1375,7 @@ dependencies = [
"base64 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"chrono 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"xml-rs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
]

@@ -1413,7 +1417,7 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"getopts 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
"getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
@@ -1477,7 +1481,7 @@ version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1514,7 +1518,7 @@ name = "regex"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"aho-corasick 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
"aho-corasick 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"regex-syntax 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
"thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1526,7 +1530,7 @@ name = "regex"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"aho-corasick 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
"aho-corasick 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"regex-syntax 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
"thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1573,8 +1577,8 @@ dependencies = [
"pest 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"pest_derive 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
"pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"slug 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"syntect 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"templates 0.1.0",
@@ -1596,8 +1600,8 @@ name = "rust-stemmers"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"serde 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
@@ -1660,7 +1664,7 @@ dependencies = [
"content 0.1.0",
"elasticlunr-rs 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"errors 0.1.0",
"lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
@@ -1669,7 +1673,7 @@ version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
@@ -1679,12 +1683,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "serde"
version = "1.0.69"
version = "1.0.70"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "serde_derive"
version = "1.0.69"
version = "1.0.70"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1697,10 +1701,10 @@ name = "serde_json"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"dtoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"indexmap 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"itoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)",
"itoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
@@ -1708,10 +1712,10 @@ name = "serde_urlencoded"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"itoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"dtoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"itoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
@@ -1748,8 +1752,8 @@ dependencies = [
"rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"sass-rs 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"search 0.1.0",
"serde 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"taxonomies 0.1.0",
"tempfile 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"templates 0.1.0",
@@ -1818,7 +1822,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "string"
version = "0.1.0"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
@@ -1826,11 +1830,11 @@ name = "string_cache"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"new_debug_unreachable 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"phf_shared 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)",
"precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"string_cache_codegen 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -1928,12 +1932,12 @@ dependencies = [
"bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"onig 3.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"plist 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"regex-syntax 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)",
"walkdir 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"yaml-rust 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1947,8 +1951,8 @@ dependencies = [
"content 0.1.0",
"errors 0.1.0",
"front_matter 0.1.0",
"serde 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"slug 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"tera 0.11.8 (registry+https://github.com/rust-lang/crates.io-index)",
"utils 0.1.0",
@@ -1984,7 +1988,7 @@ dependencies = [
"content 0.1.0",
"errors 0.1.0",
"imageproc 0.1.0",
"lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"taxonomies 0.1.0",
"tera 0.11.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2010,14 +2014,14 @@ dependencies = [
"error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"humansize 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"pest 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"pest_derive 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)",
"slug 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
@@ -2060,7 +2064,7 @@ name = "thread_local"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]

@@ -2079,14 +2083,14 @@ name = "tokio"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-fs 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-fs 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-reactor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-tcp 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-threadpool 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-threadpool 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-timer 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-udp 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -2097,7 +2101,7 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
]

@@ -2107,7 +2111,7 @@ version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
"iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2124,17 +2128,17 @@ name = "tokio-executor"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "tokio-fs"
version = "0.1.1"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-threadpool 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-threadpool 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
@@ -2143,7 +2147,7 @@ version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
]

@@ -2152,7 +2156,7 @@ name = "tokio-reactor"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2165,7 +2169,7 @@ name = "tokio-signal"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)",
"mio-uds 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2180,7 +2184,7 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
"iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2189,11 +2193,11 @@ dependencies = [

[[package]]
name = "tokio-threadpool"
version = "0.1.4"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"crossbeam-deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2205,7 +2209,7 @@ name = "tokio-timer"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
]

@@ -2215,7 +2219,7 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-codec 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2228,7 +2232,7 @@ name = "toml"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"serde 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
@@ -2238,14 +2242,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"error-chain 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
"idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
"idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
@@ -2254,9 +2258,9 @@ version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"error-chain 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
"ipconfig 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"lru-cache 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"resolv-conf 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2274,7 +2278,7 @@ name = "unicase"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"version_check 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
@@ -2282,7 +2286,7 @@ name = "unicase"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"version_check 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
@@ -2333,11 +2337,11 @@ dependencies = [

[[package]]
name = "url"
version = "1.7.0"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"encoding 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
"idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -2379,7 +2383,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "version_check"
version = "0.1.3"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
@@ -2459,7 +2463,7 @@ dependencies = [
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
@@ -2489,10 +2493,10 @@ dependencies = [

[metadata]
"checksum actix 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7f0b2daad36916ccd2b162dbc5a04a74df642a29391b1a341c8ee3e82026cb16"
"checksum actix-web 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)" = "e35bb192338dc7726564b0bdf2d49d43cbf4c7845231a82527f5f302bdb8f477"
"checksum actix-web 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)" = "cebfb353ebcae66f93c190b80ef12b8c82557413856e3e65dbaab662a48ec72d"
"checksum actix_derive 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c4b1dc922654b9aca7a8a31eab875fde804fa9fbd67f220f2e457787b23590f2"
"checksum adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7e522997b529f05601e05166c07ed17789691f562762c7f3b987263d2dedee5c"
"checksum aho-corasick 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f0ba20154ea1f47ce2793322f049c5646cc6d0fa9759d5f333f286e507bf8080"
"checksum aho-corasick 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c1c6d463cbe7ed28720b5b489e7c083eeb8f90d08be2a0d6bb9e1ffea9ce1afa"
"checksum ammonia 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fd4c682378117e4186a492b2252b9537990e1617f44aed9788b9a1149de45477"
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
"checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef"
@@ -2512,7 +2516,7 @@ dependencies = [
"checksum bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c129aff112dcc562970abb69e2508b40850dd24c274761bb50fb8a0067ba6c27"
"checksum bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7dd32989a66957d3f0cba6588f15d4281a733f4e9ffc43fcd2385f57d3bf99ff"
"checksum cargo_metadata 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1efca0b863ca03ed4c109fb1c55e0bc4bbeb221d3e103d86251046b06a526bd0"
"checksum cc 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "49ec142f5768efb5b7622aebc3fdbdbb8950a4b9ba996393cb76ef7466e8747d"
"checksum cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)" = "2119ea4867bd2b8ed3aecab467709720b2d55b1bcfe09f772fd68066eaf15275"
"checksum cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "efe5c877e17a9c717a0bf3613b2709f723202c4e4675cc8f12926ded29bcb17e"
"checksum chrono 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6962c635d530328acc53ac6a955e83093fedc91c5809dfac1fa60fa470830a37"
"checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e"
@@ -2529,7 +2533,7 @@ dependencies = [
"checksum ctrlc 3.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "630391922b1b893692c6334369ff528dcc3a9d8061ccf4c803aa8f83cb13db5e"
"checksum dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97590ba53bcb8ac28279161ca943a924d1fd4a8fb3fa63302591647c4fc5b850"
"checksum deflate 0.7.18 (registry+https://github.com/rust-lang/crates.io-index)" = "32c8120d981901a9970a3a1c97cf8b630e0fa8c3ca31e75b6fd6fd5f9f427b31"
"checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab"
"checksum dtoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6d301140eb411af13d3115f9a562c85cc6b541ade9dfa314132244aaee7489dd"
"checksum duct 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "166298c17c5b4fe5997b962c2f22e887c7c5adc44308eb9103ce5b66af45a423"
"checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0"
"checksum elasticlunr-rs 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4837d77a1e157489a3933b743fd774ae75074e0e390b2b7f071530048a0d87ee"
@@ -2554,10 +2558,10 @@ dependencies = [
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
"checksum futf 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7c9c1ce3fa9336301af935ab852c437817d14cd33690446569392e65170aac3b"
"checksum futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "1a70b146671de62ec8c8ed572219ca5d594d9b06c0b364d5e67b722fc559b48c"
"checksum futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)" = "884dbe32a6ae4cd7da5c6db9b78114449df9953b8d490c9d7e1b51720b922c62"
"checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4"
"checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb"
"checksum getopts 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)" = "b900c08c1939860ce8b54dc6a89e26e00c04c380fd0e09796799bd7f12861e05"
"checksum getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "0a7292d30132fb5424b354f5dc02512a86e4c516fe544bb7a25e7f266951b797"
"checksum gif 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff3414b424657317e708489d2857d9575f4403698428b040b609b9d1c1a84a2c"
"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
"checksum globset 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "142754da2c9b3722affd909f9e27f2a6700a7a303f362971e0a74c652005a43d"
@@ -2568,18 +2572,18 @@ dependencies = [
"checksum http-range 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5f2e4003e6fd05ea9109db00415e670b11f511a42e567ff2d5d771cbdfa24e02"
"checksum httparse 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7b6288d7db100340ca12873fd4d08ad1b8f206a9457798dfb17c018a33fee540"
"checksum humansize 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b6cab2627acfc432780848602f3f558f7e9dd427352224b0d9324025796d2a5e"
"checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d"
"checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e"
"checksum image 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ebdff791af04e30089bde8ad2a632b86af433b40c04db8d70ad4b21487db7a6a"
"checksum indexmap 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08173ba1e906efb6538785a8844dd496f5d34f0a2d88038e95195172fc667220"
"checksum inflate 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6f53b811ee8e2057ccf9643ca6b4277de90efaf5e61e55fd5254576926bb4245"
"checksum inotify 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "887fcc180136e77a85e6a6128579a719027b1bab9b1c38ea4444244fe262c20c"
"checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08"
"checksum ipconfig 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9ec4e18c0a0d4340870c14284293632d8421f419008371422dd327892b88877c"
"checksum itoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c069bbec61e1ca5a596166e55dfe4773ff745c3d16b700013bcaff9a6df2c682"
"checksum itoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5adb58558dcd1d786b5f0bd15f3226ee23486e24b7b58304b60f64dc68e62606"
"checksum jpeg-decoder 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "c8b7d43206b34b3f94ea9445174bda196e772049b9bddbc620c9d29b2d20110d"
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
"checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a"
"checksum lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e6412c5e2ad9584b0b8e979393122026cdd6d2a80b933f890dcd694ddbe73739"
"checksum lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fb497c35d362b6a331cfd94956a07fc2c78a4604cdbee844a81170386b996dd3"
"checksum lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a6f08839bc70ef4a3fe1d566d5350f519c5912ea86be0df1740a7d247c7fc0ef"
"checksum libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)" = "b685088df2b950fccadf07a7187c8ef846a959c142338a48f9dc0b94517eb5f1"
"checksum linked-hash-map 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7860ec297f7008ff7a1e3382d7f7e1dcd69efc94751a2284bafc3d013c2aa939"
@@ -2595,7 +2599,7 @@ dependencies = [
"checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d"
"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3"
"checksum mime 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "fe51c8699d2dc522bf8c1ebe26ea2193d151fb54bcdfd7d0318750c189994cd9"
"checksum mime_guess 2.0.0-alpha.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d1a78b5e2283080d5a8ba68216171b4fe34f6ccdd909bb29be16ce8a9a831341"
"checksum mime_guess 2.0.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)" = "30de2e4613efcba1ec63d8133f344076952090c122992a903359be5a4f99c3ed"
"checksum miniz-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "609ce024854aeb19a0ef7567d348aaa5a746b32fb72e336df7fcc16869d7e2b4"
"checksum mio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a637d1ca14eacae06296a008fa7ad955347e34efcb5891cfd8ba05491a37907e"
"checksum mio 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)" = "4fcfcb32d63961fb6f367bfd5d21e4600b92cd310f71f9dca25acae196eb1560"
@@ -2663,8 +2667,8 @@ dependencies = [
"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27"
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
"checksum serde 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)" = "210e5a3b159c566d7527e9b22e44be73f2e0fcc330bb78fef4dbccb56d2e74c8"
"checksum serde_derive 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)" = "dd724d68017ae3a7e63600ee4b2fdb3cad2158ffd1821d44aff4580f63e2b593"
"checksum serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)" = "0c3adf19c07af6d186d91dae8927b83b0553d07ca56cbf7f2f32560455c91920"
"checksum serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)" = "3525a779832b08693031b8ecfb0de81cd71cfd3812088fafe9a7496789572124"
"checksum serde_json 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)" = "84b8035cabe9b35878adec8ac5fe03d5f6bc97ff6edd7ccb96b44c1276ba390e"
"checksum serde_urlencoded 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e703cef904312097cfceab9ce131ff6bbe09e8c964a0703345a5f49238757bc1"
"checksum sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d"
@@ -2678,7 +2682,7 @@ dependencies = [
"checksum smallvec 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "312a7df010092e73d6bbaf141957e868d4f30efd2bfd9bb1028ad91abec58514"
"checksum socket2 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "962a516af4d3a7c272cb3a1d50a8cc4e5b41802e4ad54cfb7bee8ba61d37d703"
"checksum stable_deref_trait 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ffbc596e092fe5f598b12ef46cc03754085ac2f4d8c739ad61c4ae266cc3b3fa"
"checksum string 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "31f98b200e7caca9efca50fc0aa69cd58a5ec81d5f6e75b2f3ecaad2e998972a"
"checksum string 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00caf261d6f90f588f8450b8e1230fa0d5be49ee6140fdfbcb55335aff350970"
"checksum string_cache 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "25d70109977172b127fe834e5449e5ab1740b9ba49fa18a2020f509174f25423"
"checksum string_cache_codegen 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "35293b05cf1494e8ddd042a7df6756bf18d07f42d234f32e71dce8a7aabb0191"
"checksum string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b1884d1bc09741d466d9b14e6d37ac89d6909cbcac41dd9ae982d4d063bbedfc"
@@ -2705,12 +2709,12 @@ dependencies = [
"checksum tokio-codec 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "881e9645b81c2ce95fcb799ded2c29ffb9f25ef5bef909089a420e5961dd8ccb"
"checksum tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "aeeffbbb94209023feaef3c196a41cbcdafa06b4a6f893f68779bb5e53796f71"
"checksum tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8cac2a7883ff3567e9d66bb09100d09b33d90311feca0206c7ca034bc0c55113"
"checksum tokio-fs 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fc42bae2f6e33865b99069d95bcddfc85c9f0849b4e7e7399eeee71956ef34d7"
"checksum tokio-fs 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "40697ecbea5660df15b15d50a077386477d2f6a35002adf01ce76ff9dd9dce48"
"checksum tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a5c9635ee806f26d302b8baa1e145689a280d8f5aa8d0552e7344808da54cc21"
"checksum tokio-reactor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e00ec63bbec2c97ce1178cb0587b2c438b2f6b09d3ee54a33c45a9cf0d530810"
"checksum tokio-signal 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e8f46863230f9a05cf52d173721ec391b9c5782a2465f593029922b8782b9ffe"
"checksum tokio-tcp 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ec9b094851aadd2caf83ba3ad8e8c4ce65a42104f7b94d9e6550023f0407853f"
"checksum tokio-threadpool 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c3873a6d8d0b636e024e77b9a82eaab6739578a06189ecd0e731c7308fbc5d"
"checksum tokio-threadpool 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "24ab84f574027b0e875378f31575cf175360891919e93a3490f07e76e00e4efb"
"checksum tokio-timer 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "028b94314065b90f026a21826cffd62a4e40a92cda3e5c069cc7b02e5945f5e9"
"checksum tokio-udp 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "43eb534af6e8f37d43ab1b612660df14755c42bd003c5f8d2475ee78cc4600c0"
"checksum toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a0263c6c02c4db6c8f7681f9fd35e90de799ebd4cfdeab77a38f4ff6b3d8c0d9"
@@ -2727,12 +2731,12 @@ dependencies = [
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
"checksum unidecode 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "402bb19d8e03f1d1a7450e2bd613980869438e0666331be3e073089124aa1adc"
"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
"checksum url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f808aadd8cfec6ef90e4a14eb46f24511824d1ac596b9682703c87056c8678b7"
"checksum url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2a321979c09843d272956e73700d12c4e7d3d92b2ee112b31548aef0d4efc5a6"
"checksum utf-8 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f1262dfab4c30d5cb7c07026be00ee343a6cf5027fdc0104a9160f354e5db75c"
"checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122"
"checksum uuid 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e1436e58182935dcd9ce0add9ea0b558e8a87befe01c1a301e6020aeb0876363"
"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
"checksum version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6b772017e347561807c1aa192438c5fd74242a670a6cffacc40f2defd1dc069d"
"checksum version_check 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7716c242968ee87e5542f8021178248f267f295a5c4803beae8b8b7fd9bc6051"
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
"checksum walkdir 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "63636bd0eb3d00ccb8b9036381b526efac53caf112b7783b730ab3f8e44da369"
"checksum widestring 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7157704c2e12e3d2189c507b7482c52820a16dfa4465ba91add92f266667cadb"


+ 37
- 6
components/config/src/lib.rs View File

@@ -28,6 +28,40 @@ use theme::Theme;
static DEFAULT_BASE_URL: &'static str = "http://a-website.com";


#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(default)]
pub struct Taxonomy {
/// The name used in the URL, usually the plural
pub name: String,
/// If this is set, the list of individual taxonomy term page will be paginated
/// by this much
pub paginate: Option<usize>,
pub paginate_path: Option<String>,
/// Whether to generate a RSS feed only for each taxonomy term, defaults to false
pub rss: bool,
}

impl Taxonomy {
pub fn is_paginated(&self) -> bool {
if let Some(paginate_by) = self.paginate {
paginate_by > 0
} else {
false
}
}
}

impl Default for Taxonomy {
fn default() -> Taxonomy {
Taxonomy {
name: String::new(),
paginate: None,
paginate_path: None,
rss: false,
}
}
}

#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(default)]
pub struct Config {
@@ -56,10 +90,8 @@ pub struct Config {
pub generate_rss: bool,
/// The number of articles to include in the RSS feed. Defaults to 10_000
pub rss_limit: usize,
/// Whether to generate tags and individual tag pages if some pages have them. Defaults to true
pub generate_tags_pages: bool,
/// Whether to generate categories and individual tag categories if some pages have them. Defaults to true
pub generate_categories_pages: bool,

pub taxonomies: Vec<Taxonomy>,

/// Whether to compile the `sass` directory and output the css files into the static folder
pub compile_sass: bool,
@@ -191,8 +223,7 @@ impl Default for Config {
default_language: "en".to_string(),
generate_rss: false,
rss_limit: 10_000,
generate_tags_pages: true,
generate_categories_pages: true,
taxonomies: Vec::new(),
compile_sass: false,
build_search_index: false,
ignored_content: Vec::new(),


+ 2
- 3
components/content/src/page.rs View File

@@ -238,7 +238,7 @@ impl Default for Page {

impl ser::Serialize for Page {
fn serialize<S>(&self, serializer: S) -> StdResult<S::Ok, S::Error> where S: ser::Serializer {
let mut state = serializer.serialize_struct("page", 21)?;
let mut state = serializer.serialize_struct("page", 20)?;
state.serialize_field("content", &self.content)?;
state.serialize_field("title", &self.meta.title)?;
state.serialize_field("description", &self.meta.description)?;
@@ -258,8 +258,7 @@ impl ser::Serialize for Page {
state.serialize_field("components", &self.components)?;
state.serialize_field("permalink", &self.permalink)?;
state.serialize_field("summary", &self.summary)?;
state.serialize_field("tags", &self.meta.tags)?;
state.serialize_field("category", &self.meta.category)?;
state.serialize_field("taxonomies", &self.meta.taxonomies)?;
state.serialize_field("extra", &self.meta.extra)?;
let (word_count, reading_time) = get_reading_analytics(&self.raw_content);
state.serialize_field("word_count", &word_count)?;


+ 20
- 45
components/front_matter/src/page.rs View File

@@ -1,3 +1,4 @@
use std::collections::HashMap;
use std::result::{Result as StdResult};

use chrono::prelude::*;
@@ -80,10 +81,7 @@ pub struct PageFrontMatter {
/// otherwise is set after parsing front matter and sections
/// Can't be an empty string if present
pub path: Option<String>,
/// Tags, not to be confused with categories
pub tags: Option<Vec<String>>,
/// Only one category allowed. Can't be an empty string if present
pub category: Option<String>,
pub taxonomies: HashMap<String, Vec<String>>,
/// Integer to use to order content. Lowest is at the bottom, highest first
pub order: Option<usize>,
/// Integer to use to order content. Highest is at the bottom, lowest first
@@ -122,12 +120,6 @@ impl PageFrontMatter {
}
}

if let Some(ref category) = f.category {
if category == "" {
bail!("`category` can't be empty if present")
}
}

f.extra = match fix_toml_dates(f.extra) {
Value::Object(o) => o,
_ => unreachable!("Got something other than a table in page extra"),
@@ -155,13 +147,6 @@ impl PageFrontMatter {
pub fn weight(&self) -> usize {
self.weight.unwrap()
}

pub fn has_tags(&self) -> bool {
match self.tags {
Some(ref t) => !t.is_empty(),
None => false
}
}
}

impl Default for PageFrontMatter {
@@ -173,8 +158,7 @@ impl Default for PageFrontMatter {
draft: false,
slug: None,
path: None,
tags: None,
category: None,
taxonomies: HashMap::new(),
order: None,
weight: None,
aliases: Vec::new(),
@@ -211,21 +195,6 @@ mod tests {
assert_eq!(res.description.unwrap(), "hey there".to_string())
}

#[test]
fn can_parse_tags() {
let content = r#"
title = "Hello"
description = "hey there"
slug = "hello-world"
tags = ["rust", "html"]"#;
let res = PageFrontMatter::parse(content);
assert!(res.is_ok());
let res = res.unwrap();

assert_eq!(res.title.unwrap(), "Hello".to_string());
assert_eq!(res.slug.unwrap(), "hello-world".to_string());
assert_eq!(res.tags.unwrap(), ["rust".to_string(), "html".to_string()]);
}

#[test]
fn errors_with_invalid_front_matter() {
@@ -234,17 +203,6 @@ mod tests {
assert!(res.is_err());
}

#[test]
fn errors_on_non_string_tag() {
let content = r#"
title = "Hello"
description = "hey there"
slug = "hello-world"
tags = ["rust", 1]"#;
let res = PageFrontMatter::parse(content);
assert!(res.is_err());
}

#[test]
fn errors_on_present_but_empty_slug() {
let content = r#"
@@ -344,4 +302,21 @@ mod tests {
assert!(res.is_ok());
assert_eq!(res.unwrap().extra["something"]["some-date"], to_value("2002-14-01").unwrap());
}

#[test]
fn can_parse_taxonomies() {
let content = r#"
title = "Hello World"

[taxonomies]
tags = ["Rust", "JavaScript"]
categories = ["Dev"]
"#;
let res = PageFrontMatter::parse(content);
println!("{:?}", res);
assert!(res.is_ok());
let res2 = res.unwrap();
assert_eq!(res2.taxonomies["categories"], vec!["Dev"]);
assert_eq!(res2.taxonomies["tags"], vec!["Rust", "JavaScript"]);
}
}

+ 9
- 0
components/imageproc/src/lib.rs View File

@@ -328,6 +328,11 @@ impl Processor {
}

pub fn prune(&self) -> Result<()> {
// Do not create folders if they don't exist
if !self.resized_path.exists() {
return Ok(());
}

ufs::ensure_directory_exists(&self.resized_path)?;
let entries = fs::read_dir(&self.resized_path)?;
for entry in entries {
@@ -350,6 +355,10 @@ impl Processor {
}

pub fn do_process(&mut self) -> Result<()> {
if !self.img_ops.is_empty() {
ufs::ensure_directory_exists(&self.resized_path)?;
}

self.img_ops.par_iter().map(|(hash, op)| {
let target = self.resized_path.join(Self::op_filename(*hash, op.collision_id));
op.perform(&self.content_path, &target)


+ 1
- 0
components/pagination/Cargo.toml View File

@@ -12,6 +12,7 @@ errors = { path = "../errors" }
config = { path = "../config" }
content = { path = "../content" }
utils = { path = "../utils" }
taxonomies = { path = "../taxonomies" }

[dev-dependencies]
front_matter = { path = "../front_matter" }

+ 119
- 25
components/pagination/src/lib.rs View File

@@ -6,6 +6,7 @@ extern crate errors;
extern crate config;
extern crate content;
extern crate utils;
extern crate taxonomies;

#[cfg(test)]
extern crate front_matter;
@@ -18,6 +19,14 @@ use errors::{Result, ResultExt};
use config::Config;
use content::{Page, Section};
use utils::templates::render_template;
use taxonomies::{Taxonomy, TaxonomyItem};


#[derive(Clone, Debug, PartialEq)]
enum PaginationRoot<'a> {
Section(&'a Section),
Taxonomy(&'a Taxonomy),
}


/// A list of all the pages in the paginator with their index and links
@@ -63,22 +72,62 @@ pub struct Paginator<'a> {
pub pagers: Vec<Pager<'a>>,
/// How many content pages on a paginated page at max
paginate_by: usize,
/// The section struct we're building the paginator for
section: &'a Section,
/// The thing we are creating the paginator for: section or taxonomy
root: PaginationRoot<'a>,
// Those below can be obtained from the root but it would make the code more complex than needed
pub permalink: String,
path: String,
pub paginate_path: String,
is_index: bool,
}

impl<'a> Paginator<'a> {
/// Create a new paginator
/// Create a new paginator from a section
/// It will always at least create one pager (the first) even if there are no pages to paginate
pub fn new(all_pages: &'a [Page], section: &'a Section) -> Paginator<'a> {
pub fn from_section(all_pages: &'a [Page], section: &'a Section) -> Paginator<'a> {
let paginate_by = section.meta.paginate_by.unwrap();
let mut paginator = Paginator {
all_pages,
pagers: vec![],
paginate_by,
root: PaginationRoot::Section(section),
permalink: section.permalink.clone(),
path: section.path.clone(),
paginate_path: section.meta.paginate_path.clone(),
is_index: section.is_index(),
};

paginator.fill_pagers();
paginator
}

/// Create a new paginator from a taxonomy
/// It will always at least create one pager (the first) even if there are no pages to paginate
pub fn from_taxonomy(taxonomy: &'a Taxonomy, item: &'a TaxonomyItem) -> Paginator<'a> {
let paginate_by = taxonomy.kind.paginate.unwrap();
let mut paginator = Paginator {
all_pages: &item.pages,
pagers: vec![],
paginate_by,
root: PaginationRoot::Taxonomy(taxonomy),
permalink: item.permalink.clone(),
path: format!("{}/{}", taxonomy.kind.name, item.slug),
paginate_path: taxonomy.kind.paginate_path.clone().unwrap_or_else(|| "pages".to_string()),
is_index: false,
};

paginator.fill_pagers();
paginator
}

fn fill_pagers(&mut self) {
let mut pages = vec![];
let mut current_page = vec![];

for page in all_pages {
for page in self.all_pages {
current_page.push(page);

if current_page.len() == paginate_by {
if current_page.len() == self.paginate_by {
pages.push(current_page);
current_page = vec![];
}
@@ -91,17 +140,23 @@ impl<'a> Paginator<'a> {
for (index, page) in pages.iter().enumerate() {
// First page has no pagination path
if index == 0 {
pagers.push(Pager::new(1, page.clone(), section.permalink.clone(), section.path.clone()));
pagers.push(Pager::new(1, page.clone(), self.permalink.clone(), self.path.clone()));
continue;
}

let page_path = format!("{}/{}/", section.meta.paginate_path, index + 1);
let permalink = format!("{}{}", section.permalink, page_path);
let pager_path = if section.is_index() {
let page_path = format!("{}/{}/", self.paginate_path, index + 1);
let permalink = format!("{}{}", self.permalink, page_path);

let pager_path = if self.is_index {
page_path
} else {
format!("{}{}", section.path, page_path)
if self.path.ends_with("/") {
format!("{}{}", self.path, page_path)
} else {
format!("{}/{}", self.path, page_path)
}
};

pagers.push(Pager::new(
index + 1,
page.clone(),
@@ -112,15 +167,10 @@ impl<'a> Paginator<'a> {

// We always have the index one at least
if pagers.is_empty() {
pagers.push(Pager::new(1, vec![], section.permalink.clone(), section.path.clone()));
pagers.push(Pager::new(1, vec![], self.permalink.clone(), self.path.clone()));
}

Paginator {
all_pages,
pagers,
paginate_by,
section,
}
self.pagers = pagers;
}

pub fn build_paginator_context(&self, current_pager: &Pager) -> HashMap<&str, Value> {
@@ -130,7 +180,7 @@ impl<'a> Paginator<'a> {

// Global variables
paginator.insert("paginate_by", to_value(self.paginate_by).unwrap());
paginator.insert("first", to_value(&self.section.permalink).unwrap());
paginator.insert("first", to_value(&self.permalink).unwrap());
let last_pager = &self.pagers[self.pagers.len() - 1];
paginator.insert("last", to_value(&last_pager.permalink).unwrap());
paginator.insert(
@@ -163,13 +213,22 @@ impl<'a> Paginator<'a> {
pub fn render_pager(&self, pager: &Pager, config: &Config, tera: &Tera) -> Result<String> {
let mut context = Context::new();
context.add("config", &config);
context.add("section", self.section);
let template_name = match self.root {
PaginationRoot::Section(s) => {
context.add("section", &s);
s.get_template_name()
},
PaginationRoot::Taxonomy(t) => {
context.add("taxonomy", &t.kind);
format!("{}/single.html", t.kind.name)
},
};
context.add("current_url", &pager.permalink);
context.add("current_path", &pager.path);
context.add("paginator", &self.build_paginator_context(pager));

render_template(&self.section.get_template_name(), tera, &context, &config.theme)
.chain_err(|| format!("Failed to render pager {} of section '{}'", pager.index, self.section.file.path.display()))
render_template(&template_name, tera, &context, &config.theme)
.chain_err(|| format!("Failed to render pager {}", pager.index))
}
}

@@ -179,6 +238,8 @@ mod tests {

use front_matter::SectionFrontMatter;
use content::{Page, Section};
use config::{Taxonomy as TaxonomyConfig};
use taxonomies::{Taxonomy, TaxonomyItem};

use super::Paginator;

@@ -205,7 +266,7 @@ mod tests {
Page::default(),
];
let section = create_section(false);
let paginator = Paginator::new(pages.as_slice(), &section);
let paginator = Paginator::from_section(pages.as_slice(), &section);
assert_eq!(paginator.pagers.len(), 2);

assert_eq!(paginator.pagers[0].index, 1);
@@ -227,7 +288,7 @@ mod tests {
Page::default(),
];
let section = create_section(true);
let paginator = Paginator::new(pages.as_slice(), &section);
let paginator = Paginator::from_section(pages.as_slice(), &section);
assert_eq!(paginator.pagers.len(), 2);

assert_eq!(paginator.pagers[0].index, 1);
@@ -249,7 +310,7 @@ mod tests {
Page::default(),
];
let section = create_section(false);
let paginator = Paginator::new(pages.as_slice(), &section);
let paginator = Paginator::from_section(pages.as_slice(), &section);
assert_eq!(paginator.pagers.len(), 2);

let context = paginator.build_paginator_context(&paginator.pagers[0]);
@@ -268,4 +329,37 @@ mod tests {
assert_eq!(context["previous"], to_value("https://vincent.is/posts/").unwrap());
assert_eq!(context["current_index"], to_value(2).unwrap());
}

#[test]
fn test_can_create_paginator_for_taxonomy() {
let pages = vec![
Page::default(),
Page::default(),
Page::default(),
];
let taxonomy_def = TaxonomyConfig {
name: "tags".to_string(),
paginate: Some(2),
..TaxonomyConfig::default()
};
let taxonomy_item = TaxonomyItem {
name: "Something".to_string(),
slug: "something".to_string(),
permalink: "https://vincent.is/tags/something/".to_string(),
pages,
};
let taxonomy = Taxonomy {kind: taxonomy_def, items: vec![taxonomy_item.clone()]};
let paginator = Paginator::from_taxonomy(&taxonomy, &taxonomy_item);
assert_eq!(paginator.pagers.len(), 2);

assert_eq!(paginator.pagers[0].index, 1);
assert_eq!(paginator.pagers[0].pages.len(), 2);
assert_eq!(paginator.pagers[0].permalink, "https://vincent.is/tags/something/");
assert_eq!(paginator.pagers[0].path, "tags/something");

assert_eq!(paginator.pagers[1].index, 2);
assert_eq!(paginator.pagers[1].pages.len(), 1);
assert_eq!(paginator.pagers[1].permalink, "https://vincent.is/tags/something/pages/2/");
assert_eq!(paginator.pagers[1].path, "tags/something/pages/2/");
}
}

+ 24
- 45
components/rebuild/src/lib.rs View File

@@ -26,10 +26,8 @@ pub fn find_parent_section<'a>(site: &'a Site, page: &Page) -> Option<&'a Sectio

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum PageChangesNeeded {
/// Editing `tags`
Tags,
/// Editing `categories`
Categories,
/// Editing `taxonomies`
Taxonomies,
/// Editing `date`, `order` or `weight`
Sort,
/// Editing anything causes a re-render of the page
@@ -85,12 +83,8 @@ fn find_section_front_matter_changes(current: &SectionFrontMatter, new: &Section
fn find_page_front_matter_changes(current: &PageFrontMatter, other: &PageFrontMatter) -> Vec<PageChangesNeeded> {
let mut changes_needed = vec![];

if current.tags != other.tags {
changes_needed.push(PageChangesNeeded::Tags);
}

if current.category != other.category {
changes_needed.push(PageChangesNeeded::Categories);
if current.taxonomies != other.taxonomies {
changes_needed.push(PageChangesNeeded::Taxonomies);
}

if current.date != other.date || current.order != other.order || current.weight != other.weight {
@@ -117,8 +111,8 @@ fn delete_element(site: &mut Site, path: &Path, is_section: bool) -> Result<()>
if let Some(p) = site.pages.remove(path) {
site.permalinks.remove(&p.file.relative);

if p.meta.has_tags() || p.meta.category.is_some() {
site.populate_tags_and_categories();
if !p.meta.taxonomies.is_empty() {
site.populate_taxonomies();
}

// if there is a parent section, we will need to re-render it
@@ -208,26 +202,14 @@ fn handle_page_editing(site: &mut Site, path: &Path) -> Result<()> {
}

// Front matter changed
let mut taxonomies_populated = false;
let mut sections_populated = false;
for changes in find_page_front_matter_changes(&site.pages[path].meta, &prev.meta) {
// Sort always comes first if present so the rendering will be fine
match changes {
PageChangesNeeded::Tags => {
if !taxonomies_populated {
site.populate_tags_and_categories();
taxonomies_populated = true;
}
site.register_tera_global_fns();
site.render_tags()?;
},
PageChangesNeeded::Categories => {
if !taxonomies_populated {
site.populate_tags_and_categories();
taxonomies_populated = true;
}
PageChangesNeeded::Taxonomies => {
site.populate_taxonomies();
site.register_tera_global_fns();
site.render_categories()?;
site.render_taxonomies()?;
},
PageChangesNeeded::Sort => {
let section_path = match find_parent_section(site, &site.pages[path]) {
@@ -258,7 +240,7 @@ fn handle_page_editing(site: &mut Site, path: &Path) -> Result<()> {
// It's a new page!
None => {
site.populate_sections();
site.populate_tags_and_categories();
site.populate_taxonomies();
site.register_tera_global_fns();
// No need to optimise that yet, we can revisit if it becomes an issue
site.build()
@@ -322,10 +304,9 @@ pub fn after_template_change(site: &mut Site, path: &Path) -> Result<()> {

match filename {
"sitemap.xml" => site.render_sitemap(),
"rss.xml" => site.render_rss_feed(),
"rss.xml" => site.render_rss_feed(None, None),
"robots.txt" => site.render_robots(),
"categories.html" | "category.html" => site.render_categories(),
"tags.html" | "tag.html" => site.render_tags(),
"single.html" | "list.html" => site.render_taxonomies(),
"page.html" => {
site.render_sections()?;
site.render_orphan_pages()
@@ -345,8 +326,7 @@ pub fn after_template_change(site: &mut Site, path: &Path) -> Result<()> {
site.populate_sections();
site.render_sections()?;
site.render_orphan_pages()?;
site.render_categories()?;
site.render_tags()
site.render_taxonomies()
},
}
}
@@ -354,6 +334,8 @@ pub fn after_template_change(site: &mut Site, path: &Path) -> Result<()> {

#[cfg(test)]
mod tests {
use std::collections::HashMap;

use front_matter::{PageFrontMatter, SectionFrontMatter, SortBy};
use super::{
find_page_front_matter_changes, find_section_front_matter_changes,
@@ -361,24 +343,21 @@ mod tests {
};

#[test]
fn can_find_tag_changes_in_page_frontmatter() {
let new = PageFrontMatter { tags: Some(vec!["a tag".to_string()]), ..PageFrontMatter::default() };
fn can_find_taxonomy_changes_in_page_frontmatter() {
let mut taxonomies = HashMap::new();
taxonomies.insert("tags".to_string(), vec!["a tag".to_string()]);
let new = PageFrontMatter { taxonomies, ..PageFrontMatter::default() };
let changes = find_page_front_matter_changes(&PageFrontMatter::default(), &new);
assert_eq!(changes, vec![PageChangesNeeded::Tags, PageChangesNeeded::Render]);
}

#[test]
fn can_find_category_changes_in_page_frontmatter() {
let current = PageFrontMatter { category: Some("a category".to_string()), ..PageFrontMatter::default() };
let changes = find_page_front_matter_changes(&current, &PageFrontMatter::default());
assert_eq!(changes, vec![PageChangesNeeded::Categories, PageChangesNeeded::Render]);
assert_eq!(changes, vec![PageChangesNeeded::Taxonomies, PageChangesNeeded::Render]);
}

#[test]
fn can_find_multiple_changes_in_page_frontmatter() {
let current = PageFrontMatter { category: Some("a category".to_string()), order: Some(1), ..PageFrontMatter::default() };
let mut taxonomies = HashMap::new();
taxonomies.insert("categories".to_string(), vec!["a category".to_string()]);
let current = PageFrontMatter { taxonomies, order: Some(1), ..PageFrontMatter::default() };
let changes = find_page_front_matter_changes(&current, &PageFrontMatter::default());
assert_eq!(changes, vec![PageChangesNeeded::Categories, PageChangesNeeded::Sort, PageChangesNeeded::Render]);
assert_eq!(changes, vec![PageChangesNeeded::Taxonomies, PageChangesNeeded::Sort, PageChangesNeeded::Render]);
}

#[test]


+ 77
- 81
components/site/src/lib.rs View File

@@ -39,7 +39,7 @@ use utils::net::get_available_port;
use content::{Page, Section, populate_previous_and_next_pages, sort_pages};
use templates::{GUTENBERG_TERA, global_fns, render_redirect_template};
use front_matter::{SortBy, InsertAnchor};
use taxonomies::Taxonomy;
use taxonomies::{Taxonomy, find_taxonomies};
use pagination::Paginator;

use rayon::prelude::*;
@@ -74,8 +74,7 @@ pub struct Site {
pub output_path: PathBuf,
content_path: PathBuf,
pub static_path: PathBuf,
pub tags: Option<Taxonomy>,
pub categories: Option<Taxonomy>,
pub taxonomies: Vec<Taxonomy>,
/// A map of all .md files (section and pages) and their permalink
/// We need that if there are relative links in the content that need to be resolved
pub permalinks: HashMap<String, String>,
@@ -128,8 +127,7 @@ impl Site {
output_path: path.join("public"),
content_path,
static_path,
tags: None,
categories: None,
taxonomies: Vec::new(),
permalinks: HashMap::new(),
};

@@ -248,7 +246,7 @@ impl Site {
self.register_early_global_fns();
self.render_markdown()?;
self.populate_sections();
self.populate_tags_and_categories();
self.populate_taxonomies();
self.register_tera_global_fns();

Ok(())
@@ -302,7 +300,7 @@ impl Site {
self.tera.register_global_function("get_section", global_fns::make_get_section(&self.sections));
self.tera.register_global_function(
"get_taxonomy_url",
global_fns::make_get_taxonomy_url(self.tags.clone(), self.categories.clone())
global_fns::make_get_taxonomy(self.taxonomies.clone())
);
}

@@ -409,15 +407,12 @@ impl Site {
}

/// Find all the tags and categories if it's asked in the config
pub fn populate_tags_and_categories(&mut self) {
let generate_tags_pages = self.config.generate_tags_pages;
let generate_categories_pages = self.config.generate_categories_pages;
if !generate_tags_pages && !generate_categories_pages {
pub fn populate_taxonomies(&mut self) {
if self.config.taxonomies.is_empty() {
return;
}

// TODO: can we pass a reference?
let (tags, categories) = Taxonomy::find_tags_and_categories(
self.taxonomies = find_taxonomies(
&self.config,
self.pages
.values()
@@ -426,12 +421,6 @@ impl Site {
.collect::<Vec<_>>()
.as_slice()
);
if generate_tags_pages {
self.tags = Some(tags);
}
if generate_categories_pages {
self.categories = Some(categories);
}
}

/// Inject live reload script tag if in live reload mode
@@ -524,14 +513,11 @@ impl Site {
self.render_orphan_pages()?;
self.render_sitemap()?;
if self.config.generate_rss {
self.render_rss_feed()?;
self.render_rss_feed(None, None)?;
}
self.render_404()?;
self.render_robots()?;
// `render_categories` and `render_tags` will check whether the config allows
// them to render or not
self.render_categories()?;
self.render_tags()?;
self.render_taxonomies()?;

if let Some(ref theme) = self.config.theme {
let theme_path = self.base_path.join("themes").join(theme);
@@ -681,19 +667,11 @@ impl Site {
)
}

/// Renders all categories and the single category pages if there are some
pub fn render_categories(&self) -> Result<()> {
if let Some(ref categories) = self.categories {
self.render_taxonomy(categories)?;
}

Ok(())
}

/// Renders all tags and the single tag pages if there are some
pub fn render_tags(&self) -> Result<()> {
if let Some(ref tags) = self.tags {
self.render_taxonomy(tags)?;
/// Renders all taxonomies with at least one non-draft post
pub fn render_taxonomies(&self) -> Result<()> {
// TODO: make parallel?
for taxonomy in &self.taxonomies {
self.render_taxonomy(taxonomy)?;
}

Ok(())
@@ -705,8 +683,8 @@ impl Site {
}

ensure_directory_exists(&self.output_path)?;
let output_path = self.output_path.join(&taxonomy.get_list_name());
let list_output = taxonomy.render_list(&self.tera, &self.config)?;
let output_path = self.output_path.join(&taxonomy.kind.name);
let list_output = taxonomy.render_all_terms(&self.tera, &self.config)?;
create_directory(&output_path)?;
create_file(&output_path.join("index.html"), &self.inject_livereload(list_output))?;

@@ -714,12 +692,25 @@ impl Site {
.items
.par_iter()
.map(|item| {
let single_output = taxonomy.render_single_item(item, &self.tera, &self.config)?;
create_directory(&output_path.join(&item.slug))?;
create_file(
&output_path.join(&item.slug).join("index.html"),
&self.inject_livereload(single_output)
)
if taxonomy.kind.rss {
// TODO: can we get rid of `clone()`?
self.render_rss_feed(
Some(item.pages.clone()),
Some(&PathBuf::from(format!("{}/{}", taxonomy.kind.name, item.slug)))
)?;
}

if taxonomy.kind.is_paginated() {
self.render_paginated(&output_path, &Paginator::from_taxonomy(&taxonomy, item))
} else {
let single_output = taxonomy.render_term(item, &self.tera, &self.config)?;
let path = output_path.join(&item.slug);
create_directory(&path)?;
create_file(
&path.join("index.html"),
&self.inject_livereload(single_output),
)
}
})
.fold(|| Ok(()), Result::and)
.reduce(|| Ok(()), Result::and)
@@ -752,31 +743,19 @@ impl Site {
sections.sort_by(|a, b| a.permalink.cmp(&b.permalink));
context.add("sections", &sections);

let mut categories = vec![];
if let Some(ref c) = self.categories {
let name = c.get_list_name();
categories.push(SitemapEntry::new(self.config.make_permalink(&name), None));
for item in &c.items {
categories.push(
SitemapEntry::new(self.config.make_permalink(&format!("{}/{}", &name, item.slug)), None),
);
let mut taxonomies = vec![];
for taxonomy in &self.taxonomies {
let name = &taxonomy.kind.name;
let mut terms = vec![];
terms.push(SitemapEntry::new(self.config.make_permalink(name), None));
for item in &taxonomy.items {
terms.push(SitemapEntry::new(self.config.make_permalink(&format!("{}/{}", &name, item.slug)), None));
}
terms.sort_by(|a, b| a.permalink.cmp(&b.permalink));
taxonomies.push(terms);
}
categories.sort_by(|a, b| a.permalink.cmp(&b.permalink));
context.add("categories", &categories);
context.add("taxonomies", &taxonomies);

let mut tags = vec![];
if let Some(ref t) = self.tags {
let name = t.get_list_name();
tags.push(SitemapEntry::new(self.config.make_permalink(&name), None));
for item in &t.items {
tags.push(
SitemapEntry::new(self.config.make_permalink(&format!("{}/{}", &name, item.slug)), None),
);
}
}
tags.sort_by(|a, b| a.permalink.cmp(&b.permalink));
context.add("tags", &tags);
context.add("config", &self.config);

let sitemap = &render_template("sitemap.xml", &self.tera, &context, &self.config.theme)?;
@@ -786,14 +765,20 @@ impl Site {
Ok(())
}

pub fn render_rss_feed(&self) -> Result<()> {
/// Renders a RSS feed for the given path and at the given path
/// If both arguments are `None`, it will render only the RSS feed for the whole
/// site at the root folder.
pub fn render_rss_feed(&self, all_pages: Option<Vec<Page>>, base_path: Option<&PathBuf>) -> Result<()> {
ensure_directory_exists(&self.output_path)?;

let mut context = Context::new();
let pages = self.pages.values()
let pages = all_pages
// TODO: avoid that cloned().
// It requires having `sort_pages` take references of Page
.unwrap_or_else(|| self.pages.values().cloned().collect::<Vec<_>>())
.into_iter()
.filter(|p| p.meta.date.is_some() && !p.is_draft())
.cloned()
.collect::<Vec<Page>>();
.collect::<Vec<_>>();

// Don't generate a RSS feed if none of the pages has a date
if pages.is_empty() {
@@ -802,20 +787,32 @@ impl Site {

let (sorted_pages, _) = sort_pages(pages, SortBy::Date);
context.add("last_build_date", &sorted_pages[0].meta.date.clone().map(|d| d.to_string()));
// limit to the last n elements)
// limit to the last n elements
context.add("pages", &sorted_pages.iter().take(self.config.rss_limit).collect::<Vec<_>>());
context.add("config", &self.config);

let rss_feed_url = if self.config.base_url.ends_with('/') {
format!("{}{}", self.config.base_url, "rss.xml")
let rss_feed_url = if let Some(ref base) = base_path {
self.config.make_permalink(&base.join("rss.xml").to_string_lossy())
} else {
format!("{}/{}", self.config.base_url, "rss.xml")
self.config.make_permalink("rss.xml")
};

context.add("feed_url", &rss_feed_url);

let feed = &render_template("rss.xml", &self.tera, &context, &self.config.theme)?;

create_file(&self.output_path.join("rss.xml"), feed)?;
if let Some(ref base) = base_path {
let mut output_path = self.output_path.clone().to_path_buf();
for component in base.components() {
output_path.push(component);
if !output_path.exists() {
create_directory(&output_path)?;
}
}
create_file(&output_path.join("rss.xml"), feed)?;
} else {
create_file(&self.output_path.join("rss.xml"), feed)?;
}

Ok(())
}
@@ -854,7 +851,7 @@ impl Site {
}

if section.meta.is_paginated() {
self.render_paginated(&output_path, section)?;
self.render_paginated(&output_path, &Paginator::from_section(&section.pages, section))?;
} else {
let output = section.render_html(&self.tera, &self.config)?;
create_file(&output_path.join("index.html"), &self.inject_livereload(output))?;
@@ -894,11 +891,10 @@ impl Site {
}

/// Renders a list of pages when the section/index is wanting pagination.
pub fn render_paginated(&self, output_path: &Path, section: &Section) -> Result<()> {
pub fn render_paginated(&self, output_path: &Path, paginator: &Paginator) -> Result<()> {
ensure_directory_exists(&self.output_path)?;

let paginator = Paginator::new(&section.pages, section);
let folder_path = output_path.join(&section.meta.paginate_path);
let folder_path = output_path.join(&paginator.paginate_path);
create_directory(&folder_path)?;

paginator
@@ -913,7 +909,7 @@ impl Site {
create_file(&page_path.join("index.html"), &self.inject_livereload(output))?;
} else {
create_file(&output_path.join("index.html"), &self.inject_livereload(output))?;
create_file(&page_path.join("index.html"), &render_redirect_template(&section.permalink, &self.tera)?)?;
create_file(&page_path.join("index.html"), &render_redirect_template(&paginator.permalink, &self.tera)?)?;
}
Ok(())
})


+ 10
- 61
components/site/tests/site.rs View File

@@ -1,6 +1,7 @@
extern crate site;
extern crate tempfile;

use std::collections::HashMap;
use std::env;
use std::path::Path;
use std::fs::File;
@@ -209,28 +210,27 @@ fn can_build_site_with_live_reload() {
}

#[test]
fn can_build_site_with_categories() {
fn can_build_site_with_taxonomies() {
let mut path = env::current_dir().unwrap().parent().unwrap().parent().unwrap().to_path_buf();
path.push("test_site");
let mut site = Site::new(&path, "config.toml").unwrap();
site.config.generate_categories_pages = true;
site.load().unwrap();

for (i, page) in site.pages.values_mut().enumerate() {
page.meta.category = if i % 2 == 0 {
Some("A".to_string())
} else {
Some("B".to_string())
page.meta.taxonomies = {
let mut taxonomies = HashMap::new();
taxonomies.insert("categories".to_string(), vec![if i % 2 == 0 { "A" } else { "B" }.to_string()]);
taxonomies
};
}
site.populate_tags_and_categories();
site.populate_taxonomies();
let tmp_dir = tempdir().expect("create temp dir");
let public = &tmp_dir.path().join("public");
site.set_output_path(&public);
site.build().unwrap();

assert!(Path::new(&public).exists());
assert_eq!(site.categories.unwrap().len(), 2);
assert_eq!(site.taxonomies.len(), 1);

assert!(file_exists!(public, "index.html"));
assert!(file_exists!(public, "sitemap.xml"));
@@ -246,12 +246,13 @@ fn can_build_site_with_categories() {
assert!(file_exists!(public, "posts/tutorials/index.html"));
assert!(file_exists!(public, "posts/tutorials/devops/index.html"));
assert!(file_exists!(public, "posts/tutorials/programming/index.html"));
// TODO: add assertion for syntax highlighting

// Categories are there
assert!(file_exists!(public, "categories/index.html"));
assert!(file_exists!(public, "categories/a/index.html"));
assert!(file_exists!(public, "categories/b/index.html"));
assert!(file_exists!(public, "categories/a/rss.xml"));
assert!(file_contains!(public, "categories/a/rss.xml", "https://replace-this-with-your-url.com/categories/a/rss.xml"));
// Extending from a theme works
assert!(file_contains!(public, "categories/a/index.html", "EXTENDED"));
// Tags aren't
@@ -262,58 +263,6 @@ fn can_build_site_with_categories() {
assert!(file_contains!(public, "sitemap.xml", "<loc>https://replace-this-with-your-url.com/categories/a/</loc>"));
}

#[test]
fn can_build_site_with_tags() {
let mut path = env::current_dir().unwrap().parent().unwrap().parent().unwrap().to_path_buf();
path.push("test_site");
let mut site = Site::new(&path, "config.toml").unwrap();
site.config.generate_tags_pages = true;
site.load().unwrap();

for (i, page) in site.pages.values_mut().enumerate() {
page.meta.tags = if i % 2 == 0 {
Some(vec!["tag1".to_string(), "tag2".to_string()])
} else {
Some(vec!["tag with space".to_string()])
};
}
site.populate_tags_and_categories();

let tmp_dir = tempdir().expect("create temp dir");
let public = &tmp_dir.path().join("public");
site.set_output_path(&public);
site.build().unwrap();

assert!(Path::new(&public).exists());
assert_eq!(site.tags.unwrap().len(), 3);

assert!(file_exists!(public, "index.html"));
assert!(file_exists!(public, "sitemap.xml"));
assert!(file_exists!(public, "robots.txt"));
assert!(file_exists!(public, "a-fixed-url/index.html"));
assert!(file_exists!(public, "posts/python/index.html"));
assert!(file_exists!(public, "posts/tutorials/devops/nix/index.html"));
assert!(file_exists!(public, "posts/with-assets/index.html"));

// Sections
assert!(file_exists!(public, "posts/index.html"));
assert!(file_exists!(public, "posts/tutorials/index.html"));
assert!(file_exists!(public, "posts/tutorials/devops/index.html"));
assert!(file_exists!(public, "posts/tutorials/programming/index.html"));
// TODO: add assertion for syntax highlighting

// Tags are there
assert!(file_exists!(public, "tags/index.html"));
assert!(file_exists!(public, "tags/tag1/index.html"));
assert!(file_exists!(public, "tags/tag2/index.html"));
assert!(file_exists!(public, "tags/tag-with-space/index.html"));
// Categories aren't
assert_eq!(file_exists!(public, "categories/index.html"), false);
// Tags are in the sitemap
assert!(file_contains!(public, "sitemap.xml", "<loc>https://replace-this-with-your-url.com/tags/</loc>"));
assert!(file_contains!(public, "sitemap.xml", "<loc>https://replace-this-with-your-url.com/tags/tag-with-space/</loc>"));
}

#[test]
fn can_build_site_and_insert_anchor_links() {
let mut path = env::current_dir().unwrap().parent().unwrap().parent().unwrap().to_path_buf();


+ 98
- 81
components/taxonomies/src/lib.rs View File

@@ -14,19 +14,13 @@ use std::collections::HashMap;
use slug::slugify;
use tera::{Context, Tera};

use config::Config;
use config::{Config, Taxonomy as TaxonomyConfig};
use errors::{Result, ResultExt};
use content::{Page, sort_pages};
use front_matter::SortBy;
use utils::templates::render_template;


#[derive(Debug, Copy, Clone, PartialEq)]
pub enum TaxonomyKind {
Tags,
Categories,
}

/// A tag or category
#[derive(Debug, Clone, Serialize, PartialEq)]
pub struct TaxonomyItem {
@@ -37,15 +31,14 @@ pub struct TaxonomyItem {
}

impl TaxonomyItem {
pub fn new(name: &str, kind: TaxonomyKind, config: &Config, pages: Vec<Page>) -> TaxonomyItem {
pub fn new(name: &str, path: &str, config: &Config, pages: Vec<Page>) -> TaxonomyItem {
// Taxonomy are almost always used for blogs so we filter by dates
// and it's not like we can sort things across sections by anything other
// than dates
let (mut pages, ignored_pages) = sort_pages(pages, SortBy::Date);
let slug = slugify(name);
let permalink = {
let kind_path = if kind == TaxonomyKind::Tags { "tags" } else { "categories" };
config.make_permalink(&format!("/{}/{}", kind_path, slug))
config.make_permalink(&format!("/{}/{}", path, slug))
};

// We still append pages without dates at the end
@@ -61,49 +54,19 @@ impl TaxonomyItem {
}

/// All the tags or categories
#[derive(Debug, Clone, PartialEq)]
#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct Taxonomy {
pub kind: TaxonomyKind,
pub kind: TaxonomyConfig,
// this vec is sorted by the count of item
pub items: Vec<TaxonomyItem>,
}

impl Taxonomy {
pub fn find_tags_and_categories(config: &Config, all_pages: &[Page]) -> (Taxonomy, Taxonomy) {
let mut tags = HashMap::new();
let mut categories = HashMap::new();

// Find all the tags/categories first
for page in all_pages {
if let Some(ref category) = page.meta.category {
categories
.entry(category.to_string())
.or_insert_with(|| vec![])
.push(page.clone());
}

if let Some(ref t) = page.meta.tags {
for tag in t {
tags
.entry(tag.to_string())
.or_insert_with(|| vec![])
.push(page.clone());
}
}
}

// Then make TaxonomyItem out of them, after sorting it
let tags_taxonomy = Taxonomy::new(TaxonomyKind::Tags, config, tags);
let categories_taxonomy = Taxonomy::new(TaxonomyKind::Categories, config, categories);

(tags_taxonomy, categories_taxonomy)
}

fn new(kind: TaxonomyKind, config: &Config, items: HashMap<String, Vec<Page>>) -> Taxonomy {
fn new(kind: TaxonomyConfig, config: &Config, items: HashMap<String, Vec<Page>>) -> Taxonomy {
let mut sorted_items = vec![];
for (name, pages) in &items {
for (name, pages) in items {
sorted_items.push(
TaxonomyItem::new(name, kind, config, pages.clone())
TaxonomyItem::new(&name, &kind.name, config, pages)
);
}
sorted_items.sort_by(|a, b| a.name.cmp(&b.name));
@@ -122,69 +85,123 @@ impl Taxonomy {
self.len() == 0
}

pub fn get_single_item_name(&self) -> String {
match self.kind {
TaxonomyKind::Tags => "tag".to_string(),
TaxonomyKind::Categories => "category".to_string(),
}
}
pub fn render_term(&self, item: &TaxonomyItem, tera: &Tera, config: &Config) -> Result<String> {
let mut context = Context::new();
context.add("config", config);
context.add("term", item);
context.add("taxonomy", &self.kind);
context.add("current_url", &config.make_permalink(&format!("{}/{}", self.kind.name, item.slug)));
context.add("current_path", &format!("/{}/{}", self.kind.name, item.slug));

pub fn get_list_name(&self) -> String {
match self.kind {
TaxonomyKind::Tags => "tags".to_string(),
TaxonomyKind::Categories => "categories".to_string(),
}
render_template(&format!("{}/single.html", self.kind.name), tera, &context, &config.theme)
.chain_err(|| format!("Failed to render single term {} page.", self.kind.name))
}

pub fn render_single_item(&self, item: &TaxonomyItem, tera: &Tera, config: &Config) -> Result<String> {
let name = self.get_single_item_name();
pub fn render_all_terms(&self, tera: &Tera, config: &Config) -> Result<String> {
let mut context = Context::new();
context.add("config", config);
context.add(&name, item);
context.add("current_url", &config.make_permalink(&format!("{}/{}", name, item.slug)));
context.add("current_path", &format!("/{}/{}", name, item.slug));
context.add("terms", &self.items);
context.add("taxonomy", &self.kind);
context.add("current_url", &config.make_permalink(&self.kind.name));
context.add("current_path", &self.kind.name);

render_template(&format!("{}.html", name), tera, &context, &config.theme)
.chain_err(|| format!("Failed to render {} page.", name))
render_template(&format!("{}/list.html", self.kind.name), tera, &context, &config.theme)
.chain_err(|| format!("Failed to render a list of {} page.", self.kind.name))
}
}

pub fn render_list(&self, tera: &Tera, config: &Config) -> Result<String> {
let name = self.get_list_name();
let mut context = Context::new();
context.add("config", config);
context.add(&name, &self.items);
context.add("current_url", &config.make_permalink(&name));
context.add("current_path", &name);
pub fn find_taxonomies(config: &Config, all_pages: &[Page]) -> Vec<Taxonomy> {
let taxonomies_def = {
let mut m = HashMap::new();
for t in &config.taxonomies {
m.insert(t.name.clone(), t);
}
m
};
let mut all_taxonomies = HashMap::new();

// Find all the taxonomies first
for page in all_pages {
for (name, val) in &page.meta.taxonomies {
if taxonomies_def.contains_key(name) {
all_taxonomies
.entry(name)
.or_insert_with(|| HashMap::new());

for v in val {
all_taxonomies.get_mut(name)
.unwrap()
.entry(v.to_string())
.or_insert_with(|| vec![])
.push(page.clone());
}
} else {
// TODO: bail with error
}
}
}

let mut taxonomies = vec![];

render_template(&format!("{}.html", name), tera, &context, &config.theme)
.chain_err(|| format!("Failed to render {} page.", name))
for (name, taxo) in all_taxonomies {
taxonomies.push(Taxonomy::new(taxonomies_def[name].clone(), config, taxo));
}

taxonomies
}


#[cfg(test)]
mod tests {
use super::*;
use std::collections::HashMap;

use config::Config;
use config::{Config, Taxonomy};
use content::Page;

#[test]
fn can_make_taxonomies() {
let config = Config::default();
let mut config = Config::default();
config.taxonomies = vec![
Taxonomy {name: "categories".to_string(), ..Taxonomy::default()},
Taxonomy {name: "tags".to_string(), ..Taxonomy::default()},
Taxonomy {name: "authors".to_string(), ..Taxonomy::default()},
];
let mut page1 = Page::default();
page1.meta.tags = Some(vec!["rust".to_string(), "db".to_string()]);
page1.meta.category = Some("Programming tutorials".to_string());
let mut taxo_page1 = HashMap::new();
taxo_page1.insert("tags".to_string(), vec!["rust".to_string(), "db".to_string()]);
taxo_page1.insert("categories".to_string(), vec!["Programming tutorials".to_string()]);
page1.meta.taxonomies = taxo_page1;
let mut page2 = Page::default();
page2.meta.tags = Some(vec!["rust".to_string(), "js".to_string()]);
page2.meta.category = Some("Other".to_string());
let mut taxo_page2 = HashMap::new();
taxo_page2.insert("tags".to_string(), vec!["rust".to_string(), "js".to_string()]);
taxo_page2.insert("categories".to_string(), vec!["Other".to_string()]);
page2.meta.taxonomies = taxo_page2;
let mut page3 = Page::default();
page3.meta.tags = Some(vec!["js".to_string()]);
let mut taxo_page3 = HashMap::new();
taxo_page3.insert("tags".to_string(), vec!["js".to_string()]);
taxo_page3.insert("authors".to_string(), vec!["Vincent Prouillet".to_string()]);
page3.meta.taxonomies = taxo_page3;
let pages = vec![page1, page2, page3];

let (tags, categories) = Taxonomy::find_tags_and_categories(&config, &pages);

let taxonomies = find_taxonomies(&config, &pages);
let (tags, categories, authors) = {
let mut t = None;
let mut c = None;
let mut a = None;
for x in taxonomies {
match x.kind.name.as_ref() {
"tags" => t = Some(x),
"categories" => c = Some(x),
"authors" => a = Some(x),
_ => unreachable!(),
}
}
(t.unwrap(), c.unwrap(), a.unwrap())
};
assert_eq!(tags.items.len(), 3);
assert_eq!(categories.items.len(), 2);
assert_eq!(authors.items.len(), 1);

assert_eq!(tags.items[0].name, "db");
assert_eq!(tags.items[0].slug, "db");


+ 4
- 4
components/templates/src/builtins/rss.xml View File

@@ -1,18 +1,18 @@
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
<channel>
<title>{{ config.title }}</title>
<link>{{ config.base_url }}</link>
<link>{{ config.base_url | safe }}</link>
<description>{{ config.description }}</description>
<generator>Gutenberg</generator>
<language>{{ config.default_language }}</language>
<atom:link href="{{ feed_url }}" rel="self" type="application/rss+xml"/>
<atom:link href="{{ feed_url | safe }}" rel="self" type="application/rss+xml"/>
<lastBuildDate>{{ last_build_date | date(format="%a, %d %b %Y %H:%M:%S %z") }}</lastBuildDate>
{% for page in pages %}
<item>
<title>{{ page.title }}</title>
<pubDate>{{ page.date | date(format="%a, %d %b %Y %H:%M:%S %z") }}</pubDate>
<link>{{ page.permalink }}</link>
<guid>{{ page.permalink }}</guid>
<link>{{ page.permalink | safe }}</link>
<guid>{{ page.permalink | safe }}</guid>
<description>{% if page.summary %}{{ page.summary }}{% else %}{{ page.content }}{% endif %}</description>
</item>
{% endfor %}


+ 4
- 7
components/templates/src/builtins/sitemap.xml View File

@@ -12,14 +12,11 @@
<loc>{{ section.permalink | safe }}</loc>
</url>
{% endfor %}
{% for category in categories %}
{% for taxonomy in taxonomies %}
{% for entry in taxonomy %}
<url>
<loc>{{ category.permalink | safe }}</loc>
</url>
{% endfor %}
{% for tag in tags %}
<url>
<loc>{{ tag.permalink | safe }}</loc>
<loc>{{ entry.permalink | safe }}</loc>
</url>
{% endfor %}
{% endfor %}
</urlset>

+ 22
- 34
components/templates/src/global_fns.rs View File

@@ -134,36 +134,25 @@ pub fn make_get_url(permalinks: HashMap<String, String>, config: Config) -> Glob
})
}

pub fn make_get_taxonomy_url(tags: Option<Taxonomy>, categories: Option<Taxonomy>) -> GlobalFn {
pub fn make_get_taxonomy(all_taxonomies: Vec<Taxonomy>) -> GlobalFn {
let mut taxonomies = HashMap::new();
for taxonomy in all_taxonomies {
taxonomies.insert(taxonomy.kind.name.clone(), taxonomy);
}
Box::new(move |args| -> Result<Value> {
let kind = required_arg!(
String,
args.get("kind"),
"`get_taxonomy_url` requires a `kind` argument with a string value"
);
let name = required_arg!(
String,
args.get("name"),
"`get_taxonomy_url` requires a `name` argument with a string value"
"`get_taxonomy` requires a `kind` argument with a string value"
);
let container = match kind.as_ref() {
"tag" => &tags,
"category" => &categories,
_ => return Err(
"`get_taxonomy_url` can only get `tag` or `category` for the `kind` argument".into()
let container = match taxonomies.get(&kind) {
Some(c) => c,
None => return Err(
format!("`get_taxonomy` received an unknown taxonomy as kind: {}", kind).into()
),
};

if let Some(ref c) = *container {
for item in &c.items {
if item.name == name {
return Ok(to_value(item.permalink.clone()).unwrap());
}
}
bail!("`get_taxonomy_url`: couldn't find `{}` in `{}` taxonomy", name, kind);
} else {
bail!("`get_taxonomy_url` tried to get a taxonomy of kind `{}` but there isn't any", kind);
}
return Ok(to_value(container).unwrap());
})
}

@@ -217,14 +206,14 @@ pub fn make_resize_image(imageproc: Arc<Mutex<imageproc::Processor>>) -> GlobalF

#[cfg(test)]
mod tests {
use super::{make_get_url, make_get_taxonomy_url, make_trans};
use super::{make_get_url, make_get_taxonomy, make_trans};

use std::collections::HashMap;

use tera::to_value;

use config::Config;
use taxonomies::{Taxonomy, TaxonomyKind, TaxonomyItem};
use config::{Config, Taxonomy as TaxonomyConfig};
use taxonomies::{Taxonomy, TaxonomyItem};


#[test]
@@ -268,28 +257,27 @@ mod tests {
}

#[test]
fn can_get_tag_url() {
fn can_get_taxonomy() {
let taxo_config = TaxonomyConfig {name: "tags".to_string(), ..TaxonomyConfig::default()};
let tag = TaxonomyItem::new(
"Prog amming",
TaxonomyKind::Tags,
"tags",
&Config::default(),
vec![],
);
let tags = Taxonomy {
kind: TaxonomyKind::Tags,
kind: taxo_config,
items: vec![tag],
};

let static_fn = make_get_taxonomy_url(Some(tags), None);
let static_fn = make_get_taxonomy(vec![tags.clone()]);
// can find it correctly
let mut args = HashMap::new();
args.insert("kind".to_string(), to_value("tag").unwrap());
args.insert("name".to_string(), to_value("Prog amming").unwrap());
assert_eq!(static_fn(args).unwrap(), "http://a-website.com/tags/prog-amming/");
args.insert("kind".to_string(), to_value("tags").unwrap());
assert_eq!(static_fn(args).unwrap(), to_value(&tags).unwrap());
// and errors if it can't find it
let mut args = HashMap::new();
args.insert("kind".to_string(), to_value("tag").unwrap());
args.insert("name".to_string(), to_value("random").unwrap());
args.insert("kind".to_string(), to_value("something-else").unwrap());
assert!(static_fn(args).is_err());
}



+ 0
- 1
components/templates/src/lib.rs View File

@@ -5,7 +5,6 @@ extern crate tera;
extern crate base64;
extern crate pulldown_cmark;

#[macro_use]
extern crate errors;
extern crate utils;
extern crate content;


+ 2
- 2
components/utils/src/templates.rs View File

@@ -41,8 +41,8 @@ pub fn render_template(name: &str, tera: &Tera, context: &Context, theme: &Optio
"page.html" => {
render_default_tpl!(name, "https://www.getgutenberg.io/documentation/templates/pages-sections/#page-variables")
},
"tag.html" | "tags.html" | "category.html" | "categories.html" => {
render_default_tpl!(name, "https://www.getgutenberg.io/documentation/templates/tags-categories/")
"single.html" | "list.html" => {
render_default_tpl!(name, "https://www.getgutenberg.io/documentation/templates/taxonomies/")
},
_ => bail!("Tried to render `{}` but the template wasn't found", name)
}


+ 4
- 5
docs/content/documentation/content/page.md View File

@@ -38,11 +38,10 @@ slug = ""
# It should not start with a `/` and the slash will be removed if it does
path = ""

# An array of strings allowing you to group pages with them
tags = []

# An overarching category name for that page, allowing you to group pages with it
category = ""
# A dict of taxonomies: the key is the name of the taxonomy which must match
# one of the taxonomy defined in `config.toml` and the value is a list of
# strings
[taxonomies]

# The order as defined in the Section page
order = 0


+ 0
- 23
docs/content/documentation/content/tags-categories.md View File

@@ -1,23 +0,0 @@
+++
title = "Tags & Categories"
weight = 90
+++

Gutenberg has built-in support for basic taxonomies: tags and categories.

Those taxonomies are automatically built across the whole site based on
the `tags` and `category` fields of the front-matter: you do not need to define
that a tag or a category exists. You have to set `generate_tags_pages` and/or
`generate_categories_pages` in your [config.toml](./documentation/getting-started/configuration.md).

The taxonomy pages will only be created if at least one item is found and
are available at the following paths:

```plain
$BASE_URL/tags/
$BASE_URL/tags/$TAG_SLUG
$BASE_URL/categories/
$BASE_URL/categories/$CATEGORY_SLUG
```

It is currently not possible to change those paths or to create custom taxonomies.

+ 27
- 0
docs/content/documentation/content/taxonomies.md View File

@@ -0,0 +1,27 @@
+++
title = "Taxonomies"
weight = 90
+++

Gutenberg has built-in support for taxonomies.

The first step is to define the taxonomies in your [config.toml](./documentation/getting-started/configuration.md).

A taxonomy has 4 variables:

- `name`: a required string that will be used in the URLs, usually the plural version (i.e. tags, categories etc)
- `paginate`: if this is set to a number, each term page will be paginated by this much.
- `paginate_path`: if set, will be the path used by paginated page and the page number will be appended after it.
For example the default would be page/1
- `rss`: if set to `true`, a RSS feed will be generated for each individual term.

Once this is done, you can then set taxonomies in your content and Gutenberg will pick
them up.

The taxonomy pages will only be created if at least one non-draft page is found and
are available at the following paths:

```plain
$BASE_URL/$NAME/
$BASE_URL/$NAME/$SLUG
```

+ 8
- 7
docs/content/documentation/getting-started/configuration.md View File

@@ -40,13 +40,14 @@ generate_rss = false
# The number of articles to include in the RSS feed
rss_limit = 20

# Whether to generate a tags page and individual
# tag pages for pages with tags
generate_tags_pages = false

# Whether to generate a categories page and individual
# category pages for pages with a category
generate_categories_pages = false
# The taxonomies to be rendered for that site and their configuration
# Example:
# taxonomies = [
# {name: "tags", rss: true}, # each tag will have its own RSS feed
# {name: "categories", paginate: 5}, # 5 terms per page
# ]
#
taxonomies = []

# Whether to compile the Sass files found in the `sass` directory
compile_sass = false


+ 7
- 2
docs/content/documentation/templates/pagination.md View File

@@ -3,9 +3,14 @@ title = "Pagination"
weight = 30
+++

Two things can get paginated: a section or a taxonomy term.

A paginated section gets the same `section` variable as a normal
[section page](./documentation/templates/pages-sections.md#section-variables).
In addition, a paginated section gets a `paginator` variable of the `Pager` type:
[section page](./documentation/templates/pages-sections.md#section-variables)
while a paginated taxonomy gets the a `taxonomy` variable of type `TaxonomyConfig`, equivalent
to the taxonomy definition in the `config.toml`.

In addition, a paginated page gets a `paginator` variable of the `Pager` type:

```ts
// How many items per page


+ 0
- 31
docs/content/documentation/templates/tags-categories.md View File

@@ -1,31 +0,0 @@
+++
title = "Tags & Categories"
weight = 40
+++

Tags and categories actually get the same data but with different variable names.
The default templates for those pages are the following:

- `tags.html`: list of tags, gets variable `tags` sorted alphabetically
- `tag.html`: individual tag, gets variable `tag`
- `categories.html`: list of categories, gets variable `categories` sorted alphabetically
- `category.html`: individual category, gets variable `category`

You can override any of those templates by putting one with the same name in the `templates` directory.
`tags` and `categories` both are an array of `TaxonomyItem` sorted alphabetically, while `tag` and `category`
are a `TaxonomyItem`.

A `TaxonomyItem` has the following fields:

```ts
name: String;
slug: String;
permalink: String;
pages: Array<Page>;
```

As `pages` can span many sections, the `pages` array is sorted by date.

Currently, there is no way to define different taxonomy templates per section, change
the path used for them or paginate them.


+ 53
- 0
docs/content/documentation/templates/taxonomies.md View File

@@ -0,0 +1,53 @@
+++
title = "Taxonomies"
weight = 40
+++

The default templates for the taxonomies pages are the following:

- `$TAXONOMY_NAME/single.html`
- `$TAXONOMY_NAME/list.html`

You can override any of those templates by putting one with the same path in the `templates` directory.

First, a `TaxonomyTerm` has the following fields:

```ts
name: String;
slug: String;
permalink: String;
pages: Array<Page>;
```

## Non-paginated taxonomies
If a taxonomy is not paginated, the templates get the following variables:

### Single term (`single.html`)
```ts
// The site config
config: Config;
// The data of the taxonomy, from the config
taxonomy: TaxonomyConfig;
// The current full permalink for that page
current_url: String;
// The current path for that page
current_path: String;
// The current term being rendered
term: TaxonomyTerm;
```

### Taxonomy list (`list.html`)
```ts
// The site config
config: Config;
// The data of the taxonomy, from the config
taxonomy: TaxonomyConfig;
// The current full permalink for that page
current_url: String;
// The current path for that page
current_path: String;
// All terms for that taxonomy
terms: Array<TaxonomyTerm>;
```

## Paginated taxonomies

+ 4
- 0
test_site/config.toml View File

@@ -6,5 +6,9 @@ generate_rss = true
rss_limit = 2
theme = "sample"

taxonomies = [
{name = "categories", rss = true},
]

[extra.author]
name = "Vincent Prouillet"

+ 0
- 3
test_site/templates/categories.html View File

@@ -1,3 +0,0 @@
{% for category in categories %}
{{ category.name }} {{ category.slug }} {{ category.pages | length }}
{% endfor %}

+ 3
- 0
test_site/templates/categories/list.html View File

@@ -0,0 +1,3 @@
{% for term in terms %}
{{ term.name }} {{ term.slug }} {{ term.pages | length }}
{% endfor %}

test_site/templates/category.html → test_site/templates/categories/single.html View File

@@ -1,4 +1,4 @@
{% extends "sample/templates/category.html" %}
{% extends "sample/templates/categories/single.html" %}

{% block extra_category %}
EXTENDED

test_site/themes/sample/templates/category.html → test_site/themes/sample/templates/categories/single.html View File

@@ -1,7 +1,7 @@
Category: {{ category.name }}
Category: {{ term.name }}


{% for page in category.pages %}
{% for page in term.pages %}
<article>
<h3 class="post__title"><a href="{{ page.permalink }}">{{ page.title }}</a></h3>
</article>

Loading…
Cancel
Save